Skip to main content

OpenTelemetry instrumentation for the Anthropic Claude Agent SDK

Project description

opentelemetry-instrumentation-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() and ClaudeSDKClient operations
  • 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 Instrumentor pattern (instrument()/uninstrument())

Installation

pip install opentelemetry-instrumentation-claude-agent-sdk

With the Claude Agent SDK (if not already installed):

pip install opentelemetry-instrumentation-claude-agent-sdk[instruments]

Requirements

  • Python >= 3.10
  • opentelemetry-api >= 1.12
  • opentelemetry-instrumentation >= 0.50b0
  • claude-agent-sdk >= 0.1.37

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.

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)

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:

  1. Copy the env template:
    cp tests/integration/.env.example tests/integration/.env
    
  2. Add your OAuth token to tests/integration/.env:
    CLAUDE_CODE_OAUTH_TOKEN=your-token-here
    
  3. Run:
    make test-integration
    

Integration tests use max_turns=1 and permission_mode="plan" to minimize cost and prevent runaway execution.

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, 58 tests)
    integration/         # Integration tests (real API, 18 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

otel_instrumentation_claude_agent_sdk-0.0.2.tar.gz (210.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

File details

Details for the file otel_instrumentation_claude_agent_sdk-0.0.2.tar.gz.

File metadata

File hashes

Hashes for otel_instrumentation_claude_agent_sdk-0.0.2.tar.gz
Algorithm Hash digest
SHA256 1b979e1838487bf63fb4b7a91c063b46da531e0f9c428c6d5b9dfefb3458f810
MD5 a67db84e244657c62e217dfbdeedbfff
BLAKE2b-256 ccee7d93f6a8a2508decfb612ff50bf28e02b6a7f1d71d4066aabd0ebf1e70ef

See more details on using hashes here.

Provenance

The following attestation bundles were made for otel_instrumentation_claude_agent_sdk-0.0.2.tar.gz:

Publisher: release.yml on justinbarias/opentelemetry-instrumentation-claude-agent-sdk

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file otel_instrumentation_claude_agent_sdk-0.0.2-py3-none-any.whl.

File metadata

File hashes

Hashes for otel_instrumentation_claude_agent_sdk-0.0.2-py3-none-any.whl
Algorithm Hash digest
SHA256 3787d9ff3309584abe375762e7873bb7a5084d6c38378dfd048465b27a82af64
MD5 bf7c4a8bf593f7aba3d31d771f5225f2
BLAKE2b-256 7eb492a19ec680451ebff5b2417a7da1ae6c824006350f1deee25adf89bfd678

See more details on using hashes here.

Provenance

The following attestation bundles were made for otel_instrumentation_claude_agent_sdk-0.0.2-py3-none-any.whl:

Publisher: release.yml on justinbarias/opentelemetry-instrumentation-claude-agent-sdk

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page