OpenTelemetry instrumentation for the Anthropic Claude Agent SDK
Project description
opentelemetry-claude-agent-sdk
OpenTelemetry instrumentation for the Anthropic Claude Agent SDK.
This package provides automatic tracing and metrics for Claude Agent SDK operations following the OpenTelemetry GenAI Semantic Conventions.
Status
Alpha - Under active development.
Features
- Automatic span creation for
query()andClaudeSDKClientoperations - Hook-driven
execute_toolchild spans for every tool call (PreToolUse/PostToolUse/PostToolUseFailure) - Optional tool content capture (arguments and results) via
capture_content=True - Token usage tracking (input, output, cache creation, cache read)
- Operation duration histograms
- Conversation ID propagation across multi-turn interactions
- Response model and finish reason capture
- Zero overhead when no TracerProvider/MeterProvider is configured
- Follows the standard OTel
Instrumentorpattern (instrument()/uninstrument())
Installation
pip install opentelemetry-claude-agent-sdk
With the Claude Agent SDK (if not already installed):
pip install opentelemetry-claude-agent-sdk[instruments]
Requirements
- Python >= 3.10
- opentelemetry-api >= 1.12
- opentelemetry-instrumentation >= 0.50b0
- claude-agent-sdk >= 0.1.44 (hooks support in
query()requires >= 0.1.44)
Quick Start
Basic Instrumentation
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import SimpleSpanProcessor, ConsoleSpanExporter
from opentelemetry.instrumentation.claude_agent_sdk import ClaudeAgentSdkInstrumentor
# Set up OTel tracing
provider = TracerProvider()
provider.add_span_processor(SimpleSpanProcessor(ConsoleSpanExporter()))
# Instrument the Claude Agent SDK
instrumentor = ClaudeAgentSdkInstrumentor()
instrumentor.instrument(tracer_provider=provider)
# Now all query() and ClaudeSDKClient calls are automatically traced
import claude_agent_sdk
async for message in claude_agent_sdk.query(prompt="Hello, Claude!"):
pass # Spans are created and exported automatically
# To remove instrumentation
instrumentor.uninstrument()
With Metrics
from opentelemetry.sdk.metrics import MeterProvider
from opentelemetry.sdk.metrics.export import ConsoleMetricReader
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.trace.export import SimpleSpanProcessor, ConsoleSpanExporter
from opentelemetry.instrumentation.claude_agent_sdk import ClaudeAgentSdkInstrumentor
# Set up tracing
tracer_provider = TracerProvider()
tracer_provider.add_span_processor(SimpleSpanProcessor(ConsoleSpanExporter()))
# Set up metrics
meter_provider = MeterProvider(metric_readers=[ConsoleMetricReader()])
# Instrument with both
instrumentor = ClaudeAgentSdkInstrumentor()
instrumentor.instrument(
tracer_provider=tracer_provider,
meter_provider=meter_provider,
)
With Agent Name
Setting an agent name adds it to span names and attributes, useful for distinguishing multiple agents:
instrumentor.instrument(
tracer_provider=tracer_provider,
agent_name="my-research-agent",
)
# Span names become: "invoke_agent my-research-agent"
Multi-Turn with ClaudeSDKClient
The instrumentor automatically traces ClaudeSDKClient multi-turn conversations, creating one span per query/receive_response cycle:
import claude_agent_sdk
client = claude_agent_sdk.ClaudeSDKClient(options=claude_agent_sdk.ClaudeAgentOptions())
await client.connect()
# Turn 1 — creates span 1
await client.query("What is quantum computing?")
async for message in client.receive_response():
pass
# Turn 2 — creates span 2 (shares conversation ID with span 1)
await client.query("Explain it simpler.")
async for message in client.receive_response():
pass
await client.disconnect()
Telemetry Reference
Spans
Each query() call or ClaudeSDKClient.query()/receive_response() cycle produces one invoke_agent span with kind CLIENT. When tools are used, each tool call produces an execute_tool child span with kind INTERNAL.
invoke_agent span (CLIENT)
| Attribute | Type | Description |
|---|---|---|
gen_ai.operation.name |
string | Always "invoke_agent" |
gen_ai.system |
string | Always "anthropic" |
gen_ai.agent.name |
string | Agent name (if configured) |
gen_ai.request.model |
string | Requested model (from options) |
gen_ai.response.model |
string | Actual model used (from response) |
gen_ai.usage.input_tokens |
int | Total input tokens (including cache) |
gen_ai.usage.output_tokens |
int | Output tokens |
gen_ai.usage.cache_creation_input_tokens |
int | Cache creation tokens (if > 0) |
gen_ai.usage.cache_read_input_tokens |
int | Cache read tokens (if > 0) |
gen_ai.response.finish_reasons |
string[] | e.g. ["end_turn"], ["error"], ["max_tokens"] |
gen_ai.conversation.id |
string | Session ID (shared across multi-turn) |
error.type |
string | Exception type (on error only) |
execute_tool span (INTERNAL, child of invoke_agent)
| Attribute | Type | Description |
|---|---|---|
gen_ai.operation.name |
string | Always "execute_tool" |
gen_ai.system |
string | Always "anthropic" |
gen_ai.tool.name |
string | Tool name (e.g., "Bash", "Read") |
gen_ai.tool.call.id |
string | Unique tool use ID for correlation |
gen_ai.tool.type |
string | "function" for built-in tools, "extension" for MCP tools (mcp__*) |
gen_ai.tool.call.arguments |
string | Tool input (only when capture_content=True) |
gen_ai.tool.call.result |
string | Tool output (only when capture_content=True) |
error.type |
string | Error message (on tool failure only) |
Metrics
| Metric | Type | Unit | Description |
|---|---|---|---|
gen_ai.client.token.usage |
Histogram | {token} |
Token counts with gen_ai.token.type dimension ("input" or "output") |
gen_ai.client.operation.duration |
Histogram | s |
Operation wall-clock duration |
Both metrics include gen_ai.operation.name, gen_ai.system, and gen_ai.request.model as dimensions. The duration metric includes error.type on failure.
Configuration Options
| Parameter | Type | Default | Description |
|---|---|---|---|
tracer_provider |
TracerProvider |
Global | Custom tracer provider |
meter_provider |
MeterProvider |
Global | Custom meter provider |
agent_name |
str |
None |
Agent name for span names and attributes |
capture_content |
bool |
False |
Reserved for future content capture support |
Development
Prerequisites
- uv (Python package manager)
- Python 3.10+
Setup
# Full initialization (install deps + pre-commit hooks)
make init
# Or step by step:
make install-dev
make install-hooks
Running Tests
make test # Run all tests (unit + integration)
make test-unit # Run unit tests only (58 tests)
make test-integration # Run integration tests (requires API token)
make test-coverage # Run tests with coverage (80% threshold)
Integration Tests
Integration tests make real API calls to Claude. To run them:
- Copy the env template:
cp tests/integration/.env.example tests/integration/.env
- Add your OAuth token to
tests/integration/.env:CLAUDE_CODE_OAUTH_TOKEN=your-token-here - Run:
make test-integration
Integration tests use max_turns=3 and permission_mode="bypassPermissions" for tool tracing tests, or max_turns=1 for basic span/metric tests.
Code Quality
make lint # Ruff linter
make lint-fix # Ruff with auto-fix
make format # Black + isort formatting
make type-check # mypy (strict mode)
make security # bandit + pip-audit
make ci # Full CI pipeline locally
make ci-fast # Quick check: lint + test only
Project Structure
src/opentelemetry/instrumentation/claude_agent_sdk/
__init__.py # Package entry point, exports ClaudeAgentSdkInstrumentor
version.py # Dynamic version from package metadata
_instrumentor.py # Core instrumentor (wraps query, ClaudeSDKClient)
_spans.py # Span creation and attribute helpers
_metrics.py # Histogram creation and recording helpers
_hooks.py # SDK hook callbacks and merge utility
_context.py # Per-invocation context via contextvars
_constants.py # GenAI semantic convention constants
tests/
unit/ # Unit tests (mock SDK, 89 tests)
integration/ # Integration tests (real API, 28 tests)
License
MIT
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file opentelemetry_claude_agent_sdk-0.1.4.tar.gz.
File metadata
- Download URL: opentelemetry_claude_agent_sdk-0.1.4.tar.gz
- Upload date:
- Size: 224.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9836af0a4bf32ac81a2326655e666119d1b4532fcdef73696742f4baeeb6a658
|
|
| MD5 |
f3694136eec720abc40feb7fa0c20574
|
|
| BLAKE2b-256 |
41473b7a08ddba5e5e54b6fd964ec85b6686bcc73cb6a6c19a39461574adfbba
|
Provenance
The following attestation bundles were made for opentelemetry_claude_agent_sdk-0.1.4.tar.gz:
Publisher:
release.yml on zbirenbaum/opentelemetry-instrumentation-claude-agent-sdk
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
opentelemetry_claude_agent_sdk-0.1.4.tar.gz -
Subject digest:
9836af0a4bf32ac81a2326655e666119d1b4532fcdef73696742f4baeeb6a658 - Sigstore transparency entry: 1176835667
- Sigstore integration time:
-
Permalink:
zbirenbaum/opentelemetry-instrumentation-claude-agent-sdk@d65dcd974969073a6fbf77d865bc4c4c1d081da4 -
Branch / Tag:
refs/tags/v0.1.4 - Owner: https://github.com/zbirenbaum
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@d65dcd974969073a6fbf77d865bc4c4c1d081da4 -
Trigger Event:
release
-
Statement type:
File details
Details for the file opentelemetry_claude_agent_sdk-0.1.4-py3-none-any.whl.
File metadata
- Download URL: opentelemetry_claude_agent_sdk-0.1.4-py3-none-any.whl
- Upload date:
- Size: 18.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ba771c121d01747fba181b79c6a3bbbb340cb46a0044e4a6e8004acf9435d888
|
|
| MD5 |
1180ca14ecd8c40f36aefa94290edf85
|
|
| BLAKE2b-256 |
bce5aa7ba918d7699423d704844cbaf9516478154cb78e5f9b0943c39cfc1bf1
|
Provenance
The following attestation bundles were made for opentelemetry_claude_agent_sdk-0.1.4-py3-none-any.whl:
Publisher:
release.yml on zbirenbaum/opentelemetry-instrumentation-claude-agent-sdk
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
opentelemetry_claude_agent_sdk-0.1.4-py3-none-any.whl -
Subject digest:
ba771c121d01747fba181b79c6a3bbbb340cb46a0044e4a6e8004acf9435d888 - Sigstore transparency entry: 1176835875
- Sigstore integration time:
-
Permalink:
zbirenbaum/opentelemetry-instrumentation-claude-agent-sdk@d65dcd974969073a6fbf77d865bc4c4c1d081da4 -
Branch / Tag:
refs/tags/v0.1.4 - Owner: https://github.com/zbirenbaum
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@d65dcd974969073a6fbf77d865bc4c4c1d081da4 -
Trigger Event:
release
-
Statement type: