Stack local de observabilidade para ferramentas de IA de código (Claude Code e OpenAI Codex CLI), via OpenTelemetry.
Coleta métricas e logs das duas ferramentas e entrega dashboards no Grafana, com filtro por vendor e por project.
Claude Code / Codex ──OTLP──► OTel Collector ──► Prometheus (métricas)
└─► Loki (logs)
└──► Grafana (dashboards)
| Serviço | Porta | Papel |
|---|---|---|
| otel-collector | 4317/4318/9464 | Recebe OTLP, reexporta p/ Prometheus e Loki |
| prometheus | 9090 | Métricas (retenção 90d) |
| loki | 3100 | Logs |
| grafana | 3000 | Dashboards (login inicial: admin / admin) |
docker compose up -d
docker compose psGrafana em http://localhost:3000. Os datasources (Prometheus, Loki) e os dashboards são provisionados automaticamente por arquivo — nada de importar à mão.
Importante: use
docker compose stop/startoudown/upno dia a dia. NUNCA usedocker compose down -va menos que queira apagar todo o histórico de métricas e logs (os volumes).
Aparecem na pasta AI Observability do Grafana:
- Claude Code (25255) — uso, custo real e latência do Claude Code
- Codex CLI - Telemetria — uso, custo estimado e latência do Codex
- Multi-vendor (Claude vs Codex) — comparativo lado a lado
- Orçamento - Custo por vendor — custo por vendor + total, base para orçamento
Os JSONs ficam em grafana/dashboards/. Para alterar um dashboard de forma permanente: edite na UI, exporte o JSON (Dashboard settings → JSON Model) e substitua o arquivo correspondente.
O repo sobe a stack, mas cada máquina precisa ligar a telemetria das ferramentas. Isso vive no ambiente do usuário, não no repo.
# --- Telemetria Claude Code ---
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_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE=cumulative
export OTEL_LOG_USER_PROMPTS=1
export OTEL_METRIC_EXPORT_INTERVAL=10000
# Injeta vendor + project por sessão (deriva o projeto da raiz do repo git)
claude() {
local root proj
root="$(git rev-parse --show-toplevel 2>/dev/null)"
proj="$(basename "${root:-$PWD}")"
OTEL_RESOURCE_ATTRIBUTES="vendor=claude_code,project=${proj}" command claude "$@"
}
codex() {
local root proj
root="$(git rev-parse --show-toplevel 2>/dev/null)"
proj="$(basename "${root:-$PWD}")"
OTEL_RESOURCE_ATTRIBUTES="vendor=codex,project=${proj}" command codex "$@"
}[otel]
environment = "local"
log_user_prompt = false
exporter = { otlp-http = { endpoint = "http://localhost:4318/v1/logs", protocol = "binary" } }
metrics_exporter = { otlp-http = { endpoint = "http://localhost:4318/v1/metrics", protocol = "binary" } }
trace_exporter = { otlp-http = { endpoint = "http://localhost:4318/v1/traces", protocol = "binary" } }Aplique com source ~/.zshrc (ou abra um terminal novo). A telemetria só é capturada quando a stack está no ar no momento do uso das ferramentas.
metric_expirationnootel-collector-config.yamlcontrola por quanto tempo o collector mantém uma métrica exposta entre sessões. Sem ele, o default é 5 min (gráficos esvaziam logo após o uso). Valores maiores (ex.:168h) dão continuidade, ao custo de mais cardinalidade.- O custo do Claude é medido (
claude_code_cost_usage_USD_total); o do Codex é estimado (tokens × preço editável no dashboard). Use os totais como base de orçamento, não como valor contábil.
Baseado no projeto beerandcodeteam/claude-otel.