TUI interactif
perf-sentinel embarque un TUI interactif pour explorer les findings, les arbres de spans et les corrélations cross-trace. Il expose trois vues en un seul drill-down : Analyze (le tableau de bord de synthèse), Inspect (le navigateur multi-panneaux) et Explain (l'arbre de spans plein écran d'une trace). Quel que soit le point d'entrée, on circule entre les trois vues sans quitter le TUI. Une quatrième vue, Disclose, reste à part : elle prévisualise un rapport de divulgation publique au lieu d'explorer des findings, elle n'a donc pas de drill-down vers les trois autres (voir Divulgation).
Points d'entrée :
perf-sentinel analyze --tui [--input <events.json>]: ouvre sur la vue Analyze.perf-sentinel demo --tui: même vue sur le jeu de démonstration embarqué, sans fichier d'entrée.perf-sentinel inspect --input <events.json>: ouvre sur la vue Inspect, lit un fichier d'événements brut ou un JSON Report pré-calculé.perf-sentinel explain --tui --trace-id <id> --input <events.json>: ouvre sur la vue Explain, centrée sur cette trace.perf-sentinel query --daemon <URL> inspect [--sort <KEY>]: mode live, ouvre sur Inspect, lit les findings et les traces depuis un daemon en cours d'exécution via HTTP.--sortprend les mêmes clés queanalyze --sort.perf-sentinel disclose --tui --input <archive>... --org-config <PATH>: ouvre l'aperçu Disclose.
En mode live (0.5.24+), le TUI permet aussi à l'opérateur d'acquitter et de révoquer des findings interactivement depuis le terminal.
Ce TUI est le navigateur de traces et de findings du développeur. Pour le monitoring d'exploitation, il existe un TUI opérateur live séparé, perf-sentinel query monitor (depuis 0.8.8). Il a six onglets, parcourus avec Tab : Advisor (les indications du conseiller de réglages du daemon), Energy (le mix énergie/carbone effectif par service et par région), Trends (courbes braille live de l'énergie/carbone par fenêtre et des jauges runtime en part de leur plafond configuré), Scrapers (santé live des backends énergie via /api/energy), Config (les paramètres du daemon en lecture seule, avec leur défaut et une explication d'une ligne pour chacun) et Incidents (les redémarrages et événements mémoire postés par l'alerting, chacun avec les findings figés de sa fenêtre, depuis 0.20.0). Les onglets se rafraîchissent depuis le daemon toutes les --refresh secondes (défaut 5). Quand le daemon devient injoignable, le dernier instantané valide reste affiché avec un indicateur d'obsolescence. Lecture seule : pas d'acquittement. Aucune clé d'API n'est requise sauf pour l'onglet Incidents, ou pour chaque onglet sur un daemon avec [daemon] require_read_key = true. Passez --api-key-file (ou PERF_SENTINEL_DAEMON_API_KEY), la clé en lecture seule [daemon] read_api_key suffit, et le moniteur l'envoie à chaque interrogation.
Vues et drill-down
Les trois vues forment un seul drill-down. Enter descend, Esc remonte :
Analyze --Enter--> Inspect --Enter--> Explain
<---Esc--- <---Esc---- Analyze : la synthèse à défilement (gaspillage GreenOps, principaux postes, quality gate), le même contenu que la sortie stdout d'
analyze.Enterdescend vers Inspect. - Inspect : le navigateur multi-panneaux décrit ci-dessous.
Enterparcourt les panneaux puis, depuis Detail, ouvre Explain.Escremonte vers Analyze. - Explain : l'arbre de spans annoté de la trace sélectionnée, plein écran, avec défilement.
Escrevient au panneau Detail d'Inspect.
Une barre d'onglets en haut met en évidence la vue active. Les arbres de spans se dessinent depuis des spans bruts (inspect --input <events>.json ou query inspect) ou depuis les arbres masqués qu'un Report porte (un instantané daemon, ou tempo/jaeger-query --format json). Une trace dont l'entrée ne contient pas les spans affiche une indication à la place.
Disposition
L'écran se découpe en une disposition sur 2 lignes :
┌─ Traces ──┬─ Findings ────────────────┬─ Correlations ────┐
│ trace-1 │ [1] N+1 SQL CRITICAL │ svc-a -> svc-b │
│ trace-2 │ [2] Redundant SQL WARNING │ ... │
│ ... │ [3] Slow HTTP INFO │ │
├───────────┴───────────────────────────┴───────────────────┤
│ Detail (full-width, span tree + finding metadata) │
└───────────────────────────────────────────────────────────┘La bordure du panneau actif est cyan, celles des autres restent grises.
Raccourcis clavier
La navigation fonctionne aux flèches partout. Dans la vue Inspect, les touches vim h / j / k / l s'appliquent aussi, et j / k font défiler les vues Analyze et Explain.
| Touche | Action |
|---|---|
q | Quitter |
↑ / k | Monte la sélection, ou fait défiler (Analyze, Explain) |
↓ / j | Descend la sélection, ou fait défiler (Analyze, Explain) |
→ / Tab / l | Passe au panneau suivant (Inspect) |
← / BackTab / h | Passe au panneau précédent (Inspect) |
Enter | Descend d'un cran dans le drill-down (voir ci-dessous) |
Esc | Remonte d'un cran |
m | Bascule le mode souris pour glisser les bordures |
r | Réinitialise les tailles des panneaux (Inspect) |
s | Passe au tri suivant : impact, sévérité, id (Inspect) |
f | Passe au filtre de sévérité suivant (Inspect) |
a | Acquitter le finding sélectionné (mode live) |
u | Révoquer l'ack existant (mode live) |
s ordonne les deux listes à la fois, les traces et les findings de la trace sélectionnée, sur les mêmes clés et les mêmes directions que analyze --sort et le dashboard. --sort sur analyze --tui et sur query inspect ouvre directement dans cet ordre.
f fait passer le panneau Findings par toutes les sévérités, puis critical, warning et info isolément. Le titre du panneau et la barre d'onglets nomment tous deux le filtre actif, et une trace dont tous les findings sont filtrés garde sa ligne avec un panneau vide : la liste des traces répond à ce qui a tourné, pas à ce qui correspond.
m bascule la capture souris (optionnelle, la sélection et le copier-coller natifs du terminal restent donc disponibles quand elle est coupée). Une fois activée, glisser la bordure entre deux panneaux redistribue leur espace. Survoler une bordure la met en évidence avec une poignée, car une application terminal ne peut pas changer le curseur souris de l'OS. r réinitialise la disposition par défaut. Les tailles sont propres à la session et non persistées.
Enter descend : d'Analyze vers Inspect, puis à travers les panneaux d'Inspect (Traces, Findings, Detail), puis de Detail vers Explain. Depuis le panneau Correlations, il saute vers le Detail de la trace d'exemple de la corrélation. Esc inverse chaque étape, remontant des panneaux de tête d'Inspect jusqu'à Analyze.
a et u sont sans effet en mode batch (inspect --input) puisque l'acquittement a besoin d'un daemon qui tourne pour persister.
Workflow d'acquittement (mode live)
Quand le TUI est lancé via query inspect, il récupère les findings avec ?include_acked=true pour que les findings déjà acquittés apparaissent dans la liste avec un indicateur italique gris [acked by <user>] en fin de ligne.
a : créer un ack
Presser a sur un finding sélectionné ouvre une modale centrée sur l'écran avec trois champs de saisie :
| Champ | Contrainte | Défaut |
|---|---|---|
| Reason | 1 à 256 caractères, une ligne | vide (requis) |
| Expires | vide, 24h, 7d, ISO8601, etc | vide (pas d'expiration) |
| By | 1 à 128 caractères | variable d'env $USER |
Plus deux boutons (Submit / Cancel).
Navigation modale :
| Touche | Action |
|---|---|
Tab | Focus sur le champ ou bouton suivant |
BackTab | Focus sur le champ ou bouton précédent |
Enter (texte) | Avance au champ suivant |
Enter (Submit) | Envoie le formulaire |
Enter (Cancel) | Ferme la modale sans envoyer |
Esc | Annule la modale |
Backspace | Supprime le dernier caractère du champ actif |
À l'envoi, le TUI poste sur /api/findings/<sig>/ack et ferme la modale sur 201. En cas d'erreur (4xx/5xx), la modale reste ouverte avec le message d'erreur en bas (texte rouge).
u : révoquer un ack
Presser u sur un finding acquitté ouvre une modale de confirmation. Submit / Enter envoie un DELETE /api/findings/<sig>/ack. Cancel / Esc ferme sans révoquer.
Format expires
Identique à l'utilitaire ack du CLI (depuis 0.5.22) :
- Vide : pas d'expiration, l'ack persiste jusqu'à révocation manuelle
24h,7d,30m: durée relative analysée par humantime2026-05-11T00:00:00Z: datetime ISO8601 absolu
Une entrée invalide affiche expires: <error> en bas de la modale sans envoyer la requête.
Authentification
Le TUI reprend la résolution d'authentification de l'utilitaire ack du CLI :
- Variable d'env
PERF_SENTINEL_DAEMON_API_KEY(priorité 1) - Flag
--api-key-file <path>surquery inspect(priorité 2)
# variable d'env
export PERF_SENTINEL_DAEMON_API_KEY=$(cat ~/.config/perf-sentinel/key)
perf-sentinel query --daemon http://localhost:4318 inspect
# fichier
perf-sentinel query --daemon http://localhost:4318 inspect \
--api-key-file ~/.config/perf-sentinel/keyLes deux sont équivalents. Les sauts de ligne en fin de fichier sont supprimés et, sur Unix, le fichier est ouvert avec O_NOFOLLOW (les liens symboliques sont refusés).
Pas d'invite de mot de passe interactive dans le TUI. Le mode raw et l'écran alternatif sont incompatibles avec la saisie TTY de rpassword. Si le daemon répond 401 sans clé en variable d'environnement ni en fichier, la modale affiche "API key required: set PERF_SENTINEL_DAEMON_API_KEY or pass --api-key-file when launching query inspect." Quitter, définir la clé, relancer.
Quand le daemon n'a pas de [daemon.ack] api_key configuré (défaut pour les déploiements loopback), aucune clé n'est requise et la modale envoie directement.
Limites
Le HTTP synchrone fige l'UI
run_loop est synchrone et l'écriture de l'ack daemon est exécutée via tokio::runtime::Handle::current().block_on(...) depuis l'intérieur de la boucle. L'UI se fige pendant la durée de la requête, typiquement 100-300 ms en localhost, plus longtemps sur le réseau. Acceptable pour une version au périmètre minimal. Une refonte en boucle d'événements async pourra suivre si les retours utilisateurs signalent de la friction.
Instantané de la liste des findings
La liste des findings est récupérée une seule fois au démarrage. a/u rafraîchissent uniquement l'état des acks via un second GET /api/findings?include_acked=true. La liste des findings elle-même ne change pas en cours de session. Pour récupérer des traces nouvellement ingérées, quitter et relancer.
Acks TOML visibles, pas modifiables
Les findings acquittés dans .perf-sentinel-acknowledgments.toml (CI ack) apparaissent avec l'indicateur [acked by <user>] et le champ source positionné à toml. Le TUI ne peut pas promouvoir un ack daemon vers TOML ni éditer le fichier TOML. Pour les acks permanents, éditer le fichier via revue PR comme décrit dans Flux d’acquittement.
Le moniteur opérateur live
perf-sentinel query monitor (depuis 0.8.8) est le pendant côté exploitation du navigateur Inspect du développeur ci-dessus. Il tourne contre un daemon vivant, le sonde à cadence fixe (--refresh secondes, défaut 5) et fonctionne en lecture seule. Tab parcourt les six onglets et BackTab revient en arrière, j/k ou les flèches font défiler, q ou Esc quitte. Sur l'onglet Trends, m bascule le mode souris pour glisser les bordures des graphes et r les réinitialise, comme dans le navigateur Inspect. Les données de chaque onglet (indications de config, provenance des sources, intensités par région) sont catégorielles et à haute cardinalité, donc la règle des labels bornés les garde hors du /metrics Prometheus.
- Advisor affiche les indications du conseiller de réglages du daemon (
warning_details), colorées par type. Un daemon bien dimensionné ne signale aucune indication. La capture ci-dessous montre un daemon sous-dimensionné dont la fenêtre de traces est bloquée près de son plafond. [Onglet Advisor : une indication de réglage, traces actives à 90 % ou plus de max_active_traces] - Energy montre le mix énergie/carbone effectif directement depuis le
green_summarylive : par service (source effective, part mesurée, énergie, région) et par région (intensité de grille, source froide embarquée vs chaude temps réel). La ligne de fenêtre nomme la source d'énergie, par exemplesource scaphandre_rapl on 2 of 5 services · rest modeled from I/O counts. Un service dont aucune opération n'a été mesurée afficheI/O countscomme source. [Onglet Energy : mix énergie/carbone par service et par région avec des sources d'intensité froides] - Trends trace l'historique de sondage en courbes braille live : l'énergie et le carbone par fenêtre de scoring en haut, et en dessous le graphe Headroom, chaque jauge runtime (
active_traces,analysis_queue_depth,stored_findings) en pourcentage de son plafond configuré, avec le seuil de 90 % du conseiller de réglages tracé en référence. Quand l'intensité de grille effective est statique, les deux courbes du haut se suivent. Elles divergent dès que l'intensité bouge, soit par le flux temps réel Electricity Maps, soit par un mix régional qui se déplace (la capture ci-dessous met en scène ce second cas). Un point arrive par tick de rafraîchissement, jusqu'à 240 points (20 minutes au défaut de 5 s), et l'historique vit dans le moniteur seul : le relancer repart d'une fenêtre vierge. Les champs de plafond demandent un daemon 0.8.8. Face à un daemon plus ancien, le panneau Headroom se dégrade en indication. [Onglet Trends : courbes d'énergie et de carbone sur l'historique de sondage, pourcentages de headroom sous le seuil advisor] - Scrapers lit
/api/energypour la santé live des backends. Icicloud_energyest configuré mais son endpoint est injoignable, donc son âge de fraîcheur grimpe tandis que les backends non configurés restent en tiret. [Onglet Scrapers : santé des backends, cloud_energy configuré avec un âge de fraîcheur qui grimpe] - Config lit
/api/configpour les réglages[daemon]effectifs du daemon, en lecture seule. Chaque paramètre montre sa valeur actuelle, le défaut compilé (calculé localement) et une explication d'une ligne de ce qu'il fait. Les valeurs qui diffèrent du défaut sont marquéesmodified. Les secrets sont résumés côté serveur (TLS configured/not, clés d'API ack et de lecture set/unset, store d'incidents enabled/disabled) et jamais montrés en clair. Nécessite un daemon 0.8.8+, les plus anciens affichent une indication. [Onglet Config : paramètres du daemon avec valeur actuelle, défaut et description, valeurs modifiées signalées] - Incidents lit
GET /api/incidentspour les redémarrages et événements mémoire que votre alerting a postés au daemon (depuis 0.20.0), du plus récent au plus ancien, chacun avec les findings figés de la fenêtre qui l'a précédé. Chaque incident s'affiche en une ligne en gras, le détail de l'alerte en dessous, puis une ligne indentée par finding. La ligne en gras porte le début en heure locale, le service enns/servicequand l'alerte portait un namespace, le genre,firingouended, le nombre de findings et un marqueur de capture :complete,partialquand le ring avait déjà évincé une partie de la fenêtre et que la liste est donc en deçà de ce qui s'est déclenché, ouempty ring. Une ligne de finding montre son type, sa sévérité, son endpoint, son décompte sur la fenêtre et s'il s'est déclenchébeforeouafterle redémarrage, ce marqueur ouvrant la ligne pour qu'un terminal étroit ne le coupe jamais. C'est le seul onglet qui demande une clé d'API, sauf si le daemon tourne avec[daemon] require_read_key = true, qui la demande sur chaque onglet : passez--api-key-file <PATH>(ou posezPERF_SENTINEL_DAEMON_API_KEY), et la clé en lecture seule[daemon] read_api_keysuffit. Sans clé l'onglet nomme le 401 et comment en passer une. Un daemon qui tourne avec[daemon.incidents] enabled = falsese lit comme une indication 503, un daemon antérieur à 0.20.0 comme une indication 404. Aucun des trois ne bascule[STALE], qui ne suit que le sondage du rapport, et un échec passager garde la dernière liste à l'écran. Le moniteur sonde les 20 incidents les plus récents.perf-sentinel query incidents --offsetpagine au-delà et--namespacerestreint la liste à un namespace. [Onglet Incidents : un OOM kill de checkout-svc encore actif, sa fenêtre capturée complète, un finding qui se déclenchait avant le redémarrage]
Quand le daemon devient injoignable, le dernier instantané valide reste affiché avec un indicateur [STALE] au lieu de se vider.
Thème du terminal
Les deux TUI (ce moniteur et le navigateur Inspect) suivent le thème du terminal lui-même : ils utilisent les 16 couleurs ANSI nommées et n'imposent jamais de fond, donc un terminal en thème clair les rend sur fond clair et un terminal sombre sur fond sombre. Le texte secondaire (titres, indications, en-têtes de colonnes) utilise l'attribut d'atténuation du terminal plutôt qu'un gris figé, pour rester lisible sur l'un comme sur l'autre fond. Il n'y a pas de flag --theme : configurez les couleurs dans votre émulateur de terminal.
Voir aussi
- Flux d’acquittement pour la relation entre les acks TOML CI et les acks JSONL daemon, plus la table de décision complète.
- Référence CLI pour la référence de la sous-commande
perf-sentinel ack(équivalent CLI dea/u). - Rapport HTML pour le flux d'ack côté navigateur via
--daemon-url. - API de query pour l'endpoint
/api/energyque lit l'onglet Scrapers, et la surface HTTP en lecture seule du daemon. - Configuration pour la référence config
[daemon.ack]côté serveur.