La moitie qui manquait. Les roles declaraient leurs panneaux, Prometheus en derivait ses cibles, les expressions repondaient, et rien ne les assemblait. serveur_grafana lit les memes meta/metriques.yml que serveur_prometheus et en assemble un tableau par role — la raison du panneau devient sa description dans Grafana. Moisson des tableaux orphelins, prefixe setops-role- pour ne jamais toucher un tableau ecrit a la main, JSON valide avant d etre pose (Grafana ne tombe pas sur un tableau illisible : il le saute en silence). client_metrique declare quatre panneaux sans exportateur — le cas symetrique. Celui qui compte : la memoire disponible, depuis que le ballon est actif. Eprouve sur le site : les deux tableaux charges dans le stockage unifie, un temoin orphelin retire, les quatre panneaux de flotte a 10 series chacun. Un panneau etait faux — /var/lib/lxcfs rapporte toujours zero octet libre et un min() en meurt. Corrige en liste blanche : un montage inconnu manque au graphe, ce qui se voit, au lieu de l ecraser. P77 garde la table des unites : une unite inventee retombe sur short, lisible et fausse. 76 OK. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Crgis8CxCWkAGFA1ecBz3q
77 lines
3.4 KiB
Django/Jinja
77 lines
3.4 KiB
Django/Jinja
{#- GENERE par Set-OPS (role serveur_grafana). Ne pas editer a la main.
|
|
|
|
UN TABLEAU PAR ROLE, ASSEMBLE DEPUIS SON `meta/metriques.yml`.
|
|
|
|
C'EST LA MOITIE QUI MANQUAIT. Les roles declaraient leurs panneaux, Prometheus
|
|
collectait les series, les expressions repondaient — et rien ne les assemblait. Un
|
|
panneau declare que personne ne peut regarder n'est pas une observabilite, c'est une
|
|
intention.
|
|
|
|
POURQUOI UN TABLEAU PAR ROLE ET PAS UN GRAND. Parce que la question qu'on se pose est
|
|
« comment va PostgreSQL », pas « comment va la flotte » — celle-la est deja repondue
|
|
par Icinga, et par le tableau des journaux. Un tableau par role suit la meme ligne de
|
|
partage que tout le reste ici : le role est l'unite qui declare, donc l'unite qui
|
|
s'affiche.
|
|
|
|
LA `raison` DEVIENT LA DESCRIPTION DU PANNEAU. Elle est le seul champ obligatoire qui
|
|
ne produit aucun pixel de graphe, et c'est le plus important : sans elle, celui qui
|
|
regarde a six mois de distance voit une courbe sans savoir ce qu'elle annonce. Grafana
|
|
l'affiche au survol du titre.
|
|
-#}
|
|
{%- set roles_unites = serveur_grafana_unites -%}
|
|
{
|
|
"uid": {{ ("setops-" ~ tableau_role | replace("serveur_", "") | replace("_", "-")) | truncate(40, true, "") | tojson }},
|
|
"title": {{ ("Set-OPS — " ~ tableau_role | replace("serveur_", "") | replace("_", " ")) | tojson }},
|
|
"tags": ["set-ops", "derive", {{ tableau_role | tojson }}],
|
|
"timezone": "browser",
|
|
"refresh": "1m",
|
|
"time": { "from": "now-6h", "to": "now" },
|
|
"schemaVersion": 39,
|
|
"version": 1,
|
|
"templating": {
|
|
"list": [
|
|
{
|
|
"name": "ds_prom",
|
|
"label": "Source Prometheus",
|
|
"type": "datasource",
|
|
"query": "prometheus",
|
|
"hide": 2,
|
|
"current": {}
|
|
}
|
|
]
|
|
},
|
|
"panels": [
|
|
{%- for p in tableau_panneaux %}
|
|
{
|
|
"id": {{ loop.index }},
|
|
"type": "timeseries",
|
|
"title": {{ p.titre | tojson }},
|
|
{#- LA RAISON, TELLE QUELLE. On ne la resume pas : c'est le texte que le role a
|
|
ecrit pour expliquer ce que la courbe annonce. #}
|
|
"description": {{ (p.raison | default("") | trim) | tojson }},
|
|
"datasource": { "type": "prometheus", "uid": "${ds_prom}" },
|
|
{#- DEUX PAR RANGEE. Une expression PromQL rend souvent plusieurs series ; a pleine
|
|
largeur on ne compare rien, a un quart de largeur on ne lit rien. #}
|
|
"gridPos": { "h": 8, "w": 12, "x": {{ 0 if loop.index0 % 2 == 0 else 12 }}, "y": {{ (loop.index0 // 2) * 8 }} },
|
|
"fieldConfig": {
|
|
"defaults": {
|
|
{#- L'UNITE VIENT DU ROLE, TRADUITE EN UNITE GRAFANA. Un `unite:` inconnu
|
|
retombe sur `short` — et P77 refuse de laisser ce cas passer inapercu. #}
|
|
"unit": {{ roles_unites.get(p.unite | default("") | string, "short") | tojson }},
|
|
"custom": { "drawStyle": "line", "fillOpacity": 10, "showPoints": "never" }
|
|
}
|
|
},
|
|
"options": { "legend": { "displayMode": "list", "placement": "bottom" } },
|
|
"targets": [
|
|
{
|
|
"refId": "A",
|
|
"datasource": { "type": "prometheus", "uid": "${ds_prom}" },
|
|
{#- L'EXPRESSION EST CELLE DU ROLE, non reecrite. Repliee sur une ligne parce
|
|
que `>-` en YAML laisse des retours que JSON refuse. #}
|
|
"expr": {{ (p.expr | trim | replace("\n", " ")) | regex_replace("\\s+", " ") | tojson }}
|
|
}
|
|
]
|
|
}{{ "," if not loop.last else "" }}
|
|
{%- endfor %}
|
|
]
|
|
}
|