AppScope sees a copy of all the application data coming in and out of the wire, in clear text. AppScope has basic protocol support to understand if a flow is HTTP data, and it understands enough of the protocol (in HTTP 1.1 only, today) to emit events about HTTP activity. AppScope understands HTTP status codes and endpoints, and it allows for custom header extractions.
AppScope can do this because it runs in userland, inside the application. It interposes itself not just between the application and system calls, but also between the application and TLS libraries. In Java, we insert some byte code instrumentation to interpose TLS inside the JVM. We interpose between most TLS implementations, like OpenSSL and GnuTLS.
Let's see it in action. We have nginx
running locally, you might remember. Let's scope
the popular http utilty curl
.
Scoping curls
- In Terminal 1, run:
scope curl -so /dev/null http://localhost/
scope events
From the results, we can see curl
doing a lot of things, including opening openssl configs, /etc/hosts
, and more. We can see a network connection to localhost on port 80, and most importantly we can see an HTTP request and response event. Let's see the HTTP response in more detail.
HTTP Event Details
- In Terminal 1, run:
scope events $(scope events -s http.resp -j | jq -r .Id | head -1)
AppScope exposes a ton of information here. HTTP Version, Host, Method, Content Length, Endpoint, User Agent, Source & Destination IPs & Ports, and Duration. With this basic information, we can understand a lot about an application's performance. Response time by endpoint. Error rates by host. In agent deployments, environment variables can help expand the dimensionality of this data, helping expose application information by service, tag, or other metadata.
Many approaches can do this with HTTP in clear text. What if it's encrypted on the wire? We can do that too.
HTTP Event Details
- In Terminal 1, run:
scope curl -kso /dev/null https://localhost/
scope events $(scope events -s http.resp -j | jq -r .Id | head -1)
Now we see the same event details, but this time notably http.scheme
is https
. Next, let's prove that this works on some Internet site we don't own and works with a different command. Let's use a different common HTTP utility, wget
, instead and request a page over the Internet. Donn, our lead engineer, likes to demo with wttr.in
, which returns your local weather. We're based in San Francisco, so let's get our local weather:
HTTP Event Details
- In Terminal 1, run:
scope run -p -- wget -q -O /dev/null https://wttr.in/94105
scope events $(scope events -s http.resp -j | jq -r .Id | head -1)
Now we see that our http.user_agent
and proc
have changed, and we're still https
scheme with a new http.target
. Since we ran scope
with payloads on, let's see what came through the wire.
HTTP Event Payloads
- In Terminal 1, to see the request, run:
scope flows $(scope flows | tail -n 1 | awk '{ print $1 }') --out
- To see the response, still in Terminal 1, run:
scope flows $(scope flows | tail -n 1 | awk '{ print $1 }') --in
Pretty cool! We can easily grab payload data from any unmodified binary. This also works with statically linked languages, including Go. We've included a simple Go HTTPS Client in this sandbox.
Static Binaries
- In Terminal 1, to see the source code for our HTTP client:
bat https.go
- To run the compiled binary and see the payload:
scope run -p -- ./goHttps >/dev/null
scope flows $(scope flows | tail -n 1 | awk '{ print $1 }') --in
Lastly, AppScope is designed to work with everything. We've included HTTPS clients in Java, Python, Perl, Go, and also curl
and wget
. scope
will see HTTP events from all of them.
Works with Everything
- In Terminal 1, to see what HTTP clients we're running, execute:
bat https.sh
- Still in Terminal 1, run all the HTTPS clients:
scope ./https.sh
scope events -t http
Next Steps
With HTTP-level visibility, we can see into our applications and understand what they're doing in terms of accepting and making HTTP requests. No need for proxies or new SDKs or modifying your runtime configurations. Simply prepend scope
and you'll immediately see HTTP-level data.
Next, we'll walk through some capabilities of visualizing data in the scope
CLI.