Follow Discord
Sweep 22 Oct 2026 · 04:32Z Build v2.1.308 527 read Stable v2.1.308 Latest v2.1.308 Next v2.1.308 Feeds RSS JSON llms.txt llms-full.txt Unofficial
One change · claude-code

Observability with OpenTelemetry changedagent-sdk/observability

Nearest release: v2.1.300, published 11 hours before upstream edited the page. Shown because the two are within 24 hours of each other. Nothing here says the release caused the edit.

Upstream edited this page at 15 Oct 2026 01:28 UTC, give or take a minute or two: the time comes from Anthropic’s own sitemap rather than from a commit. This site recorded the change at 20 Oct 2026 18:37 UTC.

Upstream edited
Recorded here
Lines+128added
Lines−136removed
From line 13 where the diff opens
First seen 14 Aug 2026 this site's first read of the page
Recorded edits11to this page, all time

The whole hunk

from line 13, old and new numbered
/
lines
from line 13
1313 
1414This guide explains how the SDK emits telemetry, how to configure the export, and how to tag and filter the data once it reaches your backend. To read token usage and cost directly from the SDK response stream instead of exporting to a backend, see [Track cost and usage](/docs/en/agent-sdk/cost-tracking).
1515 
16<Note>
17 For the Claude API or Managed Agents, see [OpenTelemetry for the Claude API](https://platform.claude.com/docs/en/manage-claude/opentelemetry).
18</Note>
16> [!NOTE]
17>
18> For the Claude API or Managed Agents, see [OpenTelemetry for the Claude API](https://platform.claude.com/docs/en/manage-claude/opentelemetry).
1919 
2020## How telemetry flows from the SDK
2121 
from line 42
4242 
4343The following example sets the variables in a dictionary and passes them through `options.env`. The agent runs a single task, and the CLI exports spans, metrics, and events to the collector at `collector.example.com` while the loop consumes the response stream:
4444 
45<CodeGroup>
46 ```python Python theme={null}
47 import asyncio
48 from claude_agent_sdk import query, ClaudeAgentOptions
45```python Python theme={null}
46import asyncio
47from claude_agent_sdk import query, ClaudeAgentOptions
4948 
50 OTEL_ENV = {
51 "CLAUDE_CODE_ENABLE_TELEMETRY": "1",
52 # Required for traces, which are in beta. Metrics and log events do not need this.
53 "CLAUDE_CODE_ENHANCED_TELEMETRY_BETA": "1",
54 # Choose an exporter per signal. Use otlp for the SDK; see the Note below.
55 "OTEL_TRACES_EXPORTER": "otlp",
56 "OTEL_METRICS_EXPORTER": "otlp",
57 "OTEL_LOGS_EXPORTER": "otlp",
58 # Standard OTLP transport configuration.
59 "OTEL_EXPORTER_OTLP_PROTOCOL": "http/protobuf",
60 "OTEL_EXPORTER_OTLP_ENDPOINT": "http://collector.example.com:4318",
61 "OTEL_EXPORTER_OTLP_HEADERS": "Authorization=Bearer your-token",
62 }
49OTEL_ENV = {
50 "CLAUDE_CODE_ENABLE_TELEMETRY": "1",
51 # Required for traces, which are in beta. Metrics and log events do not need this.
52 "CLAUDE_CODE_ENHANCED_TELEMETRY_BETA": "1",
53 # Choose an exporter per signal. Use otlp for the SDK; see the Note below.
54 "OTEL_TRACES_EXPORTER": "otlp",
55 "OTEL_METRICS_EXPORTER": "otlp",
56 "OTEL_LOGS_EXPORTER": "otlp",
57 # Standard OTLP transport configuration.
58 "OTEL_EXPORTER_OTLP_PROTOCOL": "http/protobuf",
59 "OTEL_EXPORTER_OTLP_ENDPOINT": "http://collector.example.com:4318",
60 "OTEL_EXPORTER_OTLP_HEADERS": "Authorization=Bearer your-token",
61}
6362 
6463 
65 async def main():
66 options = ClaudeAgentOptions(env=OTEL_ENV)
67 async for message in query(
68 prompt="List the files in this directory", options=options
69 ):
70 print(message)
64async def main():
65 options = ClaudeAgentOptions(env=OTEL_ENV)
66 async for message in query(
67 prompt="List the files in this directory", options=options
68 ):
69 print(message)
7170 
7271 
73 asyncio.run(main())
74 ```
72asyncio.run(main())
73```
7574 
76 ```typescript TypeScript theme={null}
77 import { query } from "@anthropic-ai/claude-agent-sdk";
75```typescript TypeScript theme={null}
76import { query } from "@anthropic-ai/claude-agent-sdk";
7877 
79 const otelEnv = {
80 CLAUDE_CODE_ENABLE_TELEMETRY: "1",
81 // Required for traces, which are in beta. Metrics and log events do not need this.
82 CLAUDE_CODE_ENHANCED_TELEMETRY_BETA: "1",
83 // Choose an exporter per signal. Use otlp for the SDK; see the Note below.
84 OTEL_TRACES_EXPORTER: "otlp",
85 OTEL_METRICS_EXPORTER: "otlp",
86 OTEL_LOGS_EXPORTER: "otlp",
87 // Standard OTLP transport configuration.
88 OTEL_EXPORTER_OTLP_PROTOCOL: "http/protobuf",
89 OTEL_EXPORTER_OTLP_ENDPOINT: "http://collector.example.com:4318",
90 OTEL_EXPORTER_OTLP_HEADERS: "Authorization=Bearer your-token",
91 };
78const otelEnv = {
79 CLAUDE_CODE_ENABLE_TELEMETRY: "1",
80 // Required for traces, which are in beta. Metrics and log events do not need this.
81 CLAUDE_CODE_ENHANCED_TELEMETRY_BETA: "1",
82 // Choose an exporter per signal. Use otlp for the SDK; see the Note below.
83 OTEL_TRACES_EXPORTER: "otlp",
84 OTEL_METRICS_EXPORTER: "otlp",
85 OTEL_LOGS_EXPORTER: "otlp",
86 // Standard OTLP transport configuration.
87 OTEL_EXPORTER_OTLP_PROTOCOL: "http/protobuf",
88 OTEL_EXPORTER_OTLP_ENDPOINT: "http://collector.example.com:4318",
89 OTEL_EXPORTER_OTLP_HEADERS: "Authorization=Bearer your-token",
90};
9291 
93 for await (const message of query({
94 prompt: "List the files in this directory",
95 // env replaces the inherited environment in TypeScript, so spread
96 // process.env first to keep PATH, ANTHROPIC_API_KEY, and other variables.
97 options: { env: { ...process.env, ...otelEnv } },
98 })) {
99 console.log(message);
100 }
101 ```
102</CodeGroup>
92for await (const message of query({
93 prompt: "List the files in this directory",
94 // env replaces the inherited environment in TypeScript, so spread
95 // process.env first to keep PATH, ANTHROPIC_API_KEY, and other variables.
96 options: { env: { ...process.env, ...otelEnv } },
97})) {
98 console.log(message);
99}
100```
103101 
104102Because the child process inherits your application's environment by default, you can achieve the same result by exporting these variables in a Dockerfile, Kubernetes manifest, or shell profile and omitting `options.env` entirely.
105103 
106104To confirm that export is working, check your collector's logs for incoming spans, metrics, and log events after the task completes. The CLI fails silently on export errors by default: if the endpoint is unreachable or rejects the data, the agent still runs normally and the CLI drops the telemetry without surfacing an error in your application. To surface exporter errors, set [`CLAUDE_CODE_OTEL_DIAG_STDERR=1`](/docs/en/env-vars) alongside the exporter variables and read the diagnostics through the SDK's `stderr` callback (Python) or `stderr` option (TypeScript). Requires Claude Code v2.1.179 or later.
107105 
108<Note>
109 The `console` exporter writes telemetry to standard output, which the SDK uses
110 as its message channel. Do not set `console` as an exporter value when running
111 through the SDK. To inspect telemetry locally, point
112 `OTEL_EXPORTER_OTLP_ENDPOINT` at a local OpenTelemetry Collector instead.
113</Note>
106> [!NOTE]
107>
108> The `console` exporter writes telemetry to standard output, which the SDK uses
109> as its message channel. Do not set `console` as an exporter value when running
110> through the SDK. To inspect telemetry locally, point
111> `OTEL_EXPORTER_OTLP_ENDPOINT` at a local OpenTelemetry Collector instead.
114112 
115113### Flush telemetry from short-lived calls
116114 
from line 116
118116 
119117By default, metrics export every 60 seconds and traces and logs export every 5 seconds. The following example shortens all three intervals so that data reaches the collector while a short task is still running:
120118 
121<CodeGroup>
122 ```python Python theme={null}
123 OTEL_ENV = {
124 # ... exporter configuration from the previous example ...
125 "OTEL_METRIC_EXPORT_INTERVAL": "1000",
126 "OTEL_LOGS_EXPORT_INTERVAL": "1000",
127 "OTEL_TRACES_EXPORT_INTERVAL": "1000",
128 }
129 ```
119```python Python theme={null}
120OTEL_ENV = {
121 # ... exporter configuration from the previous example ...
122 "OTEL_METRIC_EXPORT_INTERVAL": "1000",
123 "OTEL_LOGS_EXPORT_INTERVAL": "1000",
124 "OTEL_TRACES_EXPORT_INTERVAL": "1000",
125}
126```
130127 
131 ```typescript TypeScript theme={null}
132 const otelEnv = {
133 // ... exporter configuration from the previous example ...
134 OTEL_METRIC_EXPORT_INTERVAL: "1000",
135 OTEL_LOGS_EXPORT_INTERVAL: "1000",
136 OTEL_TRACES_EXPORT_INTERVAL: "1000",
137 };
138 ```
139</CodeGroup>
128```typescript TypeScript theme={null}
129const otelEnv = {
130 // ... exporter configuration from the previous example ...
131 OTEL_METRIC_EXPORT_INTERVAL: "1000",
132 OTEL_LOGS_EXPORT_INTERVAL: "1000",
133 OTEL_TRACES_EXPORT_INTERVAL: "1000",
134};
135```
140136 
141137## Read agent traces
142138 
from line 147
151147 
152148Spans carry a `session.id` attribute by default. When you make several `query()` calls against the same [session](/docs/en/agent-sdk/sessions), filter on `session.id` in your backend to see them as one timeline. Claude Code omits the attribute if you set `OTEL_METRICS_INCLUDE_SESSION_ID` to a falsy value.
153149 
154<Note>
155 Tracing is in beta. Span names and attributes may change between releases. See
156 [Traces (beta)](/docs/en/monitoring-usage#traces-beta) in the Monitoring reference
157 for the trace exporter configuration variables.
158</Note>
150> [!NOTE]
151>
152> Tracing is in beta. Span names and attributes may change between releases. See
153> [Traces (beta)](/docs/en/monitoring-usage#traces-beta) in the Monitoring reference
154> for the trace exporter configuration variables.
159155 
160156## Link traces to your application
161157 
from line 169
173169 
174170The following example renames the service and attaches deployment metadata. These values are applied as OpenTelemetry resource attributes on every span, metric, and event the agent emits:
175171 
176<CodeGroup>
177 ```python Python theme={null}
178 options = ClaudeAgentOptions(
179 env={
180 # ... exporter configuration from the Enable telemetry export example ...
181 "OTEL_SERVICE_NAME": "support-triage-agent",
182 "OTEL_RESOURCE_ATTRIBUTES": "service.version=1.4.0,deployment.environment=production",
183 },
184 )
185 ```
186 
187 ```typescript TypeScript theme={null}
188 const options = {
189 env: {
190 ...process.env,
191 // ... exporter configuration from the Enable telemetry export example ...
192 OTEL_SERVICE_NAME: "support-triage-agent",
193 OTEL_RESOURCE_ATTRIBUTES:
194 "service.version=1.4.0,deployment.environment=production",
172```python Python theme={null}
173options = ClaudeAgentOptions(
174 env={
175 # ... exporter configuration from the Enable telemetry export example ...
176 "OTEL_SERVICE_NAME": "support-triage-agent",
177 "OTEL_RESOURCE_ATTRIBUTES": "service.version=1.4.0,deployment.environment=production",
195178 },
196 };
197 ```
198</CodeGroup>
179)
180```
199181 
182```typescript TypeScript theme={null}
183const options = {
184 env: {
185 ...process.env,
186 // ... exporter configuration from the Enable telemetry export example ...
187 OTEL_SERVICE_NAME: "support-triage-agent",
188 OTEL_RESOURCE_ATTRIBUTES:
189 "service.version=1.4.0,deployment.environment=production",
190 },
191};
192```
193 
200194## Attribute actions to your end users
201195 
202196The CLI attaches [identity attributes](/docs/en/monitoring-usage#standard-attributes) to every event based on the credential it uses to call Anthropic. When you build an application that serves many end users from one deployment, these attributes identify your service's credential, not the end user on whose behalf the agent acted.
from line 197
203197 
204198To make tool calls and MCP activity attributable to your application's end users, inject end-user identity as resource attributes on each `query()` call. Percent-encode values before interpolating them, since `OTEL_RESOURCE_ATTRIBUTES` [reserves commas, spaces, and equals signs](/docs/en/monitoring-usage#multi-team-organization-support). The following example attaches the requesting user and tenant to every span and event from one request. It assumes a `request` object from your web framework carrying the user and tenant IDs:
205199 
206<CodeGroup>
207 ```python Python theme={null}
208 from urllib.parse import quote
200```python Python theme={null}
201from urllib.parse import quote
209202 
210 options = ClaudeAgentOptions(
211 env={
212 # ... exporter configuration from the Enable telemetry export example ...
213 # request is the incoming request object from your web framework.
214 "OTEL_RESOURCE_ATTRIBUTES": f"enduser.id={quote(request.user_id)},tenant.id={quote(request.tenant_id)}",
215 },
216 )
217 ```
218 
219 ```typescript TypeScript theme={null}
220 const options = {
221 env: {
222 ...process.env,
223 // ... exporter configuration from the Enable telemetry export example ...
224 // request is the incoming request object from your web framework.
225 OTEL_RESOURCE_ATTRIBUTES: `enduser.id=${encodeURIComponent(request.userId)},tenant.id=${encodeURIComponent(request.tenantId)}`,
203options = ClaudeAgentOptions(
204 env={
205 # ... exporter configuration from the Enable telemetry export example ...
206 # request is the incoming request object from your web framework.
207 "OTEL_RESOURCE_ATTRIBUTES": f"enduser.id={quote(request.user_id)},tenant.id={quote(request.tenant_id)}",
226208 },
227 };
228 ```
229</CodeGroup>
209)
210```
211 
212```typescript TypeScript theme={null}
213const options = {
214 env: {
215 ...process.env,
216 // ... exporter configuration from the Enable telemetry export example ...
217 // request is the incoming request object from your web framework.
218 OTEL_RESOURCE_ATTRIBUTES: `enduser.id=${encodeURIComponent(request.userId)},tenant.id=${encodeURIComponent(request.tenantId)}`,
219 },
220};
221```
230222 
231223With end-user identity attached, the `tool_decision`, `tool_result`, `mcp_server_connection`, and `permission_mode_changed` events, which export as log records named with a `claude_code.` prefix, become a per-user audit trail you can forward to a Security Information and Event Management (SIEM) platform. See [Audit security events](/docs/en/monitoring-usage#audit-security-events) in the Monitoring reference for the full list of security-relevant events and the attributes each one carries.
232224 
Feedback