Aller au contenu
6 minutes

Claude Code dans Grafana : télémétrie OpenTelemetry, Prometheus et pièges

Activer la télémétrie de Claude Code, la recevoir dans Prometheus, l’afficher dans Grafana. Et ce que le terrain ajoute, endpoint imposé, increase() muet, historique à rejouer.

Claude Code dans Grafana : télémétrie OpenTelemetry, Prometheus et pièges

Claude Code exporte en OpenTelemetry coût, tokens, sessions et lignes de code, et un tableau Grafana public attend ces compteurs. Restent une stack à monter et des pièges que la doc ne montre pas.

Le contexte

Objectif : suivre l’usage de Claude Code sur un poste Windows, sans Docker, tout en écoute locale. Prometheus 3.15 stocke, Grafana 13.2.3 affiche le tableau communautaire 25255, « Claude Code Metrics (Prometheus) ».

Activer l’export

Rien ne part sans CLAUDE_CODE_ENABLE_TELEMETRY=1. Claude Code ignore ces variables dans le .claude/settings.json d’un dépôt : on les pose dans le shell ou dans ~/.claude/settings.json.

{
  "env": {
    "CLAUDE_CODE_ENABLE_TELEMETRY": "1",
    "OTEL_METRICS_EXPORTER": "otlp",
    "OTEL_EXPORTER_OTLP_PROTOCOL": "http/protobuf",
    "OTEL_EXPORTER_OTLP_ENDPOINT": "http://127.0.0.1:9090/api/v1/otlp",
    "OTEL_EXPORTER_OTLP_METRICS_TEMPORALITY_PREFERENCE": "cumulative"
  }
}

Claude Code n’a pas de protocole par défaut, et Prometheus ne reçoit l’OTLP qu’en HTTP. Sa temporalité par défaut est delta ; Prometheus attend du cumulatif. Sur l’endpoint général, la spécification OpenTelemetry ajoute /v1/metrics, le chemin du récepteur.

Le mode OTEL_METRICS_EXPORTER=prometheus (port 9464) omet les unités USD, tokens et s ; non testé ici avec le tableau, qui attend claude_code_cost_usage_USD_total.

Ce qui remonte

Huit métriques : sessions, coût, tokens, lignes de code, commits, pull requests, décisions d’édition, temps actif. Avec une connexion OAuth, user.email les accompagne : une donnée personnelle dans votre base (voir le billet sur la confidentialité). Coûts approximatifs ; pour les réduire, voir le billet sur les tokens.

Prometheus et Grafana

Le récepteur s’active par --web.enable-otlp-receiver ; par défaut, aucun attribut de ressource n’est promu en label.

otlp:
  promote_resource_attributes: [service.name, service.version, os.type, host.arch]
  translation_strategy: UnderscoreEscapingWithSuffixes
storage:
  tsdb:
    out_of_order_time_window: 30m

Prometheus et Grafana écoutent par défaut sur toutes les interfaces : fixez --web.listen-address=127.0.0.1:9090 et http_addr = 127.0.0.1 dans la section [server], et changez le mot de passe admin de Grafana. Le tableau s’importe par son identifiant.

Sur notre poste, cette chaîne OTLP n’a pas pu être validée de bout en bout (voir plus bas).

Premier piège : l’endpoint ne vous appartient pas

Une configuration d’entreprise y fixait OTEL_EXPORTER_OTLP_METRICS_ENDPOINT vers un proxy ou collecteur d’entreprise. La variable par signal l’emporte sur la générale ; et selon la doc, une variable OTEL_EXPORTER_OTLP_* posée en réglages gérés fait retirer au démarrage celles du développeur en conflit, avec un avertissement dans le journal de débogage. Ni ~/.claude/settings.json ni le shell ne l’ont surchargée : rien n’arrivait en local. C’est une décision de l’organisation, pas un réglage à forcer.

La stack a donc été alimentée par un petit exporter, lui aussi sur 127.0.0.1, qui lit les transcripts ~/.claude/projects/**/*.jsonl. Le récapitulatif de coût n’y est écrit qu’à la fermeture de session, jamais par claude -p. Les blocs d’usage écrits en direct comptent chaque requête deux fois ; dédupliqués par requestId, ils collent au récapitulatif à 0,1 % près.

Deuxième piège : increase() ne voit rien

Les panneaux sont en increase() et rate(). Un compteur publié d’emblée à sa valeur finale ne montre aucune hausse : « No data » partout. Il a fallu rejouer l’historique, Prometheus arrêté, puis déposer les blocs dans son répertoire de données. Figez la date de coupure avec le direct ; la doc déconseille de rejouer les trois dernières heures.

.\promtool.exe tsdb create-blocks-from openmetrics historique.om .\data
  • un point par session fait extrapoler increase() aux bords de la fenêtre, environ +50 % sur le coût ; une grille régulière ramène l’écart à 0,2 % ;
  • à 15 min de pas, le $__rate_interval de Grafana (environ 10 min sur 7 jours) tombe souvent à vide ; grille retenue : 5 min ;
  • chaque session est étalée sur sa durée, sinon tout s’empile à sa fin en pics.

En direct, l’exporter ne publie rien avant la fin de son premier dépouillement, sinon le nombre de lignes de code est compté environ deux fois.

Démarrage

Une tâche planifiée nommée, visible dans le Planificateur, lance à l’ouverture de session les briques qui n’écoutent pas encore. Elle se coupe ainsi :

Disable-ScheduledTask -TaskName "<nom>"

Ce qu’il faut retenir

  • La chaîne documentée : CLAUDE_CODE_ENABLE_TELEMETRY=1, exporter otlp en http/protobuf, temporalité cumulative, --web.enable-otlp-receiver.
  • Un endpoint par signal l’emporte sur le général ; posé par l’entreprise, vérifiez où partent vos métriques.
  • user.email devient un label : tout sur 127.0.0.1, mot de passe admin changé.
  • Un compteur sans historique laisse increase() muet : rejouez-le sur une grille régulière.

In English

Enable Claude Code telemetry, receive it in Prometheus and display it in Grafana, plus what the field adds: an enforced endpoint, a silent increase(), and history to replay. Nothing is exported without CLAUDE_CODE_ENABLE_TELEMETRY=1, Prometheus only receives OTLP over HTTP, and with an OAuth login, user.email ends up as a label in the local database.

Sources & vérification

Testé sur : Prometheus 3.15, Grafana 13.2.3, Claude Code sous Windows (version non relevée), relevé 2026-10

Comment les billets sont vérifiés et corrigés