RousselTMLEARNING

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

TP : Instrumenter des traces à la main (spans, événements, erreurs, liens, échantillonnage) avec correction

La correction est intégrée au TP (Voir les encadrés de couleur vert)

Ce que vous allez apprendre dans ce TP
  • Créer des spans avec le SDK
  • Signaler erreurs, événements et liens
  • Interroger avec TraceQL et échantillonner

Introduction #

Ce que vous allez apprendre dans cette section
  • Créer des spans avec le SDK
  • Signaler erreurs, événements et liens
  • Interroger avec TraceQL et échantillonner

Contexte. Le service de commandes n'a aucune bibliothèque auto-instrumentée pour sa logique métier. Vous l'instrumentez à la main pour voir les étapes d'une commande, ses erreurs de paiement et ses traitements par lots.

Prérequis : Docker et Python 3.10 ou plus ; la pile grafana/otel-lgtm (Collector, Tempo, Loki, Prometheus, Pyroscope et Grafana dans un seul conteneur)  ·  Durée estimée : 50 min

Des traces riches et interrogeables, et un échantillonnage maîtrisé.

Mise en place #

Étapes guidées, avec leur correction.

  1. 1. Démarrer la pile d'observabilité

    Pourquoi ? Une seule image fournit un Collector OTLP et tous les backends : on se concentre sur le signal.

    Lancez grafana/otel-lgtm, créez un environnement Python et pointez les exportateurs vers le port OTLP/HTTP 4318.
    Voir la correction
    docker run -d --name lgtm -p 3000:3000 -p 4317:4317 -p 4318:4318 -p 4040:4040 grafana/otel-lgtm
    python3 -m venv .venv && . .venv/bin/activate
    export OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318 OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf
    # Grafana : http://localhost:3000 (admin / admin)
  2. 2. Initialiser le SDK

    Pourquoi ? Le TracerProvider porte la ressource et l'exportateur ; le BatchSpanProcessor envoie par lots.

    Installez le SDK et l'exportateur OTLP/HTTP, puis écrivez otel_setup.py qui configure la ressource (service.name, service.version, deployment.environment.name) et l'export.
    Voir la correction
    pip install opentelemetry-sdk opentelemetry-exporter-otlp-proto-http
    cat > otel_setup.py <<'EOF'
    from opentelemetry import trace
    from opentelemetry.sdk.resources import Resource
    from opentelemetry.sdk.trace import TracerProvider
    from opentelemetry.sdk.trace.export import BatchSpanProcessor
    from opentelemetry.exporter.otlp.proto.http.trace_exporter import OTLPSpanExporter
    
    resource = Resource.create({"service.name": "commandes", "service.version": "1.0.0",
                                "deployment.environment.name": "tp"})
    provider = TracerProvider(resource=resource)      # l'échantillonneur est lu dans OTEL_TRACES_SAMPLER
    provider.add_span_processor(BatchSpanProcessor(OTLPSpanExporter()))
    trace.set_tracer_provider(provider)
    EOF
  3. 3. Créer une trace métier

    Pourquoi ? Des spans nommés par étape, avec SpanKind et attributs conformes aux conventions, rendent la trace lisible par tous les outils.

    Écrivez commande.py : un span racine traiter commande et trois enfants (stock en CLIENT avec attributs de base de données, calcul, paiement), un événement, et une erreur de paiement une fois sur trois avec record_exception et statut ERROR.
    Voir la correction
    cat > commande.py <<'EOF'
    import random, time
    from otel_setup import provider
    from opentelemetry import trace
    from opentelemetry.trace import SpanKind, Status, StatusCode
    
    tracer = trace.get_tracer("tp.commandes", "1.0.0")
    
    class PaiementRefuse(Exception):
        pass
    
    def traiter(numero):
        with tracer.start_as_current_span("traiter commande", kind=SpanKind.SERVER) as span:
            span.set_attribute("shop.order.id", numero)
            with tracer.start_as_current_span("SELECT stock", kind=SpanKind.CLIENT) as db:
                db.set_attribute("db.system.name", "postgresql")
                db.set_attribute("db.collection.name", "stock")
                db.set_attribute("db.operation.name", "SELECT")
                time.sleep(random.uniform(0.01, 0.05))
            with tracer.start_as_current_span("calculer total"):
                time.sleep(random.uniform(0.005, 0.02))
            with tracer.start_as_current_span("payer", kind=SpanKind.CLIENT) as pay:
                pay.add_event("fraude.verifiee", {"shop.fraud.score": round(random.random(), 2)})
                time.sleep(random.uniform(0.05, 0.3))
                try:
                    if numero % 3 == 0:
                        raise PaiementRefuse("carte refusée")
                except PaiementRefuse as exc:
                    pay.record_exception(exc)
                    pay.set_status(Status(StatusCode.ERROR, str(exc)))
                    span.set_status(Status(StatusCode.ERROR, "paiement refusé"))
                    span.set_attribute("error.type", "PaiementRefuse")
    
    for n in range(1, 31):
        traiter(n)
    provider.shutdown()      # vide le dernier lot
    EOF
    python commande.py
  4. 4. Explorer et interroger avec TraceQL

    Pourquoi ? TraceQL filtre sur la structure et les attributs des spans : on trouve en une requête les traces qui comptent.

    Dans Grafana, ouvrez Explore > Tempo. Exécutez les requêtes ci-dessous, ouvrez une trace en erreur et retrouvez l'événement et l'exception du span payer.
    Voir la correction
    { resource.service.name = "commandes" && status = error }
    { name = "payer" && duration > 200ms }
    { span.db.system.name = "postgresql" }
    { name = "traiter commande" } >> { name = "payer" && status = error }
  5. 5. Relier un traitement par lots avec des liens

    Pourquoi ? Un lot qui traite des éléments venant de plusieurs traces ne peut pas avoir plusieurs parents : on utilise des liens.

    Écrivez lot.py : trois traces « réception » indépendantes, puis un span facturer lot lié aux trois. Retrouvez les liens dans le détail du span.
    Voir la correction
    cat > lot.py <<'EOF'
    from otel_setup import provider
    from opentelemetry import trace
    from opentelemetry.trace import Link
    
    tracer = trace.get_tracer("tp.lots")
    contextes = []
    for i in range(3):
        with tracer.start_as_current_span("recevoir message") as span:
            span.set_attribute("messaging.message.id", f"msg-{i}")
            contextes.append(span.get_span_context())
    with tracer.start_as_current_span("facturer lot", links=[Link(c) for c in contextes]) as lot:
        lot.set_attribute("messaging.batch.message_count", len(contextes))
    provider.shutdown()
    EOF
    python lot.py
  6. 6. Échantillonner

    Pourquoi ? L'échantillonnage par ratio réduit le volume ; parentbased garantit qu'une trace est gardée ou jetée en entier.

    Relancez commande.py avec un échantillonnage à 20 % et comparez le nombre de traces reçues ; vérifiez qu'aucune trace n'est partielle. Expliquez pourquoi le tail sampling du Collector serait préférable pour garder toutes les erreurs.
    Voir la correction
    OTEL_TRACES_SAMPLER=parentbased_traceidratio OTEL_TRACES_SAMPLER_ARG=0.2 python commande.py
    # Grafana : { resource.service.name = "commandes" } sur les 5 dernières minutes : ~6 nouvelles traces au lieu de 30
    # le head sampling jette aussi ~80 % des traces en erreur : le tail sampling (politique status_code) les garderait toutes

Niveau de difficulté : ●●●○○ (3/5)

Mon suivi

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

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

✉️ Poser une question

Articles recommandés

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

Maîtriser le signal trace : anatomie d'une trace distribuée, span et SpanKind, attributs, statut ...

Tracing distribué : la propagation du contexte (W3C Trace Context et baggage)

Comprendre et mettre en œuvre la propagation de contexte OpenTelemetry : en-tête traceparent, tra...

Comprendre la notion de score

Le concept de score va permettre à Elasticsearch de classer vos documents par pertinence lors d u...

Elastic Common Schema (ECS) : le format standard des données Elastic et son rôle dans Elastic SIEM

Comprendre l'Elastic Common Schema (ECS) : format standard des champs dans Elasticsearch, convent...

Grail : Dynatrace Data Lakehouse

Désormais vous disposez dans Dynatrace (SaaS) d'un Data Lakehouse nommé Grail dont vous pouvez co...

C'est quoi l'observabilité

La capacité à connaître l'état interne d'un système à partir des données que cette dernière émet...

Les types de transactions dans les base de données

Cet article détaille les différences entre trois concepts essentiels dans l'exécution des instruc...

Différences entre Technologies et Services dans Dynatrace

Dans Dynatrace, les concepts de 'Technologie' et de 'Services' aident à organiser et surveiller l...

Dynatrace : Différences entre SQL Modifications, SQL Queries or Procedures, et SQL Transactions

Cet article détaille les différences entre trois concepts essentiels dans l'exécution des instruc...