Use Cases#
tinytap attaches to a process’s socket syscalls and libssl uprobes and
decodes what it sees as HTTP/1.1; see
How It Works for the mechanism. That
gives it a few concrete uses beyond “watch traffic go by.”
See exactly what your app sent, including over HTTPS#
An app makes an HTTPS call and you need to know precisely what went out: the
request line, every header (including Authorization), the JSON body as
sent. Normally that means a proxy (mitmproxy, Charles) with a CA certificate
installed in the app’s trust store, which is extra setup and doesn’t work at
all against apps that pin certificates.
tinytap reads the outgoing payload (the process’s write/sendmsg, before
TLS encrypts it) directly via libssl uprobes, so there’s no proxy and no CA
cert to install. See
TLS Compatibility for which TLS stacks
that covers.
flowchart LR
A["App"] -->|"plaintext"| L["libssl"]
L -->|"encrypted"| S["Server"]
L -.->|"uprobe reads the plaintext\nbefore encryption"| T["tinytap"]Check what a third-party SDK or library actually sends#
Client libraries retry, add headers, or rewrite requests in ways their docs
don’t fully spell out. Rather than reading the library’s source to guess,
tinytap shows the literal bytes it puts on the wire: how many requests a
“single” call actually issues, which header it sends for auth, whether a
retry changes the request at all.
flowchart LR
Code["your code\nclient.get(url)"] --> SDK["SDK"]
SDK -->|"request #1"| Server
SDK -.->|"retry: request #2"| Server
T["tinytap"] -.->|"captures every request the SDK actually sends"| SDKDiagnose a request that never got a response#
A client reports a hang or a failure with no clear cause, and you own the
server it’s calling but can’t see why it never answered. Run tinytap on
the server, attached to the process handling the request (any of the
servers on the Server Compatibility
list works). peer closed and timeout are two different failures wearing
the same symptom, and from the server’s own socket they’re easy to tell
apart.
timeout means the server read the request and then never called write
on that connection for 30 seconds straight: the request arrived, the
server just never got back to it. That points squarely at the server
process itself, stuck processing, deadlocked, or blocked on a downstream
call that never returns, and since tinytap is already running on that
host, you’re straight into the process with no need to reproduce the
failure somewhere else.
peer closed means the connection died before the server ever wrote a
response. The caller (client, or a load balancer/proxy in between) gave up
and disconnected first. tinytap also reports how long the connection
stayed open before that happened: closed after 5 seconds points at a
specific timeout configured somewhere upstream of the server; closed
instantly suggests the server’s handler errored out without writing
anything back at all.
Either way, the line also carries the exact request that went unanswered (method, path, every header) without adding a single log line to the server.
sequenceDiagram
participant Client
participant Server
Note over Server: tinytap attaches here
Client->>Server: request
alt normal
Server-->>Client: response (status code)
else timeout
Note over Server: 30s pass, Server never calls write()
Note over Server: ABANDONED (timeout): Server itself is stuck
else peer closed
Client--xServer: caller disconnects first
Note over Server: ABANDONED (peer closed): Server never got to answer
endDebug traffic across container boundaries without a sidecar#
eBPF probes attach at the kernel, so tinytap sees every process on the
host, containerized or not, with no sidecar container and no proxy injected
into the pod. Run it on the host and it captures traffic for containers
running there too; see Where tinytap Runs
for the container story in full.
flowchart TB
subgraph Host["Host kernel"]
Tinytap["tinytap"]
subgraph C1["Container A"]
App1["App"]
end
subgraph C2["Container B"]
App2["App"]
end
end
App1 -.->|"socket syscalls"| Tinytap
App2 -.->|"socket syscalls"| TinytapInspect an incoming webhook payload without adding logging#
A third-party service (GitHub, Stripe, PagerDuty) posts a webhook to your server and something is off: an event that should have triggered a handler didn’t, or the payload looks different from what the docs describe. You need to see exactly what arrived: the path, every header, the body.
The usual move is to add a log statement, redeploy, and then reproduce the
event. Reproducing a webhook event often means manually triggering the
upstream action (merging a PR, making a test payment) and waiting. tinytap
attaches to the already-running server process and shows the incoming request
the moment it arrives, with no code change and no restart required.
tinytap captures the payload before any middleware, body parser, or
framework layer touches it: plaintext connections via socket syscalls, and
TLS connections via libssl uprobes (see
TLS Compatibility for which stacks that
covers). That makes it useful precisely when you’re not sure whether the
problem is in what arrived or in how your code handled it.
sequenceDiagram
participant GH as GitHub
participant Server as Your server
Note over Server: tinytap attaches here
GH->>Server: POST /webhooks/github (push event)
Note over Server: tinytap captures the incoming request as the process reads itSpot-check traffic without touching the app#
Sometimes you just want to confirm “did that request actually go out, and
what came back” during local development, without adding a logging
statement, restarting the app, or reaching for a full debugger. tinytap
attaches to an already-running process and starts showing traffic
immediately; no app changes, no restart required.
flowchart LR
A["app already running"] --> B["tinytap attaches"]
B --> C["traffic shows up immediately"]
B -.->|"no code change, no restart"| A