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.
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"
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 var | Purpose | Default |
|---|---|---|
AIRPIPE_OTEL_ENDPOINT | OTLP HTTP endpoint | (disabled) |
AIRPIPE_OTEL_HDR_<NAME> | Add header <name> to exports (e.g. AIRPIPE_OTEL_HDR_AUTHORIZATION) | — |
AIRPIPE__OTEL_SAMPLE_RATIO | Sampling ratio 0.0–1.0 (note the double underscore) | 1.0 |
AIRPIPE__OTEL_EXPORT_TIMEOUT_SECS | Export timeout | 30 |
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 exampleGET api/users), or just<METHOD>when no route matches. Attributeshttp.method,http.route,http.response.status_codeandserver.address(the host running the engine). - Interface span
<interface>::start, withairpipe.interfaceandairpipe.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>::lookupspans for fan-out. - Outbound HTTP spans for
httpactions, named by the method (GET), withhttp.request.method,server.addressandserver.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.
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.