遥测 (Telemetry) 架构 Deep-Dive

June 12, 2026 · View on GitHub

AI Agent 收集什么数据、如何上报、用户如何控制?本文基于 Claude Code(v2.1.89 源码分析)和 Qwen Code(v0.16.0 开源)的源码分析,对比两者在遥测 (Telemetry) 架构、事件体系和隐私控制方面的差异。


1. 架构总览

维度Claude CodeQwen Code
遥测框架自定义 1P Logger + OpenTelemetryQwenLogger(RUM)+ OpenTelemetry
上报端点Anthropic 内部 API + Datadog阿里云 RUM + OTLP(可配置,支持 gRPC / HTTP 双协议)
事件数量~656 个 tengu_* 事件~50 个事件类型
采样策略按事件类型动态采样(GrowthBook)批量刷新(1,000 条 / 60 秒)
调试追踪Perfetto(Chrome Trace,ant-only)层级 Span 树(interaction → llm_request → tool/hook,#3731;2026-05 加 TTFT + GenAI semconv + 跨进程 daemon trace)
PII 保护元数据禁止原始字符串选择性 prompt 日志控制 + 敏感属性 opt-in
禁用方式DISABLE_TELEMETRY=trueOTel 链 QWEN_TELEMETRY_ENABLED=false(默认已关);RUM 使用统计另需关 getUsageStatisticsEnabled()(默认开)

2. Claude Code:双通道遥测

2.1 事件日志通道(1P Event Logging)

// 源码: services/analytics/firstPartyEventLogger.ts
// 使用 @opentelemetry/sdk-logs 的 LoggerProvider + BatchLogRecordProcessor
// 自定义 Exporter: FirstPartyEventLoggingExporter
// 端点: ${BASE_API_URL}/api/event_logging/batch
// 批量配置通过 GrowthBook 动态控制(tengu_1p_event_batch_config)

事件类型(~656 个唯一 tengu_* 前缀,源码 grep -roh 统计;含动态构造事件名时约 782 个):

类别示例
Agent 生命周期tengu_agent_created, tengu_agent_tool_selected, tengu_agent_tool_completed
API 交互tengu_api, tengu_api_error, tengu_api_cache_breakpoints
工具执行tengu_tool_*, tengu_streaming_tool_execution_used
会话管理tengu_session_*, tengu_compact_*
Feature Flagtengu_amber_flint, tengu_amber_prism
安全tengu_cancel, tengu_pre_stop_hooks_cancelled
UItengu_brief_mode_toggled, tengu_conversation_forked

PII 保护

// 源码: services/analytics/index.ts
// 元数据类型标注: AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS
// → 开发者必须显式声明元数据不含代码或文件路径
// → 类型系统阻止意外记录敏感信息

2.2 Perfetto 调试追踪(ant-only)

// 源码: utils/telemetry/perfettoTracing.ts
// 格式: Chrome Trace Event (JSON),在 ui.perfetto.dev 或 chrome://tracing 查看
// 启用: CLAUDE_CODE_PERFETTO_TRACE=1 或 CLAUDE_CODE_PERFETTO_TRACE=<path>
// 输出: ~/.claude/traces/trace-<session-id>.json
// 事件上限: 100K 条(超出时淘汰最老的 50%,约 30MB)

Perfetto 追踪捕获

捕获内容详情
Agent 层级父子 swarm 关系
API 请求TTFT、TTLT、prompt 长度、cache 统计
工具执行名称、耗时、token 用量
用户等待输入等待时间
Speculation推测执行标记

2.3 采样 (Sampling) 与降级 (Fallback)

// 按事件采样 (Sampling): GrowthBook tengu_event_sampling_config(每事件 0-1 概率)
// 第三方 Provider: 自动禁用分析(Bedrock/Vertex/Foundry)
// 测试环境: NODE_ENV === 'test' 时禁用
// 隐私模式: isTelemetryDisabled() 检查

3. Qwen Code:RUM + OTLP 双通道

3.1 QwenLogger(RUM 通道)

// 源码: qwen-code/packages/core/src/telemetry/qwen-logger/qwen-logger.ts
// 类型: 单例 RUM (Real User Monitoring) Logger
// 端点: gb4w8c3ygj-default-sea.rum.aliyuncs.com(阿里云 RUM)
// 批量: 默认 1,000 条 / 60 秒刷新
// 队列: FixedDeque(溢出时丢弃最老事件)
// v0.16.0 变化: readSourceInfo() 新增支持 QWEN_HOME 自定义路径,
//   同时兼容遗留 ~/.qwen/source.json(#2953);移除 tool_token_count 上报(#3727)

事件类型(~50 种):

类别事件
会话session_start, session_end
用户操作new_prompt, retry, slash_command, user_feedback
工具tool_call#<name>, file_operation#<name>, tool_output_truncated
APIapi_request, api_response, api_cancel, api_error
错误invalid_chunk, malformed_json_response, loop_detected
扩展extension_install, extension_uninstall, extension_update
Arenaarena_session_started, arena_agent_completed
Hookhook_call#<event_name>
压缩chat_compression

3.2 OpenTelemetry 通道

// 源码: qwen-code/packages/core/src/telemetry/sdk.ts
// 3 种 Exporter(v0.16.0,移除 Console Exporter):
// 1. OTLP gRPC   — OTLPTraceExporter + GZIP 压缩
// 2. OTLP HTTP   — OTLPTraceExporter[Http](v0.16.0 新增 per-signal 端点路由)
// 3. File        — FileSpanExporter(本地文件)
//
// Processor: BatchSpanProcessor, BatchLogRecordProcessor, LogToSpanProcessor(新增)
// 检测: HttpInstrumentation(HTTP 请求自动追踪)
// 诊断日志: 改为写 debug log 而非 console,避免 UI 污染(#3986)
// shutdown 上限: 10 秒(#3813)

遥测目标(v0.16.0):

目标用途
TelemetryTarget.LOCAL本地 OTEL Collector
TelemetryTarget.GCPGoogle Cloud
TelemetryTarget.QWEN已移除(#4061 移除 dead 代码)

3.3 层级 Span 树(v0.16.0 新增)

v0.16.0 新增 session-tracing.ts(883 行),建立完整的层级 Trace 结构:

session(根)
  └─ interaction(每次用户 prompt)
       ├─ llm_request(每次 API 调用)
       └─ tool(每次工具调用)
            ├─ tool.execution(实际执行子 span)
            ├─ tool.blocked_on_user(等待用户审批)
            └─ hook(Hook 执行)

关键新 Span 函数

函数PR说明
startInteractionSpan / endInteractionSpan#4071每轮对话根 span
startLLMRequestSpan / endLLMRequestSpan#4071API 调用子 span
startToolSpan / endToolSpan#4071/#4126工具调用子 span
startToolBlockedOnUserSpan#3731权限等待阶段子 span
startHookSpan / endHookSpan#3731Hook 执行子 span

敏感属性 opt-in(#3893/#4097):设置 QWEN_TELEMETRY_INCLUDE_SENSITIVE_SPAN_ATTRIBUTES=true 后,span 记录 user prompt、system prompt、tool schema、model output、tool input/result 等敏感内容(明确 opt-in,默认关闭)。

traceId/spanId 注入 debug log(#3847):debug log 行自动附加当前 span context,可与 OTEL 后端关联。

3.4 OTLP HTTP per-signal 端点路由(v0.16.0 新增)

// 源码: telemetry/sdk.ts
// 支持 per-signal 端点覆盖(优先级:QWEN_ 变量 > OTEL_ 标准变量 > settings.json):
// QWEN_TELEMETRY_OTLP_TRACES_ENDPOINT / OTEL_EXPORTER_OTLP_TRACES_ENDPOINT
// QWEN_TELEMETRY_OTLP_LOGS_ENDPOINT   / OTEL_EXPORTER_OTLP_LOGS_ENDPOINT
// QWEN_TELEMETRY_OTLP_METRICS_ENDPOINT/ OTEL_EXPORTER_OTLP_METRICS_ENDPOINT
//
// 自动追加 v1/traces、v1/logs、v1/metrics 路径(标准 OTLP HTTP 路由)

3.5 自定义 Resource Attributes 与 Metric Cardinality 控制(v0.16.0 新增)

// 源码: telemetry/config.ts + telemetry/resource-attributes.ts(#4367)
// OTEL_RESOURCE_ATTRIBUTES 环境变量 或 settings.telemetry.resourceAttributes 自定义标签
// RESERVED 键(service.version, session.id)强制过滤 + 警告日志
// OTEL_SERVICE_NAME 覆盖 service.name
//
// Metric session ID cardinality 控制(#4367):
// QWEN_TELEMETRY_METRICS_INCLUDE_SESSION_ID=true 才在 metric 标签中包含 session.id
// 默认关闭,防止高基数导致 TSDB 膨胀

3.6 RUM 事件协议

// 源码: qwen-code/packages/core/src/telemetry/qwen-logger/event-types.ts
// RUM 事件层级:
// RumViewEvent     — 页面/视图导航
// RumActionEvent   — 用户交互
// RumResourceEvent — API/网络调用
// RumExceptionEvent — 错误
// 每类含 snapshot (JSON 序列化详细指标)

3.7 四条并行管道(澄清"默认开启"的歧义)

Qwen Code 的遥测不是单一系统,是四条并行管道,各有独立开关——理解这点才能正确判断"默认开不开":

#管道去向开关默认
OTel TracesOTLP(gRPC/HTTP) / 本地文件 / LogToSpan 桥telemetry.enabled (QWEN_TELEMETRY_ENABLED)OFF
OTel MetricsOTLP / 文件(10s 周期)同上OFF
OTel Logs(events)OTLP / 文件同上OFF
QwenLogger RUM阿里云 *.rum.aliyuncs.comgetUsageStatisticsEnabled()ON
UI Telemetry纯本地内存(驱动 TUI/IDE token·cost 面板)无(永不外传)本地

关键纠正隐私与遥测对比 表里 Qwen Code 标"默认开启"指的是管道④ QwenLogger RUM(使用统计,默认 on,发阿里云);而 OTel 主链(①②③)telemetry.enabled 默认 false。两者是独立开关,不要混为一谈:用户不配 OTel 就完全不产生 OTel 数据,但 RUM 使用统计需单独用 getUsageStatisticsEnabled() / 配置关闭。

3.8 2026-05 演进:#3731 分层 tracing 全 phase + 跨进程 daemon trace

#3731 是一个宽泛的"加固 OpenTelemetry 配置"伞 issue,其下 hierarchical session-tracing 子线在 2026-05 密集推进(session-tracing.ts 已从 883 行增至 975 行):

PhasePR状态加了什么
1#4126统一 span 创建路径,扁平树→层级树(LLM/tool span 成 interaction 子节点)
1.5#4302parent fallback / abort-as-result / log-span 一致性 polish
2#4321tool.blocked_on_user(审批等待时长 + decision + source)+ qwen-code.hook(区分慢 hook vs 慢 tool);tool span 生命周期上移到 _schedule 验证循环
3#4410⏳ OPENqwen-code.subagent span + 并发隔离(前台 child 继承 T0;fork/background 用 linked root + OTel Link)
4a#4417TTFT 捕获(首个用户可见 chunk,method-local 闭包防并发污染)+ GenAI semconv 双发gen_ai.* 兼容层)
4b#4432⏳ OPENper-attempt HTTP-status 重试可见性(api.retry.count + 每次重试独立 LLM span)

配套 PR

  • #4390 客户端 HTTP span(instrumentation-undici,每出站 fetch 一个 client span,分离网络延迟 vs 模型处理)+ opt-in W3C traceparent 传播 + OTLP 自反馈防回环 guard
  • #4499startInteractionSpan 漏传 parent ctx → 被铸随机 traceId 与 session 子树分裂;钉到 session root(基于 issue #4486 生产数据)
  • #4482 LogToSpanProcessor 桥(后端收 traces 不收 logs 时,如阿里云 ARMS):导出失败给有用错误 + 可注入 diagnosticsSink 不污染 Ink TUI
  • #4565 skill-based RT 优化的遥测地基(接上死代码 logSkillLaunchEvent + SkillLaunchEventprompt_id 做 turn join),论点是"降 agent 轮数的杠杆在 skill 设计层不在框架层"

TTFT 语义差异(vs Claude Code):Qwen 测"首个用户可见内容 chunk"(含 text/functionCall/thought/inlineData,排除 metadata-only),比 Claude 测 message_start 更普适。

刻意规避 Claude 并发 bugstartToolBlockedOnUserSpan(toolSpan) 显式传 span 对象,源码注释明说避开 Claude sessionTracingfindLast-by-type 反查(并发工具会错配 parent)。

3.9 daemon 侧遥测(两条独立线)

qwen serve daemon 的遥测分两条机制不同的线:

  1. OTel trace 跨进程传播(#4556 → #4630 → #4682):daemon HTTP 路由 → ACP bridge dispatch → ACP child 三层,W3C traceparent 塞进 _meta 跨进程串成一条 trace,前端协议零改动;prompt FIFO 排队时恢复捕获的 OTel context。最终层级:

    [Daemon] qwen-code.daemon.request(路由 span)
      └ qwen-code.daemon.bridge(prompt.dispatch)
           ▼ 跨进程 W3C traceparent in _meta
    [ACP Child] qwen-code.interaction(session.id, turn_status)
      ├ qwen-code.llm_request / qwen-code.tool → tool.execution
      └ conversation_finished
    

    #4630 给 daemon 路径的 llm_request/tool/tool.execution 补 session.id(ARMS 可按 session 查);#4682 把覆盖扩到除 heartbeat 外所有写路由。

  2. SSE 事件协议 stamping(#4360,F4 prereq):_meta.serverTimestamp / errorKind / provenance(builtin\|mcp\|subagent) / originatorClientId 打进 SSE 事件 _meta——服务多客户端重连去重 + triage,进 SSE 事件流给 SDK reducer(非 OTLP 后端)。与上面 OTel 线机制不同:前者进 OTLP/ARMS,后者进 SSE 流。

daemon 遥测设计详见 Qwen Code Daemon 设计文档


4. 隐私控制对比

维度Claude CodeQwen Code
全局禁用DISABLE_TELEMETRY=trueQWEN_TELEMETRY_ENABLED=false
非必要流量CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=true
Prompt 日志禁止(类型系统强制)telemetryLogPromptsEnabled() 控制
敏感 span 属性opt-in(QWEN_TELEMETRY_INCLUDE_SENSITIVE_SPAN_ATTRIBUTES,默认关闭)
3P Provider自动禁用分析
MDM 控制✅ 策略可关闭遥测
采样按事件动态(GrowthBook)全量批刷
自定义资源标签OTEL_RESOURCE_ATTRIBUTES / settings.telemetry.resourceAttributes(v0.16.0)
Metric session 基数QWEN_TELEMETRY_METRICS_INCLUDE_SESSION_ID,默认 false(v0.16.0)

5. 关键源码文件

Claude Code

文件职责
services/analytics/index.tslogEvent() 中央入口 + 队列
services/analytics/firstPartyEventLogger.ts1P 事件日志(OTLP LoggerProvider)
services/analytics/growthbook.tsFeature Flag + 采样配置
services/analytics/config.ts禁用条件判断
utils/telemetry/perfettoTracing.tsPerfetto Chrome Trace

Qwen Code

文件职责
packages/core/src/telemetry/qwen-logger/qwen-logger.tsRUM Logger 单例
packages/core/src/telemetry/qwen-logger/event-types.tsRUM 事件协议
packages/core/src/telemetry/sdk.tsOTLP Exporter 配置(v0.16.0 新增 HTTP per-signal 路由、LogToSpanProcessor)
packages/core/src/telemetry/config.ts隐私控制 + 目标选择 + resource attributes 解析(v0.16.0 扩展)
packages/core/src/telemetry/session-tracing.ts层级 Span 树(#3731,975 行)
packages/core/src/telemetry/session-context.ts全局 session root OTel context(parent fallback / /clear 后 correlation)
packages/core/src/telemetry/detailed-span-attributes.ts敏感 span 属性(opt-in,含 hash 去重 + 60KB 截断)
packages/core/src/telemetry/metrics.ts~35 metric 定义(含 GenAI semconv 双发 + session.id cardinality 控制);#4868 新增 runtime 采样 qwen-code.memory.usage / qwen-code.cpu.usage(60 槽环形缓冲,crash 诊断 dump 附 recentSamples[],OTel 上报可选)
packages/core/src/telemetry/log-to-span-processor.tslog→span 桥(后端只收 trace 时)+ 敏感属性黑名单脱敏

免责声明: 初稿基于 2026 Q1,2026-05-22 对照 v0.16.0 复核,2026-06-03 再次复核补全 2026-05 演进。Claude Code v2.1.89;Qwen Code 源码 HEAD(含 #4321/#4417/#4390/#4499/#4482/#4565 已合,#4410/#4432 仍 OPEN)。

2026-05 实质变化:#3731 分层 tracing 推进到 Phase 4a(TTFT 捕获 + GenAI semconv 双发)、客户端 HTTP span + W3C traceparent 传播(#4390)、interaction span 钉 session root 修 trace 分裂(#4499)、LogToSpan 桥可观测性修复(#4482)、daemon 跨进程 trace 传播(#4556/#4630/#4682)、skill-RT 遥测地基(#4565)。详 §3.7–§3.9。