Tempo (OpenTelemetry)¶
Tempo est le puits de traces distribuées de PerfShop. Il reçoit les spans OTLP exportés par l'agent Java OpenTelemetry embarqué dans le backend, les stocke dans des blocs locaux, et alimente les datasources Grafana avec des fonctionnalités riches : corrélation traces ↔ logs, service map, span-metrics dérivées poussées vers Prometheus.
Source de vérité
Cette page est tirée de tempo/tempo-config.yml, des JAVA_OPTS du backend dans les fichiers compose, et de la datasource Tempo dans grafana/provisioning/datasources/tempo.yml.
Version pinned¶
PerfShop fige Tempo à la version 2.4.2 (image grafana/tempo:2.4.2). C'est la seule image d'observabilité avec Grafana à être pinnée à une version précise (les autres sont en latest). La raison : la configuration metrics_generator et le format des span-metrics ont évolué entre les versions majeures, et l'intégration avec Grafana 12.0.0 a été validée précisément contre Tempo 2.4.2.
Architecture¶
flowchart LR
subgraph BE["perfshop-app (JVM)"]
direction TB
APP["Spring Boot 3.2"]
OA["agent OpenTelemetry<br/>opentelemetry-javaagent.jar"]
APP -.injecté.-> OA
end
TEMPO["perfshop-tempo<br/>(2.4.2)"]
PROM[("Prometheus")]
GRAF["Grafana"]
OA -->|"OTLP gRPC :4317<br/>(spans)"| TEMPO
TEMPO -->|"metrics_generator<br/>service-graphs<br/>span-metrics<br/>remote_write"| PROM
TEMPO -->|"datasource Tempo<br/>(query)"| GRAF
PROM -->|"datasource Prometheus<br/>(spanmetrics + serviceMap)"| GRAF
Configuration Tempo¶
Receivers OTLP¶
Tempo expose deux endpoints OTLP simultanément :
| Port | Protocole | Usage |
|---|---|---|
| 4317 | gRPC | Utilisé par l'agent Java OpenTelemetry de perfshop-app |
| 4318 | HTTP | Disponible pour des SDK qui ne supportent pas gRPC (curl, Python sans grpcio, etc.) |
Les deux ports sont exposés à l'hôte via les variables TEMPO_OTLP_GRPC_PORT et TEMPO_OTLP_HTTP_PORT.
Ingester et stockage¶
ingester:
trace_idle_period: 10s
max_block_bytes: 1_000_000
max_block_duration: 5m
storage:
trace:
backend: local
block:
bloom_filter_false_positive: .05
wal:
path: /var/tempo/wal
local:
path: /var/tempo/blocks
pool:
max_workers: 100
queue_depth: 10000
| Paramètre | Valeur | Effet |
|---|---|---|
trace_idle_period |
10s | Une trace inactive depuis 10 s est considérée terminée et flushée |
max_block_bytes |
1 Mo | Les blocs WAL sont coupés à 1 Mo |
max_block_duration |
5m | Cap dur de durée par bloc |
backend: local |
— | Stockage filesystem (volume nommé tempo-data) |
wal.path |
/var/tempo/wal |
Write-Ahead Log avant flush |
local.path |
/var/tempo/blocks |
Blocs flushés (immutables, compactés) |
bloom_filter_false_positive |
0.05 | 5 % de faux positifs sur les bloom filters d'index |
Server¶
| Paramètre | Valeur | Effet |
|---|---|---|
http_listen_port |
3200 | API HTTP query (utilisée par Grafana datasource Tempo) |
log_level |
warn | Niveau de log Tempo lui-même (pas verbeux) |
stream_over_http_enabled |
true | Active le streaming HTTP pour les recherches longues |
Le port hôte par défaut est 19200 (variable TEMPO_HTTP_PORT). Le port interne du conteneur reste 3200 — seul le mapping vers le host change.
metrics_generator — l'élément qui change tout¶
metrics_generator:
registry:
external_labels:
source: tempo
cluster: perfshop
job: perfshop-backend
storage:
path: /var/tempo/generator/wal
remote_write:
- url: http://prometheus:9090/api/v1/write
send_exemplars: true
overrides:
defaults:
metrics_generator:
processors:
- service-graphs
- span-metrics
C'est ici que Tempo devient bien plus qu'un simple stockage de traces. Le metrics_generator analyse les spans en temps réel et génère deux familles de métriques dérivées qu'il pousse dans Prometheus via remote-write :
Famille 1 — service-graphs¶
Pour chaque paire d'entités (service appelant → service appelé), génère des métriques :
| Métrique | Type | Description |
|---|---|---|
traces_service_graph_request_total |
counter | Nombre d'appels |
traces_service_graph_request_failed_total |
counter | Nombre d'appels échoués |
traces_service_graph_request_server_seconds_* |
histogram | Latence côté serveur |
traces_service_graph_request_client_seconds_* |
histogram | Latence côté client |
Ces métriques alimentent le Service Map de Grafana (datasource Tempo → onglet Service Graph) qui affiche un graphe orienté des dépendances entre services.
Famille 2 — span-metrics¶
Pour chaque opération instrumentée (URI HTTP, méthode, statut), génère :
| Métrique | Type | Description |
|---|---|---|
traces_spanmetrics_calls_total{service, span_name, status_code, ...} |
counter | Nombre d'invocations |
traces_spanmetrics_latency_*{service, span_name, ...} |
histogram | Distribution de latence |
Ces métriques permettent au panel « Latence P50 / P95 / P99 — toutes routes » du dashboard APM Formateur de fonctionner — il interroge Prometheus, pas Tempo, mais sur des séries dérivées des spans.
Labels externes¶
Ces trois labels sont ajoutés à toutes les métriques poussées par Tempo dans Prometheus. Le label job: perfshop-backend aligne les span-metrics avec les autres métriques Spring Boot, ce qui permet de mélanger les deux dans une même requête PromQL.
Exemplaires¶
Les exemplaires sont des liens depuis une métrique vers un trace_id spécifique. Quand send_exemplars: true, chaque sample histogram peut transporter un trace_id qui remonte jusqu'à Grafana — l'utilisateur voit alors des points cliquables dans les graphiques de latence, et un clic ouvre la trace correspondante. C'est l'un des trois mécanismes de corrélation métriques ↔ traces de la stack.
Agent OpenTelemetry côté backend¶
L'agent Java OpenTelemetry est embarqué dans l'image perfshop-backend (chemin /agents/opentelemetry-javaagent.jar) et activé via JAVA_OPTS dans les fichiers compose :
-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
Décodage des propriétés¶
| Propriété | Effet pédagogique |
|---|---|
otel.service.name=perfshop |
Tous les spans portent service.name=perfshop — apparaît dans les attributs Tempo et permet le filtrage TraceQL {resource.service.name="perfshop"} |
otel.exporter.otlp.endpoint=http://perfshop-tempo:4317 |
Cible l'endpoint gRPC du collector Tempo via DNS Docker |
otel.exporter.otlp.protocol=grpc |
Force gRPC (le défaut bascule selon le port) |
otel.traces.exporter=otlp |
Export OTLP des traces uniquement |
otel.metrics.exporter=none |
Pas d'export OTel des métriques (Prometheus est le puits préféré) |
otel.logs.exporter=none |
Pas d'export OTel des logs (Loki/OpenSearch sont les puits préférés) |
otel.instrumentation.http.capture-headers.server.request=X-Admin-Token,Content-Type |
Capture explicite des headers HTTP côté serveur — c'est ce qui permet le panel formateur « Traces avec déclenchement admin — X-Admin-Token capturé » |
otel.instrumentation.jdbc.captured-statements.enabled=true |
Capture les statements SQL JDBC — affichés dans les détails de span Tempo et utilisés par le panel « Traces SQL instrumentées » du dashboard APM Formateur (utile pour le scénario Security S1 — SQL injection) |
otel.span.attribute.count.limit=256 |
Cap à 256 attributs par span — protège contre l'explosion de cardinalité |
Auto-instrumentation¶
L'agent OpenTelemetry Java auto-instrumente automatiquement plus de 100 frameworks. Pour PerfShop, les plus utiles sont :
| Instrumentation | Spans générés |
|---|---|
| Spring Web MVC | HTTP GET /api/products, HTTP POST /api/orders, etc. |
| HikariCP / JDBC | SELECT users.*, INSERT orders, avec capture du statement SQL |
| Hibernate ORM | Hibernate Session.flush, etc. |
| Tomcat HTTP server | Spans serveur racine pour chaque requête |
| java.net.http / OkHttp | Spans clients pour les appels HTTP sortants |
| Logback / SLF4J MDC | Injection automatique du trace_id et span_id dans les logs (pour la corrélation Loki) |
Aucune ligne de code Spring n'a besoin d'être modifiée pour bénéficier de cette instrumentation — l'agent fait tout au démarrage de la JVM.
Datasource Grafana — corrélations¶
La datasource Tempo dans grafana/provisioning/datasources/tempo.yml active trois mécanismes de corrélation déjà décrits dans grafana.md :
flowchart LR
TEMPO["Datasource Tempo"]
TEMPO -->|tracesToLogsV2| L["Loki<br/>filtre ±1 min<br/>autour du span"]
TEMPO -->|tracesToMetrics| P["Prometheus<br/>métriques de l'opération"]
TEMPO -->|serviceMap| SM["Service Map<br/>(via traces_service_graph_*)"]
TEMPO -->|nodeGraph| NG["Node Graph<br/>(visualisation graphe)"]
TEMPO -->|lokiSearch| LS["Loki Search<br/>(recherche libre)"]
Le flux pédagogique typique :
- Le formateur active un chaos qui provoque des
NullPointerException. - Il ouvre le dashboard APM Formateur et regarde le panel « F1 — Traces NullPointerException » (TraceQL
{span.exception.type="NullPointerException"}). - Il clique sur une trace pour voir le détail des spans.
- Il clique sur un span → tracesToLogsV2 ouvre Loki avec le filtre temporel et le
traceID→ il voit les logs Spring Boot autour de l'exception. - Optionnellement, il clique sur tracesToMetrics pour voir la latence Prometheus de l'opération sur la même fenêtre.
- Pour comprendre le contexte global, il ouvre le Service Map de la datasource Tempo qui affiche le graphe
client → perfshop-app → mysqlavec les latences moyennes sur chaque arête.
Volumes et persistance¶
| Volume | Montage | Contenu |
|---|---|---|
tempo-data (volume nommé) |
/var/tempo |
WAL, blocs, generator WAL |
./tempo/tempo-config.yml (bind mount) |
/etc/tempo/tempo-config.yml |
Configuration Tempo (lecture seule) |
Ports¶
| Service | Port hôte | Port container | Variable d'env | Usage |
|---|---|---|---|---|
perfshop-tempo |
19200 | 3200 | TEMPO_HTTP_PORT |
API HTTP query (Grafana datasource) |
perfshop-tempo |
4317 | 4317 | TEMPO_OTLP_GRPC_PORT |
OTLP gRPC (export depuis l'agent Java) |
perfshop-tempo |
4318 | 4318 | TEMPO_OTLP_HTTP_PORT |
OTLP HTTP (alternative) |
Pour aller plus loin¶
- Vue d'ensemble — quatre signaux et corrélations
- Grafana — datasource Tempo et corrélations
tracesToLogsV2,tracesToMetrics - Dashboards livrés — détail des panels TraceQL du dashboard APM Formateur
- Prometheus — réception des span-metrics via remote-write
- Pyroscope — l'autre agent embarqué dans l'image backend