Tutorial - Enabling Tracing for a Python Application in a Container and an Agent on a Host

Información general

Este tutorial te guiará a través de los pasos para habilitar el rastreo en una aplicación de ejemplo Python instalada en un contenedor. En este caso, el Datadog Agent está instalado en un host.

Diagrama que muestra el escenario de instalación de este tutorial

Para otros casos, incluyendo el de una aplicación y el Agent en un host, el de una aplicación y el Agent en un contenedor y el de aplicaciones escritas en otros lenguajes, consulta Tutoriales: Habilitación del rastreo.

Para obtener documentación general sobre la configuración del rastreo en Python, consulta Rastreo de aplicaciones Python.

Requisitos previos

Instalación del Agent

Si no tienes instalado el Datadog Agent en tu máquina, ve a Integrations > Agent (Integraciones > Agent) y selecciona tu sistema operativo. Por ejemplo, en la mayoría de las plataformas Linux, puedes instalar el Agent ejecutando el siguiente script, sustituyendo <YOUR_API_KEY> por tu clave de API Datadog:

DD_AGENT_MAJOR_VERSION=7 DD_API_KEY=<YOUR_API_KEY> DD_SITE="datadoghq.com" bash -c "$(curl -L https://install.datadoghq.com/scripts/install_script.sh)"

Para enviar datos a un sitio Datadog distinto de datadoghq.com, sustituye la variable de entorno DD_SITE por tu sitio Datadog .

Asegúrate de que tu Agent está configurado para recibir datos de rastreo de los contenedores. Abre su archivo de configuración y asegúrate de que apm_config: está sin comentar, y que apm_non_local_traffic está sin comentar y configurado como true.

Si ya tienes un Agent instalado en el host, asegúrate de que es al menos la versión 7.28. Puedes consultar la versión mínima del Datadog Agent necesaria para utilizar las aplicaciones de rastreo Python ddtrace en la documentación para desarrolladores de bibliotecas de rastreo.

Instalación de la aplicación de ejemplo Python en Docker

El código de ejemplo para este tutorial está en GitHub, en github.com/Datadog/apm-tutorial-python. Para empezar, clona el repositorio:

git clone https://github.com/DataDog/apm-tutorial-python.git

El repositorio contiene una aplicación Python preconfigurada para ejecutarse en contenedores Docker. La aplicación de ejemplo es una aplicación básica de notas con una API REST para añadir y modificar datos.

Para iniciar y ejercitar la aplicación de ejemplo

  1. Crea el contenedor de la aplicación ejecutando:

    docker-compose -f docker/host-and-containers/exercise/docker-compose.yaml build notes_app
  2. Inicia el contenedor:

    docker-compose -f docker/host-and-containers/exercise/docker-compose.yaml up db notes_app

    La aplicación estará lista para su uso cuando veas el siguiente resultado en el terminal:

    notes          |  * Debug mode: on
    notes          | INFO:werkzeug:WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
    notes          |  * Running on all addresses (0.0.0.0)
    notes          |  * Running on http://127.0.0.1:8080
    notes          |  * Running on http://192.168.32.3:8080
    notes          | INFO:werkzeug:Press CTRL+C to quit
    notes          | INFO:werkzeug: * Restarting with stat
    notes          | WARNING:werkzeug: * Debugger is active!
    notes          | INFO:werkzeug: * Debugger PIN: 143-375-699
    

    También puedes verificar que se está ejecutando, observando los contenedores con el comando docker ps.

  3. Abre otro terminal y envía solicitudes API para ejercitar la aplicación. La aplicación de notas es una API REST que almacena datos en una base de datos Postgres en memoria que se ejecuta en el mismo contenedor. Envíale algunos comandos:

curl -X GET 'localhost:8080/notes'
{}
curl -X POST 'localhost:8080/notes?desc=hello'
(1, hello)
curl -X GET 'localhost:8080/notes?id=1'
(1, hello)
curl -X GET 'localhost:8080/notes'
{"1", "hello"}
curl -X PUT 'localhost:8080/notes?id=1&desc=UpdatedNote'
(1, UpdatedNote)
curl -X DELETE 'localhost:8080/notes?id=1'
Deleted

Detener la aplicación

Una vez que hayas comprobado que la aplicación se ejecuta, detenla para poder habilitar el rastreo en ella:

  1. Detén los contenedores:

    docker-compose -f docker/host-and-containers/exercise/docker-compose.yaml down

  2. Elimina los contenedores:

    docker-compose -f docker/host-and-containers/exercise/docker-compose.yaml rm

Habilitación del rastreo

Ahora que ya tienes una aplicación Python en funcionamiento, configúrala para habilitar el rastreo.

  1. Añada el paquete de rastreo Python a tu proyecto. Abre el archivo apm-tutorial-python/requirements.txt y añade ddtrace a la lista, si no está ya allí:

    flask==2.2.2
    psycopg2-binary==2.9.3
    requests==2.28.1
    ddtrace
    
  2. Dentro del archivo Docker de la aplicación de notas, docker/host-and-containers/exercise/Dockerfile.notes, cambia la línea CMD que inicia la aplicación para utilizar el paquete ddtrace:

    # Run the application with Datadog
    CMD ["ddtrace-run", "python", "-m", "notes_app.app"]
    

    De este modo, la aplicación se instrumenta automáticamente con servicios Datadog.

  3. El Etiquetado unificado de servicios identifica servicios rastreados en diferentes versiones y entornos de despliegue, para que puedan correlacionarse en Datadog y puedas utilizarlos para buscar y filtrar. Las tres variables de entorno utilizadas para el etiquetado unificado de servicios son DD_SERVICE, DD_ENV y DD_VERSION. Añade las siguientes variables de entorno en el archivo Docker:

    ENV DD_SERVICE="notes"
    ENV DD_ENV="dev"
    ENV DD_VERSION="0.1.0"
    
  4. Añade etiquetas (labels) Docker que correspondan a las etiquetas unificadas de servicios. Esto también te permite obtener métricas Docker una vez que ejecute tu aplicación.

    LABEL com.datadoghq.tags.service="notes"
    LABEL com.datadoghq.tags.env="dev"
    LABEL com.datadoghq.tags.version="0.1.0"
    

Para comprobar que has configurado todo correctamente, compara tu archivo Docker con el proporcionado en el archivo de solución del repositorio de ejemplo, docker/host-and-containers/solution/Dockerfile.notes.

Configuración del contenedor para enviar trazas al Agent

  1. Abre el archivo de composición de los contenedores, docker/host-and-containers/exercise/docker-compose.yaml.

  2. En la sección del contenedor notes_app, añade la variable de entorno DD_AGENT_HOST y especifica el nombre de host del contenedor del Agent:

        environment:
         - DD_AGENT_HOST=host.docker.internal
    
  3. En Linux: Añade también un extra_host al archivo de composición para permitir la comunicación en la red interna de Docker. La sección notes-app de tu archivo de composición debería tener este aspecto:

      notes_app:
        container_name: notes
        restart: always
        build:
           context: ../../..
           dockerfile: docker/host-and-containers/exercise/Dockerfile.notes
        ports:
           - "8080:8080"
        depends_on:
           - db
        extra_hosts:                             # Linux only configuration
          - "host.docker.internal:host-gateway"  # Linux only configuration
       environment:
          - DB_HOST=test_postgres                 # the Postgres container
          - CALENDAR_HOST=calendar                # the calendar container
          - DD_AGENT_HOST=host.docker.internal    # the Agent running on the local machine using docker network
    

Para comprobar que has configurado todo correctamente, compara tu archivo docker-compose.yamlcon el proporcionado en el archivo de solución del repositorio de ejemplo, docker/host-and-containers/solution/docker-compose.yaml.

Iniciar el Agent

Inicia el servicio del Agent en el host. El comando depende del sistema operativo, por ejemplo:

MacOS
launchctl start com.datadoghq.agent
Linux
sudo service datadog-agent start

Verifica que el Agent se está ejecutando y enviando datos a Datadog, accediendo a Events > Explorer (Eventos > Explorador). También puedes filtrar por la faceta Datadog de origen y buscar un evento que confirme la instalación del Agent en el host:

Event Explorer que muestra un mensaje de Datadog que indica que el Agent se ha instalado en un host.
Si al cabo de unos minutos no ves tu host en Datadog en (Infraestructure > Host map (Infraestructura > Asignación de hosts), asegúrate de haber utilizado la clave de API correcta para tu organización, disponible en Organization Settings > API Keys (Parámetros de organización > Claves de API).

Inicio de los contenedores para observar el rastreo automático

Ahora que la biblioteca de rastreo está instalada y el Agent se está ejecutando, reinicia tu aplicación para empezar a recibir trazas. Ejecuta los siguientes comandos:

docker-compose -f docker/host-and-containers/exercise/docker-compose.yaml build notes_app
docker-compose -f docker/host-and-containers/exercise/docker-compose.yaml up db notes_app

Con la aplicación en ejecución, envíale algunas solicitudes curl:

curl -X POST 'localhost:8080/notes?desc=hello'
(1, hello)
curl -X GET 'localhost:8080/notes?id=1'
(1, hello)
curl -X PUT 'localhost:8080/notes?id=1&desc=UpdatedNote'
(1, UpdatedNote)
curl -X DELETE 'localhost:8080/notes?id=1'
Deleted

Espera unos instantes y ve a APM > Traces (APM > Trazas) en Datadog, donde podrás ver una lista de trazas correspondiente a tus llamadas de API:

Trazas de la aplicación de ejemplo en APM Trace Explorer

Si no ves trazas después de varios minutos, borra cualquier filtro en el campo de búsqueda de trazas (a veces se filtra sobre una variable de entorno como ENV que no estás utilizando).

Análisis de una traza

En la página de trazas, haz clic en una traza POST /notes para ver un gráfico de llamas que muestra cuánto tiempo ha tardado cada tramo y qué otros tramos han ocurrido antes de que se completara un tramo. La barra de la parte superior del gráfico es el tramo seleccionado en la pantalla anterior (en este caso, el punto de entrada inicial en la aplicación de notas).

El ancho de una barra indica el tiempo que ha tardado en completarse. Una barra de menor profundidad representa un tramo que se completa durante el tiempo de vida de una barra a mayor profundidad.

El gráfico de llamas de una traza POST tiene este aspecto:

Gráfico de llamas de una traza POST.

Una traza GET /notes tiene este aspecto:

Gráfico de llamas de una traza GET.

Añadir la instrumentación manual a la aplicación Python

La instrumentación automática es práctica, pero a veces prefieres utilizar tramos más precisos. La API de rastreo DD Python Datadog te permite especificar tramos en tu código mediante anotaciones o código.

Los siguientes pasos te guiarán a través de la adición de anotaciones al código para rastrear algunos métodos de ejemplo.

  1. Abre notes_app/notes_helper.py.

  2. Añade la siguiente importación:

    from ddtrace import tracer

  3. Dentro de la clase NotesHelper, añade un envoltorio del rastreador llamado notes_helper para ver mejor cómo funciona el método notes_helper.long_running_process:

    class NotesHelper:
    
        @tracer.wrap(service="notes_helper")
        def long_running_process(self):
            time.sleep(.3)
            logging.info("Hello from the long running process")
            self.__private_method_1()

    Ahora, el rastreador etiqueta automáticamente el recurso con el nombre de la función por la cual está envuelto, en este caso, long_running_process.

  4. Reconstruye los contenedores ejecutando:

    docker-compose -f docker/host-and-containers/exercise/docker-compose.yaml build notes_app
    docker-compose -f docker/host-and-containers/exercise/docker-compose.yaml up db notes_app

  5. Reenvía algunas solicitudes HTTP, concretamente algunas solicitudes GET.

  6. En el Trace Explorer, haz clic en una de las nuevas solicitudes GET y verás un gráfico de llamas como éste:

    Gráfico de llamas de una traza GET con instrumentación privada.

    Observa el mayor nivel de detalle de la traza del stack tecnológico ahora que la función get_notes cuenta con el rastreo personalizado.

Para obtener más información, consulta la instrumentación personalizada.

Añadir una segunda aplicación para ver trazas distribuidas

El rastreo de una única aplicación es un buen comienzo, pero el verdadero valor del rastreo consiste en ver cómo fluyen las solicitudes a través de tus servicios. Esto se llama rastreo distribuido.

El proyecto de ejemplo incluye una segunda aplicación llamada calendar_app que devuelve una fecha aleatoria cada vez que se invoca. El endpoint POST de la aplicación de notas tiene un segundo parámetro de consulta llamado add_date. Cuando se configura en y, la aplicación de notas llama a la aplicación de calendario para obtener una fecha y añadirla a una nota.

  1. Configura la aplicación de calendario para el rastreo añadiendo dd_trace al comando de inicio en el archivo Docker, como hiciste anteriormente para la aplicación de notas. Abre docker/host-and-containers/exercise/Dockerfile.calendar y actualiza la línea CMD de la siguiente forma:

    CMD ["ddtrace-run", "python", "-m", "calendar_app.app"]
    
  2. Aplica etiquetas de servicio unificadas, como lo hicimos para la aplicación de notas. Añade las siguientes variables de entorno en el archivo Dockerfile.calendar:

    ENV DD_SERVICE="calendar"
    ENV DD_ENV="dev"
    ENV DD_VERSION="0.1.0"
    
  3. Nuevamente, añade etiquetas (labels) Docker que correspondan a las etiquetas unificadas de servicios. Esto también te permite obtener métricas Docker una vez que ejecute tu aplicación.

    LABEL com.datadoghq.tags.service="calendar"
    LABEL com.datadoghq.tags.env="dev"
    LABEL com.datadoghq.tags.version="0.1.0"
    
  4. Al igual que hiciste anteriormente para la aplicación de notas, añade el nombre de host del contenedor del Agent, DD_AGENT_HOST, al contenedor de la aplicación de calendario para que envíe trazas (traces) a la localización correcta. Abre docker/host-and-containers/exercise/docker-compose.yaml y añade las siguientes líneas a la sección calendar_app:

        environment:
         - DD_AGENT_HOST=host.docker.internal
    

    Y, si utilizas Linux, añade también extra_host:

        extra_hosts:
          - "host.docker.internal:host-gateway"
    

Para comprobar que has configurado todo correctamente, compara tu configuración con el archivo Docker y con los archivos docker-config.yaml proporcionados en el archivo docker/host-and-containers/solution del repositorio de ejemplo, docker/host-and-containers/solution/Dockerfile.notes.

  1. Crea la aplicación de servicio múltiple reiniciando los contenedores. En primer lugar, detén todos los contenedores en ejecución:

    docker-compose -f docker/host-and-containers/exercise/docker-compose.yaml down
    

    A continuación, ejecuta los siguientes comandos para iniciarlos:

    docker-compose -f docker/host-and-containers/exercise/docker-compose.yaml build
    docker-compose -f docker/host-and-containers/exercise/docker-compose.yaml up
    
  2. Envía una solicitud POST con el parámetro add_date:

curl -X POST 'localhost:8080/notes?desc=hello_again&add_date=y'
(2, hello_again with date 2022-11-06)
  1. En el Trace Explorer, haz clic en esta última traza para ver un rastreo distribuido entre ambos servicios:

    Gráfico de llamas de una traza distribuida.

Añadir más instrumentación personalizada

Puedes añadir Instrumentación personalizada utilizando código. Supongamos que quieres instrumentar aún más el servicio de calendario para ver mejor la traza:

  1. Abre notes_app/notes_logic.py.

  2. Añadir la siguiente importación

    from ddtrace import tracer
    
  3. Dentro del bloque try, aproximadamente en la línea 28, añade la siguiente sentencia with:

    with tracer.trace(name="notes_helper", service="notes_helper", resource="another_process") as span:
    

    Lo que da como resultado:

    def create_note(self, desc, add_date=None):
            if (add_date):
                if (add_date.lower() == "y"):
                    try:
                        with tracer.trace(name="notes_helper", service="notes_helper", resource="another_process") as span:
                            self.nh.another_process()
                        note_date = requests.get(f"https://{CALENDAR_HOST}/calendar")
                        note_date = note_date.text
                        desc = desc + " with date " + note_date
                        print(desc)
                    except Exception as e:
                        print(e)
                        raise IOError("Cannot reach calendar service.")
            note = Note(description=desc, id=None)
            return self.db.create_note(note)

  4. Reconstruye los contenedores:

    docker-compose -f docker/host-and-containers/exercise/docker-compose.yaml build notes_app
    docker-compose -f docker/host-and-containers/exercise/docker-compose.yaml up
    
  5. Envía algunas solicitudes HTTP más, concretamente solicitudes a POST, con el argumento add_date.

  6. En el Trace Explorer, haz clic en una de las nuevas trazas POST para ver una traza personalizada a lo largo de varios servicios.

    Gráfico de llamas de una traza distribuida con instrumentación privada.
    Observa el nuevo tramo (span) etiquetado notes_helper.another_process.

Si no recibes trazas como esperabas, configura el modo de depuración en el paquete Python ddtrace. Para obtener más información, consulta Habilitar el modo de depuración.

Leer más