监控与成本追踪:从 OTel 遥测到 Token 计费的端到端流程
对应官方文档:claude-code-docs/docs/monitoring-usage.md 里的 Monitoring。
它解决了什么问题
在 2.1.88 运行时中,monitoring 的本质不是简单的 OTEL_* 环境变量透传,而是一条在“信任(Trust)”建立后才接通的本地遥测分流管线。
这套系统服务于两个平行的目标:
- 性能与健康度监控(Monitoring):支持用户自定义的 OpenTelemetry (OTel) Exporter,上报 Metrics、Logs 和 Traces,用于分析工具执行耗时和模型响应延迟。
- 资源管理与费用追踪(Cost Tracking):在本地实时累加 Token 消耗、API 耗时、工具执行时长及 USD 成本。这套计费逻辑是纯本地的,不依赖云端反向通知。
代码里的真实逻辑
这套机制的实现跨越了 bootstrap/state.ts、utils/telemetry/ 和 cost-tracker.ts:
- 信任后的初始化(After-trust Telemetry):
src/entrypoints/init.ts只做基础变量加载。真正的 OTel 初始化(initializeTelemetryAfterTrust())要等交互模式下的 Trust Dialog 确认之后才触发。这是为了安全:防止恶意的otelHeadersHelper(自定义本地命令)在获得信任前被执行。 - 动态 Header 助手(OTel Headers Helper):
src/utils/auth.ts支持otelHeadersHelper环境变量。它不是启动时算一次,而是一个带 29 分钟 Debounce 的动态 Header 供应器,专门为需要定期刷新 Token 的 OTLP 后端设计。 - 三路信号分流(Signal Splitting):
- Metrics:走
MeterProvider,强制默认delta暂时性(Temporality)。 - Logs:走
LoggerProvider,所有“事件(Events)”都被包装成 Log Record 发出。 - Traces:只有在
CLAUDE_CODE_ENABLE_TELEMETRY=1且开启Enhanced Telemetry时才会记录详细的 Interaction Span。
- Metrics:走
- Token 实时计数(Token Counter):
src/bootstrap/state.ts中的getTokenCounter()维护了一个按模型和类型(Input、Output、Cache-read、Cache-write)分类的内存计数器。每次模型响应后,addToTotalSessionCost会立即被调用。 - 成本换算逻辑(Cost Calculation):
src/utils/modelCost.ts维护了一张定价查找表。即使模型不在表中,它也会继续累加 Token 并标记为“估算”。 - 会话持久化(Cost Tracker):
src/cost-tracker.ts负责将当前 Session 的 Usage 实时落入~/.claude.json。这支持了--resume时的成本连续性:Claude 知道这整场实验已经花了多少钱。 - 组织级 Opt-out:
src/services/api/metricsOptOut.ts实现了组织级开关。如果是 Claude for Teams/Enterprise,系统会通过磁盘缓存记录该组织是否允许内部 BigQuery Metrics 上报。
实战注意事项
- 开关差异:
CLAUDE_CODE_ENABLE_TELEMETRY控制的是 Customer OTel,而内部 Analytics(Datadog/1P)受另一套 Privacy 逻辑控制。 - 计费非实时云同步:Token 和 Cost 追踪完全基于 SDK 返回的 usage 信息在本地计算,不代表云端账单的最终核算。
- 延迟初始化:Telemetry 初始化是分段的。如果 Trust 没过,Customer OTel Exporter 根本不会被创建。
- Flush 退出策略:OTel 退出时尝试 Flush 的超时是 2 秒。系统优先保住主流程退出,而不是死等监控数据发完。
接下来看什么
- 如果你关心具体事件是如何产出的,下一篇该看 Analytics 管线(event-pipeline.md)。
- 如果你关心 Token 计费如何与 Compaction(上下文压缩)联动,去看 Context Compaction 策略。
- 如果你关心如何配置多层级的 Settings,去看 Settings Hierarchy。
源码锚点
claude-code-opensource/src/utils/telemetry/instrumentation.ts:Customer OTel 的主初始化流程:Metrics、Logs、Traces、Headers Helper。
📄 src/utils/telemetry/instrumentation.ts — Customer OTel 的主初始化流程:Metrics、Logs、Traces、Headers Helper。
typescript
is1PApiCustomer,
isClaudeAISubscriber,
} from 'src/utils/auth.js'
import { getPlatform, getWslVersion } from 'src/utils/platform.js'claude-code-opensource/src/cost-tracker.ts:Session 级成本与 Token 累加与持久化管理。
📄 src/cost-tracker.ts — Session 级成本与 Token 累加与持久化管理。
typescript
getSessionId,
getTokenCounter,
getTotalAPIDuration,
getTotalAPIDurationWithoutRetries,
getTotalCacheCreationInputTokens,
getTotalCacheReadInputTokens,
getTotalCostUSD,
getTotalDuration,
getTotalInputTokens,
getTotalLinesAdded,
getTotalLinesRemoved,
getTotalOutputTokens,
getTotalToolDuration,
getTotalWebSearchRequests,
getUsageForModel,
hasUnknownModelCost,
resetCostState,
resetStateForTests,
setCostStateForRestore,
setHasUnknownModelCost,
} from './bootstrap/state.js'
import type { ModelUsage } from './entrypoints/agentSdkTypes.js'claude-code-opensource/src/utils/modelCost.ts:从 Token 到 USD 的转换算法及定价表。
📄 src/utils/modelCost.ts — 从 Token 到 USD 的转换算法及定价表。
typescript
inputTokens: number
outputTokens: number
promptCacheWriteTokens: number
promptCacheReadTokens: number
webSearchRequests: number
}
// Standard pricing tier for Sonnet models: $3 input / $15 output per Mtok
export const COST_TIER_3_15 = {claude-code-opensource/src/bootstrap/state.ts:内存中的 Token 计数器与 Cost 状态定义。
📄 src/bootstrap/state.ts — 内存中的 Token 计数器与 Cost 状态定义。
typescript
sessionIngressToken: string | null | undefined
oauthTokenFromFd: string | null | undefined
apiKeyFromFd: string | null | undefined
// Telemetry state
meter: Meter | null
sessionCounter: AttributedCounter | null
locCounter: AttributedCounter | null
prCounter: AttributedCounter | null
commitCounter: AttributedCounter | null
costCounter: AttributedCounter | null
tokenCounter: AttributedCounter | null
codeEditToolDecisionCounter: AttributedCounter | null
activeTimeCounter: AttributedCounter | null
statsStore: { observe(name: string, value: number): void } | nullclaude-code-opensource/src/utils/auth.ts:otelHeadersHelper的 Trust 检查与 Debounce 机制。
📄 src/utils/auth.ts — `otelHeadersHelper` 的 Trust 检查与 Debounce 机制。
typescript
const otelHeadersHelper = getConfiguredOtelHeadersHelper()
if (!otelHeadersHelper) {
return false
}claude-code-opensource/src/utils/telemetry/bigqueryExporter.ts:内部 BigQuery Metrics Exporter 的上报控制。
📄 src/utils/telemetry/bigqueryExporter.ts — 内部 BigQuery Metrics Exporter 的上报控制。
typescript
export class BigQueryMetricsExporter implements PushMetricExporter {
private readonly endpoint: string
private readonly timeout: number
private pendingExports: Promise<void>[] = []
private isShutdown = false
constructor(options: { timeout?: number } = {}) {
const defaultEndpoint = 'https://api.anthropic.com/api/claude_code/metrics'
if (
process.env.USER_TYPE === 'ant' &&
process.env.ANT_CLAUDE_CODE_METRICS_ENDPOINT
) {
this.endpoint =
process.env.ANT_CLAUDE_CODE_METRICS_ENDPOINT +
'/api/claude_code/metrics'
} else {
this.endpoint = defaultEndpoint
}
this.timeout = options.timeout || 5000
}
async export(
metrics: ResourceMetrics,
resultCallback: (result: ExportResult) => void,
): Promise<void> {
if (this.isShutdown) {
resultCallback({
code: ExportResultCode.FAILED,