This guide walks through setting up OTEL telemetry from Claude Code to Prometheus + Grafana.
Architecture #
Claude Code --> OTLP/HTTP --> Prometheus --> Grafana
(metrics) (protobuf) (storage) (viz)
1. Environment Variables #
Add to your shell profile (~/.bashrc for Linux, ~/.zshrc for macOS):
export CLAUDE_CODE_ENABLE_TELEMETRY=1
export OTEL_METRICS_EXPORTER=otlp
export OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf
export OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:9090/api/v1/otlp
export OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE=delta
Reload your shell: source ~/.bashrc
2. Prometheus Setup #
Install (AL2023 / Amazon Linux)
cd /tmp
curl -LO https://github.com/prometheus/prometheus/releases/download/v3.0.0/prometheus-3.0.0.linux-amd64.tar.gz
tar xzf prometheus-3.0.0.linux-amd64.tar.gz
sudo mv prometheus-3.0.0.linux-amd64 /opt/prometheus
mkdir -p ~/.prometheus/data
Install (macOS with Homebrew)
brew install prometheus
Configuration
Create ~/.prometheus/prometheus.yml:
global:
scrape_interval: 15s
scrape_configs:
- job_name: "prometheus"
static_configs:
- targets: ["localhost:9090"]
Run Prometheus with OTLP Receiver
Critical flags:
--web.enable-otlp-receiver- Enables the OTLP ingestion endpoint--enable-feature=otlp-deltatocumulative- Converts delta metrics (like lines_of_code) to cumulative
/opt/prometheus/prometheus \
--config.file=~/.prometheus/prometheus.yml \
--storage.tsdb.path=~/.prometheus/data \
--web.listen-address=127.0.0.1:9090 \
--web.enable-otlp-receiver \
--enable-feature=otlp-deltatocumulative
prometheus \
--config.file=/opt/homebrew/etc/prometheus.yml \
--storage.tsdb.path=/opt/homebrew/var/prometheus \
--web.listen-address=127.0.0.1:9090 \
--web.enable-otlp-receiver \
--enable-feature=otlp-deltatocumulative
You can run this in a tmux session or background it.
3. Grafana Setup #
Install (AL2023 / Amazon Linux)
sudo tee /etc/yum.repos.d/grafana.repo << 'EOF'
[grafana]
name=grafana
baseurl=https://rpm.grafana.com
repo_gpgcheck=1
enabled=1
gpgcheck=1
gpgkey=https://rpm.grafana.com/gpg.key
sslverify=1
sslcacert=/etc/pki/tls/certs/ca-bundle.crt
EOF
sudo dnf install grafana -y
sudo systemctl start grafana-server
Install (macOS)
brew install grafana
brew services start grafana
Access
- URL: http://localhost:3000
- Default login: admin / admin
Add Prometheus Data Source
- Go to Connections → Data Sources → Add data source
- Select Prometheus
- URL:
http://localhost:9090 - Save & Test
Import Dashboards
- Go to Dashboards → Import
- Paste the JSON from the dashboard files in this directory
- Select your Prometheus data source
- Import
Dashboard files included:
dashboard-metrics.json- Claude Code Metrics (tokens, cost, productivity ratio)dashboard-summary.json- Daily/Weekly Summary (aggregated stats)dashboard-economics.json- Engineering Economics (ROI, team equivalence)
4. Verify Metrics Are Flowing #
After using Claude Code with telemetry enabled:
curl -s 'http://localhost:9090/api/v1/label/__name__/values' | jq '.data[]' | grep claude
You should see:
claude_code_token_usage_tokens_totalclaude_code_cost_usage_USD_totalclaude_code_active_time_seconds_totalclaude_code_lines_of_code_count_totalclaude_code_session_count_total
5. Available Metrics #
| Metric | Labels | Description |
|---|---|---|
claude_code_token_usage_tokens_total |
type (input/output/cacheRead/cacheCreation), model |
Token consumption |
claude_code_cost_usage_USD_total |
model |
Estimated API cost in USD |
claude_code_active_time_seconds_total |
type (cli/user) |
Time tracking |
claude_code_lines_of_code_count_total |
type (added/removed) |
Code output (delta metric!) |
claude_code_session_count_total |
Session count | |
claude_code_event_count_total |
event |
Events (commits, PRs, etc.) |
6. Key Queries #
Productivity Ratio (CLI time / User time):
sum(claude_code_active_time_seconds_total{type="cli"})
/ sum(claude_code_active_time_seconds_total{type="user"})
Lines per Dollar:
sum(sum_over_time(claude_code_lines_of_code_count_total[$__range]))
/ sum(increase(claude_code_cost_usage_USD_total[$__range]))
Cache Efficiency:
sum(claude_code_token_usage_tokens_total{type="cacheRead"})
/ (sum(claude_code_token_usage_tokens_total{type="cacheRead"}) + sum(claude_code_token_usage_tokens_total{type="input"}))
* 100
Important: The lines_of_code metric is a delta metric, not cumulative. Use sum_over_time() instead of increase():
sum(sum_over_time(claude_code_lines_of_code_count_total[$__range]))
sum(increase(claude_code_lines_of_code_count_total[$__range]))
7. Troubleshooting #
No metrics showing up
- Check env vars are set:
env | grep OTEL - Verify Prometheus is running with OTLP flags:
ps aux | grep prometheus - Check Prometheus logs for OTLP errors
- Make sure you've used Claude Code after setting env vars (restart terminal first)
Grafana can't connect to Prometheus
- Verify Prometheus is running:
curl http://localhost:9090/-/healthy - Check Grafana data source URL matches Prometheus listen address
Dashboard shows no data
- Check time range (try "Last 24 hours")
- Verify metrics exist:
curl 'http://localhost:9090/api/v1/query?query=claude_code_token_usage_tokens_total' - Make sure Prometheus data source is selected in dashboard
8. For Datadog (Alternative) #
If pushing to Datadog instead of local Prometheus:
export OTEL_METRICS_EXPORTER=otlp
export OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf
export OTEL_EXPORTER_OTLP_ENDPOINT=https://otel.datadoghq.com
export OTEL_EXPORTER_OTLP_HEADERS="DD-API-KEY=your_api_key"
The same metrics will flow to Datadog, and you can build similar dashboards there.