Qpoint Data Schema Reference

Overview

Qpoint captures network traffic data in two distinct storage layers, each with different data structures and security characteristics:

  1. EventStore: Anonymized connection metadata (summary information)

  2. ObjectStore: Complete HTTP transaction payloads (may contain sensitive data)

This separation allows you to:

  • Store metadata in observability platforms (Axiom, OTLP backends)

  • Keep sensitive payloads in your own S3-compatible storage for data sovereignty

  • Link metadata to payloads using identifiers


EventStore Schema

EventStore contains anonymized metadata about network connections and HTTP transactions. These events do not include request/response bodies or sensitive headers.

Event Types

Event Type
Purpose
Sensitive Data

connection

TCP connection lifecycle and source attribution

No

artifact_record

Reference (and summary) for each stored HTTP artifact

No

issue

Error/anomaly detection

No


Connection Event

Establishes a network session with full source attribution via eBPF. Fields are grouped under meta, tags, source, destination, and other top-level properties:

Field Reference

Identifiers:

  • meta.connectionId (string): Unique identifier for this TCP connection. Links all events for this session.

  • meta.endpointId (string): Destination domain or IP observed for this connection.

Source (your application):

  • source.address.ip / source.address.port: IP:port of the originating process.

  • source.exe: Full executable path captured via eBPF.

  • source.userId: UID of the process owner.

Destination (external service):

  • destination.address.*: IP and port of the peer endpoint.

Protocol detection & TLS probes:

  • l7Protocol: http1, http2, or other if Qtap could not parse HTTP.

  • socketProtocol: Typically tcp.

  • tlsVersion: Numeric TLS version (772 = TLS 1.3, 771 = TLS 1.2).

  • meta.tlsProbeTypesDetected: TLS libraries hooked for this flow (openssl, gotls, etc.).

Context tags:

  • tags.bin: Process or container binary (e.g., curl, tailscaled).

  • tags.host, tags.ip, tags.protocol, tags.strategy: Additional grouping metadata added by Qtap.

Traffic metrics:

  • bytesSent, bytesReceived (optional): Directional byte counts for this socket. Only present when data transfer occurs on the connection.

  • direction: Capture perspective (egress-external, egress-internal, ingress, etc.).


ArtifactRecord Event

Each stored object produces an artifact_record entry. Multiple records can share the same connectionId/requestId pair:

item.type

Description

Typical content

http_transaction

Full request+response artifact

Includes summary block with method/status/duration

req-headers, res-headers

Standalone header blobs

digest points to JSON containing only headers

req-body, res-body

Base64 body blobs

digest points to raw body object

Example (type: "http_transaction")

Field Reference

Identifiers:

  • connectionId, endpointId, requestId: Match the corresponding connection and HTTP transaction.

  • digest: Object key in your S3-compatible store (sha1 hex string).

  • url: Direct fetch URL (Qtap substitutes {{DIGEST}} into the configured access_url).

Summary (only on http_transaction records):

  • summary.connection_id (string): Connection ID matching the parent connection event

  • summary.direction (string): Traffic direction (e.g., "egress-external")

  • summary.duration_ms (number): Request duration in milliseconds

  • summary.process_exe (string): Full path to the process executable

  • summary.request_host (string): Request authority/hostname

  • summary.request_method (string): HTTP method (GET, POST, etc.)

  • summary.request_protocol (string): HTTP version (http1, http2)

  • summary.request_scheme (string): Request scheme (http, https)

  • summary.request_content_type (string, optional): Content-Type of request body (only present when request includes a body)

  • summary.response_content_type (string): Content-Type of response

  • summary.response_status (number): HTTP status code

Use summary.response_status and summary.duration_ms to filter events without fetching full payloads from ObjectStore.

Other artifact types (req-headers, res-body, etc.) do not carry a summary block—they only include digest, type, timestamp, and the URL.


Issue Event

Issues are emitted by plugins such as detect_errors and appear as flat payloads (no nested issue/context objects). Example:

Key fields:

  • error: Name of the rule or issue type (e.g., Server Errors).

  • triggerConditions / triggerReasons: Why the rule fired.

  • requestId: Use to pull the associated artifact.


ObjectStore Schema

ObjectStore contains complete HTTP transaction payloads, including headers and bodies. This data often contains:

  • Authentication tokens (JWTs, API keys)

  • Personally Identifiable Information (PII)

  • Business-sensitive data (financial info, user records)

triangle-exclamation

HttpTransaction Object

The complete HTTP request and response captured by Qtap.

Schema

circle-info

Optional Top-Level Fields: When using Docker logging drivers (e.g., with Fluent Bit), you may see additional top-level fields like container_id, container_name, and source added by the Docker logging infrastructure.

Field Reference

Metadata (Source Attribution):

  • metadata.process_id, metadata.process_exe: Process identity.

  • metadata.bytes_sent / metadata.bytes_received: Same byte counters as the connection event.

  • metadata.connection_id, metadata.endpoint_id: Identifiers for correlation.

  • Optional fields (only when Qtap observes them): metadata.container_name, metadata.pod_name, etc. These were not present in the observed captures but can appear in containerized/Kubernetes deployments.

Request:

  • request.method (string): HTTP method

  • request.url (string): Complete URL

  • request.scheme (string): http or https

  • request.path (string): URL path

  • request.authority (string): Host header

  • request.protocol (string): HTTP version (http1, http2)

  • request.request_id (string): Unique transaction ID

  • request.user_agent (string): User-Agent header

  • request.content_type (string): Content-Type header value (when request has a body)

  • request.headers (object): All request headers (including Authorization)

  • request.body (string): Base64-encoded request body (present when request includes body)

circle-exclamation

Response:

  • response.status, response.headers, response.body (base64). Body may be absent when capture level < full.

Timing & Direction:

  • transaction_time (string): ISO 8601 timestamp with nanosecond precision

  • duration_ms (number): Request duration in milliseconds

  • direction (string): Traffic direction (see Connection Event)

Decoding Bodies

Request and response bodies are base64-encoded to safely handle binary data:


Capture Levels

Qtap provides four capture levels that control what data appears in the HttpTransaction object:

Level
Description
Includes
Use Case

none

No capture

Nothing

Disabled capture (can use with rules for selective capture)

summary

Basic info

metadata, request.method/url/status, duration_ms

High-level traffic monitoring

details

With headers

Everything in summary + request.headers + response.headers

Debugging without exposing bodies

full

Complete

Everything including request.body + response.body

Deep troubleshooting, audit trails

Example Configuration


Key Relationships

Identifier Hierarchy

connectionId: Links all events for a single TCP connection

  • One TCP connection can carry multiple HTTP requests (HTTP keep-alive)

  • Useful for correlating requests from the same socket

endpointId: The destination domain (e.g., "api.example.com")

  • NOT the source - this is the external service being called

  • Useful for grouping requests by destination

requestId: Unique per HTTP transaction

  • One-to-one mapping to HttpTransaction object

  • Primary key for correlating EventStore → ObjectStore

Source vs Destination

Critical distinction:

Field
Represents
Contains
Captured Via

Source

Your application

Process, container, pod, user details

eBPF syscall hooks

Destination

External service

IP address, port, resolved hostname

Network layer

Why source has more detail:

  • Qtap uses eBPF to hook into the source process's system calls

  • Full process context (exe path, user, container ID) available via kernel

  • Destination is just an IP:port visible from network packets


Direction Values

The direction field indicates traffic flow relative to Qtap's capture point:

Value
Description
Example

egress

All outbound traffic

Any request leaving your application

egress-external

Outbound to external networks

API calls to public internet

egress-internal

Outbound to internal networks

Service-to-service calls within cluster

ingress

Inbound traffic

Requests received by your server

all

Bidirectional

Capture both ingress and egress

Configure in qtap.yaml:


Protocol Detection

L7 Protocol Values

The l7Protocol field indicates whether Qtap successfully parsed the traffic as HTTP:

Value
Meaning
What You Get

http1

HTTP/1.1 successfully parsed

✅ Connection Event + HttpTransaction + ArtifactRecord

http2

HTTP/2 successfully parsed

✅ Connection Event + HttpTransaction + ArtifactRecord

other

Non-HTTP protocol or parsing failed

⚠️ Connection Event only (no HTTP parsing)

Understanding l7Protocol: "other"

When you see l7Protocol: "other", Qtap detected a TCP connection but could not parse it as HTTP. This is expected and normal for non-HTTP protocols:

Common Protocols That Show as "other":

  • Database connections (MySQL port 3306, PostgreSQL port 5432, MongoDB port 27017, Redis port 6379)

  • SSH connections (port 22)

  • SMTP/email traffic (ports 25, 465, 587)

  • Custom binary protocols

  • gRPC with binary protobuf payloads (HTTP/2 framing detected, but content is binary)

  • DNS over HTTPS/TLS (HTTPS connection, but not standard HTTP request/response pattern)

What You Still Get:

  • Connection Event with full metadata

  • Process Attribution: Exact executable path (source.exe)

  • Byte Counts: bytesSent and bytesReceived

  • TLS Detection: tlsVersion and tlsProbeTypesDetected (when applicable)

  • Endpoint: Destination IP/domain (endpointId)

What You Don't Get:

  • ❌ HttpTransaction object (no request/response parsing)

  • ❌ ArtifactRecord events

  • ❌ Request headers, bodies, or application-level data

Troubleshooting HTTP Traffic Showing as "other":

If you expect HTTP traffic but see l7Protocol: "other":

  1. Check tlsProbeTypesDetected - Is TLS detected? If empty, qtap may not have hooked the TLS library

  2. Check gotProtocolEvent: true - Was protocol detection attempted?

  3. Enable --bpf-trace for syscall-level debugging

  4. Verify the application uses a supported TLS library (OpenSSL, Go TLS, Java SSL, Node TLS)

TLS Detection

  • is_tls: true - HTTPS traffic detected

  • tls_version: 772 - TLS 1.3 (771 = TLS 1.2)

  • tls_sni: "api.example.com" - Server Name Indication from handshake

  • tls_probe_types_detected: ["openssl"] - OpenSSL library hooks attached

Supported TLS libraries:

  • openssl - OpenSSL library (all versions)

  • gotls - Go's native TLS implementation (Pro version)

  • javassl - Java SSL/TLS implementation (Pro version)

  • nodetls - Node.js TLS implementation (Pro version)


Complete Example: Correlating Events

Scenario

Your application makes a POST request that returns a 500 error. Here's how the data flows:

1. Connection Event (EventStore)

2. Issue Event (EventStore)

3. ArtifactRecord Event (EventStore)

4. HttpTransaction Object (ObjectStore, retrieved from S3)

Query Pattern


Best Practices

Data Storage

  1. EventStore → Observability Platform

    • Axiom, Datadog, Honeycomb, etc.

    • Safe for third-party platforms (no sensitive data)

    • Enables dashboards, alerts, and real-time monitoring

  2. ObjectStore → Your S3

    • MinIO, AWS S3, Google Cloud Storage

    • Keep sensitive data in your infrastructure

    • Set TTL policies (recommended: 30-90 days)

Querying Strategy

  1. Query EventStore first (fast, indexed)

    • Find relevant connections/requests by metadata

    • Filter by status codes, endpoints, duration, etc.

  2. Fetch from ObjectStore only when needed (slower, S3 API calls)

    • Retrieve full payloads for specific incidents

    • Analyze auth tokens, request bodies, error details

  3. Use identifiers to correlate

    • connection_id: Group all requests from same TCP session

    • request_id: Link metadata to payload

    • endpoint_id: Filter by destination domain

Security Considerations

  • Never log ObjectStore data to stdout in production

  • Set appropriate S3 bucket policies (private, encrypted)

  • Use IAM roles, not static credentials

  • Implement TTL/lifecycle policies to auto-delete old data

  • Audit access to S3 payloads (contains auth tokens)

Performance Optimization

  • Use capture levels strategically:

    • summary by default (low overhead)

    • full only for errors or specific endpoints (via rules)

  • Filter noisy traffic at capture time (process filters, direction settings)

  • Batch S3 uploads with Fluent Bit for cost efficiency


Troubleshooting

Missing Fields

Problem: Expected fields not present in event

Solutions:

  • Container fields only present when running in Docker/containerd

  • Pod fields only present when running in Kubernetes

  • user/user_id only available with sufficient permissions

l7Protocol: "other"

Problem: HTTP parsing failed, no HttpTransaction created

Diagnostics:

  1. Check tlsProbeTypesDetected - Empty array means TLS library not hooked

  2. Check gotProtocolEvent: false - Protocol detection didn't run

  3. Enable --bpf-trace="mod:socket,exe.contains:yourapp" for syscall traces

Common causes:

  • Non-standard HTTP libraries

  • Custom TLS wrappers

  • Binary not using OpenSSL/BoringSSL

Empty Bodies

Problem: request.body or response.body is empty string

Check capture level:

  • Must be level: full to capture bodies

  • level: headers only captures headers

  • level: summary captures neither

Verify with rules:


Additional Resources

Last updated