L’instrumentation automatique (Lab 2) trace les frontières techniques (HTTP, SQL). Pour tracer la logique métier, on crée des spans manuels. Dans ce lab : un span manuel via annotation, la propagation de contexte vers un autre service, le bagage, puis la maîtrise du volume avec le tail sampling.
Prérequis
Labs 1 à 6 terminés, agent Java actif sur review-service.
Port-forward UIs actif (./scripts/open-ui.sh).
Les variables de la formation chargées dans votre shell : . ./scripts/env.sh. Elles donnent le port du review-service ($APP_PORT, accès direct au service, pas via le frontend-proxy) ainsi que $PF_ADDR et $PF_HOST, l’adresse sur laquelle vos port-forward écoutent.
Étapes
Partie 1 — Spans manuels & propagation
Lire l’instrumentation manuelle dans ProductCatalogClient.java :
Trois mécanismes du chapitre s’y trouvent — lesquels ?
Réponse
@WithSpan (annotation) : crée un span product-catalog.lookup, enfant automatique du span serveur — équivalent déclaratif de tracer.spanBuilder(...).startSpan() ;
@SpanAttribute / Span.current().setAttribute(...) : attributs posés sur le span courant ;
Baggage : des paires clé/valeur qui voyagent avec le contexte (header W3C baggage) vers les services aval — contrairement aux attributs, qui restent sur leur span.
Lors du POST /api/reviews, le service appelle le frontend de la boutique (GET /api/products/{id}) : l’agent instrumente ce client HTTP et propage le contexte (header traceparent) — le frontend rejoint donc votre trace.
Générer une trace multi-services :
. ./scripts/env.sh # si ce n'est pas déjà fait dans ce terminalkubectl port-forward -n otel-demo --address $PF_ADDR svc/review-service $APP_PORT:8080 &
curl -X POST http://$PF_HOST:$APP_PORT/api/reviews \
-H "Content-Type: application/json"\
-d '{"productId": "OLJCESPC7Z", "rating": 5, "comment": "Trace me!", "userEmail": "ada.lovelace@example.com", "userName": "Ada Lovelace"}'
Analyser la trace dans Jaeger (service review-service, opération POST /api/reviews) :
Réponse
La hiérarchie attendue :
POST /api/reviews (review-service, span serveur)
├── product-catalog.lookup (review-service, votre span manuel @WithSpan)
│ └── GET /api/products/{id} (review-service, span client HTTP)
│ └── GET /api/products/… (frontend ! propagation inter-services)
│ └── … (spans internes du frontend)
├── INSERT reviews (review-service, span JDBC)
Deux services dans une même trace = la propagation W3C Trace Context a fonctionné. Le bagage app.review.channel=web a voyagé dans les headers (il n’apparaît pas sur les spans : c’est un canal de transport, pas une donnée stockée — un processor peut le copier en attribut si besoin).
💡 Le span INSERT reviews est un span client (côté review-service) : vous ne trouverez aucun span côté PostgreSQL. La base n’est pas instrumentée et le protocole SQL ne transporte pas traceparent — la trace s’arrête à la base, qui est une feuille. La propagation ne marche qu’entre services instrumentés (ici review-service → frontend).
Partie 2 — Tail sampling
Le problème : en production, tracer 100 % du trafic coûte cher. Mais échantillonner à la source (head sampling) jette des traces avant de savoir si elles sont intéressantes. Le tail sampling décide après coup, dans le collecteur : on garde les erreurs et les requêtes lentes, on échantillonne le reste.
Écrivez la politique dans manifests/70-otel-traces-values.yaml : 100 % des traces en erreur, 100 % des traces > 1 s, 25 % du reste.
⚠️ Les politiques sont évaluées en OU : une trace est gardée si au moins une politique la retient. decision_wait : le collecteur retient les spans 5 s pour voir la trace entière avant de décider — c’est le coût mémoire du tail sampling. En multi-collecteurs, il faut router tous les spans d’une même trace vers la même instance (mode gateway + loadbalancing exporter).
Appliquer (les values des labs précédents restent empilées) :
# ~20 requêtes OK (25 % devraient survivre) :for i in $(seq 1 20); do curl -s http://$PF_HOST:$APP_PORT/api/reviews > /dev/null; done# 3 erreurs (100 % doivent survivre) :for i in $(seq 1 3); do curl -s -o /dev/null -X POST http://$PF_HOST:$APP_PORT/api/reviews \
-H "Content-Type: application/json"\
-d '{"productId": "DOESNOTEXIST", "rating": 5, "comment": "?", "userEmail": "x@example.com", "userName": "X"}'done
Dans Jaeger : comptez les traces GET /api/reviews récentes (nettement moins de 20) et les traces en erreur (les 3, toutes marquées 🔴).
Pourquoi le load generator semble-t-il moins bavard ?
Le tail sampling s’applique à tout le pipeline traces : la démo entière est maintenant échantillonnée à 25 % (hors erreurs/lenteurs). Effet de bord assumé : les métriques spanmetrics (Lab 4) sont calculées après sampling dans notre pipeline — en production, on placerait le connector avant le tail sampling (deux pipelines chaînés) pour garder des métriques exactes.
Livrable
Une trace multi-services (review-service + frontend) analysée, et la politique de tail sampling active (3/3 erreurs conservées, ~25 % du reste).