Observabilité — Vue d'ensemble¶
PerfShop est conçu pour être observable de bout en bout. C'est même la raison d'être pédagogique de la plateforme : un étudiant doit pouvoir voir, en temps réel, ce qu'une anomalie active fait au système. Pour cela, chaque service applicatif est instrumenté et chaque type de signal a son puits de stockage et son outil de visualisation.
Cette page donne la vue d'ensemble de la stack d'observabilité. Les pages suivantes (prometheus, grafana, dashboards, loki, tempo, pyroscope, opensearch, dashboard-html) descendent dans le détail de chaque composant.
Source de vérité
Toutes les informations de cette section sont extraites des fichiers de configuration réels : prometheus/prometheus.yml, loki/loki-config.yml, promtail/promtail-config.yml, tempo/tempo-config.yml, pyroscope/pyroscope-config.yml, vector/vector.toml, grafana/provisioning/**, et des JAVA_OPTS du backend dans les fichiers compose.
Quatre signaux, quatre puits¶
PerfShop manipule les quatre piliers de l'observabilité moderne : métriques, logs, traces, profils. Chacun a son propre canal d'export, son propre format et son propre puits de stockage, mais tous convergent vers Grafana pour la visualisation.
flowchart LR
APP["perfshop-app<br/>Spring Boot 3.2 + Java 21"]
APP -->|"métriques<br/>HTTP scrape 5s<br/>/actuator/prometheus"| PROM[("Prometheus<br/>retention 7j / 5GB")]
APP -->|"traces<br/>OTLP gRPC :4317<br/>(agent OpenTelemetry)"| TEMPO[("Tempo 2.4.2<br/>blocks locaux")]
APP -->|"profils CPU/alloc/lock<br/>JFR HTTP push :4040<br/>(agent Pyroscope)"| PYRO[("Pyroscope<br/>filesystem")]
APP -->|"logs stdout<br/>(JSON Spring Boot)"| DOC{"Docker logging<br/>driver json-file"}
DOC --> PT["Promtail<br/>(docker SD<br/>via socket)"]
DOC --> VEC["Vector<br/>(docker_logs<br/>via socket)"]
PT --> LOKI[("Loki<br/>retention 168h")]
VEC -->|"transform VRL<br/>parse JSON +<br/>service_family routing"| OS[("OpenSearch 2.13<br/>perfshop-{family}*")]
PROM --> GRAF["Grafana 12.0.0"]
LOKI --> GRAF
TEMPO --> GRAF
PYRO --> GRAF
OS --> OSD["OpenSearch<br/>Dashboards"]
TEMPO -.->|"metrics_generator<br/>service-graphs +<br/>span-metrics<br/>remote_write"| PROM
GRAF -.->|"tracesToLogsV2<br/>(corrélation trace ↔ log)"| LOKI
GRAF -.->|"serviceMap"| TEMPO
style PROM fill:#e6532d20,stroke:#e6532d
style TEMPO fill:#0099ff20,stroke:#0099ff
style PYRO fill:#ff930020,stroke:#ff9300
style LOKI fill:#00b4fa20,stroke:#00b4fa
style OS fill:#00514520,stroke:#005145
style GRAF fill:#f4750020,stroke:#f47500
Le détail des quatre flux¶
1. Métriques — Prometheus¶
- Source : Spring Boot Actuator + Micrometer exposent les métriques sur
perfshop-app:9090/actuator/prometheus. Trois jobs Prometheus scrapent toutes les 5 secondes :perfshop-backend(le backend lui-même),perfshop-docker(le serviceperfshop-monitoringqui agrège les stats Docker via socket), etjmeter(actif uniquement pendant un tir JMeter). - Stockage : TSDB local Prometheus, rétention 7 jours / 5 GB (
--storage.tsdb.retention.time=7d,--storage.tsdb.retention.size=5GB). - Transport : HTTP scrape pull (Prometheus va chercher les métriques chez les exposants).
- Autres ingestions :
--web.enable-remote-write-receiverest activé, ce qui permet à Tempo (via sonmetrics_generator) de pousser les métriques de service-graph et de span-metrics directement dans Prometheus.
Voir prometheus.md pour la configuration détaillée et 8 requêtes PromQL réelles tirées des dashboards livrés.
2. Logs — double puits Loki et OpenSearch¶
PerfShop collecte les logs Docker deux fois en parallèle, vers deux puits différents. Ce n'est pas une redondance accidentelle : c'est une démonstration pédagogique délibérée que les étudiants doivent pouvoir comparer.
| Aspect | Loki + Promtail | OpenSearch + Vector |
|---|---|---|
| Modèle | Index sur les labels uniquement, le contenu reste en texte | Index full-text sur tous les champs |
| Requêtage | LogQL (similaire à PromQL) | DQL / Lucene / queries OpenSearch |
| UI | Grafana → Explore (datasource Loki) | OpenSearch Dashboards |
| Coût stockage | Très faible (compression, pas d'inversion d'index) | Plus élevé (index inversé sur tous les champs) |
| Cas d'usage | Filtrage par container/level + recherche substring | Agrégations et facets, recherche structurée |
| Source dans PerfShop | Promtail via Docker SD socket | Vector via Docker logs source |
| Transformation | Parsing logfmt + multiline Java stacktrace | Parsing JSON Spring Boot + extraction chaos_family, chaos_level, scenario_id via VRL |
| Rétention | 168 h (7 jours) | Indexée tant que l'index OpenSearch existe (pas de purge automatique configurée) |
| Index | Un seul index index_* |
Sept index par famille : perfshop-spring, perfshop-nginx, perfshop-mysql, perfshop-jmeter, perfshop-qa, perfshop-forgejo, perfshop-observability |
Voir loki.md et opensearch.md pour les détails de chaque pipeline.
3. Traces distribuées — Tempo + OpenTelemetry¶
L'image perfshop-backend embarque l'agent OpenTelemetry Java dans /agents/opentelemetry-javaagent.jar. Il est activé inconditionnellement via JAVA_OPTS :
-javaagent:/agents/opentelemetry-javaagent.jar
-Dotel.service.name=perfshop
-Dotel.exporter.otlp.endpoint=http://perfshop-tempo:4317
-Dotel.exporter.otlp.protocol=grpc
-Dotel.traces.exporter=otlp
-Dotel.metrics.exporter=none
-Dotel.logs.exporter=none
-Dotel.instrumentation.http.capture-headers.server.request=X-Admin-Token,Content-Type
-Dotel.instrumentation.jdbc.captured-statements.enabled=true
-Dotel.span.attribute.count.limit=256
Points-clés :
- Export traces uniquement (les métriques et logs OTel sont désactivés — Prometheus et Loki/OpenSearch sont les puits préférés pour ces signaux).
- Capture du header
X-Admin-Tokencôté serveur — c'est ce qui permet le panel formateur « Traces avec déclenchement admin » du dashboard APM. - Capture des statements JDBC — c'est ce qui permet d'observer dans les traces les requêtes SQL réelles, et de support le scénario Security S1 (SQL injection).
- Limite à 256 attributs par span pour éviter les explosions de cardinalité.
Tempo est configuré avec son metrics_generator qui produit deux familles de métriques dérivées des spans (service-graphs + span-metrics) et les pousse dans Prometheus via remote-write — ces métriques alimentent ensuite des panels comme « Latence P95 par opération » dans le dashboard APM Formateur.
Voir tempo.md pour le détail.
4. Profiling continu — Pyroscope¶
L'image perfshop-backend embarque également l'agent Pyroscope Java dans /agents/pyroscope.jar, avec une configuration agressive :
-javaagent:/agents/pyroscope.jar
-Dpyroscope.server.address=http://perfshop-pyroscope:4040
-Dpyroscope.application.name=perfshop
-Dpyroscope.format=jfr
-Dpyroscope.profiler.event=cpu
-Dpyroscope.profiler.alloc=512k
-Dpyroscope.profiler.lock=10ms
-Dpyroscope.profilingInterval=PT0.02S
Trois profils sont collectés en continu :
- CPU : sampling toutes les 20 ms (
PT0.02S), viaperf_eventsous Linux ouitimersous Docker Desktop. - Allocations heap : un échantillon toutes les 512 Ko alloués.
- Contention de verrous : tous les blocages ≥ 10 ms.
Le format est JFR (Java Flight Recorder), parsé côté serveur Pyroscope. Ces profils alimentent les panels « Flamegraph » des dashboards APM Élève et APM Formateur — voir pyroscope.md.
Couche de visualisation¶
flowchart TB
subgraph datasources["Datasources Grafana<br/>(provisioning automatique)"]
direction LR
DS_P["Prometheus<br/>(default)"]
DS_L["Loki"]
DS_T["Tempo"]
DS_PY["Pyroscope"]
end
subgraph grafana["Grafana 12.0.0"]
direction TB
FE_E["Dossier Élèves<br/>(accès anonyme<br/>rôle Viewer)"]
FE_F["Dossier Formateurs<br/>(ACL Admin-only<br/>posée par grafana-seed)"]
FE_E --> D1["dashboard-apm-eleve"]
FE_E --> D2["dashboard-backend-eleve"]
FE_E --> D3["dashboard-frontend-eleve"]
FE_E --> D4["dashboard-jmeter"]
FE_E --> D5["dashboard-logs-eleve"]
FE_F --> D6["dashboard-apm-formateur"]
FE_F --> D7["dashboard-backend-formateur"]
FE_F --> D8["dashboard-frontend-formateur"]
FE_F --> D9["dashboard-logs-formateur"]
FE_F --> D10["perfshop-general-v1<br/>(home dashboard)"]
end
subgraph osd["OpenSearch Dashboards"]
OSD_DASH["PerfShop — All Logs"]
end
subgraph mon["perfshop-monitoring"]
HTML["Dashboard HTML temps réel<br/>(polling 2s côté Node)"]
end
datasources --> grafana
PerfShop expose trois interfaces de visualisation distinctes :
- Grafana (port 3002 par défaut) — l'outil principal, avec 10 dashboards livrés (5 Élèves + 5 Formateurs), datasources provisionnées automatiquement, et accès anonyme en lecture pour le dossier Élèves. Voir
grafana.mdetdashboards.md. - OpenSearch Dashboards (port 5601 par défaut) — interface alternative pour explorer les logs full-text indexés par OpenSearch. Le seed
perfshop-opensearch-seedcrée 8 index patterns (perfshop-*,perfshop-spring,perfshop-nginx…) et importe un dashboardPerfShop — All Logsau premier démarrage. Voiropensearch.md. - Dashboard HTML monitoring (port 3001 par défaut) — vue temps réel custom servie par
perfshop-monitoring(Node + Express). Polling 2 s, affichage compact, sans dépendance Grafana. C'est l'écran que l'étudiant garde ouvert en parallèle de sa page chaos pour voir l'impact instantané. Voirdashboard-html.md.
Corrélation entre signaux¶
Les datasources Tempo et Loki sont configurées pour permettre la corrélation croisée :
- Trace → Log :
tracesToLogsV2côté Tempo permet de cliquer sur un span pour ouvrir Loki avec un filtre temporel automatique (spanStartTimeShift: -1m,spanEndTimeShift: 1m) et le filtre partrace_id. - Trace → Metric :
tracesToMetricscôté Tempo permet de cliquer sur un span pour ouvrir Prometheus avec une requête sur l'opération concernée. - Service Map : Tempo génère automatiquement la cartographie des appels inter-services à partir des
service-graphsproduits par sonmetrics_generator. - Loki Search depuis Tempo :
lokiSearchpermet de chercher des logs liés à une trace.
sequenceDiagram
autonumber
actor F as Formateur
participant G as Grafana
participant T as Tempo
participant L as Loki
participant P as Prometheus
F->>G: Ouvre dashboard APM Formateur
G->>T: TraceQL { span.exception.type="NullPointerException" }
T-->>G: Liste de traces NPE
F->>G: Clique sur une trace
G->>T: GET /api/traces/{traceID}
T-->>G: Spans détaillés
F->>G: Clique sur un span
G->>L: Query Loki { container="perfshop-app" } |= "{traceID}"<br/>(fenêtre ±1 min autour du span)
L-->>G: Logs corrélés
F->>G: Clique sur "Metric for span"
G->>P: PromQL latence p99 sur l'opération
P-->>G: Série temporelle
Récapitulatif — où regarder quoi ?¶
| Question | Outil | Datasource | Dashboard / écran |
|---|---|---|---|
| « Combien de requêtes/s ? Latence p95 ? » | Grafana | Prometheus | Backend Élève / APM Élève |
| « Pourquoi mon endpoint est-il lent ? » | Grafana | Tempo | APM Formateur (TraceQL) |
| « Quel code consomme le CPU ? » | Grafana | Pyroscope | APM (panel Flamegraph) |
| « Quels logs ont été produits pendant le chaos ? » | Grafana ou OpenSearch | Loki ou OpenSearch | Logs Élève / Logs Formateur |
| « Combien de containers, combien de RAM ? » | perfshop-monitoring ou Grafana |
Prometheus (job docker) | Dashboard HTML / perfshop-general-v1 |
| « Mon tir JMeter, qu'est-ce qu'il donne ? » | Grafana | Prometheus (job jmeter) | dashboard-jmeter |
| « Y a-t-il des exceptions ? » | Grafana | Loki ou Tempo | Logs Élève (filtre ERROR) ou APM Formateur ({span.exception.type=...}) |
| « Recherche full-text dans tous les logs » | OpenSearch Dashboards | OpenSearch | Discover sur perfshop-* |
| « Heap dump pour analyser une fuite mémoire » | perfshop-monitoring |
Spring Boot Actuator | Endpoint /api/heapdump (proxy vers /actuator/heapdump) |
Pour aller plus loin¶
- Prometheus — config, jobs, exemples PromQL réels
- Grafana — datasources, ACL, accès anonyme, langue
- Dashboards livrés — détail des 10 dashboards, panel par panel
- Loki et Promtail — pipelines de logs, multiline Java, exemples LogQL
- Tempo (OpenTelemetry) — traces, agents JVM, span-metrics
- Pyroscope — profiling continu, format JFR, flamegraphs
- OpenSearch et Vector — indexation full-text, transform VRL
- Dashboard HTML temps réel — monitoring Node custom