Construire des tableaux de bord
Philosophie
- Les décisions d'abord. Chaque panneau répond à une question qui mène à une action.
- Vue d'ensemble → détails → preuves. Commencez large, réduisez au clic/filtre, terminez par les logs bruts.
- Taux et percentiles plutôt que moyennes. Les moyennes cachent les problèmes ; p95/p99 les exposent.
- La simplicité dépasse la densité. Une question par panneau. Pas de décor graphique.
- Validez avec les données. Ne devinez jamais les champs — découvrez d'abord le schéma.
- Calculez ce qu'on demande, ou reportez. Si un panneau ne peut pas être calculé, remplacez-le par une
Notedocumentant le blocage. Ne substituez jamais une quantité différente, même avec avertissement. Voir Calculer ou reporter.
Points d'entrée
| Commencer par | Flux de travail |
|---|---|
| Description vague | Intake → vérifier le type de dataset → concevoir le blueprint (APL ou MPL) → requêtes par panneau → déployer |
| Template | Choisir template → personnaliser dataset/service/env → déployer |
| Dashboard Splunk | Extraire SPL → traduire via axiom-spl-to-apl → mapper aux types de graphique → déployer |
| Dashboard Grafana | Projeter spec de panneau canonique (expr, legendFormat, unit, title, description) → traduire PromQL → mapper types de graphique → déployer. Voir reference/grafana-migration.md. |
| Exploration | Utiliser axiom-sre pour découvrir schéma/signaux → transformer en panneaux |
Intake : Questions à poser d'abord
-
Audience & décision
- Triage oncall ? (rafraîchissement rapide, erreurs en focus)
- Santé de l'équipe ? (tendances quotidiennes, suivi SLO)
- Rapports exécutifs ? (résumés hebdomadaires, haut niveau)
-
Périmètre
- Service, environnement, région, cluster, endpoint ?
- Vue d'un seul service ou multi-service ?
-
Type de dataset. Utiliser MCP
listDatasetset vérifierkind. Pour un déploiement configuré séparément, utiliserscripts/metrics/datasets <deploy>.otel:metrics:v1/otel-metrics-v1→ dataset de métriques, suivre le chemin Métriques.- n'importe quoi d'autre → dataset d'événements/logs, suivre le chemin APL.
Ne jamais exécuter
getschemasur un dataset de métriques. Il retourne 0 lignes sans erreur.Chemin APL : découvrir les champs avec
['dataset'] | where _time between (ago(1h) .. now()) | getschema. Continuer aux étapes 4–5.Chemin Métriques : Utiliser Axiom MCP pour la découverte de métriques et les requêtes, puis suivre le Blueprint Métriques/MPL.
-
Signaux clés (chemin APL)
- Trafic : requêtes/sec, événements/min
- Erreurs : taux d'erreur, compte 5xx
- Latence : p50, p95, p99 durée
- Saturation : CPU, mémoire, profondeur file, connexions
-
Dimensions de détail (chemin APL)
- Sur quoi les utilisateurs filtrent/regroupent-ils ? (service, route, status, pod, customer_id)
Blueprint de tableau de bord
Choisir le blueprint correspondant au type de dataset.
Blueprint APL (datasets événements/logs)
1. Vue d'ensemble (panneaux Statistic)
Nombres uniques qui répondent à « est-ce cassé maintenant ? »
- Taux d'erreur (5 dernières min)
- Latence p95 (5 dernières min)
- Taux de requête (5 dernières min)
- Alertes actives (si applicable)
2. Tendances (panneaux TimeSeries)
Motifs basés sur le temps qui répondent à « qu'est-ce qui a changé ? »
- Trafic au fil du temps
- Taux d'erreur au fil du temps
- Percentiles de latence au fil du temps
- Empilé par status/service pour comparaison
3. Ventilations (panneaux Table/Pie)
Analyse Top-N qui répond à « où dois-je regarder ? »
- Top 10 routes en erreur
- Top 10 messages d'erreur
- Pods les plus mauvais par taux d'erreur
- Distribution des requêtes par status
4. Preuves (LogStream + SmartFilter)
Événements bruts qui répondent à « que s'est-il exactement passé ? »
- LogStream filtré sur erreurs
- SmartFilter pour service/env/route
- Champs clés projetés pour lisibilité
Blueprint Métriques/MPL (datasets de métriques)
Utiliser align to $__interval using … pour bucketing — $__interval est fourni par le runtime du tableau de bord. Les fenêtres en dur sur- ou sous-résolvent. Suivre le contrat de graphique Métriques/MPL pour la découverte et la validation. chart-add --mpl rejette les plages de temps inline ([1h..]).
Exception : pour les métriques creuses où $__interval arrondit à des buckets vides, une fenêtre fixe plus large (ex. 1h) est acceptable ; documenter pourquoi sur le graphique.
1. Vue d'ensemble (panneaux Statistic)
Valeurs actuelles — « quel est l'état maintenant ? »
- Choisir la fonction
grouppar ce que le panneau doit montrer entre les séries. - Passer l'unité du résultat à
chart-add --unit: l'unitde la métrique depuis ses métadonnées, ou la nouvelle unité après unemapou un rate qui la change (prom::ratesurBydonneBy/s). Les métriques de ratio (0–1) besoin de| map * 100en MPL avant--unit "%".
2. Tendances (panneaux TimeSeries)
Tendances au fil du temps — « qu'est-ce qui a changé ? »
- Choisir la fonction
alignpar ce que chaque intervalle doit montrer. - Regrouper uniquement par tags de faible cardinalité (≤10 séries par graphique).
- Intégrer l'unité dans
--name("P95 Latency (ms)","Memory (MiB)"); mettre à l'échelle les magnitudes en MPL (| map / 1048576pour bytes → MiB).
3. Ventilations (panneaux TimeSeries ou Table)
Détail par entité — « où dois-je regarder ? »
- Métriques ventilées par entité (host, pod, service).
- Filtrer pour garder le compte de séries gérable.
- Une dimension par panneau ; ne pas surcharger un seul graphique.
4. État de l'entité (panneaux TimeSeries ou Table)
Métriques booléennes/état — répondre « qu'est-ce qui est on/off/actif ? »
- Choisir la fonction
alignpar la question d'état que chaque intervalle répond. - Les métriques d'état creuses peuvent avoir besoin d'un intervalle fixe plus large (1h+).
Structure de graphique requise
Chaque graphique a besoin d'un id unique kebab-case (error-rate, p95-latency) ; chaque i de layout doit en correspondre un. Passer le même id à chart-add --id et layout-pack <id>:…. dashboard-assemble fait une vérification croisée avant émission.
Configuration d'unité de graphique
Passer une string d'unité à chart-add --unit ("%", "ms", "req/s"). chart-add n'écrit jamais l'enum unit, que la Console ignore. Sur une Statistic MPL, chart-add écrit set custom_unit="<unit>"; dans la requête et ajoute un suffixe customUnits uniquement pour les unités que la Console ne formate pas. Passer le code UCUM du résultat (USD, s, By, %), jamais un symbole comme $. Pour un ratio 0–1, multiplier par 100 et passer --unit "%". Sur une Statistic APL, chart-add ajoute le suffixe uniquement pour les unités que la Console ne formate pas, car la Console formate un champ depuis ses métadonnées d'unité. % garde son suffixe là. Voir configuration de graphique pour d'autres options.
Calculer ou reporter
Chaque panneau soit calcule la quantité demandée, soit il est remplacé par une Note documentant le blocage. Substituer une quantité différente n'est jamais acceptable — les avertissements ne parviennent pas à qui agit sur le nombre.
Template de report (utiliser chart-add --type Note) :
**Reporté — bloqué par :** <raison d'une ligne>.
**Spec original :** <ce que le panneau doit calculer, dimensions, unité>.
**Pour débloquer :** <pointeur vers le correctif>.
Blocages courants : limites du parser MPL, tag manquant sans équivalent reverse-tag, métrique manquante sans correspondance de renommage OTel. Justification complète : reference/design-playbook.md § Substituting a Different Quantity for the Asked One.
Types de graphique
| Type | Quand | Contrainte clé |
|---|---|---|
| Statistic | KPI unique, valeur actuelle | La requête doit retourner une ligne. |
| TimeSeries | Tendances au fil du temps, overlays de percentiles | bin_auto(_time) ; percentiles_array() pour multi-percentile. |
| Table | Listes Top-N, ventilations | Borner avec top N ; contrôler colonnes via project. |
| Pie | Part du total pour ≤6 catégories | Agréger à ≤6 tranches ; jamais haute cardinalité. |
| LogStream | Inspection d'événement brut | Pas de limite de lignes (take, limit, top), agrégation ou join. La Console ajoute son propre tri et limite. Sélectionner les champs avec project-keep, conserver _time, et filtrer dur. |
| Heatmap | Distribution / densité de latence | summarize histogram(field, buckets) by bin_auto(_time). |
| Scatter Plot | Corréler deux métriques par groupe | summarize avg(x), avg(y) by group. |
| SmartFilter | Barre de filtre interactive | Chaque requête de panneau a besoin de declare query_parameters. Voir reference/smartfilter.md. |
| Monitor List | Affichage d'état du moniteur | Pas d'APL — sélectionner moniteurs dans l'UI. |
| Note | Contexte Markdown, headers, liens runbook | chart-add --type Note --text "<md>". |
Recettes par type APL : reference/chart-cookbook.md.
Configuration de graphique
chart-add couvre le chemin courant (type, id, name, query, dataset, unit, sparkline). Pour les options qu'il n'expose pas — variantes aggChartOpts sur TimeSeries, tableSettings.columns sur Table/LogStream, hideHeader, etc. — commencer depuis une sortie chart-add et fusionner les champs supplémentaires avec jq. Voir reference/chart-config.md pour l'ensemble complet des options, et la liste des champs rejetés avant de fusionner quoi que ce soit de bespoke.
Motifs APL
Filtrage temporal
Les requêtes du graphique de tableau de bord héritent le temps du sélecteur — omettre les filtres _time. Les requêtes ad-hoc (onglet Axiom Query, axiom-sre) ont besoin d'un filtre where _time between (ago(1h) .. now()) explicite.
Sélection de taille bin
Utiliser bin_auto(_time) — elle s'ajuste à la fenêtre de temps du tableau de bord. Le bin(_time, …) manuel est justifié uniquement pour les cas non-standard (ex. correspondre à un intervalle batch upstream) ; documenter pourquoi.
Garde-fous de cardinalité
Borner summarize … by … avec top N ou un filtre. Le regroupement non borné sur les champs haute cardinalité (user_id, trace_id) explose.
| summarize count() by route | top 10 by count_ // borné
| summarize count() by user_id // non borné — éviter
Échappement de champs
Les champs avec des points ont besoin de notation entre crochets :
| where ['kubernetes.pod.name'] == "frontend"
Les champs avec des points DANS le nom (pas hiérarchie) ont besoin d'échappement :
| where ['kubernetes.labels.app\\.kubernetes\\.io/name'] == "frontend"
Recettes
Trafic, taux-d'erreur, latence-percentile, et autres recettes APL de signal clé : reference/chart-cookbook.md.
Composition de layout
layout-pack empile les graphiques ligne-majeure dans la grille 12-colonnes en utilisant les défauts par type (Statistic 3×3, TimeSeries 6×4, Table 6×5, LogStream 12×6, Note 12×2). Remplacer avec id:WxH si besoin. Recettes de grille : reference/layout-recipes.md. Conventions de nommage et d'ordre de panneaux : reference/design-playbook.md.
Sections
Les groupes repliables sont un tableau top-level sections. Les passer à dashboard-assemble. Ne pas inventer sectionId sur le fichier de graphique, et ne pas découvrir la forme en envoyant une mise à jour invalide.
dashboard-assemble \
--name "API" \
--datasets logs \
--layout /tmp/d/layout.json \
--section "Requests:err-rate,traffic-ts" \
--section-collapsed "Errors:top-errors" \
/tmp/d/c-err-rate.json /tmp/d/c-traffic-ts.json /tmp/d/c-top-errors.json
- Le titre est le texte avant le premier
:. Les ids de graphique suivent, séparés par des virgules, et doivent correspondre auxids de graphique. - L'ordre du flag est l'ordre d'affichage.
--section-collapseddéfinitdefaultCollapsed: true. - L'
idde section est un UUID dérivé du titre, donc le même titre garde le même id à la prochaine exécution. - Un graphique omis de chaque
--sectionreste non groupé. Laisser chaque graphique SmartFilter non groupé. - Une Note utilisée comme header de grille est layout, pas une section. Utiliser
--sectionquand le tableau de bord doit replier un groupe et arrêter ses requêtes.
Paramètres du tableau de bord
Taux de rafraîchissement
dashboard-assemble --refresh oncall|team|exec (60/300/900s) ou passer un entier explicite (≥60). Rafraîchissement court + plage de temps long = requêtes chères ; choisir le plus long pour les tableaux exec/hebdomadaires.
Partage
Les tokens API créent uniquement des tableaux partagés (owner: "X-AXIOM-EVERYONE"); les tableaux privés ne sont pas supportés. La visibilité des données par utilisateur est toujours appliquée par les permissions du dataset.
Paramètres URL de plage de temps
?t_qr=24h (plage rapide), ?t_ts=...&t_te=... (personnalisée), ?t_against=-1d (comparaison)
Configuration
Outils, prérequis, et configuration ~/.axiom.toml : voir README.md. Vérifier avec scripts/setup.
Déploiement
Scripts
| Script | Utilisation |
|---|---|
scripts/chart-add --type <T> --id <id> --name <n> [--apl <q> \| --mpl <q> --dataset <d>] [--unit <u>] |
Émettre une seule JSON de graphique vers stdout. Divise APL vs MPL ; les requêtes MPL sont vérifiées pour les plages de temps inline ; champs d'unité appliqués par type de graphique. |
scripts/layout-pack <id>:<Type\|WxH> ... |
Émettre un tableau JSON de layout vers stdout. Ligne-majeure dans une grille 12-colonnes ; les noms de type correspondent à des tailles par défaut. |
scripts/dashboard-assemble --name … --datasets … --layout F.json [--section TITLE:id,id ...] [opts] CHART_FILES… |
Composer une JSON de tableau de bord complet depuis les fichiers de graphique + layout. Possède l'enveloppe (owner, schemaVersion, préfixe qr-, validation refreshTime, vérifications d'id croisées, sections). |
scripts/dashboard-list <deploy> |
Lister tous les tableaux de bord |
scripts/dashboard-get <deploy> <id> |
Récupérer JSON de tableau de bord |
scripts/dashboard-validate <file> |
Valider structure JSON |
scripts/dashboard-create <deploy> <file> |
Créer tableau de bord |
scripts/dashboard-update <deploy> <id> <file> |
Mettre à jour (a besoin de version) |
scripts/dashboard-chart-patch <deploy> <id> <chart-id> <patch-file> (--version <version> \| --overwrite) |
Patcher un graphique |
scripts/dashboard-copy <deploy> <id> |
Cloner tableau de bord |
scripts/dashboard-link <deploy> <id> |
Obtenir URL partageable |
scripts/dashboard-delete <deploy> <id> |
Supprimer (avec confirmation) |
scripts/axiom-api <deploy> <method> <path> |
Dashboard/app API uniquement (réécrit en app.*). Pour les endpoints data/metrics utiliser scripts/metrics/axiom-api |
scripts/metrics/axiom-api <deploy> <method> <path> |
Data/metrics API (supporte AXIOM_URL_OVERRIDE pour edge routing) |
scripts/metrics/datasets <deploy> |
Lister datasets avec kind et déploiement edge |
scripts/metrics/metrics-spec |
Récupérer spécification de requête MPL |
scripts/metrics/metrics-info <deploy> <dataset> ... |
Découvrir métriques, tags, et valeurs |
scripts/metrics/metrics-query <deploy> <mpl> <start> <end> |
Exécuter une requête de métrique (brut — pas injection $__interval) |
scripts/metrics/mpl-validate-chart <deploy> '<MPL>' [start] [end] |
Valider un pipeline MPL de graphique. Rejette les plages de temps inline. Le serveur remplit $__interval. Utiliser ceci à la place de raw metrics-query lors de l'authoring de requêtes de graphique. |
Les deux scripts
axiom-apine sont pas interchangeables.scripts/axiom-apiest pour l'API app de tableau de bord ;scripts/metrics/axiom-apiest pour les endpoints data/metrics et edge routing. Mauvais — 404.
Mises à jour ciblées de graphique
Utiliser scripts/dashboard-chart-patch quand changer un graphique existant et le layout du tableau de bord, métadonnées, et autres graphiques doivent rester inchangés. Il appelle PATCH /v2/dashboards/uid/{uid}/charts/{chartId} avec un JSON Merge Patch sous le champ requête chart.
Les fichiers patch contiennent uniquement les champs de graphique à changer :
{
"name": "Error Rate (5m)",
"query": { "apl": "['logs'] | summarize errors=countif(status >= 500)" },
"config": { "stale": null }
}
null supprime un champ existant. Les objets imbriqués fusionnent récursivement. Si id est présent dans le patch, il doit correspondre à l'argument de chemin <chart-id>. Le serveur valide le tableau de bord complet résultant avant sauvegarde.
Utiliser --version <version> pour concurrence optimiste après récupération du tableau de bord avec dashboard-get. Utiliser --overwrite uniquement quand le comportement last-write-wins est intentionnel. Continuer à utiliser dashboard-update pour les changements de layout, édits multi-graphique, métadonnées de tableau de bord, owner, intervalle de rafraîchissement, ou mises à jour de fenêtre de temps.
Flux de travail
chart-add, layout-pack, et dashboard-assemble possèdent la forme JSON. Chaque graphique vit dans son propre fichier temp ; rien de graphique-shaped ne rentre dans le contexte de l'agent.
- Découvrir schéma (
axiom-sre/getschemapour événements ; Axiom MCP pour métriques). - Écrire chaque requête de panneau. Valider APL via
axiom-sreavec un filtre de temps explicite ; suivre le contrat de graphique Métriques/MPL pour MPL. chart-add --type … --apl '<APL>'ouchart-add --type … --mpl '<MPL>' --dataset <name>par graphique, redirigé vers son propre fichier.layout-pack <id>:<Type|WxH> …pour le layout (ids en ordre d'affichage).dashboard-assemble --name … --datasets … --layout LAYOUT [--section TITLE:id,id ...] CHART_FILES…pour composer. Répéter--sectionpour chaque groupe repliable. Utiliser--section-collapsedquand le groupe doit démarrer replié.dashboard-validatepuisdashboard-create(oudashboard-update).dashboard-linkpour l'URL — ne jamais construire à la main.
Intégration de compétence partenaire
- axiom-spl-to-apl — Splunk SPL → APL (
timechart→ TimeSeries,stats→ Statistic/Table). Voirreference/splunk-migration.md. - axiom-sre — découverte de schéma via
getschema, exploration de baseline.
Templates
Composer avec chart-add + layout-pack + dashboard-assemble. Les templates pré-construits restent sous reference/templates/ (blank.json, service-overview.json, service-overview-with-filters.json, api-health.json) pour usage legacy ; dashboard-from-template les instancie mais suppose des noms de champs spécifiques (service, status, route, duration_ms) et a besoin de sed-fixing. Préférer la composition pour le nouveau travail.
Pièges courants
| Problème | Cause | Solution |
|---|---|---|
getschema retourne 0 lignes |
Dataset est otel:metrics:v1 ou otel-metrics-v1 |
Utiliser MCP listMetrics pour découverte de métriques. |
| 404 depuis appels API metrics | Utilisé scripts/axiom-api (dashboard) au lieu de scripts/metrics/axiom-api |
Utiliser scripts/metrics/axiom-api pour /v1/query/*, /v1/datasets. |
Statistic montre 1 au lieu de 100% pour ratio 0–1 |
La Console ne met pas à l'échelle l'unité OTel 1 |
\| map * 100 en MPL, puis chart-add --unit "%". |
Statistic montre l'unité deux fois ($1.031K$) |
Suffixe customUnits sur une unité que la Console formate ("$" sur USD) |
Passer le code UCUM (--unit USD). chart-add rejette $. |
Statistic MPL montre un nombre brut après map ou un rate |
Le résultat ne porte plus l'unité de la métrique | Passer l'unité du résultat à chart-add --unit (map / 3600 sur s donne --unit h). |
Tuile rate MPL montre KB au lieu de KB/s |
--unit nomme l'unité de la métrique, pas du rate |
Passer l'unité par-seconde (prom::rate sur By donne --unit By/s). |
| Graphique histogram OTel montre du charabia | Histogram aligné comme scalaire | Utiliser bucket … using interpolate_cumulative_histogram (ou _delta par temporality). Voir promql-to-mpl.md § Histogram translation. |
| Migration Grafana filtre/groupe sur le mauvais sous-ensemble | Lire expr sans description, ou vice versa |
Projeter les cinq champs de panneau avant authoring ; voir reference/grafana-migration.md. |
| Nom de métrique PromQL non trouvé | Omis les règles de renommage OTel | Supprimer _total, décomposer histograms, normaliser unités ; valider avec listMetrics. Les labels ont besoin découverte reverse-tag. Voir grafana-migration.md § Name Mapping. |
| Graphique MPL agrège à travers une dimension que PromQL a filtré/groupé | Supprimé un sélecteur ou by(...) lors de la traduction |
Chaque {label=…} → where ; chaque by(…) → group by. Voir reference/promql-to-mpl.md. |
| Panneau a livré une quantité différente de celle demandée | Substitué au lieu de reporter | Remplacer par une Note documentant le blocage. Voir Calculer ou reporter. |
| 403 « création de tableaux privés » | Les tokens API créent uniquement les tableaux partagés | Laisser owner comme défaut de dashboard-assemble (X-AXIOM-EVERYONE). |
400 invalid_dashboard lors d'ajout de sections |
JSON de graphique a inventé sections ou sectionId |
Passer --section / --section-collapsed à dashboard-assemble. Ne pas sonder l'API. |
Référence
reference/chart-config.md— Toutes les options de configuration de graphique (JSON)reference/metrics-mpl.md— Contrat de graphique Métriques/MPL et scripts de découvertereference/smartfilter.md— Configuration complète SmartFilter/FilterBarreference/chart-cookbook.md— Motifs APL par type de graphiquereference/layout-recipes.md— Layouts de grille et blueprints de sectionreference/splunk-migration.md— Panneau Splunk → Axiom mappingreference/grafana-migration.md— Panneau Grafana → Axiom mapping (projection canonical-spec, pointeurs PromQL→MPL, règles de renommage OTel)reference/promql-to-mpl.md— Règles de traduction PromQL → MPL (sélecteurs, groupages, rate, histograms, ratios, découverte reverse-tag)reference/design-playbook.md— Principes de conception décision-firstreference/templates/— Fichiers JSON de tableau de bord prêts à l'emploi
Pour syntaxe APL : https://axiom.co/docs/apl/introduction