Skip to content

OpenTelemetry

Opt-in OTLP export of traces, metrics, and logs to your own collector or backend.

Updated View as Markdown

shunt can export traces, metrics, and logs over OTLP/HTTP to your own OpenTelemetry Collector (or any OTLP-compatible backend). It is opt-in and off by default — with no [otel] section, nothing leaves the machine — and runs independently of Sentry, so you can enable either or both.

This page is about shunt’s own telemetry, going out. The gateway’s separate telemetry ingest handles the opposite direction: OTLP payloads that managed Claude Code clients send to shunt, relayed verbatim to the destinations in [server.gateway.telemetry]. The two are configured independently and may target different collectors.

Enable it

One key turns it on — point it at your Collector’s OTLP/HTTP receiver:

[otel]
endpoint = "http://localhost:4318"   # OTLP/HTTP base URL; shunt appends /v1/{traces,metrics,logs}

Everything else has a sensible default:

[otel]
endpoint = "http://localhost:4318"
service_name = "shunt"     # (default) service.name resource attribute
environment = "prod"       # optional deployment.environment.name
sample_ratio = 1.0         # (default) head-based trace sampling, 0.0–1.0
traces = true              # (default) export request spans
metrics = true             # (default) export usage metrics
logs = true                # (default) export log events (stderr logs unaffected)
include_session_id = false # (default) keep the client session id off spans

[otel.headers]             # optional per-request headers, e.g. a hosted-collector token
authorization = "Bearer <token>"

Setting endpoint = "" (e.g. SHUNT_OTEL__ENDPOINT="") disables export again without deleting the section. An invalid endpoint, a non-http(s) URL, or an out-of-range sample_ratio is a startup error, so a typo can’t silently drop every export.

The three signals

Signal What’s exported Notes
Traces The per-request proxy_request span (and codex_endpoint_request on the inbound Codex endpoint), tagged with gen_ai.request.model, shunt.provider, http.response.status_code, and otel.status_code (error on a 5xx response, or on a streaming request that fails mid-stream after a 200 header — an event: error frame or a connection cut before a terminal event, issue #287) Head-based sampling via sample_ratio. Low-cardinality; no request/response bodies, headers, or credentials.
Metrics The low-cardinality series listed below The same series shunt sends to Sentry when [sentry] metrics = true.
Logs shunt’s tracing log events, bridged to OTLP The stderr logs are unaffected.

Each signal toggles independently via traces / metrics / logs.

Metric series

Series Type Attributes Meaning
shunt.requests Counter provider, model, http.response.status_code Proxied inference requests.
shunt.latency Histogram (ms) provider, model, http.response.status_code Header latency for streams; full latency otherwise.
shunt.ttft Histogram (ms) provider, model Request start to the first SSE body chunk.
shunt.stream_outcome Counter provider, model, outcome One final SSE result: completed, error_event, upstream_cut, or client_disconnect.
shunt.tokens Counter provider, model, kind Last reported streaming token usage (input, output, cache_read, cache_creation). Non-streaming usage is not recorded.
shunt.codex_continuation Counter provider, outcome Codex WebSocket continuation hit or fallback.
shunt.codex_ws_overflow Counter provider, outcome Codex WebSocket dedicated overflow connection opened or ceiling-refused for a concurrent turn (issue #248).
shunt.codex_client_events Counter event Codex CLI analytics events by sanitized event name; payloads and properties are discarded.
shunt.gateway_telemetry_ingest Counter signal, outcome Inbound gateway OTLP payloads (metrics/logs/traces) by ingest outcome: relayed, discarded when no destination opted in, shed when the in-flight relay limit was saturated, or rejected for a bad bearer or over-cap body.
shunt.upstream_retries Counter provider, reason Bounded transient upstream retries.
shunt.failover Counter provider, state Ordered-upstream failover transitions: attempted, advanced, or exhausted.
shunt.requests_shed Counter Inbound requests rejected at the max_concurrent_requests limit. The rejection itself is logged only at debug!, so this counter is what makes a saturated gateway visible.
shunt.pool.quota_utilization Gauge provider, window Minimum utilization across enabled, observed, non-expired quota values for 5h, 7d, or 7d_oi.
shunt.pool.rotations Counter provider, reason Moves off an account and requests that exhaust the pool.
shunt.pool.reprobes Counter provider Reprobes committed at first HTTP dispatch for stale near-quota Codex/ChatGPT accounts; WebSocket-enabled providers count inbound HTTP probes only.
shunt.upstream.status Gauge provider Observed [server.status] Statuspage severity: 0 none, 1 minor, 2 major, 3 critical. A provider currently unknown (no signal) is omitted from this series rather than reported as 0.

Privacy

shunt never exports request/response bodies, headers, or credentials in metrics and traces.

  • Metrics and traces stay low-cardinality and body-free. With OTLP trace export, the request span’s client session id is sent to the collector only when include_session_id = true (default off), and only while trace export is active. The same rule governs Sentry trace export ([sentry] traces_sample_rate / include_session_id); with no span export active at all, the id stays on the local request span as before.
  • Logs mirror shunt’s own diagnostic events as written, so — like the stderr logs — they can include request-derived fields (an upstream error body, an authenticated client id). For strictly body-free export, set logs = false and keep metrics/traces.

The exported resource advertises service.*, telemetry.sdk.*, and — when environment is set — deployment.environment.name; no host or process detector runs, so the machine’s hostname is not attached, plus whatever you put in the standard OTEL_RESOURCE_ATTRIBUTES.

Standard OTEL_ env vars

  • endpoint and service_name come from this config and take precedence over OTEL_EXPORTER_OTLP_ENDPOINT / OTEL_SERVICE_NAME.
  • The standard OTEL_EXPORTER_OTLP_HEADERS and OTEL_RESOURCE_ATTRIBUTES are still merged in, on top of [otel.headers] and the built-in resource attributes.

See the [otel] configuration reference for every key.

Navigation

Type to search…

↑↓ navigate↵ selectEsc close