Graphiques des métriques Grafana
Vue d'ensemble
Génère un graphique en courbes PNG de style Grafana avec thème sombre à partir d'une requête PromQL, récupérée via le proxy de source de données Grafana (pas besoin d'accès réseau direct à Prometheus, le jeton SA Grafana suffit). Reproductible et scriptable, contrairement à une capture d'écran manuelle. Peut être directement attaché à un ticket Jira.
Utilisez d'abord une capture d'écran si un panneau affiche déjà la donnée. Les piles Grafana Cloud intègrent le rendu côté serveur, donc gcx dashboards snapshot retourne le vrai panneau en PNG. Cette compétence est pour ce qu'une capture ne peut pas donner : une comparaison côte à côte de requêtes ou plages temporelles qu'aucun panneau unique n'encode, et les instances auto-hébergées sans le plugin Image Renderer, où la capture échoue.
Pré-vérifications
Chaque appel Grafana ici passe par gcx. Vérifiez-le une fois par session :
command -v gcx >/dev/null || { echo "installez : brew install gcx"; exit 1; }
gcx config check || { echo "pas prêt : gcx login"; exit 1; }
Validez la requête avant de tracer. Cette compétence génère ce que vous lui donnez comme PromQL, et une requête erronée est pire ici que dans un tableau de bord : le PNG atterrit dans un ticket comme preuve figée que personne ne rejoue, et il a l'air officiel. PRÉREQUIS pour la requête elle-même : utilisez la compétence grafana-dashboards, sections Essentiels PromQL, Pièges d'agrégation et Lecture des distributions et queues. Ce qui pose problème sur un graphique comparatif : agrégation après rate et jamais avant, enveloppez les deux côtés dans max by (...) lorsqu'un déploiement laisse deux séries par pod, jamais histogram_quantile sur un histogramme exponentiel base-2, et donnez à chaque sous-requête un pas explicite.
Quand utiliser
- Comparer 2+ séries : version A vs B, canary vs contrôle, avant/après un changement.
- Attacher une preuve à un ticket Jira, MR ou rapport d'incident.
- Le rendu du panneau Grafana échoue (
gcx dashboards snapshoterreur : pas de moteur de rendu d'images dans ce contexte auto-hébergé).
Pas pour : exploration interactive (utilisez Grafana), données de valeur unique/tableau, ou capture d'écran d'un panneau existant sur Grafana Cloud (gcx dashboards snapshot).
Configuration (une fois)
matplotlib est nécessaire. S'il manque, utilisez un venv isolé (ne polluez pas le Python système) :
python3 -m venv ${CLAUDE_SKILL_DIR}/.venv
${CLAUDE_SKILL_DIR}/.venv/bin/pip install -q matplotlib
Référence rapide
| Besoin | Option |
|---|---|
| Quelle source de données | --datasource-uid (trouvez via gcx datasources list ou requêtes de panneaux) |
| La requête | --expr 'PromQL' |
| Fenêtre temporelle | --start now-6h --end now --step 60 |
| Source des étiquettes de série | --legend-key instance (par défaut ; toute étiquette de métrique) |
| Noms plus lisibles | --rename '{"valeur-brute":"Beau Nom"}' |
| Moyenne/min/max par série | affiché dans stdout après sauvegarde (pas besoin de requête supplémentaire) |
| Annotation sur le pic | --annotate-max "texte" |
| Quel Grafana | --grafana-url https://<host> : utilise le contexte gcx dont le serveur a cet hôte (par défaut : contexte courant de gcx) |
| Quel contexte gcx | --gcx-context <nom> (par défaut $GCX_CONTEXT) ; pour une instance nommée sans URL, choisissez-le parmi gcx config list-contexts |
| Attacher à Jira | --attach-jira ABC-123 (voir les variables d'environnement ci-dessous, et la porte d'approbation dans le Flux de travail) |
Environnement
Rien n'est codé en dur : pas d'hôte, pas d'adresse. Définissez-les dans votre profil shell.
| Variable | Nécessaire pour | Notes |
|---|---|---|
GRAFANA_URL + GRAFANA_TOKEN | jeton statique | le jeton est envoyé uniquement à l'hôte de GRAFANA_URL (puis GRAFANA_SERVICE_ACCOUNT_TOKEN, GTOK) |
GCX_CONTEXT | gcx | contexte gcx à forcer, identique à --gcx-context |
JIRA_API_TOKEN JIRA_EMAIL JIRA_BASE | --attach-jira seulement | les trois, pas de défaut |
Ordre de résolution, identique pour toutes les compétences Grafana : --token ; --gcx-context / $GCX_CONTEXT ; --grafana-url (le jeton env pour l'hôte de $GRAFANA_URL, sinon le contexte gctx desservant cet hôte, sinon quittez avec la commande gcx login à exécuter) ; contexte courant de gcx ; le jeton env quand gcx manque. Via gcx, son propre renouvellement OAuth s'applique et ce script ne lit ni ne met en cache un identifiant lui-même. Le résolveur est dupliqué dans chaque compétence intentionnellement, pour que l'une ou l'autre fonctionne installée seule.
Flux de travail
- Obtenez l'UID de la source de données + PromQL depuis le tableau de bord (
gcx api /api/dashboards/uid/<uid>, lisezpanels[*].targets[*].expr) ou écrivez la requête vous-même. - Exécutez le script (via le venv python). Les couleurs s'attribuent automatiquement depuis la palette Grafana dans l'ordre des séries ; la légende montre la moyenne/max par série.
- Relisez le PNG pour le vérifier avant de le partager.
- Optionnellement, attachez-le à Jira avec
--attach-jira. C'est une écriture dans le tracker visible par toute l'équipe : suivez d'abord la porte d'approbation de la compétenceticket-conventions(montrez l'ID du ticket et le PNG, attendez un oui explicite). Un échec de téléversement se termine avec un code de sortie non nul.
Exemple (le canonique : mémoire de nœud HAProxy 3.2 vs 2.7)
VENV=${CLAUDE_SKILL_DIR}/.venv/bin/python
SKILL=${CLAUDE_SKILL_DIR}
export JIRA_API_TOKEN=$(zsh -l -c 'echo $JIRA_API_TOKEN') # seulement si attachement
export [email protected] JIRA_BASE=https://example.atlassian.net
DS_UID=abc123XYZ # depuis `gcx datasources list`
$VENV $SKILL/plot_grafana.py \
--datasource-uid $DS_UID \
--expr '(1 - (node_memory_MemAvailable_bytes{instance=~"lb-edge-dc1-(1|4)"} / node_memory_MemTotal_bytes{instance=~"lb-edge-dc1-(1|4)"})) * 100' \
--start now-6h --step 60 \
--title "lb-edge - mémoire nœud utilisée % · 3.2 vs 2.7 (dc1, 6h dernières)" \
--ylabel "Mémoire utilisée %" --ymin 0 --ymax 45 \
--rename '{"lb-edge-dc1-1":"HAProxy 3.2.20 (dc1-1)","lb-edge-dc1-4":"HAProxy 2.7.11 (dc1-4, contrôle)"}' \
--annotate-max "reload : ancien+nouveau worker coexistent → mémoire nœud ~2x" \
--grafana-url https://grafana.example.com \
--out ./mem-3.2-vs-2.7.png \
--attach-jira ABC-123
Erreurs courantes
- Graphique tracé à partir d'une requête que personne n'a vérifiée → voir l'astuce PromQL ci-dessus ; un nombre erroné plausible est le mode d'échec, pas une erreur.
- 401 du proxy → avec un jeton statique, il n'appartient pas à cet hôte ; via gcx, le jeton d'actualisation a expiré (environ mensuellement), exécutez
gcx login <context>. - Utilisation du
python3système →ModuleNotFoundError: matplotlib. Utilisez le venv python. - Ligne vide/plate là où vous attendez plusieurs → l'expression
--expra matché une seule série ; élargissez le sélecteur d'étiquette. - Séries sans nom / toutes "series" →
--legend-keypointe sur une étiquette que la métrique n'a pas ; choisissez-en une qu'elle a (vérifiez le résultat brut de la requête). :9100(ou tout:port) dans les noms de légende → automatiquement supprimé du nom de série dérivé, donc--renamecible l'hôte nettoyé (par exemplelb-edge-dc1-1, paslb-edge-dc1-1:9100). Pas besoin de lister les deux formes.- Les temps relatifs prennent un nombre et une unité, s/m/h/d (
now-90m,now-6h,now-2d). Les composés (now-1h30m), les semaines (now-1w) et les arrondis (now/d) ne sont pas supportés : convertissez-les (now-90m,now-7d).