Aller au contenu

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 service perfshop-monitoring qui agrège les stats Docker via socket), et jmeter (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-receiver est activé, ce qui permet à Tempo (via son metrics_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-Token cô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), via perf_event sous Linux ou itimer sous 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 :

  1. 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.md et dashboards.md.
  2. OpenSearch Dashboards (port 5601 par défaut) — interface alternative pour explorer les logs full-text indexés par OpenSearch. Le seed perfshop-opensearch-seed crée 8 index patterns (perfshop-*, perfshop-spring, perfshop-nginx…) et importe un dashboard PerfShop — All Logs au premier démarrage. Voir opensearch.md.
  3. 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é. Voir dashboard-html.md.

Corrélation entre signaux

Les datasources Tempo et Loki sont configurées pour permettre la corrélation croisée :

  • Trace → Log : tracesToLogsV2 côté Tempo permet de cliquer sur un span pour ouvrir Loki avec un filtre temporel automatique (spanStartTimeShift: -1m, spanEndTimeShift: 1m) et le filtre par trace_id.
  • Trace → Metric : tracesToMetrics cô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-graphs produits par son metrics_generator.
  • Loki Search depuis Tempo : lokiSearch permet 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