Guide d'intégration
Ce sujet existe en version animée : voir les déploiements sur la carte du synoptique →Perf Sentinel accepte les traces OpenTelemetry via OTLP (gRPC sur 4317, HTTP sur 4318). Ce guide vous accompagne de zéro jusqu'à votre premier finding pour chaque topologie de déploiement.
Voir aussi. Pas familier d'OpenTelemetry ? L'introduction à OpenTelemetry définit OTLP, le Collector, les spans et les traces en quelques paragraphes. À lire en premier si un de ces termes ne vous est pas familier.
Sommaire
- Choisissez votre topologie : tableau comparatif des quatre modes de déploiement pris en charge.
- Démarrage rapide : CI batch : exécuter Perf Sentinel depuis un pipeline CI contre une fixture de traces.
- Démarrage rapide : collector central : déploiement production via OpenTelemetry Collector.
- Vous venez de Datadog : faire le pont avec le trafic dd-trace via un OpenTelemetry Collector quand vous n'avez pas d'instrumentation OTel.
- Démarrage rapide : sidecar : débogage d'un seul service en dev ou staging.
- Démarrage rapide : daemon direct : développement local.
- Pour aller plus loin : pointeurs vers Instrumentation et CI pour les sujets côté application et côté CI.
- Formats d'ingestion : règles d'auto-détection JSON natif, OTLP, Jaeger, Zipkin, Tempo, pg_stat_statements et performance_schema MySQL.
- Mode explain : vue arborescente d'une trace.
- Export SARIF : sortie SARIF v2.1.0 pour le code scanning GitHub ou GitLab.
- Champ de confiance sur les findings : champ
confidenceJSON / SARIF pour les consommateurs aval. - API de requêtage du daemon : API HTTP sur le port OTLP HTTP, voir aussi API de query pour la référence complète.
- Lire un Perf Sentinel Hub depuis la CI :
perf-sentinel hubavec un jeton machine dansPERF_SENTINEL_HUB_TOKEN. - Configuration avancée du scoring carbone : scoring multi-région, Scaphandre, énergie cloud-native, Electricity Maps, calibration.
- Intégration Tempo : interroger un backend Grafana Tempo directement avec
perf-sentinel tempo. - Intégration API Jaeger query : Jaeger upstream et Victoria Traces via une seule sous-commande.
- Dépannage : problèmes d'ingestion et de détection courants.
Choisissez votre topologie
| Topologie | Idéal pour | Effort | Modifications des services |
|---|---|---|---|
| CI batch | Pipelines CI, vérifications de PR | Le plus faible | Aucune (fichiers de traces) |
| Collector central | Production, multi-services | Faible | Aucune (config YAML uniquement) |
| Sidecar | Dev/staging, débogage d'un service | Faible | Aucune (Docker uniquement) |
| Daemon direct | Dev local, essais rapides | Moyen | Variables d'env par langage |
Démarrage rapide : CI batch
Exécutez Perf Sentinel dans votre pipeline CI pour détecter les requêtes N+1 avant qu'elles n'atteignent la production. Il ne faut ni daemon ni Docker : le binaire lit un fichier de traces et retourne le code 1 quand le quality gate échoue.
Installation
curl -LO https://github.com/Institut-du-Numerique-Responsable/perf-sentinel/releases/latest/download/perf-sentinel-linux-amd64
chmod +x perf-sentinel-linux-amd64
sudo mv perf-sentinel-linux-amd64 /usr/local/bin/perf-sentinelConfigurer les seuils
Créez .perf-sentinel.toml à la racine de votre projet :
[thresholds]
n_plus_one_sql_critical_max = 0 # zéro tolérance pour les N+1 SQL
io_waste_ratio_max = 0.30 # max 30% d'I/O évitables
[detection]
n_plus_one_min_occurrences = 5
slow_query_threshold_ms = 500
[green]
enabled = true
default_region = "eu-west-3" # optionnel : active les estimations gCO2eq
# surcharges par service pour les déploiements multi-région
# [green.service_regions]
# "api-us" = "us-east-1"
# "api-asia" = "ap-southeast-1"La sortie CO₂ est structurée (green_summary.co2.total.{low,mid,high} plus un tag de méthodologie SCI v1.0, incertitude multiplicative 2×). Le scoring multi-région s'active automatiquement quand les spans portent l'attribut cloud.region. Voir Configuration et Limites.
Collecter les traces
Exportez les traces depuis vos tests d'intégration. Perf Sentinel détecte automatiquement les formats JSON natif, OTLP JSON, Jaeger et Zipkin v2.
Analyser
perf-sentinel analyze --ci --input traces.json --config .perf-sentinel.tomlLe processus affiche un rapport JSON sur stdout et retourne le code 0 (succès) ou 1 (échec). Ajoutez ceci à votre job CI :
# Exemple GitLab CI
perf:sentinel:
stage: quality
script:
- perf-sentinel analyze --ci --input traces.json --config .perf-sentinel.toml
artifacts:
paths: [perf-sentinel-report.json]
when: always
allow_failure: true # commencez en warning, retirez une fois les seuils calibrésInvestiguer les findings
# Rapport coloré en terminal
perf-sentinel analyze --input traces.json --config .perf-sentinel.toml
# Vue arborescente d'une trace spécifique
perf-sentinel explain --input traces.json --trace-id <trace-id>
# TUI interactif
perf-sentinel inspect --input traces.json
# SARIF pour GitHub/GitLab code scanning
perf-sentinel analyze --input traces.json --format sarif > results.sarif
# Dashboard HTML single-file pour l'exploration post-mortem en navigateur
perf-sentinel report --input traces.json --output report.htmlLe dashboard HTML est documenté dans Rapport HTML, avec la liste complète des options, les raccourcis clavier, l'export CSV et le pipeline d'instantané /api/export/report du daemon live.
Démarrage rapide : collector central
Déploiement production où les services envoient les traces à un OpenTelemetry Collector. Zéro modification de code, uniquement de la configuration YAML.
Démarrer Perf Sentinel + collector
# Récupérer le fichier compose d'exemple (sans cloner le dépôt), puis le démarrer
curl -o docker-compose.yml https://raw.githubusercontent.com/Institut-du-Numerique-Responsable/perf-sentinel/main/examples/docker-compose-collector.yml
docker compose up -dL'URL brute suit main. Remplacez main par un tag de release (par exemple v0.8.13) pour figer une version précise.
Cela démarre un OTel Collector sur 4317 (gRPC) + 4318 (HTTP) et Perf Sentinel en mode watch derrière lui.
Pointer vos services vers le collector
OTEL_EXPORTER_OTLP_ENDPOINT=http://otel-collector:4317
OTEL_EXPORTER_OTLP_PROTOCOL=grpcSi vos services exportent déjà vers un collector existant, ajoutez Perf Sentinel comme second exporter :
exporters:
otlp/perf-sentinel:
endpoint: perf-sentinel:4317
tls:
insecure: true
service:
pipelines:
traces:
exporters: [otlp/perf-sentinel, otlp/your-existing-backend]Générer du trafic et voir les findings
docker compose logs -f perf-sentinelLes findings sont émis en NDJSON sur stdout une fois le TTL des traces expiré (30s par défaut).
Surveiller avec Prometheus + Grafana
Les métriques sont exposées à http://localhost:14318/metrics avec des exemplars OpenMetrics (clic direct vers votre backend de traces) :
# prometheus.yml
scrape_configs:
- job_name: perf-sentinel
static_configs:
- targets: ['perf-sentinel:4318']Principales métriques : perf_sentinel_findings_total{type, severity, service, grouping}, perf_sentinel_io_waste_ratio, perf_sentinel_events_processed_total, perf_sentinel_traces_analyzed_total, perf_sentinel_slow_duration_seconds{type, service, grouping}. Voir Métriques pour le schéma complet et examples/otel-collector-config.yaml pour la config du collector.
Vous venez de Datadog (dd-trace, sans OpenTelemetry)
Perf Sentinel ingère de l'OTLP, pas le format APM natif de Datadog, et n'embarque aucun adaptateur Datadog. Si vos services sont instrumentés avec dd-trace (le traceur propriétaire de Datadog) et que vous n'avez pas d'instrumentation OpenTelemetry, faites le pont avec un OpenTelemetry Collector équipé du datadogreceiver. Ce receiver implémente l'API d'intake de traces de l'agent Datadog sur le port 8126, convertit les spans dd-trace en OTLP, et un exporter otlp transmet une copie à Perf Sentinel. Aucun changement de code applicatif n'est requis : vous repointez dd-trace vers le Collector, et vous pouvez continuer à envoyer vers Datadog en parallèle.
Perf Sentinel lit nativement la ressource Datadog (dd.span.Resource, où dd-trace laisse le SQL obfusqué). La détection SQL fonctionne donc tant que chaque span conserve un signal base de données : la clé stable db.system.name (ce qu'émettent les versions récentes du receiver), l'ancienne db.system, ou le tag dd-trace db.type. Aucun remappage d'attributs dans le Collector n'est nécessaire. Si une version du Collector les retire toutes, ajoutez un processor transform qui en restaure une pour que le garde-fou se déclenche.
Réserve sur N+1 contre requêtes redondantes. dd-trace pré-obfusque le SQL (les littéraux sont déjà ?), donc les paramètres par requête qui distinguent un N+1 d'une requête légitimement répétée ont disparu avant que Perf Sentinel ne les voie. En mode de détection auto par défaut, un vrai N+1 aux durées de requête uniformes peut apparaître comme redundant_sql plutôt que n_plus_one_sql. Réglez [detection] sanitizer_aware_classification = "strict" pour récupérer les cas à forte occurrence (3 fois le n_plus_one_threshold configuré, soit 15 requêtes identiques ou plus à la valeur par défaut de 5). Le scoring de gaspillage et de carbone est identique pour les deux types de finding.
PHP (Laravel, Symfony) via dd-trace-php. La même réserve d'obfuscation s'applique : un vrai N+1 Laravel ou Symfony peut apparaître comme redundant_sql en mode auto, utilisez donc sanitizer_aware_classification = "strict". Le pont perd aussi le signal de framework : le datadogreceiver pose un scope d'instrumentation Datadog fixe et ne mappe aucun attribut code.*, donc les findings dd-trace-php n'ont pas de suggested_fix adapté au framework (ils retombent sur php_generic ou restent non enrichis). Les corrections spécifiques Laravel/Eloquent et Symfony/Doctrine exigent l'instrumentation OpenTelemetry PHP native (scopes io.opentelemetry.contrib.php.*), voir Instrumentation.
La mention "OpenTelemetry compliant" de Datadog est souvent mal comprise. Elle désigne en général l'agent Datadog qui ingère de l'OTLP (entrant, depuis des SDK OTel), ce qui est le sens inverse. Faire sortir les données dd-trace vers un backend OTLP passe par le chemin Collector ci-dessous.
Stabilité. La prise en charge des traces du datadogreceiver est en alpha dans opentelemetry-collector-contrib (en 2026). Le receiver convient à l'évaluation et aux preuves de concept. Surveillez-le si vous le maintenez en permanence devant la production.
Config du Collector (dd-trace en entrée, OTLP en sortie vers Perf Sentinel) :
receivers:
datadog:
endpoint: 0.0.0.0:8126 # intake APM dd-trace
exporters:
otlp/perf-sentinel:
endpoint: perf-sentinel:4317
tls:
insecure: true
# datadog: # optionnel : garder votre backend Datadog existant
# api:
# key: ${DD_API_KEY}
service:
pipelines:
traces:
receivers: [datadog]
exporters: [otlp/perf-sentinel] # ajouter `datadog` ici pour dupliquer vers les deuxPointez dd-trace vers le Collector au lieu de l'agent Datadog :
DD_TRACE_AGENT_URL=http://otel-collector:8126Perf Sentinel reçoit alors une copie de chaque trace et les findings sont émis en NDJSON, exactement comme dans la topologie collector central ci-dessus.
Batch plutôt que le daemon. Le chemin Collector ci-dessus alimente le daemon watch. Pour un analyze ponctuel à la place, la voie la plus simple depuis la 0.9.5 est l'exporter file du Collector : sa sortie OTLP JSON (objet unique ou NDJSON, une requête par ligne) est auto-détectée par analyze --input comme n'importe quel fichier de traces. Sinon, routez le pont vers un backend Jaeger ou Tempo et tirez-en un lot :
perf-sentinel jaeger-query --endpoint http://jaeger:16686 --service checkout --lookback 15m
perf-sentinel tempo --endpoint http://tempo:3200 --service checkout --lookback 15mUne trace exportée au format JSON Jaeger depuis l'UI Jaeger (bouton "Download JSON") fonctionne aussi avec analyze --input. Quelle que soit la voie batch, la réserve d'obfuscation ci-dessus reste valable : gardez sanitizer_aware_classification = "strict".
Démarrage rapide : sidecar
Déboguez un service unique en dev/staging. Perf Sentinel tourne à côté du service, en partageant son namespace réseau.
# Récupérer le fichier compose d'exemple (sans cloner le dépôt), puis le démarrer
curl -o docker-compose.yml https://raw.githubusercontent.com/Institut-du-Numerique-Responsable/perf-sentinel/main/examples/docker-compose-sidecar.yml
docker compose up -dConfig de l'app (pas de saut réseau, même namespace) :
OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318
OTEL_EXPORTER_OTLP_PROTOCOL=http/protobufdocker compose logs -f perf-sentinelVoir examples/docker-compose-sidecar.yml.
Démarrage rapide : daemon direct
Développement local sur votre machine hôte.
perf-sentinel watchL'adresse d'écoute par défaut est 127.0.0.1 sur 4317 (gRPC) et 4318 (HTTP). Pour que les conteneurs Docker puissent atteindre l'hôte, posez [daemon] listen_address = "0.0.0.0" dans .perf-sentinel.toml. Une adresse d'écoute autre que loopback émet un avertissement au démarrage : les endpoints n'ont pas d'auth applicative, mettez donc un reverse-proxy ou une network policy en frontal, ou posez [daemon.ack] api_key pour garder les écritures d'ack (voir Configuration).
Config de l'app :
# Pour les services sur l'hôte
OTEL_EXPORTER_OTLP_ENDPOINT=http://127.0.0.1:4317
# Pour les services conteneurisés sur Docker Desktop
OTEL_EXPORTER_OTLP_ENDPOINT=http://host.docker.internal:4317Les findings sont émis sur stdout en NDJSON. Les métriques Prometheus sont disponibles à http://localhost:4318/metrics.
Pour aller plus loin
- Instrumentation pour la configuration par langage (Java, Quarkus, .NET, Rust) et le chemin OTel Collector en production.
- CI pour le câblage CI (GitHub Actions, GitLab CI, Jenkins), la philosophie du quality gate et la sous-commande
diffpour les régressions de PR.
Formats d'ingestion
Perf Sentinel auto-détecte le format d'entrée avec perf-sentinel analyze --input :
| Format | Détection | Exemple |
|---|---|---|
| Natif (Perf Sentinel JSON) | Tableau d'objets avec champ "type" | Format par défaut |
| OTLP JSON | Objet avec clé "resourceSpans" | Dump exporter file du Collector |
| Jaeger JSON | Objet avec clé "data" contenant "spans" | Exporté depuis l'UI Jaeger |
| Zipkin JSON v2 | Tableau d'objets avec "traceId" + "localEndpoint" | Exporté depuis l'UI Zipkin |
Aucun flag --format n'est nécessaire pour l'entrée : le format est détecté automatiquement depuis les premiers octets du fichier.
L'OTLP JSON en batch (0.9.5+). analyze --input accepte la forme OTLP/JSON du protocole (ExportTraceServiceRequest, clés camelCase, ids trace/span en hexadécimal), en objet unique comme en NDJSON de l'exporter file du Collector (une requête par ligne). L'OTLP atteint aussi Perf Sentinel en live par les listeners du daemon (watch) et indirectement par les sous-commandes tempo et jaeger-query. Si vous êtes sur dd-trace, voir Vous venez de Datadog.
Entrées de statistiques base de données. Les sous-commandes pg-stat et mysql-stat lisent des exports CSV ou JSON de pg_stat_statements et de performance_schema.events_statements_summary_by_digest respectivement, avec la même auto-détection au premier octet ([ ou { signifie JSON, tout le reste CSV). Les noms de colonnes sont reconnus sans tenir compte de la casse. Les colonnes timer MySQL (picosecondes) sont converties en millisecondes au parsing. Exportez la vue MySQL avec mysqlsh --result-format=csv ou tout export CSV/JSON client. SELECT ... INTO OUTFILE produit du TSV échappé par antislash, non pris en charge.
# Export Jaeger
perf-sentinel analyze --input jaeger-export.json --ci
# Export Zipkin
perf-sentinel analyze --input zipkin-traces.json --ciMode explain
Pour déboguer une trace spécifique, utilisez la sous-commande explain :
perf-sentinel explain --input traces.json --trace-id abc123-def456Cela produit une vue arborescente de la trace avec les findings annotés en ligne. Utilisez --format json pour une sortie structurée.
Export SARIF
Qu'est-ce que SARIF. Le Static Analysis Results Interchange Format est un schéma JSON standard OASIS (v2.1.0 depuis 2020) que les outils d'analyse statique utilisent pour publier leurs findings dans un format agnostique. GitHub Advanced Security et GitLab Ultimate acceptent l'envoi de fichiers SARIF et affichent chaque finding directement sur les pull requests, de la même manière que les résultats ESLint ou Semgrep aujourd'hui. Perf Sentinel émet du SARIF pour que les findings d'anti-patterns apparaissent à côté des findings sécurité dans le même tableau de bord code scanning. Spec.
Pour l'intégration avec GitHub ou GitLab code scanning, exportez les findings en SARIF v2.1.0 :
perf-sentinel analyze --input traces.json --format sarif > results.sarifEnvoyez le fichier SARIF vers votre tableau de bord code scanning. Chaque finding est mappé vers un résultat SARIF avec ruleId, level, le service et l'endpoint dans properties.service et properties.endpoint, une entrée locations quand le finding a un fichier source, un tag personnalisé properties.confidence et une valeur standard rank SARIF (0-100) dérivée de la confiance.
Champ de confiance sur les findings
Chaque finding émis en JSON ou SARIF porte un champ confidence qui indique le contexte source de la détection. Le champ est conçu pour les consommateurs en aval comme perf-lint, une intégration IDE compagnon planifiée qui ajustera la sévérité affichée dans l'IDE selon le niveau de confiance à accorder au finding. Tout outil personnalisé qui consomme les sorties JSON ou SARIF de Perf Sentinel peut utiliser ce champ de la même manière.
Valeurs :
| Valeur | Quand émise | SARIF rank | Interprétation |
|---|---|---|---|
"local_batch" | perf-sentinel analyze (mode batch, sans environnement de CI) | 15 | Confiance la plus faible : traces locales ponctuelles, run non contrôlé |
"ci_batch" | perf-sentinel analyze (mode batch, environnement de CI détecté) | 30 | Confiance faible : la trace vient d'un run CI contrôlé avec des patterns de trafic limités |
"daemon_staging" | perf-sentinel watch avec [daemon] environment = "staging" (défaut) | 60 | Confiance moyenne : patterns de trafic réels observés sur un déploiement staging |
"daemon_production" | perf-sentinel watch avec [daemon] environment = "production" | 90 | Confiance la plus élevée : trafic réel, échelle réelle, vrais utilisateurs |
Exemple de finding JSON :
{
"type": "n_plus_one_sql",
"severity": "warning",
"trace_id": "abc123",
"service": "order-svc",
"source_endpoint": "POST /api/orders/{id}/submit",
"pattern": { "template": "SELECT * FROM order_item WHERE order_id = ?", "occurrences": 6, "window_ms": 250, "distinct_params": 6 },
"suggestion": "Use WHERE ... IN (?) to batch 6 queries into one",
"first_timestamp": "2026-04-08T03:14:01.050Z",
"last_timestamp": "2026-04-08T03:14:01.300Z",
"confidence": "daemon_production"
}Exemple de fragment de résultat SARIF :
{
"ruleId": "n_plus_one_sql",
"level": "warning",
"message": { "text": "n_plus_one_sql in order-svc on POST /api/orders/{id}/submit..." },
"properties": { "confidence": "daemon_production" },
"rank": 90
}Configuration dans le daemon :
[daemon]
# "staging" (défaut) → confidence = daemon_staging, rank = 60
# "production" → confidence = daemon_production, rank = 90
environment = "production"La valeur est tamponnée sur chaque finding émis par cette instance de daemon. Les valeurs invalides (tout sauf staging/production, insensible à la casse) sont rejetées au chargement de la config avec une erreur claire. Le mode batch analyze ignore ce champ et émet ci_batch quand il détecte un environnement de CI (CI défini à autre chose que false ou 0, ou JENKINS_URL présent), local_batch sinon.
Interopérabilité avec perf-lint (planifié). perf-lint (planifié comme intégration IDE compagnon, pas encore publié) lira le champ confidence sur les findings runtime importés et appliquera un multiplicateur de sévérité : les findings local_batch et ci_batch affichés en indications, daemon_staging en avertissements, daemon_production en erreurs. Ainsi un finding observé sur du trafic production réel remontera plus visiblement dans l'IDE qu'un finding observé uniquement dans une fixture CI.
API de requêtage du daemon
Le daemon expose une API HTTP de requêtage sur le même port que OTLP HTTP et /metrics (défaut 4318). Elle permet à des systèmes externes de récupérer les findings récents, les explications de traces, les corrélations cross-trace et la liveness du daemon sans parser les logs NDJSON. Utile pour l'alerting Prometheus, des panels Grafana personnalisés ou des runbooks SRE.
# Liveness du daemon
curl -sS http://127.0.0.1:4318/api/status
# Findings critiques récents
curl -sS "http://127.0.0.1:4318/api/findings?severity=critical&limit=10"Voir API de query pour la référence complète par endpoint, des exemples de réponses réelles capturées, des cas d'usage (alerting Prometheus, dashboard Grafana, runbook SRE) et le contrat de stabilité.
Lire un Perf Sentinel Hub depuis la CI
Un job CI lit un Perf Sentinel Hub avec perf-sentinel hub et un jeton machine dans PERF_SENTINEL_HUB_TOKEN, tiré du coffre de secrets de la CI. Un Hub dont le contrôle d'accès est désactivé n'a besoin d'aucun jeton.
export PERF_SENTINEL_HUB_URL=https://hub.example.com
export PERF_SENTINEL_HUB_TOKEN="$HUB_TOKEN" # depuis le coffre de secrets de la CI
perf-sentinel hub findings --environment production --status active --severity critical --format jsonhub findings accepte aussi --from et --to (RFC 3339 UTC ou millisecondes epoch), --offset, --include-acked true|false et --signature, pour lire une fenêtre, la parcourir par pages ou suivre un finding précis.
Le jeton part en Authorization: Bearer, uniquement en https (ou en http simple vers la boucle locale), et jamais sur la ligne de commande. Un jeton machine ne fait que lire : hub ack, hub unack et hub analyze exigent le perf-sentinel login d'une personne. Un jeton dont aucun grant ne donne findings.read au groupe reçoit 403 et la commande sort en 1 : le job échoue au lieu de lire une liste vide. Voir Référence CLI.
Configuration avancée du scoring carbone
Scoring multi-région
Si vos services couvrent plusieurs régions cloud, Perf Sentinel peut appliquer des coefficients d'intensité carbone par région. Le mécanisme principal est l'attribut de ressource OTel cloud.region, que la plupart des SDKs OTel cloud émettent automatiquement. Quand cet attribut est absent (ex. ingestion Jaeger/Zipkin), utilisez la table [green.service_regions] pour associer les services à des régions :
[green]
default_region = "eu-west-3"
[green.service_regions]
"order-svc" = "us-east-1"
"chat-svc" = "ap-southeast-1"
"auth-svc" = "eu-west-3"La chaîne de résolution de la région est : attribut cloud.region du span > service_regions[service] > default_region > bucket synthétique "unknown". Le rapport JSON inclut un tableau regions[] trié par CO₂ décroissant, chaque ligne indiquant le nom de la région, l'intensité carbone du réseau, le PUE, le nombre d'opérations I/O et le CO₂ opérationnel.
Intégration Scaphandre (on-premise / bare metal)
Pour les serveurs on-premise ou bare metal avec prise en charge d'Intel RAPL, Perf Sentinel peut scraper les métriques de puissance par processus de Scaphandre pour remplacer le modèle proxy I/O par des données d'énergie mesurées.
Prérequis :
- Scaphandre installé et en cours d'exécution sur chaque hôte, exposant un endpoint Prometheus
/metrics. - Accès RAPL disponible (bare metal ou VM avec RAPL passthrough).
Configuration :
[green.scaphandre]
endpoint = "http://localhost:8080/metrics"
scrape_interval_secs = 5
process_map = { "order-svc" = "java", "game-svc" = "game", "chat-svc" = "dotnet" }Le process_map mappe les noms de service Perf Sentinel au label exe dans la métrique scaph_process_power_consumption_microwatts de Scaphandre. Le daemon scrape cet endpoint toutes les scrape_interval_secs secondes et calcule un coefficient énergie-par-op par service avec la formule energy_kwh = (power_watts * interval) / ops / 3_600_000.
Les services absents du process_map, et tous les services quand l'endpoint est injoignable, se rabattent de manière transparente sur le modèle proxy. Le tag de modèle passe à "scaphandre_rapl" pour les services qui utilisent l'énergie mesurée. Seul le mode daemon watch utilise Scaphandre. La commande batch analyze utilise toujours le modèle proxy.
Endpoint Scaphandre authentifié
Si l'exporter Scaphandre est placé derrière un reverse proxy avec auth basic ou un ingress bearer-token, ajoutez une entrée auth_header :
[green.scaphandre]
endpoint = "https://scaphandre.my-cluster.example/metrics"
scrape_interval_secs = 5
auth_header = "Authorization: Basic <base64>"La valeur suit le même format "Name: Value" que le flag --auth-header des sous-commandes tempo et jaeger-query. Elle est marquée sensitive, hyper la masque dans les logs debug et les tables HPACK HTTP/2, et l'impl manuelle de Debug de la struct empêche toute fuite via un tracing::debug!(?config).
La variable d'environnement PERF_SENTINEL_SCAPHANDRE_AUTH_HEADER est prioritaire sur le fichier de config. Préférez la variable d'environnement en production pour éviter de versionner des secrets. Quand la valeur est définie dans le fichier de config et que la variable d'environnement est absente, un avertissement au démarrage oriente vers la variable d'environnement.
Envoyer un en-tête d'authentification en clair via http:// déclenche un tracing::warn! une fois au démarrage du scraper. Préférez https:// en production. Un en-tête mal formé désactive le sous-système du scraper avec un tracing::error! plutôt que de réessayer en silence.
Estimation d'énergie cloud (AWS / GCP / Azure)
Pour les VMs cloud qui n'exposent pas RAPL (la plupart des instances hors bare metal), Perf Sentinel peut estimer l'énergie par service via les métriques d'utilisation CPU depuis un endpoint Prometheus et le modèle SPECpower.
Prérequis :
- Un endpoint compatible Prometheus avec des métriques d'utilisation CPU (via cloudwatch_exporter, stackdriver-exporter, azure-metrics-exporter ou node_exporter).
- Perf Sentinel n'interroge PAS les APIs des fournisseurs cloud directement.
Configuration :
[green.cloud]
prometheus_endpoint = "http://prometheus:9090"
scrape_interval_secs = 15
default_provider = "aws"
default_instance_type = "m7i.xlarge"
[green.cloud.services.api-us]
provider = "aws"
instance_type = "m7i.4xlarge" # Sapphire Rapids
cpu_query = 'aws_ec2_cpuutilization_average{instance_id="i-0123456789abcdef0"}'
[green.cloud.services.analytics]
provider = "azure"
instance_type = "Standard_D8s_v6" # Emerald Rapids
cpu_query = '100 - (avg(rate(node_cpu_seconds_total{mode="idle",instance="analytics:9100"}[5m])) * 100)'Le daemon interpole la consommation avec watts = idle_watts + (max_watts - idle_watts) * (cpu% / 100) en utilisant les coefficients CCF 2026-04-24 par vCPU embarqués dans le binaire (chaque type listé dans Types d'instance, couvrant AWS, GCP, Azure et Scaleway, y compris les architectures modernes Sapphire Rapids, Emerald Rapids, Genoa, Turin, Graviton 3/4 et Cobalt 100). Le tag de modèle est "cloud_specpower". Comme Scaphandre, c'est une fonctionnalité réservée au daemon.
Précédence des sources d'énergie. Quand plusieurs sources mesurées sont configurées pour le même service, la plus précise gagne. La chaîne complète : electricity_maps_api > grid_operator_api > alumet_rapl > scaphandre_rapl > kepler_ebpf > redfish_bmc > cloud_specpower > io_proxy_v3 > io_proxy_v2 > io_proxy_v1. Voir Limites pour la discussion sur les limites de précision de chaque source mesurée.
Endpoint Prometheus authentifié
Si votre Prometheus est derrière une auth basic, un proxy bearer-token, ou un service hébergé comme Grafana Cloud ou Grafana Mimir, ajoutez une entrée auth_header :
[green.cloud]
prometheus_endpoint = "https://prometheus.grafana-cloud.example/api/prom"
auth_header = "Authorization: Bearer ${GRAFANA_CLOUD_TOKEN}"La valeur suit le même format "Name: Value" que le flag --auth-header des sous-commandes tempo et jaeger-query. Elle est marquée sensitive, hyper la masque dans les logs debug et les tables HPACK HTTP/2, et l'impl manuelle de Debug de la struct empêche toute fuite via un tracing::debug!(?config).
La variable d'environnement PERF_SENTINEL_CLOUD_AUTH_HEADER est prioritaire sur le fichier de config. Préférez la variable d'environnement en production pour éviter de versionner des secrets. Quand la valeur est définie dans le fichier de config et que la variable d'environnement est absente, un avertissement au démarrage oriente vers la variable d'environnement.
Envoyer un en-tête d'authentification en clair via http:// déclenche un tracing::warn! une fois au démarrage du scraper. Préférez https:// en production. Un en-tête mal formé désactive le sous-système du scraper avec un tracing::error! plutôt que de réessayer en silence.
Calibration du modèle proxy avec des mesures terrain
Quand ni Scaphandre ni l'estimation cloud ne sont disponibles mais que vous avez des mesures d'énergie de référence issues d'une source externe (wattmètre, export RAPL, monitoring datacenter), la sous-commande perf-sentinel calibrate ajuste les coefficients I/O vers énergie du modèle proxy par service. Le workflow en trois étapes :
1. Mesurer. Exécuter une charge de référence et collecter à la fois les traces (format JSON Perf Sentinel standard) et les mesures d'énergie (CSV avec colonnes timestamp,service,power_watts ou timestamp,service,energy_kwh, auto-détecté depuis l'en-tête).
2. Calibrer. Exécuter perf-sentinel calibrate --traces traces.json --measured-energy energy.csv --output calibration.toml. La sous-commande corrèle les ops I/O avec les lectures d'énergie par service et fenêtre temporelle, calcule factor = measured_per_op / default_proxy et écrit un fichier TOML. Les facteurs > 10x ou < 0.1x émettent des avertissements (probable erreur de mesure).
3. Utiliser. Charger le fichier de calibration à la lecture de la config via [green] calibration_file = ".perf-sentinel-calibration.toml". La boucle de scoring multiplie l'énergie proxy par le facteur du service et le tag de modèle reçoit un suffixe +cal (par exemple io_proxy_v2+cal). La calibration ne s'applique qu'au modèle proxy : l'énergie mesurée Scaphandre/cloud reste prioritaire.
Intégration Tempo
Si votre infrastructure utilise Grafana Tempo comme backend de traces, vous pouvez l'interroger directement avec perf-sentinel tempo au lieu d'exporter les traces dans des fichiers.
Workflow post-mortem. Quand une trace est plus ancienne que la fenêtre live de 30 secondes du daemon, Tempo devient la source de rejeu pour perf-sentinel tempo --trace-id …. Le workflow complet d'incident, de l'alerte Grafana à l'exemplar, puis au trace_id et au rejeu, est documenté dans Runbook.
Analyse d'une trace
perf-sentinel tempo --endpoint http://tempo:3200 --trace-id abc123def456Recherche par service
# Analyser la dernière heure de traces pour order-svc
perf-sentinel tempo --endpoint http://tempo:3200 --service order-svc --lookback 1h
# Mode CI avec quality gate
perf-sentinel tempo --endpoint http://tempo:3200 --service order-svc --lookback 30m --ciPrérequis
- Tempo doit exposer son API HTTP (port 3200 par défaut).
- Le flag
--endpointpointe vers l'URL de base de l'API Tempo. - Les traces sont récupérées en protobuf OTLP et passent par le pipeline d'analyse standard. La sortie est identique à
perf-sentinel analyze.
Tempo en mode microservices (tempo-distributed)
Si votre Tempo est déployé via le chart Helm tempo-distributed et non via l'image monolithique single-binary, l'API HTTP de requête est exposée par tempo-query-frontend, pas par tempo-querier. tempo-querier est un worker interne sans API publique, donc pointer --endpoint dessus renvoie HTTP 404 sur chaque /api/search. Résolvez le nom d'hôte du query-frontend comme votre environnement le permet (nom de Service Kubernetes, nom de service Docker Compose, ou hôte explicite en bare-metal) :
perf-sentinel tempo --endpoint http://tempo-query-frontend:3200 \
--service order-svc --lookback 1hUn 404 dû à un endpoint erroné remonte comme Tempo returned HTTP 404 for https://.../api/search?... (l'URL qui a échoué est incluse dans le message) pour rendre la mauvaise configuration diagnostiquable immédiatement.
Après la recherche, la CLI lit chaque trace par son identifiant, 16 à la fois par défaut. Le query-frontend découpe chaque lecture en trace_by_id.query_shards morceaux (50 par défaut), donc 16 lectures mettent des centaines de morceaux en file pour les queriers. Un querier avec une petite limite mémoire peut être tué par manque de mémoire sous cette charge, et le query-frontend peut redémarrer avec lui. Sur un tel déploiement, baissez --fetch-concurrency pour une exécution, ou [tempo] fetch_concurrency pour toutes (de 1 à 64). Côté Tempo, querier.max_concurrent_queries et un GOMEMLIMIT proche de la limite mémoire du querier le protègent de n'importe quel client.
Alternative : forwarding générique Tempo
Au lieu d'interroger Tempo, vous pouvez configurer Tempo pour qu'il transmette une copie des traces vers Perf Sentinel via son mécanisme de generic forwarding. Cela fonctionne en temps réel avec perf-sentinel watch.
Intégration API Jaeger query (Jaeger et Victoria Traces)
Si votre infrastructure utilise Jaeger upstream ou Victoria Traces comme backend de traces, les deux parlent l'API HTTP query de Jaeger et sont couverts par une seule sous-commande, perf-sentinel jaeger-query. Contrairement à l'API /api/search de Tempo (IDs uniquement), l'API /api/traces de Jaeger retourne les traces complètes en une seule requête HTTP, donc la CLI ne parallélise pas les récupérations trace par trace. Jaeger 2.21 et les suivantes ne servent plus cette recherche, la CLI repasse alors par l'API v3, voir les prérequis ci-dessous.
Analyse d'une trace
perf-sentinel jaeger-query --endpoint http://jaeger:16686 --trace-id abc123def456Recherche par service
# Analyser la dernière heure de traces pour order-svc
perf-sentinel jaeger-query --endpoint http://jaeger:16686 --service order-svc --lookback 1h
# Même recette contre Victoria Traces, qui sert l'API de requête Jaeger sous
# /select/jaeger et non à la racine, donc le préfixe va dans --endpoint
perf-sentinel jaeger-query --endpoint http://victoria-traces:10428/select/jaeger --service order-svc --lookback 1h
# Mode CI avec quality gate
perf-sentinel jaeger-query --endpoint http://jaeger:16686 --service order-svc --lookback 30m --ciPrérequis
- Le backend doit exposer l'API HTTP de requête Jaeger : une recherche, soit la v1
/api/traces?service=...&start=...&end=...&limit=..., soit, sur Jaeger 2.21 et suivantes, la v3/api/v3/traces, ainsi que la lecture par trace/api/traces/<id>. Jaeger upstream, 2.21 et suivantes comprises, et Victoria Traces sont compatibles nativement. Jaeger 2.21 a retiré la recherche v1 et gardé/api/traces/<id>: quand la recherche répond 404, la CLI la relance une fois par/api/v3/tracesavec la même fenêtre en RFC 3339 (query.start_time_min,query.start_time_max) et--max-tracesenquery.search_depth, puis lit l'OTLP JSON renvoyé. Une recherche v3 sans résultat répond 404 avec le corps d'erreur de Jaeger, signalé comme aucune trace trouvée.startetendsont les bornes que Perf Sentinel envoie, en microsecondes, pour une fenêtre relative comme pour une fenêtre absolue.lookbackn'est jamais envoyé : Victoria Traces ne le lit que sur son endpoint de graphe de services, jamais sur cette recherche, donc une requête qui le porterait partirait sans borne depuis l'epoch Unix. - Le flag
--endpointpointe vers l'URL de base de l'API de requête, la partie à laquelle la CLI ajoute/api/traces(ou/api/v3/traces). Jaeger upstream la sert à la racine sur le port 16686. Victoria Traces la sert sous/select/jaegersur le port 10428, et a donc besoin de ce préfixe dans le flag. - Les traces sont récupérées en JSON, parsées par le même chemin
{"data": [...]}que l'ingestion Jaeger en mode fichier (le chemin OTLP JSON pour une réponse v3), puis passent dans le pipeline d'analyse standard. La sortie est identique àperf-sentinel analyze. --lookbackaccepte le même format1h / 30m / 7d / 2h30mque la sous-commandetempo.--fromet--toremplacent--lookbackpar une fenêtre absolue en ISO 8601 UTC (2026-08-20T15:00:00Z). Les deux vont ensemble et ne se combinent pas avec--lookback. Ils servent à relire la fenêtre exacte d'un incident : une lookback est résolue au moment où la requête part, elle se décale donc à chaque exécution.--max-tracescorrespond au paramètrelimitde la requête backend (query.search_depthsur la recherche v3), qui plafonne le nombre de traces retournées par recherche.
Réserves
- La recherche côté backend est bornée par la rétention configurée (Jaeger a 48h par défaut, Victoria Traces est configurable). Un
--lookbackou une fenêtre--from/--toplus large que la rétention est silencieusement tronqué à la fenêtre conservée. Perf Sentinel ne connaît pas la rétention d'un backend, il ne peut donc pas vous prévenir avant la requête. - Une recherche plafonnée à N retourne jusqu'à N traces complètes dans un seul corps HTTP, en v1 comme en v3. Perf Sentinel plafonne la réponse à 256 MiB, ce qui couvre les charges de production typiques mais peut nécessiter un ajustement si vous recherchez régulièrement des centaines de grosses traces d'un coup. Baissez
--max-tracessi vous atteignez la limite de taille du corps.--max-tracesest lui-même borné à 10 000 côté CLI. - En-tête d'authentification via
--auth-header. Passez une ligne d'en-tête au format curl ("Name: Value") pour l'attacher à chaque requête backend. Couvre Bearer tokens, Basic Auth et en-têtes de clé d'API personnalisés. La valeur parsée est marquéesensitiveet n'apparaît donc jamais dans les logs. Voir Limites pour les notes complètes d'usage (un seul en-tête max par invocation, valeur visible dansps). Depuis 0.5.27, choisir la forme flag émet un événement de niveauWARNau démarrage qui oriente vers--auth-header-env <NAME>(même pattern quepg-stat). La forme variable d'environnement garde la valeur en dehors de la liste des arguments de processus et de l'historique shell. --endpointest une entrée de confiance. Le validateur rejette les schémas non-http et les URLs avec credentials, mais accepte loopback, RFC 1918 et link-local. Dans un contexte CI où la valeur de l'endpoint pourrait venir d'une PR externe, assainissez-la en amont avant d'invoquer la sous-commande.
Dépannage
Aucun event reçu (events_processed_total = 0)
- Vérifiez la connectivité. Depuis le conteneur :
curl http://host.docker.internal:4318/metrics. S'il échoue, Perf Sentinel n'est pas joignable. - Vérifiez l'adresse d'écoute. Perf Sentinel écoute sur
127.0.0.1par défaut. Pour l'accès Docker, configurezlisten_address = "0.0.0.0"dans.perf-sentinel.tomlou lancez-le nativement sur l'hôte. - Vérifiez le protocole. Le Java Agent 2.x utilise
http/protobufpar défaut (port 4318), tout comme le starter Spring Boot. DéfinissezOTEL_EXPORTER_OTLP_PROTOCOLexplicitement et alignez le port :grpcavec 4317,http/protobufavec 4318.
Events reçus mais aucun finding
- Vérifiez les attributs de span. Perf Sentinel ne traite que les spans avec
db.statement/db.query.text(SQL) ouhttp.url/url.full(HTTP). Les autres spans sont ignorés. - Vérifiez le kind du span. Depuis 0.11.2, un span
SERVERportant une URL HTTP est un traitement entrant et non un appel sortant, il ne produit donc aucun finding HTTP même si l'attribut est présent. Les flottes sur les anciennes conventions sémantiques, qui posent aussihttp.urlsur le span de traitement, perdent ainsi les appels qu'elles voyaient auparavant. Un appel sortant se présente comme un spanCLIENTdu côté de l'appelant. - Vérifiez les seuils de détection. Le seuil N+1 par défaut est 5 occurrences du même template normalisé dans la même trace. Si votre trace compte moins de 5 appels répétés, aucun finding n'est généré.
- Vérifiez la normalisation des URLs. Perf Sentinel remplace les segments de chemin numériques par
{id}et les UUIDs par{uuid}. Si vos URLs répétées ne diffèrent que par un identifiant texte (par exemple/account/alice,/account/bob), elles ne seront pas regroupées dans le même template.
Erreur AOT cache avec le Java Agent
Le Java Agent (-javaagent:) est incompatible avec les caches AOT de la JEP 483. Si vous voyez Unable to map shared spaces ou Mismatched values for property jdk.module.addmods, contournez le cache AOT quand l'agent est actif (voir la section Java de Instrumentation).
Starter Spring Boot : spans SQL ou HTTP sortants manquants
Le starter spring-boot-starter-opentelemetry (Spring Boot 4) ne trace que ce que les projets Spring observent. L'absence de span SQL signifie en général que JDBC n'est pas instrumenté : ajoutez datasource-micrometer-spring-boot avec son module datasource-micrometer-opentelemetry, qui écrit la requête dans db.query.text. Un appel sortant manquant vient en général d'un client construit sans le builder Spring Boot, qui ne porte ni span ni traceparent. Les deux cas sont traités dans la Instrumentation.