Real-time observability for Claude Code. One command gives you a Grafana dashboard tracking costs, tokens, tool usage, cache efficiency, and rate limits — all from the OTEL telemetry Claude Code already emits.
Claude Code emits rich OpenTelemetry metrics and logs out of the box — cost per request, token counts by type, tool calls, edit decisions, session activity, and more. But without a backend to collect them, all that data disappears.
claudefana gives you the backend (OTEL Collector + Prometheus + Loki) and a pre-built Grafana dashboard so you can see exactly where your tokens and dollars are going.
Add to your ~/.claude/settings.json:
{
"env": {
"CLAUDE_CODE_ENABLE_TELEMETRY": "1",
"OTEL_METRICS_EXPORTER": "otlp",
"OTEL_LOGS_EXPORTER": "otlp",
"OTEL_EXPORTER_OTLP_ENDPOINT": "http://localhost:4317"
}
}git clone https://github.com/JuanjoFuchs/claudefana.git
cd claudefana
docker compose -f docker-compose.otel.yaml up -dAll services use restart: unless-stopped, so they start automatically whenever Docker runs (e.g., on reboot). You only need to run up -d once. To stop the stack permanently, use docker compose -f docker-compose.otel.yaml down.
OTEL settings require a full restart of Claude Code to take effect. After restarting, metrics begin flowing within seconds.
http://localhost:3000 — no login required (anonymous access enabled by default).
A 26-panel dashboard across 8 sections:
- Total Cost — lifetime spend with threshold coloring
- Sessions / Prompts Sent / Active Time / Commits — key counters at a glance
- Cost per Prompt / Cost per Session / Cost per Commit — efficiency signals
- Model Mix (by cost) — donut chart showing spend per model
- Token Usage by Type — stacked timeseries of input, output, cache read, and cache creation tokens
- Token Usage by Model — stacked timeseries of total tokens per model
- Cache Hit Ratio — gauge showing what fraction of tokens come from cache (higher = cheaper)
- Tool Usage — ranked bar chart of every tool Claude Code uses (Read, Edit, Bash, etc.)
- Requests by Model — donut chart of API call distribution
- API Latency by Model — average request duration per model in milliseconds
- Tool Call Weight — donut chart showing each tool's share of total invocations
- Edits by Language — which languages Claude is modifying
- Terminal / IDE — where you're running Claude Code
- Lines of Code — added vs. removed
- Edit Accept Rate — what percentage of Claude's suggested edits you accepted
- Sessions Per Day / Active Time Per Day — adoption and investment trends
- Cost Per Session Trend — $/session over time (declining = getting more efficient)
- Lines Per Dollar — rising trend = more output per dollar spent
- User Prompts Over Time — prompt rate over time
- Lines of Code Over Time — added (green, above zero) vs. removed (red, below zero)
- Rate Limit Utilization — gauges for each rolling limit window (5h, 7d all models, 7d Sonnet, 7d Opus, extra monthly). Requires the optional usage exporter (see below).
- Event Stream — live log feed from Loki showing Claude Code events
Claude Code ──OTLP──▶ OTEL Collector ──▶ Prometheus ──▶ Grafana
│
▼
Loki (logs) ──────────────────▶ Grafana
| Service | Port | Purpose |
|---|---|---|
| OTEL Collector | 4317 (gRPC), 4318 (HTTP) | Receives telemetry, converts logs to metrics |
| Prometheus | 9090 | Time-series storage |
| Loki | 3100 | Log aggregation |
| Grafana | 3000 | Dashboard UI |
The OTEL Collector does the heavy lifting: it receives raw telemetry from Claude Code and uses two connectors (count and signaltometrics) to convert structured log events into Prometheus metrics — API request counts, tool call counts, per-request cost, token breakdowns, and request duration.
| Metric | Description |
|---|---|
claude_code_cost_usage_USD_total |
Cumulative cost in USD per session |
claude_code_token_usage_tokens_total |
Tokens by type (input/output/cacheRead/cacheCreation) |
claude_code_active_time_seconds_total |
Active CLI time per session |
claude_code_session_count_total |
Session starts |
claude_code_lines_of_code_count_total |
Lines added/removed |
claude_code_code_edit_tool_decision_total |
Edit accept/reject decisions by tool and language |
| Metric | Description |
|---|---|
claude_code_api_requests_total |
API request count by model |
claude_code_tool_calls_total |
Tool invocations by tool name |
claude_code_user_prompts_total |
User prompts submitted |
claude_code_cost_usd_total |
Cost extracted from log attributes |
claude_code_input_tokens_total |
Input tokens per request |
claude_code_output_tokens_total |
Output tokens per request |
claude_code_cache_read_tokens_total |
Cache hit tokens |
claude_code_cache_creation_tokens_total |
Cache miss tokens |
claude_code_request_duration_ms |
Request latency |
The included claude-usage-exporter.py scrapes Anthropic's Usage API to power the rate limit gauges. It starts automatically with the stack. If you don't have credentials or don't want limit tracking, the rest of the dashboard works fine without it.
The exporter tries three sources in order:
| Source | When to use |
|---|---|
CLAUDE_OAUTH_TOKEN env var |
macOS Docker users (Keychain can't be accessed from inside a container) |
| macOS Keychain | Running the exporter natively on macOS (auto-detected) |
~/.claude/.credentials.json |
Linux and Windows (default) |
Linux / Windows — works out of the box. Claude Code writes credentials to ~/.claude/.credentials.json, which is bind-mounted into the container.
macOS — Claude Code stores credentials in Keychain, not the file. Extract the token and pass it as an env var:
# Extract token from Keychain
export CLAUDE_OAUTH_TOKEN=$(security find-generic-password -s "Claude Code-credentials" -w \
| python3 -c "import sys,json; print(json.load(sys.stdin)['claudeAiOauth']['accessToken'])")
# Start the stack (or add to your shell profile to persist across reboots)
docker compose -f docker-compose.otel.yaml up -dThen uncomment the CLAUDE_OAUTH_TOKEN line in docker-compose.otel.yaml.
Note: OAuth tokens expire periodically. If the exporter starts failing (
claude_code_usage_scrape_success 0), re-extract the token after re-authenticating Claude Code (/logoutthen/login).
To customize the credentials file path instead:
CLAUDE_CREDENTIALS_PATH=/path/to/credentials.json docker compose -f docker-compose.otel.yaml up -dBuilt-in Prometheus alerts in prometheus-alerts/:
| Alert | Fires when |
|---|---|
| Usage limit warning | 5h rolling or 7d limit hits 70% |
| Usage limit critical | 5h rolling or 7d limit hits 85% |
| Usage limit exhausted | 5h rolling limit hits 95% |
| High burn rate | Consuming >20% of limit per hour |
| Low cache efficiency | Cache hit ratio below 50% |
| No API activity | No Claude Code requests for 30+ minutes |
Anonymous access is enabled by default so you don't need to log in. To set a password instead:
# Copy and edit .env
cp .env.example .env
# Set GF_SECURITY_ADMIN_PASSWORD=yourpasswordClaude Code defaults to a 60-second metric export interval. For more responsive dashboards:
{
"env": {
"OTEL_METRIC_EXPORT_INTERVAL": "5000"
}
}- Thinking tokens are not in OTEL — Claude's internal reasoning can be 3-10x visible output and counts toward rate limits, but is not exported. Feature request: #16943
- Usage limits only via API — rate limit data requires the optional exporter, not native OTEL. Feature request: #16942
- No project/repo context — there's no OTEL label indicating which codebase a session is working on
- Single-user scope — this stack is designed for individual use. For multi-user/org dashboards, see the enterprise section below.
For organization-level dashboards with team breakdowns, department rollups, and productivity correlation:
claudefana-enterprise adds:
- Microsoft Graph integration — user profiles, department/manager/job title enrichment
- Jira + Tempo integration — issues resolved, story points, time tracking correlation
- Org hierarchy tree panel — rollup cost and activity by manager chain
- 40+ panel dashboard with Organization and Jira correlation rows
- Kubernetes deployment manifests
Contributions welcome! Please open an issue to discuss before submitting large changes.
MIT
