Claude Code 学习站

Claude Agent SDK 可观测性:OpenTelemetry 遥测导出指南

整理 Agent SDK 通过 OpenTelemetry 导出 traces、metrics、log events 的机制、环境变量配置、span 结构与敏感数据控制。

本页目录10
AI 摘要 · 已核查整理于 2026-07-23原文:Observability with OpenTelemetry(Anthropic)Agent SDKOpenTelemetry可观测性
要点速览
  • SDK 本身不产生遥测数据,而是把环境变量透传给内置 OpenTelemetry 插桩的 Claude Code CLI 子进程,由 CLI 直接导出到 OTLP 后端
  • 必须设置 `CLAUDE_CODE_ENABLE_TELEMETRY=1` 并分别用 `OTEL_TRACES_EXPORTER`、`OTEL_METRICS_EXPORTER`、`OTEL_LOGS_EXPORTER` 开启所需信号;traces 还需 `CLAUDE_CODE_ENHANCED_TELEMETRY_BETA=1`(测试版)
  • 通过 SDK 运行时不能把导出器设为 `console`,因为该输出通道已被 SDK 用作消息流;应指向本地 collector 或 Jaeger
  • SDK 会自动把 `TRACEPARENT`/`TRACESTATE` 注入子进程,使 agent 的 `claude_code.interaction` span 挂到应用自身的 trace 下
  • prompt 文本、工具输入输出、原始 API 报文等敏感内容默认不导出,需要显式设置 `OTEL_LOG_USER_PROMPTS`、`OTEL_LOG_TOOL_DETAILS`、`OTEL_LOG_TOOL_CONTENT`、`OTEL_LOG_RAW_API_BODIES` 才会加入

本文是对 Claude Agent SDK 官方文档「Observability with OpenTelemetry」一页的中文整理,完整与最新内容以原文为准:https://code.claude.com/docs/en/agent-sdk/observability

概述

在生产环境运行 agent 时,你需要了解它做了什么:调用了哪些工具、每次模型请求耗时多久、消耗了多少 token、故障发生在哪里。

Agent SDK 可以将这些数据以 OpenTelemetry 的 traces(追踪)、metrics(指标)和 log events(日志事件)形式导出到任何接受 OpenTelemetry Protocol(OTLP)的后端,例如 Honeycomb、Datadog、Grafana、Langfuse,或自建的 collector。

若只想从 SDK 响应流中直接读取 token 用量和成本,而不导出到外部后端,参见「Track cost and usage」文档(/docs/en/agent-sdk/cost-tracking)。

遥测数据如何从 SDK 流出

Agent SDK 把 Claude Code CLI 作为子进程运行,并通过本地管道与其通信。CLI 内置了 OpenTelemetry 插桩:它会在每次模型请求和工具执行周围记录 span,为 token 和成本计数器发出 metrics,并为 prompt 与工具结果发出结构化的日志事件。SDK 本身不产生遥测数据,而是把配置透传给 CLI 进程,由 CLI 直接导出到你的 collector。

配置通过环境变量传递。默认情况下子进程会继承你应用的环境变量,因此可以在以下两处之一配置遥测:

  • 进程环境变量:在应用启动前,在 shell、容器或编排器中设置变量。每次 query() 调用都会自动读取,无需改代码。生产部署推荐这种方式。
  • 单次调用选项:在 ClaudeAgentOptions.env(Python)或 options.env(TypeScript)中设置变量。适用于同一进程内不同 agent 需要不同遥测配置的情况。Python 中 env 会合并到继承的环境变量之上;TypeScript 中 env 会完全替换继承的环境变量,因此传入的对象中要包含 ...process.env

CLI 导出三种独立的 OpenTelemetry 信号,各自有独立的启用开关和导出器,可以只开启需要的信号。

信号包含内容启用方式
Metricstoken、成本、会话数、代码行数、工具决策等计数器OTEL_METRICS_EXPORTER
Log events每个 prompt、API 请求、API 错误、工具结果的结构化记录OTEL_LOGS_EXPORTER
Traces每次交互、模型请求、工具调用、hook 的 span(测试版)OTEL_TRACES_EXPORTERCLAUDE_CODE_ENHANCED_TELEMETRY_BETA=1

完整的 metric 名称、事件名称和属性列表参见 Claude Code 的「Monitoring」参考文档(/docs/en/monitoring-usage)。Agent SDK 发出的数据与之相同,因为运行的是同一个 CLI。Span 名称见下文「读取 agent 追踪」一节。

启用遥测导出

在设置 CLAUDE_CODE_ENABLE_TELEMETRY=1 并至少选择一个导出器之前,遥测处于关闭状态。最常见的配置是通过 OTLP HTTP 把三种信号都发送到一个 collector。

下面的示例把变量放进一个字典,通过 options.env 传入。agent 运行单个任务,CLI 在消费响应流的同时把 span、metrics、events 导出到 collector.example.com 处的 collector:

import asyncio
from claude_agent_sdk import query, ClaudeAgentOptions

OTEL_ENV = {
    "CLAUDE_CODE_ENABLE_TELEMETRY": "1",
    # Required for traces, which are in beta. Metrics and log events do not need this.
    "CLAUDE_CODE_ENHANCED_TELEMETRY_BETA": "1",
    # Choose an exporter per signal. Use otlp for the SDK; see the Note below.
    "OTEL_TRACES_EXPORTER": "otlp",
    "OTEL_METRICS_EXPORTER": "otlp",
    "OTEL_LOGS_EXPORTER": "otlp",
    # Standard OTLP transport configuration.
    "OTEL_EXPORTER_OTLP_PROTOCOL": "http/protobuf",
    "OTEL_EXPORTER_OTLP_ENDPOINT": "http://collector.example.com:4318",
    "OTEL_EXPORTER_OTLP_HEADERS": "Authorization=Bearer your-token",
}


async def main():
    options = ClaudeAgentOptions(env=OTEL_ENV)
    async for message in query(
        prompt="List the files in this directory", options=options
    ):
        print(message)


asyncio.run(main())
import { query } from "@anthropic-ai/claude-agent-sdk";

const otelEnv = {
  CLAUDE_CODE_ENABLE_TELEMETRY: "1",
  // Required for traces, which are in beta. Metrics and log events do not need this.
  CLAUDE_CODE_ENHANCED_TELEMETRY_BETA: "1",
  // Choose an exporter per signal. Use otlp for the SDK; see the Note below.
  OTEL_TRACES_EXPORTER: "otlp",
  OTEL_METRICS_EXPORTER: "otlp",
  OTEL_LOGS_EXPORTER: "otlp",
  // Standard OTLP transport configuration.
  OTEL_EXPORTER_OTLP_PROTOCOL: "http/protobuf",
  OTEL_EXPORTER_OTLP_ENDPOINT: "http://collector.example.com:4318",
  OTEL_EXPORTER_OTLP_HEADERS: "Authorization=Bearer your-token",
};

for await (const message of query({
  prompt: "List the files in this directory",
  // env replaces the inherited environment in TypeScript, so spread
  // process.env first to keep PATH, ANTHROPIC_API_KEY, and other variables.
  options: { env: { ...process.env, ...otelEnv } },
})) {
  console.log(message);
}

由于子进程默认继承应用的环境变量,你也可以在 Dockerfile、Kubernetes manifest 或 shell profile 中导出这些变量,完全不传 options.env,效果相同。

要确认导出是否生效,任务完成后检查 collector 日志中是否有新到达的 span、metrics 和日志事件。CLI 默认在导出出错时静默失败:如果 endpoint 不可达或拒绝了数据,agent 仍会正常运行,CLI 会丢弃遥测数据而不会在你的应用中报错。要让导出错误显现出来,需要在导出器变量之外再设置 CLAUDE_CODE_OTEL_DIAG_STDERR=1(参见 /docs/en/env-vars),并通过 SDK 的 stderr 回调(Python)或 stderr 选项(TypeScript)读取诊断信息。此功能要求 Claude Code v2.1.179 或更高版本。

注意 console 导出器会把遥测数据写到标准输出,而 SDK 正是用标准输出作为消息通道。因此通过 SDK 运行时,不要把某个信号的导出器设为 console。如果要在本地查看遥测数据,应把 OTEL_EXPORTER_OTLP_ENDPOINT 指向本地 collector 或一体化的 Jaeger 容器。

从短生命周期调用中刷新遥测数据

CLI 会按批次缓存遥测数据,并按固定间隔导出。进程正常退出时它会尝试刷新待发送的数据,但刷新有较短的超时限制,如果 collector 响应慢,span 仍可能被丢弃。如果进程在 CLI 关闭之前被杀死,批处理缓冲区中尚未发送的数据会全部丢失。缩短导出间隔可以同时减小这两种窗口期。

默认情况下,metrics 每 60 秒导出一次,traces 和 logs 每 5 秒导出一次。下面的示例把三者的间隔都缩短,使数据能在短任务运行期间就到达 collector:

OTEL_ENV = {
    # ... exporter configuration from the previous example ...
    "OTEL_METRIC_EXPORT_INTERVAL": "1000",
    "OTEL_LOGS_EXPORT_INTERVAL": "1000",
    "OTEL_TRACES_EXPORT_INTERVAL": "1000",
}
const otelEnv = {
  // ... exporter configuration from the previous example ...
  OTEL_METRIC_EXPORT_INTERVAL: "1000",
  OTEL_LOGS_EXPORT_INTERVAL: "1000",
  OTEL_TRACES_EXPORT_INTERVAL: "1000",
};

读取 agent 追踪(traces)

Traces 提供最细粒度的 agent 运行视图。设置 CLAUDE_CODE_ENHANCED_TELEMETRY_BETA=1 后,agent 循环的每一步都会成为一个可在追踪后端中查看的 span:

  • claude_code.interaction:包裹 agent 循环的单次轮次,从接收 prompt 到产出响应。
  • claude_code.llm_request:包裹每次对 Claude API 的调用,属性中带有模型名、延迟和 token 数。
  • claude_code.tool:包裹每次工具调用,子 span 包括等待权限确认的 claude_code.tool.blocked_on_user 和执行本身的 claude_code.tool.execution
  • claude_code.hook:包裹每次 hook(参见 /docs/en/agent-sdk/hooks)执行。除上述变量外,还需要开启详细追踪测试版(ENABLE_BETA_TRACING_DETAILED=1BETA_TRACING_ENDPOINT)。

llm_requesttoolhook 这些 span 都是外层 claude_code.interaction span 的子 span。当 agent 通过 Agent 工具派生出子 agent 时,子 agent 的 llm_requesttool span 会嵌套在父 agent 的 claude_code.tool span 下,因此整条委派链会呈现为同一条 trace。

Span 默认携带 session.id 属性。如果你针对同一个 session(参见 /docs/en/agent-sdk/sessions)发起多次 query() 调用,可以在后端按 session.id 过滤,把它们看作同一条时间线。如果把 OTEL_METRICS_INCLUDE_SESSION_ID 设为假值,Claude Code 会省略该属性。

注意 追踪功能目前是测试版(beta)。Span 名称和属性可能在后续版本中变化。追踪导出器的相关配置变量参见 Monitoring 参考文档中的「Traces (beta)」一节(/docs/en/monitoring-usage#traces-beta)。

将追踪链接到你的应用

SDK 会自动把 W3C trace context 传播进 CLI 子进程。当你在应用中存在一个活跃的 OpenTelemetry span 时调用 query(),SDK 会把 TRACEPARENTTRACESTATE 注入子进程的环境变量,CLI 读取后会让它的 claude_code.interaction span 成为你那个 span 的子 span。这样 agent 运行就会出现在你应用的 trace 内部,而不是作为一条孤立的根 trace。

运行期间发出的 OTLP 事件日志记录会携带相同的 trace context:设置了 TRACEPARENT 后,每条记录的 trace_idspan_id 会与你应用的 trace 一致,因此可以在后端把 events(参见 /docs/en/monitoring-usage#events)和 span 关联起来。在 v2.1.212 之前,若事件记录是在活跃 span 之外发出的,则不携带 trace_idspan_id

启用了 trace-context 传播后,CLI 还会把 TRACEPARENT 转发给它运行的每一个 Bash 和 PowerShell 命令。如果通过 Bash 工具启动的命令自己也会发出 OpenTelemetry span,那些 span 会嵌套在包裹该命令的 claude_code.tool.execution span 下。

如果你在 options.env 中显式设置了 TRACEPARENT,自动注入会被跳过,这样你就可以固定一个特定的父 context。交互式 CLI 会话会完全忽略传入的 TRACEPARENT;只有 Agent SDK 和 claude -p 运行方式才会遵循它。完整的 span 与属性参考见 Monitoring 参考文档中的「Traces (beta)」一节(/docs/en/monitoring-usage#traces-beta)。

给来自你的 agent 的遥测打标签

默认情况下,CLI 上报的 service.nameclaude-code。如果你运行多个 agent,或者 SDK 与其他服务共用同一个 collector,可以覆盖 service name 并添加 resource attributes,以便在后端按 agent 过滤。

下面的示例重命名了 service,并附加了部署元数据。这些值会作为 OpenTelemetry resource attributes 应用到该 agent 发出的每个 span、metric 和 event 上:

options = ClaudeAgentOptions(
    env={
        # ... exporter configuration from the Enable telemetry export example ...
        "OTEL_SERVICE_NAME": "support-triage-agent",
        "OTEL_RESOURCE_ATTRIBUTES": "service.version=1.4.0,deployment.environment=production",
    },
)
const options = {
  env: {
    ...process.env,
    // ... exporter configuration from the Enable telemetry export example ...
    OTEL_SERVICE_NAME: "support-triage-agent",
    OTEL_RESOURCE_ATTRIBUTES:
      "service.version=1.4.0,deployment.environment=production",
  },
};

将操作归因到你的终端用户

CLI 会根据它调用 Anthropic 所使用的凭据,为每个事件附加身份属性(参见 /docs/en/monitoring-usage#standard-attributes)。如果你构建的应用用一次部署为多个终端用户提供服务,这些属性标识的是你服务所用的凭据,而不是 agent 实际代表的终端用户。

要让工具调用和 MCP 活动可归因到你应用的终端用户,需要在每次 query() 调用中把终端用户身份作为 resource attributes 注入。由于 OTEL_RESOURCE_ATTRIBUTES 会保留逗号、空格和等号作为分隔符(参见 /docs/en/monitoring-usage#multi-team-organization-support),插值前要对值做百分号编码。下面的示例把发起请求的用户和租户附加到该次请求产生的每个 span 和 event 上;示例假定有一个来自你 web 框架的 request 对象携带用户 ID 和租户 ID:

from urllib.parse import quote

options = ClaudeAgentOptions(
    env={
        # ... exporter configuration from the Enable telemetry export example ...
        # request is the incoming request object from your web framework.
        "OTEL_RESOURCE_ATTRIBUTES": f"enduser.id={quote(request.user_id)},tenant.id={quote(request.tenant_id)}",
    },
)
const options = {
  env: {
    ...process.env,
    // ... exporter configuration from the Enable telemetry export example ...
    // request is the incoming request object from your web framework.
    OTEL_RESOURCE_ATTRIBUTES: `enduser.id=${encodeURIComponent(request.userId)},tenant.id=${encodeURIComponent(request.tenantId)}`,
  },
};

附加了终端用户身份之后,tool_decisiontool_resultmcp_server_connectionpermission_mode_changed 这几个事件(导出为以 claude_code. 为前缀命名的日志记录)就能成为一份按用户区分的审计轨迹,可转发给 SIEM(安全信息与事件管理)平台。完整的安全相关事件列表及各自携带的属性,参见 Monitoring 参考文档中的「Audit security events」一节(/docs/en/monitoring-usage#audit-security-events)。

控制导出内容中的敏感数据

遥测数据默认只包含结构性信息。每个 span 都会记录耗时、模型名和工具名;当底层 API 请求返回了 usage 数据时才会记录 token 数,因此失败或中止的请求对应的 span 可能不包含 token 数。agent 读写的具体内容默认不会被记录。以下这些选择性开启的变量会把内容加入导出数据:

变量添加的内容
OTEL_LOG_USER_PROMPTS=1claude_code.user_prompt 事件和 claude_code.interaction span 上的 prompt 文本
OTEL_LOG_TOOL_DETAILS=1claude_code.tool_result 事件上的工具输入参数(文件路径、shell 命令、搜索模式)
OTEL_LOG_TOOL_CONTENT=1claude_code.tool 上作为 span event 的完整工具输入/输出内容,默认在 60 KB 处截断,可通过 CLAUDE_CODE_OTEL_CONTENT_MAX_LENGTH 配置(要求 Claude Code v2.1.214 或更高版本)。需要先启用上文「读取 agent 追踪(traces)」一节所述的追踪功能
OTEL_LOG_RAW_API_BODIES完整的 Anthropic Messages API 请求/响应 JSON,作为 claude_code.api_request_bodyclaude_code.api_response_body 日志事件。设为 1 表示内联正文,默认在 60 KB 处截断;设为 file:<dir> 表示正文不截断,写入磁盘,事件中带 body_ref 路径。CLAUDE_CODE_OTEL_CONTENT_MAX_LENGTH 用于配置内联截断长度,要求 Claude Code v2.1.214 或更高版本。正文包含完整的对话历史,且 extended-thinking 内容会被脱敏。启用此项即视为同意上面三个变量所能暴露的全部内容

除非你的可观测性管道已获准存储 agent 处理的数据,否则应保持这些变量不设置。完整的属性列表和脱敏行为参见 Monitoring 参考文档中的「Security and privacy」一节(/docs/en/monitoring-usage#security-and-privacy)。

相关文档

这些指南涵盖了监控与部署 agent 的相关主题:

  • Track cost and usage/docs/en/agent-sdk/cost-tracking):无需外部后端,直接从消息流中读取 token 和成本数据。
  • Hosting the Agent SDK/docs/en/agent-sdk/hosting):在容器中部署 agent,可以在环境层面设置 OpenTelemetry 变量。
  • Monitoring(/docs/en/monitoring-usage):CLI 发出的每个环境变量、metric 和 event 的完整参考。