CertSafari
    Anthropic Claude Certified Architect – Professional (CCAR-P)· Lessons

    Domain 4 · Lesson 25/38

    OpenTelemetry Metrics, Logs and Traces for Claude Agents

    Monitor system performance using logging and observability tools

    9 min read
    2.67% of exam
    2 sources
    Published 4 Oct 2026
    Docs as of 30 Sep 2026

    What you will be able to do

    • Name the three OpenTelemetry signals that Claude Code and the Agent SDK emit, and say how to enable each one
    • Configure exporters, the OTLP endpoint and export intervals, through the process environment or per-call options
    • Use claude_code.llm_request span attributes to diagnose latency, token use, caching and failures
    • Choose a backend type that fits each signal

    Key concept

    OpenTelemetry export — Claude Code and the Agent SDK can export three opt-in telemetry signals to a backend you choose: metrics, structured log events and trace spans. You turn them on and route them with environment variables. You don't need to add instrumentation code.

    1.Three signals, three questions

    An agent in production fails in ways one log line can't explain. It might call the wrong tool, a model request might stall, or it might spend far more tokens than expected. The Agent SDK observability guide lists what telemetry lets you see: which tools the agent called, how long each model request took, how many tokens were spent, and where failures occurred.

    Claude Code and the Agent SDK answer these questions with three separate OpenTelemetry signals. Each has a different shape, and each is switched on separately. Metrics are aggregate counters, which suit trends and alerts. Log events are one structured record per occurrence, which suit investigating a single request. Traces are timed spans nested in parent/child order, which show where time went within one turn.

    The three signals and how to enable each
    SignalWhat it containsEnable with
    MetricsCounters for tokens, cost, sessions, lines of code, and tool decisionsOTEL_METRICS_EXPORTER
    Log eventsStructured records for each prompt, API request, API error, and tool resultOTEL_LOGS_EXPORTER
    TracesSpans for each interaction, model request, tool call, and hook (beta)OTEL_TRACES_EXPORTER plus CLAUDE_CODE_ENHANCED_TELEMETRY_BETA=1

    None of these signals is on by default. All three need CLAUDE_CODE_ENABLE_TELEMETRY=1, which the configuration reference marks as required. Traces are in beta, so they also need a second flag that metrics and log events don't.

    Checkpoint 1 of 6· Check yourself

    You set CLAUDE_CODE_ENABLE_TELEMETRY=1 and OTEL_TRACES_EXPORTER=otlp, but no spans reach your collector. Metrics and log events arrive normally. What is missing?

    Checkpoint 2 of 6· Exam question

    A platform engineer sets CLAUDE_CODE_ENABLE_TELEMETRY=1 on every CI runner but the team's OTLP collector never receives any spans, metrics, or logs from Claude Code jobs. No other telemetry variables were configured. What is the most likely cause of the missing data?

    Sources12

    2.Wiring telemetry to a collector

    After you enable telemetry, you pick an exporter for each signal. The choices include otlp, console and none, and metrics can also use prometheus. With OTLP you also give a collector endpoint, a protocol and any authentication headers. Set the protocol explicitly. The reference says Claude Code has no default protocol, so you must set this or the signal-specific protocol variable for each otlp exporter you enable.

    The Agent SDK gives you two places to set these variables. The guide recommends the process environment for production: set the variables in your shell, container or orchestrator, and every query() call picks them up. Per-call options (ClaudeAgentOptions.env in Python, options.env in TypeScript) are for cases where different agents in one process need different settings.

    Agent SDK (Python): one dict that enables all three signals and points them at an OTLP collectorpython
    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",
    }

    The two SDKs treat per-call env differently. In Python, env is merged on top of the inherited environment. In TypeScript, env replaces the inherited environment entirely, so you have to spread process.env into it. Otherwise PATH, ANTHROPIC_API_KEY and other variables are lost.

    Export intervals control how quickly data appears. Metrics export every 60000 ms by default, and logs every 5000 ms. The setup guide suggests shortening the intervals while debugging and resetting them before production.

    Checkpoint 3 of 6· Put it in order

    Put the Claude Code telemetry setup steps in the order the monitoring guide lists them

    1. 1.Configure the OTLP protocol and collector endpoint
    2. 2.Run Claude Code
    3. 3.Set authentication headers if the collector requires them
    4. 4.Choose the metrics and logs exporters
    5. 5.Enable telemetry with CLAUDE_CODE_ENABLE_TELEMETRY=1

    Sources21

    3.Reading a trace: where the time and tokens went

    Traces divide one agent turn into nested spans. The root is claude_code.interaction, which covers one turn from prompt to response. Under it are a claude_code.llm_request span for each call to the Claude API and a claude_code.tool span for each tool invocation. Each tool span splits into the permission wait and the actual execution. So a slow turn can be traced to the model, to a tool, or to a person who hasn't approved a tool yet. Subagents launched with the Agent tool show up as their own llm_request and tool spans inside the parent tool span. The claude_code.hook span appears only with detailed beta tracing, which also changes where logs and traces are sent.

    Most of the performance data is on the llm_request span.

    claude_code.llm_request attributes and the question each one answers
    AttributeMeaningDiagnoses
    duration_msWall-clock duration including retriesSlow model calls
    ttft_msTime to first token in millisecondsPerceived responsiveness
    input_tokens / output_tokensToken counts from the API usage blockCost and context growth
    cache_read_tokens / cache_creation_tokensTokens read from / written to prompt cacheWhether caching is working
    attemptTotal attempts made for this requestRetries hiding behind latency
    error_classShort error class token, such as api_timeout or server_overloadFailure categories
    stop_reasonend_turn, tool_use, max_tokens, stop_sequence, pause_turn, or refusalTruncated or refused output
    agent_idSubagent or teammate that issued the request; absent on the main sessionWhich agent spent the tokens

    Because duration_ms includes retries, a high value doesn't by itself mean the model was slow. Check attempt and error_class before you blame the model. A stop_reason of max_tokens explains a truncated answer that the latency numbers would not reveal.

    Checkpoint 4 of 6· Match them up

    Match each llm_request attribute to what it tells you

    Tap a term, then the definition that fits it.

    Checkpoint 5 of 6· Exam question

    A metrics backend's bill spikes because every exported time series carries a unique session.id, fragmenting cardinality across thousands of short-lived CLI sessions. The team still needs cost and token totals broken down by model. Which change addresses the cardinality problem without losing the model breakdown?

    Sources12

    4.Matching each signal to a backend

    The signals have different shapes, so they suit different storage. The monitoring guide lists which backend types fit each signal. Many teams send all three to one full-featured observability platform so they can correlate them, for example by jumping from a cost spike on a metric chart to the trace that caused it.

    Backend types suggested for each signal
    SignalBackend typeStrength
    MetricsTime series databasesRate calculations, aggregated metrics
    MetricsColumnar storesComplex queries, unique user analysis
    Log eventsLog aggregation systemsFull-text search, log analysis
    Log eventsColumnar storesStructured event analysis
    TracesDistributed tracing systemsSpan visualization, request waterfalls, latency analysis
    All signalsFull-featured observability platformsQuerying, visualization, alerting, and correlation across signals

    Checkpoint 6 of 6· Check yourself

    You want a request waterfall that shows a slow tool call nested inside an agent turn. Which backend type is listed for this?

    Sources2

    Exam traps

    Each one states something that sounds right. Open it to see what is actually true.

    1. 1.Setting OTEL_TRACES_EXPORTER=otlp is enough to start exporting spans.Why is that wrong?

      Traces are in beta. They also need CLAUDE_CODE_ENHANCED_TELEMETRY_BETA=1 on top of CLAUDE_CODE_ENABLE_TELEMETRY=1.

      Covered in Three signals, three questions

    2. 2.Per-call env in the TypeScript Agent SDK is merged with the inherited environment, as it is in Python.Why is that wrong?

      In TypeScript, env replaces the inherited environment. Spread process.env into it or you lose PATH and ANTHROPIC_API_KEY.

      Covered in Wiring telemetry to a collector

    Sources

    Every claim above is drawn from one of these pages, quoted as it was written on the date shown.

    1. 1.
      “Counters for tokens, cost, sessions, lines of code, and tool decisions”
      ↩︎ Three signals, three questions
      “This is the recommended approach for production deployments.”
      ↩︎ Wiring telemetry to a collector
      “wraps each call to the Claude API, with model name, latency, and token counts as attributes.”
      ↩︎ Reading a trace: where the time and tokens went
      “Export traces, metrics, and events from the Agent SDK to your observability backend using OpenTelemetry.”
      ↩︎ Key concept
      “OTEL_TRACES_EXPORTER plus CLAUDE_CODE_ENHANCED_TELEMETRY_BETA=1”
      ↩︎ Exam trap 1
      “In TypeScript, env replaces the inherited environment entirely, so include ...process.env in the object you pass.”
      ↩︎ Exam trap 2
      “OTEL_TRACES_EXPORTER plus CLAUDE_CODE_ENHANCED_TELEMETRY_BETA=1”
      ↩︎ Checkpoint
      “with child spans for the permission wait (claude_code.tool.blocked_on_user) and the execution itself (claude_code.tool.execution).”
      ↩︎ Prediction
    2. 2.
      “Enables telemetry collection (required)”
      ↩︎ Three signals, three questions
      “Claude Code has no default protocol, so set this or the signal-specific protocol variable for each otlp exporter you enable”
      ↩︎ Wiring telemetry to a collector
      “For debugging: reduce export intervals, and reset them for production use”
      ↩︎ Wiring telemetry to a collector
      “Wall-clock duration including retries”
      ↩︎ Reading a trace: where the time and tokens went
      “Full-featured observability platforms: Correlation between metrics and events”
      ↩︎ Matching each signal to a backend
      “# 2. Choose exporters (both are optional - configure only what you need)”
      ↩︎ Checkpoint
      “Short error class token when the request failed, such as api_timeout or server_overload.”
      ↩︎ Checkpoint
      “Distributed tracing systems: Span visualization, request waterfalls, latency analysis”
      ↩︎ Checkpoint

    Continue to page 2 of 2

    Telemetry Content Gates, Audit Events and the Usage & Cost API

    Spotted a mistake, or was something unclear? Tell us.