Skip to main content

OpenTelemetry tracing

Air Pipe emits distributed traces with zero code when run as the self-hosted binary. Point it at any OTLP collector and you get spans for every request, interface, action, lookup and outbound HTTP call, with W3C trace-context propagation to upstreams.

note

Trace export needs engine 3.11.2 or later. Earlier versions logged failed to initialize OTel tracer — tracing disabled with Exporter build error: no http client specified at startup and sent nothing.

Enable it​

Supply your collector endpoint via env var or flag:

AIRPIPE_OTEL_ENDPOINT="http://localhost:4318/v1/traces" ./airpipe server
# or
./airpipe server --otel-endpoint "http://localhost:4318/v1/traces"
warning

The exporter uses OTLP over HTTP/protobuf, not gRPC. Point it at your collector's HTTP port (commonly 4318, path /v1/traces) — not the gRPC 4317 port, or no traces will arrive. A malformed endpoint now fails to initialize with a logged error (engine ≥ 1.7.2); but a collector that's simply unreachable at runtime drops spans silently (OTLP batches in the background), so still verify spans land in your backend.

Configuration​

Env varPurposeDefault
AIRPIPE_OTEL_ENDPOINTOTLP HTTP endpoint(disabled)
AIRPIPE_OTEL_HDR_<NAME>Add header <name> to exports (e.g. AIRPIPE_OTEL_HDR_AUTHORIZATION)—
AIRPIPE__OTEL_SAMPLE_RATIOSampling ratio 0.0–1.0 (note the double underscore)1.0
AIRPIPE__OTEL_EXPORT_TIMEOUT_SECSExport timeout30
AIRPIPE_OTEL_ENDPOINT="https://otel.example.com/v1/traces" \
AIRPIPE_OTEL_HDR_AUTHORIZATION="Basic 123==" \
AIRPIPE__OTEL_SAMPLE_RATIO=0.25 \
./airpipe server

Resource identity is service.name=airpipe-api with the binary's service.version.

What gets traced​

  • HTTP root span per request, named <METHOD> <route> (for example GET api/users), or just <METHOD> when no route matches. Attributes http.method, http.route, http.response.status_code and server.address (the host running the engine).
  • Interface span <interface>::start, with airpipe.interface and airpipe.run_uuid (the same run id the editor's captured traces show, so you can find one from the other).
  • Action spans: one per action, named after it, a <action>:<attempt> span per attempt, and <action>::lookup spans for fan-out.
  • Outbound HTTP spans for http actions, named by the method (GET), with http.request.method, server.address and server.port.

Spans never carry the request path or an outbound URL. Both can hold secrets or personal data (an api_key in a query string, a token in a path), so spans are named by method and route template instead.

Trace context is propagated to http actions, so upstream services on the same standard continue the trace. An incoming traceparent header is honoured: the request's root span joins the caller's trace.

In CLI mode, spans are exported before the process exits.

note

With the fast path on (AP_FASTPATH=1), actions it runs have no spans of their own. The request, interface and outbound HTTP spans are still exported, in one trace.

Quick local test (Jaeger)​

docker run --rm -p 16686:16686 -p 4318:4318 jaegertracing/all-in-one
AIRPIPE_OTEL_ENDPOINT="http://localhost:4318/v1/traces" ./airpipe server
# open http://localhost:16686

See also Metrics for Prometheus.