Claude Code官方文档Agent SDKOpenTelemetry可观测性

Claude Agent SDK OpenTelemetry 可观测性 - 追踪 / 指标 / 事件

使用 OpenTelemetry 将跟踪、指标和事件从 Agent SDK 导出到你的可观测性后端。(原文为英文,已翻译)

· 阅读约 17 分钟

在生产环境中运行代理时,你需要可见性了解它们的活动:

  • 它们调用了哪些工具
  • 每个模型请求花了多长时间
  • 花费了多少 token
  • 故障发生在哪里

Agent SDK 可以将此数据作为 OpenTelemetry 跟踪、指标和日志事件导出到接受 OpenTelemetry 协议(OTLP)的任何后端,例如 Honeycomb、Datadog、Grafana、Langfuse 或自托管的收集器。

本指南介绍 SDK 如何发出遥测数据、如何配置导出,以及在数据到达后端后如何对数据进行标记和过滤。要直接从 SDK 响应流读取 token 使用情况和成本,而不是导出到后端,请参阅跟踪成本和使用情况

遥测如何从 SDK 流出

Agent SDK 将 Claude Code CLI 作为子进程运行,并通过本地管道与之通信。CLI 内置了 OpenTelemetry 工具:它记录围绕每个模型请求和工具执行的跨度,发出用于 token 和成本计数器的指标,并发出用于提示和工具结果的结构化日志事件。SDK 本身不会产生遥测数据。相反,它将配置传递给 CLI 进程,CLI 直接导出到你的收集器。

配置作为环境变量传递。默认情况下,子进程继承你应用程序的环境,因此你可以在两个位置之一配置遥测:

  • 进程环境: 在你的应用程序启动之前在 shell、容器或编排器中设置变量。每个 query() 调用都会自动获取它们,无需更改代码。这是生产部署的推荐方法。
  • 每次调用选项:ClaudeAgentOptions.env(Python)或 options.env(TypeScript)中设置变量。当同一进程中的不同代理需要不同的遥测设置时使用此方法。在 Python 中,env 合并到继承的环境之上。在 TypeScript 中,env 完全替换继承的环境,因此请在传递的对象中包含 ...process.env

CLI 导出三个独立的 OpenTelemetry 信号。每个都有自己的启用开关和自己的导出器,因此你可以只打开你需要的信号。

信号它包含什么启用方式
指标token、成本、会话、代码行和工具决定的计数器OTEL_METRICS_EXPORTER
日志事件每个提示、API 请求、API 错误和工具结果的结构化记录OTEL_LOGS_EXPORTER
跟踪每次交互、模型请求、工具调用和 hook 的跨度(beta)OTEL_TRACES_EXPORTERCLAUDE_CODE_ENHANCED_TELEMETRY_BETA=1

有关指标名称、事件名称和属性的完整列表,请参阅 Claude Code 监控参考。Agent SDK 发出相同的数据,因为它运行相同的 CLI。跨度名称列在下面的读取代理跟踪中。

启用遥测导出

在设置 CLAUDE_CODE_ENABLE_TELEMETRY=1 并选择至少一个导出器之前,遥测都是关闭的。最常见的配置通过 OTLP HTTP 将所有三个信号发送到收集器。

以下示例在字典中设置变量并通过 options.env 传递它们。代理运行一个单一任务,CLI 在循环消费响应流时将跨度、指标和事件导出到 collector.example.com 的收集器:

Python

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())

TypeScript

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 清单或 shell 配置文件中导出这些变量,并完全省略 options.env 来达到相同的结果。

ℹ️ console 导出器将遥测写入标准输出,而 SDK 将其用作消息通道。通过 SDK 运行时,请勿将 console 设置为导出器值。要在本地检查遥测数据,请将 OTEL_EXPORTER_OTLP_ENDPOINT 指向本地收集器或一体化 Jaeger 容器。

从短期调用刷新遥测

CLI 批处理遥测并按间隔导出。在干净的进程退出时,它尝试刷新待处理的数据,但刷新受短超时限制,因此如果收集器响应缓慢,跨度仍可能被丢弃。如果你的进程在 CLI 关闭之前被杀死,批处理缓冲区中的任何内容都将丢失。降低导出间隔可减少这两个窗口。

默认情况下,指标每 60 秒导出一次,跟踪和日志每 5 秒导出一次。以下示例缩短了所有三个间隔,以便数据在短任务仍在运行时到达收集器:

Python

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

TypeScript

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

读取代理跟踪

跟踪为你提供代理运行的最详细视图。设置了 CLAUDE_CODE_ENHANCED_TELEMETRY_BETA=1 后,代理循环的每一步都成为你可以在跟踪后端检查的跨度:

  • claude_code.interaction 包装代理循环的单个回合,从接收提示到产生响应。
  • claude_code.llm_request 包装对 Claude API 的每次调用,模型名称、延迟和 token 计数作为属性。
  • claude_code.tool 包装每个工具调用,权限等待的子跨度(claude_code.tool.blocked_on_user)和执行本身(claude_code.tool.execution)。
  • claude_code.hook 包装每个 hook 执行。除了上述变量之外,还需要详细 beta 跟踪(ENABLE_BETA_TRACING_DETAILED=1BETA_TRACING_ENDPOINT)。

llm_requesttoolhook 跨度是封闭 claude_code.interaction 跨度的子跨度。当代理通过 Task 工具产生子代理时,子代理的 llm_requesttool 跨度嵌套在父代理的 claude_code.tool 跨度下,因此完整的委托链显示为一个跟踪。

跨度默认带有 session.id 属性。当你对同一个会话进行多次 query() 调用时,在后端过滤 session.id 以将它们视为一个时间线。如果 OTEL_METRICS_INCLUDE_SESSION_ID 设置为假值,则该属性被省略。

ℹ️ 跟踪处于 beta 阶段。跨度名称和属性可能在版本之间发生变化。有关跟踪导出器配置变量,请参阅监控参考中的跟踪(beta)

将跟踪链接到你的应用程序

SDK 自动将 W3C 跟踪上下文传播到 CLI 子进程。当你在应用程序中有活动的 OpenTelemetry 跨度时调用 query(),SDK 会将 TRACEPARENTTRACESTATE 注入子进程环境,CLI 读取它们以使其 claude_code.interaction 跨度成为你跨度的子级。然后代理运行出现在你应用程序的跟踪中,而不是作为不相连的根。

CLI 还将 TRACEPARENT 转发到它运行的每个 Bash 和 PowerShell 命令。如果通过 Bash 工具启动的命令发出自己的 OpenTelemetry 跨度,那些跨度会嵌套在包装该命令的 claude_code.tool.execution 跨度下。

当你在 options.env 中显式设置 TRACEPARENT 时,跳过自动注入,因此你可以在需要时固定特定的父上下文。交互式 CLI 会话完全忽略入站 TRACEPARENT;只有 Agent SDK 和 claude -p 运行才会遵守它。有关完整的跨度和属性参考,请参阅监控参考中的跟踪(beta)

标记来自你代理的遥测

默认情况下,CLI 将 service.name 报告为 claude-code。如果你运行多个代理,或者与导出到同一收集器的其他服务一起运行 SDK,请覆盖服务名称并添加资源属性,以便你可以在后端按代理过滤。

以下示例重命名服务并附加部署元数据。这些值作为 OpenTelemetry 资源属性应用于代理发出的每个跨度、指标和事件:

Python

options = ClaudeAgentOptions(
    env={
        # ... exporter configuration ...
        "OTEL_SERVICE_NAME": "support-triage-agent",
        "OTEL_RESOURCE_ATTRIBUTES": "service.version=1.4.0,deployment.environment=production",
    },
)

TypeScript

const options = {
  env: {
    ...process.env,
    // ... exporter configuration ...
    OTEL_SERVICE_NAME: "support-triage-agent",
    OTEL_RESOURCE_ATTRIBUTES:
      "service.version=1.4.0,deployment.environment=production",
  },
};

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

CLI 基于用于调用 Anthropic 的凭证将身份属性附加到每个事件。当你构建一个从一个部署服务许多终端用户的应用程序时,这些属性标识你服务的凭证,而不是代理代表其行事的终端用户。

要使工具调用和 MCP 活动可归因于你应用程序的终端用户,请在每个 query() 调用中将终端用户身份注入为资源属性。在插入前对值进行百分比编码,因为 OTEL_RESOURCE_ATTRIBUTES 保留逗号、空格和等号。以下示例将请求用户和租户附加到一个请求的每个跨度和事件:

Python

from urllib.parse import quote

options = ClaudeAgentOptions(
    env={
        # ... exporter configuration ...
        "OTEL_RESOURCE_ATTRIBUTES": f"enduser.id={quote(request.user_id)},tenant.id={quote(request.tenant_id)}",
    },
)

TypeScript

const options = {
  env: {
    ...process.env,
    // ... exporter configuration ...
    OTEL_RESOURCE_ATTRIBUTES: `enduser.id=${encodeURIComponent(request.userId)},tenant.id=${encodeURIComponent(request.tenantId)}`,
  },
};

附加终端用户身份后,tool_decisiontool_resultmcp_server_connectionpermission_mode_changed 事件成为你可以转发到安全信息和事件管理(SIEM)平台的每个用户审计跟踪。有关安全相关事件的完整列表以及每个事件携带的属性,请参阅监控参考中的审计安全事件

控制导出中的敏感数据

遥测默认是结构化的。持续时间、模型名称和工具名称记录在每个跨度上;当底层 API 请求返回使用数据时记录 token 计数,因此失败或中止请求的跨度可能省略它们。代理读取和写入的内容默认不会记录。这些可选变量将内容添加到导出的数据中:

变量添加
OTEL_LOG_USER_PROMPTS=1claude_code.user_prompt 事件和 claude_code.interaction 跨度上的提示文本
OTEL_LOG_TOOL_DETAILS=1claude_code.tool_result 事件上的工具输入参数(文件路径、shell 命令、搜索模式)
OTEL_LOG_TOOL_CONTENT=1claude_code.tool 上作为跨度事件的完整工具输入和输出主体,截断为 60 KB。需要启用跟踪
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 路径。主体包括整个对话历史,扩展思维内容已编辑。启用此项即表示同意上面三个变量将揭示的所有内容

除非你的可观测性管道被批准存储代理处理的数据,否则请保留这些变量未设置。有关属性的完整列表和编辑行为,请参阅监控参考中的安全和隐私

相关文档

这些指南涵盖了监控和部署代理的相关主题:

  • 跟踪成本和使用情况:在没有外部后端的情况下从消息流中读取 token 和成本数据。
  • 托管 Agent SDK:在你可以在环境级别设置 OpenTelemetry 变量的容器中部署代理。
  • 监控:CLI 发出的每个环境变量、指标和事件的完整参考。

本文翻译自 Anthropic Claude Code 官方文档,最近一次同步:2025-05-01。