v1.1.0
[1.1.0] — 2026-05-24
Adds opt-in OpenTelemetry tracing. Off by default — a zero-allocation no-op until an OTLP endpoint or exporter is configured.
Added
- OpenTelemetry tracing (issue #49): new public
observabilitypackage (stableProvider/Span/Exporter/Eventseam +gen_ai.*/ferro.*attribute constants) backed by aninternal/otelOTLP pipeline (gRPC + HTTP/protobuf, W3C propagation). EachRoute()/RouteStream()emits agateway.requestspan carrying model, token-usage, cost, and routing attributes; plugins and MCP tool calls emit child spans; outbound provider calls areotelhttp-instrumented. - Unified trace ID: the OTel
trace_id, log trace ID,X-Request-IDheader, andferro.gateway.trace_idattribute are identical per request (customIDGeneratoradopting the logging trace ID). Holds for self-originated requests too; embedders bypassinglogging.Middlewareget a consistent independent ID. - Privacy levels:
observability.tracing.privacy_level—none(records only"redacted"),metadata(default; redacts email/JWT/AWS keys viainternal/redact), orfull(raw error text). Validated at config load. - Exporter event pathway: registered exporters receive
gateway.request.completed/failedevents, configured via the newobservability.exportersblock (non-fatal on unknown/failing exporters). Contract + wiring only — no built-in exporters ship here; vendor bridges live in the forthcomingai-gateway-pluginsrepo. - Config:
ObservabilityConfig/TracingConfig/ExporterConfig(endpoint, protocol, sample_ratio, privacy_level, shutdown_grace) ingateway.Config;OTEL_*env vars take precedence. NewGateway.SetObservability/Observabilityaccessors. - OTLP exporter headers:
observability.tracing.headers(values support${ENV}interpolation) enables authenticated OTLP export to managed backends (Datadog, New Relic, Honeycomb, …). The standardOTEL_EXPORTER_OTLP_HEADERSenv var also applies. The endpoint scheme selects transport security —https://uses TLS, whilehttp://or a barehost:portconnects in plaintext.
Changed
internal/logging.Middlewaretrace-ID precedence: existing context ID → inboundX-Request-ID→ freshly generated.internal/transport.Manager.DefaultTransportandProviderPool.Transportnow return the raw*http.Transport(the clientRoundTripperis theotelhttpwrapper) — inspect via these accessors.
Documentation
- New Observability section in both README.md and README.zh-CN.md (Jaeger quickstart, config, OTLP headers, endpoint TLS, privacy levels, plugin exporters);
config.example.{yaml,json}and ROADMAP updated for the OTel scope.
Full changelog: https://github.com/ferro-labs/ai-gateway/blob/v1.1.0/CHANGELOG.md