shunt 可以通过 OTLP/HTTP 将 trace、指标和日志 导出到你自己的 OpenTelemetry Collector(或任何 OTLP 兼容后端)。它是可选启用、默认关闭的 —— 没有 [otel] 段时,任何数据都不会离开本机 —— 并且与 Sentry 相互独立,你可以只启用其一或两者都启用。
本页讲的是 shunt 自身向外发送的遥测。网关独立的遥测接收处理相反的方向 —— 托管 Claude Code 客户端发送给 shunt 的 OTLP 载荷,verbatim 中继到 [server.gateway.telemetry] 中的目标。两者独立配置,可以指向不同的 collector。
启用
一个键即可启用 —— 指向你的 collector 的 OTLP/HTTP 接收端:
[otel]
endpoint = "http://localhost:4318" # OTLP/HTTP 基础 URL;shunt 会追加 /v1/{traces,metrics,logs}其余项都有合理的默认值:
[otel]
endpoint = "http://localhost:4318"
service_name = "shunt" # (默认) service.name 资源属性
environment = "prod" # 可选:deployment.environment.name
sample_ratio = 1.0 # (默认) 基于 head 的 trace 采样,0.0–1.0
traces = true # (默认) 导出请求 span
metrics = true # (默认) 导出用量指标
logs = true # (默认) 导出日志事件(stderr 日志不受影响)
include_session_id = false # (默认) 将客户端 session id 排除在 span 之外
[otel.headers] # 可选:每次请求附带的 header,例如托管 collector 的令牌
authorization = "Bearer <token>"设置 endpoint = ""(例如 SHUNT_OTEL__ENDPOINT="")可在不删除该段的情况下再次关闭导出。无效的 endpoint、非 http(s) 的 URL、或超出范围的 sample_ratio 都是启动错误,因此一个拼写错误不会悄无声息地丢弃所有导出。
三种信号
| 信号 | 导出内容 | 说明 |
|---|---|---|
| Trace | 每次请求的 proxy_request span |
通过 sample_ratio 进行 head 采样。低基数;不含请求/响应正文。 |
| 指标 | 下方列出的低基数序列 | 与 [sentry] metrics = true 时 shunt 发往 Sentry 的序列相同。 |
| 日志 | shunt 的 tracing 日志事件,桥接到 OTLP |
stderr 日志不受影响。 |
每种信号都可通过 traces / metrics / logs 单独开关。
指标序列
| 序列 | 类型 | 属性 | 含义 |
|---|---|---|---|
shunt.requests |
计数器 | provider, model, http.response.status_code |
代理的推理请求。 |
shunt.latency |
直方图(ms) | provider, model, http.response.status_code |
流式响应为到 header 的延迟;其他响应为完整延迟。 |
shunt.ttft |
直方图(ms) | provider, model |
从请求开始到第一个 SSE body chunk 的时间。 |
shunt.stream_outcome |
计数器 | provider, model, outcome |
每个 SSE 记录一个最终结果:completed、error_event、upstream_cut 或 client_disconnect。 |
shunt.tokens |
计数器 | provider, model, kind |
最后报告的流式 token 用量(input、output、cache_read、cache_creation);不记录非流式用量。 |
shunt.codex_continuation |
计数器 | provider, outcome |
Codex WebSocket continuation 的 hit 或 fallback。 |
shunt.codex_ws_overflow |
计数器 | provider, outcome |
并发 turn 使用专用 overflow 连接时记录 opened,达到连接上限被拒绝时记录 refused(issue #248)。 |
shunt.codex_client_events |
计数器 | event |
按净化后的事件名称统计 Codex CLI 分析事件;payload 和属性会被丢弃。 |
shunt.gateway_telemetry_ingest |
计数器 | signal, outcome |
按接收结果统计入站网关 OTLP 载荷(metrics/logs/traces):relayed;没有任何目标 opt-in 时为 discarded;在途中继上限饱和时为 shed;bearer 无效或 body 超限时为 rejected。 |
shunt.upstream_retries |
计数器 | provider, reason |
有次数限制的临时上游重试。 |
shunt.failover |
计数器 | provider, state |
有序上游故障转移状态:attempted、advanced 或 exhausted。 |
shunt.requests_shed |
计数器 | — | 在 max_concurrent_requests 上限处被拒绝的入站请求。拒绝本身仅以 debug! 记录,因此这个计数器才是网关饱和的可见信号。 |
shunt.pool.quota_utilization |
仪表 | provider, window |
5h、7d 或 7d_oi 窗口中已启用、已观测且未过期的 quota 值的最小使用率。 |
shunt.pool.rotations |
计数器 | provider, reason |
离开账户的切换次数以及 pool 耗尽的请求数。 |
shunt.pool.reprobes |
计数器 | provider |
在陈旧近配额 Codex/ChatGPT 账户的首次 HTTP 发送时提交的重新探测;启用 WebSocket 的提供方只统计 inbound HTTP 探测。 |
shunt.upstream.status |
仪表 | provider |
观测到的 [server.status] Statuspage severity:0 none、1 minor、2 major、3 critical。当前处于 unknown(无信号)状态的 provider 不会以 0 上报,而是从该序列中完全省略。 |
隐私
shunt 在指标和 trace 中从不导出请求/响应正文、header 或凭据。
- 指标和 trace 保持低基数且不含正文。在 OTLP trace 导出中,请求 span 的客户端 session id 仅在
include_session_id = true(默认关闭)时、且仅在 trace 导出处于启用状态时才发送给 collector。同样的规则也适用于 Sentry 的 trace 导出([sentry] traces_sample_rate/include_session_id)。当没有任何 span 导出处于启用状态时,该 id 仍会像以前一样只保留在本地请求 span 上。 - 日志 会如实反映 shunt 自身的诊断事件,因此与 stderr 日志一样,可能包含源自请求的字段(上游错误正文、已认证的客户端 id)。若需要严格不含正文的导出,请将
logs = false,仅保留指标/trace。
导出的 resource 公布 service.*、telemetry.sdk.*,以及在设置了 environment 时的 deployment.environment.name —— 不运行 host 或 process detector,因此不会附带本机主机名 —— 再加上你通过标准 OTEL_RESOURCE_ATTRIBUTES 设置的内容。
标准 OTEL_ 环境变量
endpoint和service_name来自本配置,并优先于OTEL_EXPORTER_OTLP_ENDPOINT/OTEL_SERVICE_NAME。- 标准的
OTEL_EXPORTER_OTLP_HEADERS和OTEL_RESOURCE_ATTRIBUTES仍会在[otel.headers]与内置资源属性之上合并进来。
每个键的详情见 [otel] 配置参考。