See exactly what Claude Code is doing — every prompt, tool call, API request, and dollar spent — in beautiful Grafana dashboards.
┌──────────────┐ OTLP gRPC ┌─────────────────┐ ┌────────────┐ ┌──────────┐
│ Claude Code │ ─────────────► │ OTel Collector │───►│ Prometheus │───►│ │
│ (your CLI) │ :4317 │ │ └────────────┘ │ Grafana │
└──────────────┘ │ │ ┌────────────┐ │ :3001 │
│ │───►│ Loki │───►│ │
└─────────────────┘ └────────────┘ └──────────┘
Prerequisites: Docker Desktop must be installed and running.
git clone https://github.com/ealexisaraujo/claude-code-otel.git
cd claude-code-otel
./setup.shThat's it. Open a new terminal, run claude, and watch the data flow into your dashboards.
http://localhost:3001/d/claude-code-personal/
- Total cost (USD), tokens used, active sessions
- Cost over time by model
- Token usage breakdown (input/output/cache)
- Session activity timeline
http://localhost:3001/d/claude-code-deep/
- Full prompt log with actual text content
- Tool usage distribution and execution times
- MCP server and Skills tracking
- API cost per request, response times by model
- Complete session event stream
Claude Code has built-in OpenTelemetry support. When enabled, it exports metrics and events to any OTLP-compatible collector.
This project runs four Docker containers:
| Service | What It Does |
|---|---|
| OTel Collector | Receives telemetry from Claude Code and routes it |
| Prometheus | Stores metrics (cost, tokens, sessions) |
| Loki | Stores events (prompts, tool calls, API requests) |
| Grafana | Visualizes everything in two dashboards |
| Image Renderer | Enables PNG export and sharing of dashboard panels |
The setup script configures the environment variables that tell Claude Code where to send telemetry.
If you prefer to set things up yourself instead of using the setup script:
Add these to your ~/.zshrc (or ~/.bashrc):
# Claude Code OpenTelemetry - Observability Stack
export CLAUDE_CODE_ENABLE_TELEMETRY=1
export OTEL_METRICS_EXPORTER=otlp
export OTEL_LOGS_EXPORTER=otlp
export OTEL_EXPORTER_OTLP_PROTOCOL=grpc
export OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4317
export OTEL_METRIC_EXPORT_INTERVAL=60000
export OTEL_LOGS_EXPORT_INTERVAL=5000
export OTEL_METRICS_INCLUDE_SESSION_ID=true
export OTEL_METRICS_INCLUDE_ACCOUNT_UUID=true
export OTEL_LOG_TOOL_DETAILS=1
export OTEL_LOG_USER_PROMPTS=1docker compose up -dclaudeEnvironment variables are read at Claude Code startup, so you need a fresh terminal.
# Start the stack
docker compose up -d
# Stop (keeps your data)
docker compose stop
# View container status
docker compose ps
# View collector logs (see telemetry arriving)
docker logs otel-collector --tail 20 -f| URL | http://localhost:3001 |
| Username | admin |
| Password | ClaudeCode2026 |
| Port | Service |
|---|---|
| 3001 | Grafana (dashboards) |
| 4317 | OTel Collector (OTLP gRPC — Claude Code sends here) |
| 4318 | OTel Collector (OTLP HTTP) |
| 8889 | OTel Collector (Prometheus exporter) |
| 9090 | Prometheus |
| 3100 | Loki |
Most common cause: Claude Code was started before the environment variables were set.
- Verify the env vars are active:
echo $CLAUDE_CODE_ENABLE_TELEMETRYshould print1 - If not, open a new terminal (to pick up the env vars) and restart Claude Code
- Check containers are running:
docker compose ps— all 4 should show "Up"
- Check
echo $OTEL_LOGS_EXPORTER— should printotlp - Check Loki is healthy:
curl http://localhost:3100/ready
- Check
echo $OTEL_LOG_TOOL_DETAILS— should print1 - Without this, MCP server names and skill names are redacted from events
- Metrics export every 60 seconds (
OTEL_METRIC_EXPORT_INTERVAL) - Events export every 5 seconds (
OTEL_LOGS_EXPORT_INTERVAL) - After starting Claude Code, wait ~60s for the first metrics to appear
# Stop and remove containers + data
docker compose down -v
# Remove environment variables: delete the "Claude Code OpenTelemetry" block from ~/.zshrc- Prometheus metrics: 200 hours (~8 days)
- Loki events: 744 hours (31 days)
- Data persists across container restarts. Only
docker compose down -vdeletes data.
| Event | When | Key Data |
|---|---|---|
user_prompt |
You send a prompt | Prompt text, length |
tool_result |
A tool finishes | Tool name, success, duration, MCP server |
api_request |
API call completes | Model, cost, tokens, response time |
api_error |
API call fails | Error, status code, retry attempt |
tool_decision |
Tool accepted/rejected | Tool name, decision, source |
- Claude Code Monitoring Docs
- Claude Code Monitoring Guide
- OpenTelemetry Collector Contrib
- Loki OTLP Ingestion
MIT