RousselTMLEARNING

Article · Opentelemetry : de la découverte à l'expertise

Les traces en profondeur

1. Anatomie d'une trace #

Trace, span, contexte.

Trace et spans #

Trace distribuée
La vue en cascade montre immédiatement que le paiement consomme l'essentiel du temps et finit en erreur.

Une trace représente le parcours complet d'une requête. Elle se compose de spans : des opérations nommées, avec un début, une fin, un parent, des attributs, des événements et un statut. Tous les spans partagent le même trace_id (16 octets) ; chacun a son span_id (8 octets).

ChampRôle
nameopération, à faible cardinalité : GET /users/{id}
trace_id, span_id, parent_span_idstructure de l'arbre
start / enddurée
kindrôle du span dans l'échange
attributescontexte (semconv)
eventsfaits horodatés pendant le span
linksrelations avec d'autres traces
statusUnset, Ok ou Error

SpanKind #

KindQuandExemple
SERVERréception d'une requête synchronehandler HTTP, méthode gRPC
CLIENTappel synchrone sortantrequête HTTP, requête SQL
PRODUCERenvoi d'un message asynchronepublication Kafka, RabbitMQ
CONSUMERtraitement d'un message reçuconsommateur Kafka
INTERNALopération internecalcul, étape métier

2. Instrumenter manuellement #

Attributs, statut, événements, liens.

Créer des spans #

from opentelemetry import trace
from opentelemetry.trace import SpanKind, Status, StatusCode, Link

tracer = trace.get_tracer("shop.checkout", "1.4.0")

def payer(commande):
    with tracer.start_as_current_span("payer commande", kind=SpanKind.INTERNAL) as span:
        span.set_attribute("shop.order.id", commande.id)          # attribut métier
        span.set_attribute("shop.order.amount", commande.total)
        span.add_event("fraude.verifiee", {"shop.fraud.score": 0.12})
        try:
            passerelle.debiter(commande)
        except PaiementRefuse as exc:
            span.record_exception(exc)                            # événement "exception"
            span.set_status(Status(StatusCode.ERROR, "paiement refusé"))
            raise

Statut et erreurs #

Le statut vaut Unset par défaut. On le passe à Error quand l'opération a échoué ; on ne met Ok que pour forcer un succès malgré une règle contraire. Pour HTTP, les conventions disent : côté serveur, seules les réponses 5xx sont des erreurs ; côté client, 4xx et 5xx le sont.

Erreur Courante : N'utilisez pas les attributs pour stocker des données volumineuses ou personnelles (corps de requête, e-mails) : coût, cardinalité et RGPD.

Liens #

Un lien relie un span à un ou plusieurs autres contextes sans relation parent-enfant : un traitement par lots qui agrège 100 messages venant de 100 traces différentes, ou une tâche asynchrone déclenchée par une requête. tracer.start_as_current_span("lot", links=[Link(ctx1), Link(ctx2)]).

3. Le pipeline des spans dans le SDK #

Processors, exportateurs, limites.

Span processors #

ComposantRôle
SimpleSpanProcessorexporte chaque span à sa fin : uniquement pour le débogage
BatchSpanProcessorregroupe et exporte par lots : à utiliser en production
LimitesOTEL_SPAN_ATTRIBUTE_COUNT_LIMIT, OTEL_SPAN_EVENT_COUNT_LIMIT protègent contre l'explosion de taille

Arrêt propre #

Bonne Pratique : Appelez provider.shutdown() (ou force_flush()) à l'arrêt d'un processus court (job, fonction serverless) : sinon le dernier lot de spans est perdu.

4. Échantillonnage #

Garder les bonnes traces sans payer pour toutes.

Head et tail #

Head ou tail sampling
Une approche courante : 100 % en tête, tail sampling au Collector gateway.
Échantillonneur (SDK)Comportement
always_on / always_offtout ou rien
traceidratiogarde un ratio, calculé sur le trace_id (décision identique partout)
parentbased_traceidratiosuit la décision du parent ; ratio pour les traces qui démarrent ici (recommandé)
processors:
  tail_sampling:
    decision_wait: 10s
    policies:
      - { name: erreurs, type: status_code, status_code: { status_codes: [ERROR] } }
      - { name: lentes,  type: latency, latency: { threshold_ms: 1000 } }
      - { name: reste,   type: probabilistic, probabilistic: { sampling_percentage: 5 } }
Erreur Courante : Le tail sampling exige que tous les spans d'une trace arrivent sur le même Collector : placez devant un Collector avec l'exportateur loadbalancing routé par TraceID.

Interroger les traces #

{ resource.service.name = "checkout" && status = error }
{ span.http.route = "/orders" && duration > 500ms }
{ span.db.system.name = "postgresql" } | count() > 20          # traces qui font plus de 20 requêtes SQL (N+1)
{ resource.service.name = "frontend" } >> { resource.service.name = "payment" && status = error }

📄 Les traces OpenTelemetry en profondeur : spans, statuts, événements, liens et échantillonnage →

Mon suivi

  • ⏱ Durée estimée : ≈ 7 min

Connectez-vous pour suivre votre progression et prendre des notes. Se connecter

✉️ Poser une question

Articles recommandés

Bonnes pratiques Beats : Filebeat, Metricbeat et collecte fiable

Bonnes pratiques Beats : filestream, modules, processors, files d'attente sur disque, sorties séc...

Bonnes pratiques Grafana Tempo : instrumentation, échantillonnage, requêtes et coûts

Bonnes pratiques Tempo : conventions d'attributs, instrumentation utile, échantillonnage, utilisa...

Bonnes pratiques Grafana Loki : labels, requêtes, stockage et coûts

Bonnes pratiques Loki : choix des labels et cardinalité, structured metadata, requêtes LogQL perf...

Bonnes pratiques Thanos : architecture, stockage, requêtes et exploitation

Bonnes pratiques Thanos : adopter les composants progressivement, labels externes, objstore, comp...

Pourquoi Grafana Mimir ? Architecture et modes de déploiement

Les limites de Prometheus seul, ce qu'apporte Mimir (stockage long terme, haute disponibilité, mu...

Mimir : le chemin d'écriture (distributor, ingesters, réplication et déduplication HA)

Comment Mimir ingère les métriques : remote_write, validation et limites du distributor, hash rin...

Mimir : le chemin de lecture (query-frontend, querier, store-gateway et caches)

Comment Mimir répond à une requête PromQL : découpage et cache du query-frontend, file d'attente,...

Mimir : compactor, rétention et stockage objet

Configurer le stockage objet de Mimir (S3, GCS, Azure, MinIO), comprendre la compaction et le spl...

Mimir : multi-tenant, limites et configuration d'exécution

Isoler des équipes dans Mimir : tenants et en-tête X-Scope-OrgID, authentification par passerelle...