Si no has leído las instrucciones de configuración de la instrumentación automática, empieza por las Instrucciones de configuración de Python.

Si no utilizas la instrumentación de biblioteca compatible (consulta Compatibilidad de bibliotecas), puede que desees instrumentar manualmente tu código.

También es posible que desees ampliar la funcionalidad de la biblioteca ddtrace u obtener un control más preciso sobre la instrumentación de tu aplicación. La biblioteca proporciona varias técnicas para conseguirlo.

Creación de tramos

La biblioteca ddtrace crea tramos automáticamente con ddtrace-run para muchas bibliotecas y marcos. Sin embargo, es posible que desees obtener visibilidad de tu propio código y esto se logra utilizando tramos.

Dentro de tu solicitud web (por ejemplo, make_sandwich_request), puedes realizar varias operaciones, como get_ingredients() y assemble_sandwich(), que son útiles para hacer mediciones.

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

ddtrace proporciona un decorador tracer.wrap() que puede utilizarse para añadir las funciones de interés. Esto es útil si deseas rastrear la función independientemente de desde donde se está llamando.

  from ddtrace import tracer

  @tracer.wrap(service="my-sandwich-making-svc", resource="resource_name")
  def get_ingredients():
      # go to the pantry
      # go to the fridge
      # maybe go to the store
      return

  # You can provide more information to customize the span
  @tracer.wrap("assemble_sandwich", service="my-sandwich-making-svc", resource="resource_name")
  def assemble_sandwich(ingredients):
      return

Para obtener más información, lee Detalles de la API del decorador para ddtrace.Tracer.wrap().

Para rastrear un bloque arbitrario de código, utiliza el gestor de contexto ddtrace.Span como se indica a continuación, o consulta la documentación de uso avanzado.

from ddtrace import tracer

def make_sandwich_request(request):
    # Capture both operations in a span
    with tracer.trace("sandwich.make"):
        ingredients = get_ingredients()
        sandwich = assemble_sandwich(ingredients)

def make_sandwich_request(request):
    # Capture both operations in a span
    with tracer.trace("sandwich.create", resource="resource_name") as outer_span:

        with tracer.trace("get_ingredients", resource="resource_name") as span:
            ingredients = get_ingredients()

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

Para más información, lee todos los detalles de la API de ddtrace.Tracer().

Si los métodos del decorador y del gestor de contexto aún no alcanzan para tus necesidades de rastreo, se proporciona una API manual que te permite iniciar y finalizar tramos como lo necesites:


def make_sandwich_request(request):
    span = tracer.trace("sandwich.create", resource="resource_name")
    ingredients = get_ingredients()
    sandwich = assemble_sandwich(ingredients)
    span.finish()  # remember to finish the span

Para más detalles de la API del decorador, lee la documentación de ddtrace.Tracer.trace o la documentación de ddtrace.Span.finish.

Acceso a tramos activos

La instrumentación incorporada y tu propia instrumentación personalizada crean tramos alrededor de operaciones significativas. Puedes acceder al tramo activo para incluir datos significativos.

from ddtrace import tracer

def make_sandwich_request(request):
    # Capture both operations in a span
    with tracer.trace("sandwich.make") as my_span:
        ingredients = get_ingredients()
        sandwich = assemble_sandwich(ingredients)
def get_ingredients():
    # Get the active span
    span = tracer.current_span()
    # this span is my_span from make_sandwich_request above
def assemble_sandwich(ingredients):
    with tracer.trace("another.operation") as another_span:
        # Get the active root span
        span = tracer.current_root_span()
        # this span is my_span from make_sandwich_request above

Añadir etiquetas

Pueden añadirse etiquetas a un tramo utilizando el método set_tag en un tramo:

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))

Pueden establecerse etiquetas globalmente en el rastreador. Estas etiquetas se aplican a cada tramo que se crea.

from ddtrace import tracer
from myapp import __version__

# This will be applied to every span
tracer.set_tags({"version": __version__, "<TAG_KEY_2>": "<TAG_VALUE_2>"})

La información de la excepción se captura y se adjunta a un tramo si hay uno activo cuando se produce la excepción.

from ddtrace import tracer

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

# `span` will be flagged as erroneous and have
# the stack trace and exception message attached as tags

También se puede marcar manualmente una traza como errónea:

from ddtrace import tracer

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

En caso que desees marcar el tramo raíz local con el error planteado:

import os
from ddtrace import tracer

try:
    raise TypeError
except TypeError as e:
    root_span = tracer.current_root_span()
    (exc_type, exc_val, exc_tb) = sys.exc_info()
    # this sets the error type, marks the span as an error, and adds the traceback
    root_span.set_exc_info(exc_type, exc_val, exc_tb)

Propagación de contexto con extracción e inyección de encabezados

Puedes configurar la propagación de contexto para trazas distribuidas al inyectar y extraer encabezados. Consulta Propagación de contexto de traza para obtener información.

Baggage

Manipulación de Baggage en un span (tramo):

from ddtrace import tracer

# Start a new span and set baggage
with tracer.trace("example") as span:
    # set_baggage_item
    span.context.set_baggage_item("key1", "value1")
    span.context.set_baggage_item("key2", "value2")

    # get_all_baggage_items
    all_baggage = span.context.get_all_baggage_items()
    print(all_baggage) # {'key1': 'value1', 'key2': 'value2'}

    # remove_baggage_item
    span.context.remove_baggage_item("key1")
    print(span.context.get_all_baggage_items()) # {'key2': 'value2'}

    # get_baggage_item
    print(span.context.get_baggage_item("key1")) # None
    print(span.context.get_baggage_item("key2")) # value2

    # remove_all_baggage_items
    span.context.remove_all_baggage_items()
    print(span.context.get_all_baggage_items()) # {}

Para ver un ejemplo en acción, consulta flask-baggage en trace-examples.

ddtrace-api

ddtrace-api está en vista previa

El paquete ddtrace-api de Python está en vista previa y puede que no incluya todas las llamadas a la API que necesitas. Si necesitas una funcionalidad más completa, utiliza la API como se describe en las secciones anteriores.

Los siguientes pasos sólo son necesarios si deseas experimentar con el paquete ddtrace-api en vista previa .

El paquete ddtrace-api proporciona una API pública estable para la instrumentación personalizada de Python de Datadog APM. Este paquete implementa sólo la interfaz de la API, no la funcionalidad subyacente que crea y envía tramos a Datadog.

Esta separación entre interfaz (ddtrace-api) e implementación (ddtrace) ofrece varias ventajas:

  • Puedes confiar en una API que cambia con menos frecuencia y de forma más predecible para tu instrumentación personalizada
  • Si sólo utilizas la instrumentación automática, puedes ignorar por completo los cambios de la API
  • Si implementas tanto el paso único como la instrumentación personalizada, evitarás depender de múltiples copias del paquete ddtrace

Para utilizar ddtrace-api:

  1. Instala las bibliotecas ddtrace y ddtrace-api:

    pip install 'ddtrace>=3.1' ddtrace-api
    
  2. Instrumenta tu aplicación de Python mediante el uso de ddtrace-run anteponiendo tu comando de punto de entrada de Python:

    ddtrace-run python app.py
    
  3. Una vez configurado esto, puedes escribir instrumentación personalizada exactamente igual que en los ejemplos de las secciones anteriores, pero importando desde ddtrace_api en lugar de ddtrace.

    Por ejemplo:

    from ddtrace_api import tracer
    
    @tracer.wrap(service="my-sandwich-making-svc", resource="resource_name")
    def get_ingredients():
        # go to the pantry
        # go to the fridge
        # maybe go to the store
        return
    

Consulte la definición de la API del paquete para conocer la lista completa de las llamadas a la API compatibles.

Referencias adicionales