Instrumentation personnalisée Python
Rapport de recherche Datadog : Bilan sur l'adoption de l'informatique sans serveur Rapport : Bilan sur l'adoption de l'informatique sans serveur

Instrumentation personnalisée Python

Si vous n'avez pas encore lu les instructions sur l'instrumentation automatique et la configuration, commencez par lire la section Tracer des applications Python.

SI vous n’utilisez pas une instrumentation de bibliothèque compatible (voir la compatibilité des bibliothèques), vous pouvez choisir d’instrumenter manuellement votre code.

Vous pouvez également choisir d’accroître les fonctionnalités de la bibliothèque ddtrace ou de contrôler plus précisément l’instrumentation de votre application. La bibliothèque propose plusieurs méthodes afin d’y parvenir.

Création de spans

La bibliothèque ddtrace crée automatiquement des spans avec ddtrace-run pour un grand nombre de frameworks et bibliothèques. Toutefois, si vous souhaitez bénéficier d’une visibilité accrue sur votre propre code, utilisez des spans.

Dans votre requête Web (par exemple, make_sandwich_request), vous pouvez effectuer plusieurs opérations, comme get_ingredients() et assemble_sandwich(), particulièrement utiles pour les mesures.

def make_sandwich_request(request):
    ingredients = get_ingredients()
    sandwich = assemble_sandwich(ingredients)

ddtrace fournit un décorateur tracer.wrap(). Il sert à décorer les fonctions pertinentes. Cette approche vous permet de tracer une fonction, peu importe l’origine de son appel.

  from ddtrace import tracer

  @tracer.wrap()
  def get_ingredients():
      # ouvrir le placard
      # vérifier le frigo
      # aller éventuellement faire des courses
      return

  # Vous pouvez indiquer des informations supplémentaires afin de personnaliser la span
  @tracer.wrap("assemble_sandwich", service="my-sandwich-making-svc")
  def assemble_sandwich(ingredients):
      return

Cliquez ici pour consulter les détails sur l’API concernant le décorateur pour ddtrace.Tracer.wrap().

Pour tracer un bloc arbitraire de code, utilisez le gestionnaire de contextes ddtrace.Span comme ci-dessous. Vous pouvez également consulter la documentation sur l’utilisation avancée de ddtrace (en anglais).

from ddtrace import tracer

def make_sandwich_request(request):
    # Capturer les deux opérations au sein d'une span
    with tracer.trace("sandwich.make"):
        ingredients = get_ingredients()
        sandwich = assemble_sandwich(ingredients)

def make_sandwich_request(request):
    # Capturer les deux opérations au sein d'une span
    with tracer.trace("sandwich.create") as outer_span:
        with tracer.trace("get_ingredients") as span:
            ingredients = get_ingredients()

        with tracer.trace("assemble_sandwich") as span:
            sandwich = assemble_sandwich(ingredients)

Cliquez ici pour consulter tous les détails sur l’API pour ddtrace.Tracer().

Si l’utilisation du décorateur et du gestionnaire de contextes ne vous permet pas de répondre à vos besoins en tracing, vous pouvez utiliser l’API manuelle fournie afin d’initialiser des spans et d’y mettre fin comme bon vous semble :

def make_sandwich_request(request):
    span = tracer.trace("sandwich.create")
    ingredients = get_ingredients()
    sandwich = assemble_sandwich(ingredients)
    span.finish()  # Bien fermer la span

Pour obtenir plus de détails sur l’API pour le décorateur, consultez la documentation relative à ddtrace.Tracer.trace ou à ddtrace.Span.finish.

Accès aux spans actives

L’instrumentation intégrée et votre instrumentation personnalisée créent des spans autour des opérations pertinentes. Vous pouvez accéder à la span active afin d’y inclure des données utiles.

from ddtrace import tracer

def make_sandwich_request(request):
    # Capturer les deux opérations au sein d'une span
    with tracer.trace("sandwich.make") as my_span:
        ingredients = get_ingredients()
        sandwich = assemble_sandwich(ingredients)
def get_ingredients():
    # Récupérer la span active
    span = tracer.current_span()
    # Cette span correspond à my_span pour l'option make_sandwich_request précédente
def assemble_sandwich(ingredients):
    with tracer.trace("another.operation") as another_span:
        # Récupérer la span racine active
        span = tracer.current_root_span()
        # Cette span correspond à my_span pour l'option make_sandwich_request précédente

Ajout de tags

Vous pouvez ajouter des tags à une span en utilisant la méthode set_tag sur cette span :

from ddtrace import tracer

def make_sandwich_request(request):
    with tracer.trace("sandwich.make") as span:
        ingredients = get_ingredients()
        span.set_tag("num_ingredients", len(ingredients))

Vous pouvez définir de façon globale des tags sur le traceur. Ces tags seront appliqués à chaque span créée.

from ddtrace import tracer
from myapp import __version__

# Cela sera appliqué à chaque span
tracer.set_tag("version", __version__)

Les informations sur les exceptions sont capturées et ajoutées à une span lorsque celle-ci est active au moment du déclenchement de l’exception.

from ddtrace import tracer

with tracer.trace("throws.an.error") as span:
    raise Exception("Oups !")

# `span` renvoie une erreur.
# La trace de pile et le message d'exception sont alors ajoutés à la span en tant que tags.

Vous pouvez également signaler manuellement qu’une span est erronée :

from ddtrace import tracer

span = tracer.trace("operation")
span.error = 1
span.finish()

OpenTracing

La prise en charge d’OpenTracing est incluse dans le package ddtrace. Utilisez pip pour installer le package opentracing requis :

pip install ddtrace[opentracing]

Pour initialiser un traceur, OpenTracing définit une méthode d’initialisation qui configure et instancie un nouveau traceur et remplace la référence opentracing.tracer globale :

import time
import opentracing
from ddtrace.opentracer import Tracer, set_global_tracer

def init_tracer(service_name):
    config = {
      "agent_hostname": "localhost",
      "agent_port": 8126,
    }
    tracer = Tracer(service_name, config=config)
    set_global_tracer(tracer)
    return tracer

def my_operation():
  span = opentracing.tracer.start_span("<NOM_OPÉRATION>")
  span.set_tag("<KEY_TAG>", "<VALUE_TAG>")
  time.sleep(0.05)
  span.finish()

init_tracer("<NOM_SERVICE>")
my_operation()

Le traceur peut désormais être utilisé comme dans toute autre application OpenTracing. Consultez le site opentracing.io (en anglais) pour en savoir plus sur l’utilisation de Python avec OpenTracing.

Pour aller plus loin