0013. OpenTelemetry for Claude Code¶
Status¶
Accepted
Context¶
The dev-monitor dashboard (monitor/main.go) reads Claude Code JSONL logs to surface
token usage and cost estimates. Users working with multiple projects want richer
observability: distributed traces spanning agent loops and tool calls, aggregated token
counters across sessions, and structured log events that can feed a SIEM.
Two approaches were considered:
- Add Go OpenTelemetry SDK to
monitor/main.go— instrument the Go binary to re-emit parsed JSONL data as OTLP spans and metrics to an external collector. - Use Claude Code CLI's built-in OTEL instrumentation — configure the existing instrumentation via environment variables; no code changes.
Decision¶
Use the Claude Code CLI's built-in OpenTelemetry instrumentation (option 2). No changes
to monitor/main.go, go.mod, or go.sum.
The Claude Code CLI already emits three independent OTEL signals when enabled:
| Signal | Enable env var | Content |
|---|---|---|
| Metrics | OTEL_METRICS_EXPORTER=otlp |
Token counters, cost, sessions, tool decisions |
| Log events | OTEL_LOGS_EXPORTER=otlp |
Prompts, API requests, API errors, tool results |
| Traces (beta) | OTEL_TRACES_EXPORTER=otlp + CLAUDE_CODE_ENHANCED_TELEMETRY_BETA=1 |
Spans per interaction, model request, tool call |
The master enable switch is CLAUDE_CODE_ENABLE_TELEMETRY=1. All variables are
inherited by the CLI child process — no wrapping or SDK integration is required.
Configuration¶
Set in the host shell, devcontainer.json remoteEnv, or a container orchestrator:
CLAUDE_CODE_ENABLE_TELEMETRY=1
CLAUDE_CODE_ENHANCED_TELEMETRY_BETA=1 # traces (beta)
OTEL_TRACES_EXPORTER=otlp
OTEL_METRICS_EXPORTER=otlp
OTEL_LOGS_EXPORTER=otlp
OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf
OTEL_EXPORTER_OTLP_ENDPOINT=http://collector.example.com:4318
OTEL_EXPORTER_OTLP_HEADERS=Authorization=Bearer your-token
OTEL_SERVICE_NAME=claude-code # override default
Compatible backends: Honeycomb, Datadog, Grafana, Langfuse, Jaeger, or any OTLP-capable
collector. Add the collector hostname to proxy.yaml and egress-allowlist.txt.
Sensitive data opt-ins (off by default)¶
| Variable | Adds to telemetry |
|---|---|
OTEL_LOG_USER_PROMPTS=1 |
Prompt text on interaction spans |
OTEL_LOG_TOOL_DETAILS=1 |
Tool input arguments (file paths, commands) |
OTEL_LOG_TOOL_CONTENT=1 |
Full tool input/output bodies (requires traces) |
Leave these unset unless your observability pipeline is approved to handle that data.
Consequences¶
Accepted:
- Zero code changes to the monitor binary.
- No new Go dependencies — go.mod and go.sum unchanged.
- Immediate: any project can opt in by setting env vars, no rebuild required.
- Works with any OTLP-compatible backend.
- Traces are beta; span names and attributes may change between Claude Code releases.
Rejected (option 1 rationale): - Adding the Go OTEL SDK would duplicate instrumentation the CLI already provides. - It would add external dependencies to the otherwise stdlib-only monitor binary. - It would only see parsed JSONL data, not live spans with accurate latencies.
References¶
- Claude Code observability docs:
https://docs.claude.com/en/docs/claude-code/monitoring-usage - OTEL env var reference:
https://opentelemetry.io/docs/specs/otel/configuration/sdk-environment-variables/ - ADR 0009: proxy–mitm–monitor observability stack