> For the complete documentation index, see [llms.txt](https://docs.qpoint.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.qpoint.io/appendix/healthy-capture-patterns.md).

# What a Healthy Capture Looks Like

This guide shows what **successful Qtap captures look like** for different binaries and scenarios. Use these patterns as a reference when troubleshooting capture issues.

## Understanding Healthy Captures

A **healthy Qtap capture** successfully:

1. ✅ Detects the TLS handshake (SNI, TLS version)
2. ✅ Identifies the HTTP protocol (http1, http2, http3)
3. ✅ Captures process metadata (PID, binary path)
4. ✅ Parses HTTP request/response headers and body
5. ✅ Reports accurate byte counts and duration

**Key indicator**: `"l7Protocol": "http1"` or `"http2"` (NOT `"other"`)

***

## Quick Reference: Healthy Capture Checklist

When reviewing Qtap logs, a healthy capture shows:

* [ ] TLS handshake detected (for HTTPS): `"SNI": "domain.com"`
* [ ] Protocol identified: `"l7Protocol": "http1|http2|http3"`
* [ ] TLS probes attached: `"tlsProbeTypesDetected": ["openssl", ...]`
* [ ] Data captured: `"dataEventCount": > 0`
* [ ] Bytes transferred: `"bytesSent": > 0`, `"bytesReceived": > 0`
* [ ] HTTP transaction JSON present with full request/response
* [ ] Connection report shows: `"gotProtocolEvent": true`

**If ANY of these are missing, investigate further with `--bpf-trace`.**

***

## curl: HTTP/2 over HTTPS

### Complete HTTP Transaction JSON

```json
{
    "metadata": {
        "process_id": "160239",
        "process_exe": "/usr/bin/curl",
        "bytes_sent": 41,
        "bytes_received": 395,
        "connection_id": "d3t55gg7p3qr49f8485g",
        "endpoint_id": "httpbin.org"
    },
    "request": {
        "method": "GET",
        "url": "https://httpbin.org/get",
        "scheme": "https",
        "path": "/get",
        "authority": "httpbin.org",
        "protocol": "http2",
        "request_id": "d3t55gg7p3qr49f84870",
        "user_agent": "curl/8.10.1",
        "headers": {
            ":authority": "httpbin.org",
            ":method": "GET",
            ":path": "/get",
            ":scheme": "https",
            "Accept": "*/*",
            "User-Agent": "curl/8.10.1"
        }
    },
    "response": {
        "status": 200,
        "content_type": "application/json",
        "headers": {
            ":status": "200",
            "Access-Control-Allow-Credentials": "true",
            "Access-Control-Allow-Origin": "*",
            "Content-Length": "255",
            "Content-Type": "application/json",
            "Date": "Thu, 23 Oct 2025 16:07:40 GMT",
            "Server": "gunicorn/19.9.0"
        },
        "body": "ewogICJhcmdzIjoge30sIAog..."
    },
    "transaction_time": "2025-10-23T16:07:41.023379679Z",
    "duration_ms": 10731,
    "direction": "egress-external"
}
```

### Debug Log Indicators (curl)

**TLS Handshake Detection:**

```
processing tls handshake event
  "exe": "/usr/bin/curl"
  "SNI":"httpbin.org"
  "Version":772     # TLS 1.3
  "ALPNs":["h2","http/1.1"]
```

**Protocol Detection:**

```
processing protocol event
  "exe": "/usr/bin/curl"
  "Protocol":"http2"
  "IsTLS":true
```

**Connection Metadata:**

```
event store submission
  "l7Protocol":"http2"     ✅ NOT "other"
  "tlsProbeTypesDetected":["openssl","openssl",...]
  "tlsVersion":772
  "bytesSent":901
  "bytesReceived":4867
```

**Connection Report:**

```
connection report
  "gotTLSClientHelloEvent": true     ✅
  "gotProtocolEvent": true            ✅
  "dataEventCount": 6                 ✅ Non-zero
  "handler": "raw"
  "strategy": "observe"
```

***

## wget: HTTP/1.1 over HTTPS

### Debug Log Indicators (wget)

**TLS Handshake:**

```
processing tls handshake event
  "exe": "/usr/bin/wget"
  "SNI":"httpbin.org"
  "Version":772
  "ALPNs":null     # wget doesn't advertise ALPN
```

**Protocol Detection:**

```
processing protocol event
  "exe": "/usr/bin/wget"
  "Protocol":"http1"     ✅ HTTP/1.1 detected
  "IsTLS":true
```

**HTTP Request Captured:**

```
http request
  "exe": "/usr/bin/wget"
  "protocol": "http1"
  "is_tls": true
  "request": {
    "Method":"GET"
    "RequestURI":"/headers"
    "Proto":"HTTP/1.1"
    "Host":"httpbin.org"
    "Headers": {
      "Accept":["*/*"]
      "User-Agent":["Wget/1.25.0"]
      "Connection":["Keep-Alive"]
    }
  }
```

**HTTP Response Captured:**

```
http response
  "exe": "/usr/bin/wget"
  "protocol": "http1"
  "status_code": 200
  "status": "OK"
  "version": "HTTP/1.1"
```

***

## Python requests: HTTP/1.1 over HTTPS

### Debug Log Indicators (Python)

**TLS Handshake:**

```
processing tls handshake event
  "exe": "/usr/local/bin/python3.11"
  "SNI":"httpbin.org"
  "Version":772
```

**Protocol Detection:**

```
processing protocol event
  "exe": "/usr/local/bin/python3.11"
  "Protocol":"http1"
  "IsTLS":true
```

**HTTP Transaction:**

```
http request
  "exe": "/usr/local/bin/python3.11"
  "protocol": "http1"
  "is_tls": true
  "request": {
    "Method":"GET"
    "Host":"httpbin.org"
    "Headers": {
      "User-Agent":["python-requests/2.31.0"]
      "Accept-Encoding":["gzip, deflate"]
    }
  }
```

***

## Debug Log Patterns

### Healthy Capture Sequence

1. **Socket Connection**

   ```
   socket connect event
     "conn_id": "..."
     "cookie": 12345
     "exe": "/usr/bin/curl"
   ```
2. **TLS Detection** (for HTTPS)

   ```
   processing tls handshake event
     "SNI": "example.com"
     "Version": 772  # TLS 1.3
   ```
3. **Protocol Detection**

   ```
   processing protocol event
     "Protocol": "http2" | "http1"
     "IsTLS": true
   ```
4. **HTTP Capture**

   ```
   object store submission
     "artifact": {
       "type": "http_transaction"
       "contentType": "application/json"
       "bytes": 1237
     }
   ```
5. **Connection Finalization**

   ```
   socket close event
     "write_bytes": 901
     "read_bytes": 4867

   connection report
     "gotTLSClientHelloEvent": true
     "gotProtocolEvent": true
     "dataEventCount": 6
   ```

### Key Fields to Check

#### ✅ Success Indicators

* `"l7Protocol": "http1"` or `"http2"` (NOT "other")
* `"tlsProbeTypesDetected": ["openssl", ...]` for HTTPS
* `"gotTLSClientHelloEvent": true` for HTTPS
* `"gotProtocolEvent": true`
* `"dataEventCount": > 0`
* `"bytesSent": > 0` and `"bytesReceived": > 0`

#### ❌ Failure Indicators

* `"l7Protocol": "other"` - HTTP parsing failed
* `"gotProtocolEvent": false` - Protocol not detected
* `"dataEventCount": 0` - No data captured
* `"write_bytes": 0, "read_bytes": 0` - No traffic seen

***

## BPF Trace Patterns

### When to Use BPF Trace

Use `--bpf-trace` for **deep troubleshooting** of capture issues. See [BPF Trace - Advanced Debugging](/appendix/bpf-trace.md) for complete details.

```bash
--bpf-trace="mod:socket,exe.contains:curl"
```

**What it shows:**

* Individual syscall invocations (read, write, writev)
* File descriptor (FD) numbers per operation
* Data transfer sizes per syscall
* TLS/SSL detection decisions per-FD

### Healthy BPF Trace Example (curl)

#### Connection Metadata

```
event store submission
  "connectionId": "d3t57dg7p3qra5r14cg0"
  "endpointId": "httpbin.org"
  "tlsProbeTypesDetected": ["openssl","openssl","openssl","openssl","openssl"]
  "l7Protocol": "http2"     ✅
  "tlsVersion": 772
  "socketProtocol": "tcp"
  "bytesSent": 901
  "bytesReceived": 4867
```

#### HTTP Transaction Artifact

```
object store submission
  "artifact": {
    "type": "http_transaction"
    "contentType": "application/json"
    "bytes": 1237
    "connectionId": "d3t57dg7p3qra5r14cg0"
    "endpointId": "httpbin.org"
  }
```

***

## Troubleshooting: What to Look For

### Problem: HTTP Parsing Fails (`l7Protocol: "other"`)

**Check:**

1. Was TLS detected? Look for `tlsProbeTypesDetected`
2. Was protocol detected? Check `gotProtocolEvent: true`
3. Was data captured? Check `dataEventCount > 0`

**Common causes:**

* Non-standard HTTP libraries (custom TLS wrappers)
* Binary not using OpenSSL/BoringSSL (see `tlsProbeTypesDetected`)
* Compression or encryption before TLS layer

### Problem: No Capture at All

**Check:**

1. Is process filtered? Look for filter matches in debug logs
2. Is Qtap running? Check for `eBPF program loaded and listening`
3. Is traffic direction captured? Verify `direction` config matches traffic

**Debug command:**

```bash
docker logs qtap-container 2>&1 | grep -E "exe|protocol|l7Protocol"
```

### Problem: Missing Headers or Body

**Check capture level:**

* `none`: No capture
* `summary`: Basic info only (no headers/body)
* `details`: Headers included (no body)
* `full`: Everything (headers + body)

**Verify plugin config:**

```yaml
plugins:
  - type: http_capture
    config:
      level: full     # Must be 'full' to see body
```

### Problem: Zero Bytes Captured

**Check:**

1. Connection report: `write_bytes` and `read_bytes` should be > 0
2. Socket close event: Should show non-zero byte counts
3. BPF trace: Look for syscall data transfer events

**Common causes:**

* Qtap started **after** traffic (must start before)
* Connection reused from before Qtap started
* Traffic on different network interface

***

## Additional Resources

* **BPF Trace Deep Dive**: See [BPF Trace - Advanced Debugging](/appendix/bpf-trace.md) for complete BPF trace field reference
* **Configuration Examples**: See [Configuration Examples](/getting-started/qtap/configuration/configuration-examples.md)
* **Traffic Processing with Plugins**: See [Traffic Processing with Plugins](/getting-started/qtap/configuration/traffic-processing-with-plugins.md)
