Tutorial: Activación del rastreo de una aplicación Go en el mismo host que el Datadog Agent

Información general

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

Para otros casos, incluyendo el de aplicaciones en contenedores o en infraestructuras en la nube, el de un Agent en un contenedor y el de aplicaciones escritas en otros lenguajes, consulta Tutoriales: activación del rastreo.

Consulta Rastreo de aplicaciones Go para obtener documentación general sobre la configuración del rastreo para Go.

Requisitos previos

  • Una cuenta de Datadog y una clave de API de la organización
  • Un host de Linux físico o virtual con acceso root (raíz) cuando se utiliza sudo. El host tiene los siguientes requisitos:
    • Git
    • Curl
    • Go versión 1.18+
    • Make y GCC

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 de 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 de Datadog.

Verifica que el Agent se está ejecutando y está enviando datos a Datadog, al acceder 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 instaló en un host.
Si al cabo de unos minutos no ves tu host en Datadog (en Infraestructure > Host map (Infraestructura > Mapa 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).

Instalación y ejecución de la aplicación de ejemplo Go

A continuación, instala una aplicación de ejemplo para rastrear. El código de ejemplo para este tutorial se puede encontrar en github.com/DataDog/apm-tutorial-golang.git. Clona el repositorio git ejecutando:

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

Crea la aplicación de ejemplo mediante el siguiente comando. El comando puede tardar un poco la primera vez que lo ejecutes:

make runNotes

La aplicación de ejemplo notes es una API REST básica que almacena datos en una base de datos en memoria. Utiliza curl para enviar algunas solicitudes API:

curl localhost:8080/notes
devuelve [] porque todavía no hay nada en la base de datos
curl -X POST 'localhost:8080/notes?desc=hello'
añade una nota con la descripción hello y un valor de ID de 1. Devuelve {"id":1,"description":"hello"}.
curl localhost:8080/notes/1
devuelve la nota con el valor id de 1: {"id":1,"description":"hello"}
curl -X POST 'localhost:8080/notes?desc=otherNote'
añade una nota con la descripción otherNote y un valor de ID de 2. Devuelve {"id":2,"description":"otherNote"}
curl localhost:8080/notes
devuelve el contenido de la base de datos: [{"id":1,"description":"hello"},{"id";2,"description":"otherNote"}]

Ejecuta más llamadas a la API para ver la aplicación en acción. Cuando hayas terminado, ejecuta el siguiente comando para salir de la aplicación:

make exitNotes

Instalación del rastreo de Datadog

A continuación, instala el rastreador de Go. Desde tu directorio apm-tutorial-golang, ejecuta:

go get gopkg.in/DataDog/dd-trace-go.v1/ddtrace

Ahora que se ha añadido la biblioteca de rastreo a go.mod, activa el soporte de rastreo.

Elimina los comentarios de las siguientes importaciones en apm-tutorial-golang/cmd/notes/main.go:

cmd/notes/main.go

  sqltrace "gopkg.in/DataDog/dd-trace-go.v1/contrib/database/sql"
  chitrace "gopkg.in/DataDog/dd-trace-go.v1/contrib/go-chi/chi"
  httptrace "gopkg.in/DataDog/dd-trace-go.v1/contrib/net/http"
  "gopkg.in/DataDog/dd-trace-go.v1/ddtrace/tracer"
  "fmt"

Cambia la importación:

_ "github.com/mattn/go-sqlite3"

to:

"github.com/mattn/go-sqlite3"

En la función main(), elimina los comentarios de las siguientes líneas:

cmd/notes/main.go

tracer.Start()
defer tracer.Stop()

cmd/notes/main.go

client = httptrace.WrapClient(client, httptrace.RTWithResourceNamer(func(req *http.Request) string {
        return fmt.Sprintf("%s %s", req.Method, req.URL.Path)
    }))

cmd/notes/main.go

r.Use(chitrace.Middleware(chitrace.WithServiceName("notes")))

En setupDB(), elimina los comentarios de las siguientes líneas:

cmd/notes/main.go

sqltrace.Register("sqlite3", &sqlite3.SQLiteDriver{}, sqltrace.WithServiceName("db"))
db, err := sqltrace.Open("sqlite3", "file::memory:?cache=shared")

Elimina los comentarios en la siguiente línea:

cmd/notes/main.go

db, err := sql.Open("sqlite3", "file::memory:?cache=shared")

Una vez realizados estos cambios, ejecuta:

go mod tidy

Inicia la aplicación Go y explora la instrumentación automática

Para empezar a generar y recopilar trazas, inicia de nuevo la aplicación con make runNotes.

Utiliza curl para volver a enviar solicitudes a la aplicación:

curl localhost:8080/notes
[]
curl -X POST 'localhost:8080/notes?desc=hello'
{"id":1,"description":"hello"}
curl localhost:8080/notes/1
{"id":1,"description":"hello"}
curl localhost:8080/notes
[{"id":1,"description":"hello"}]

Espera unos instantes y echa un vistazo a tu interfaz de usuario de Datadog. Navega a APM > Traces (APM > Trazas). La lista de trazas muestra algo como esto:

Vista de trazas que muestra los datos de traza entrantes desde el host.

Hay entradas para la base de datos (db) y la aplicación notes. La lista de trazas muestra todos los tramos, cuándo se iniciaron, qué recurso se rastreó con el tramo y cuánto tiempo tardó.

Si no ves trazas, borra cualquier filtro en el campo de búsqueda Traces (Trazas) (a veces filtra en una variable de entorno como ENV que no estás usando).

Análisis de una traza

En la página de trazas, haz clic en una traza POST /notes para ver una gráfica 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 de la gráfica 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 más angosta representa un tramo que se completa durante el tiempo de vida de una barra de mayor ancho.

La gráfica de llamas de una traza POST tiene este aspecto:

Una gráfica de llamas para una traza POST.

Una traza GET /notes tiene este aspecto:

Una gráfica de llamas para una traza GET.

Configuración del rastreo

Puedes configurar la biblioteca de rastreo para añadir etiquetas a la telemetría que envía a Datadog. Las etiquetas ayudan a agrupar, filtrar y mostrar datos de forma significativa en dashboards y gráficos. Para añadir etiquetas, especifica las variables de entorno al ejecutar la aplicación. El proyecto Makefile incluye las variables de entorno DD_ENV , DD_SERVICE y DD_VERSION, que están configuradas para activar el etiquetado de servicios unificado:

Makefile

run: build
  DD_TRACE_SAMPLE_RATE=1 DD_SERVICE=notes DD_ENV=dev DD_VERSION=0.0.1 ./cmd/notes/notes &
El Makefile también establece la variable de entorno DD_TRACE_SAMPLE_RATE en 1, que representa una frecuencia de muestreo del 100%. Una frecuencia de muestreo del 100% garantiza que todas las solicitudes al servicio de notas se envíen al backend de Datadog para su análisis y visualización a efectos de este tutorial. En una producción real o un entorno de alto volumen, no se especificaría una frecuencia tan alta. Establecer una frecuencia de muestreo alta con esta variable en la aplicación anula la configuración del Agent y resulta en un gran volumen de datos enviados a Datadog. Para la mayoría de los casos de uso, deja que el Agent determine automáticamente la frecuencia de muestreo.

Para obtener más información sobre las opciones disponibles de configuración, consulta Configuración de la biblioteca de rastreo de Go.

Uso de bibliotecas de rastreo automático

Datadog dispone de varias bibliotecas completamente compatibles para Go que permiten el rastreo automático cuando se implementan en el código. En el archivo cmd/notes/main.go, puedes ver que las bibliotecas go-chi, sql y http tienen alias según las correspondientes bibliotecas de Datadog: chitrace sqltrace y httptrace respectivamente:

main.go

import (
  ...

  sqltrace "gopkg.in/DataDog/dd-trace-go.v1/contrib/database/sql"
  chitrace "gopkg.in/DataDog/dd-trace-go.v1/contrib/go-chi/chi"
  httptrace "gopkg.in/DataDog/dd-trace-go.v1/contrib/net/http"
  ...
)

En cmd/notes/main.go, las bibliotecas de Datadog se inicializan con la opción WithServiceName. Por ejemplo, la biblioteca chitrace se inicializa de la siguiente manera:

main.go

r := chi.NewRouter()
r.Use(middleware.Logger)
r.Use(chitrace.Middleware(chitrace.WithServiceName("notes")))
r.Mount("/", nr.Register())

El uso de chitrace.WithServiceName("notes") garantiza que todos los elementos rastreados por la biblioteca estén bajo el nombre de servicio notes.

El archivo main.go contiene más ejemplos de aplicación para cada una de estas bibliotecas. Para ver una extensa lista de bibliotecas, consulta Requisitos de compatibilidad de Go.

Uso del rastreo personalizado con contexto

En los casos en que el código no esté incluido en una biblioteca compatible, puedes crear tramos manualmente.

Elimina los comentarios de la función makeSpanMiddleware en notes/notesController.go. Genera un middleware que engloba una solicitud en un tramo con el nombre suministrado. Para utilizar este función, comenta las siguientes líneas:

notes/notesController.go

  r.Get("/notes", nr.GetAllNotes)                // GET /notes
  r.Post("/notes", nr.CreateNote)                // POST /notes
  r.Get("/notes/{noteID}", nr.GetNoteByID)       // GET /notes/123
  r.Put("/notes/{noteID}", nr.UpdateNoteByID)    // PUT /notes/123
  r.Delete("/notes/{noteID}", nr.DeleteNoteByID) // DELETE /notes/123

Elimina los comentarios de las siguientes líneas:

notes/notesController.go

  r.Get("/notes", makeSpanMiddleware("GetAllNotes", nr.GetAllNotes))               // GET /notes
  r.Post("/notes", makeSpanMiddleware("CreateNote", nr.CreateNote))                // POST /notes
  r.Get("/notes/{noteID}", makeSpanMiddleware("GetNote", nr.GetNoteByID))          // GET /notes/123
  r.Put("/notes/{noteID}", makeSpanMiddleware("UpdateNote", nr.UpdateNoteByID))    // PUT /notes/123
  r.Delete("/notes/{noteID}", makeSpanMiddleware("DeleteNote", nr.DeleteNoteByID)) // DELETE /notes/123

Elimina también el comentario de la siguiente importación:

notes/notesController.go

"gopkg.in/DataDog/dd-trace-go.v1/ddtrace/tracer"

Hay varios ejemplos de rastreo personalizado en la aplicación de ejemplo. Aquí hay un par de ejemplos más. Elimina los comentarios para habilitar estos tramos:

La función doLongRunningProcess crea tramos secundarios a partir de un contexto primario:

notes/notesHelper.go

func doLongRunningProcess(ctx context.Context) {
    childSpan, ctx := tracer.StartSpanFromContext(ctx, "traceMethod1")
    childSpan.SetTag(ext.ResourceName, "NotesHelper.doLongRunningProcess")
    defer childSpan.Finish()

    time.Sleep(300 * time.Millisecond)
    log.Println("Hello from the long running process in Notes")
    privateMethod1(ctx)
}

La función privateMethod1 demuestra la creación de un servicio completamente independiente de un contexto:

notes/notesHelper.go

func privateMethod1(ctx context.Context) {
    childSpan, _ := tracer.StartSpanFromContext(ctx, "manualSpan1",
        tracer.SpanType("web"),
        tracer.ServiceName("noteshelper"),
    )
    childSpan.SetTag(ext.ResourceName, "privateMethod1")
    defer childSpan.Finish()

    time.Sleep(30 * time.Millisecond)
    log.Println("Hello from the custom privateMethod1 in Notes")
}

Elimina los comentarios de las siguientes importaciones:

notes/notesHelper.go

  "gopkg.in/DataDog/dd-trace-go.v1/ddtrace/ext"
  "gopkg.in/DataDog/dd-trace-go.v1/ddtrace/tracer"

Inicia la aplicación con make runNotes y prueba de nuevo los comandos curl para observar los tramos y trazas personalizados que acabas de configurar:

curl localhost:8080/notes
[]
curl -X POST 'localhost:8080/notes?desc=hello'
{"id":1,"description":"hello"}
curl localhost:8080/notes/1
{"id":1,"description":"hello"}
curl localhost:8080/notes
[{"id":1,"description":"hello"}]
Una gráfica de llamas que muestra trazas personalizadas para privteMethod1 y doLongRunningProcess

Para obtener más información sobre el rastreo personalizado, consulta Instrumentación personalizada de Go.

Análisis de las 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 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.

Para activar el rastreo en la aplicación de calendario, elimina los comentarios de las siguientes líneas en cmd/calendar/main.go:

cmd/calendar/main.go

  chitrace "gopkg.in/DataDog/dd-trace-go.v1/contrib/go-chi/chi"
  "gopkg.in/DataDog/dd-trace-go.v1/ddtrace/tracer"

cmd/calendar/main.go

  tracer.Start()
  defer tracer.Stop()

cmd/calendar/main.go

  r.Use(chitrace.Middleware(chitrace.WithServiceName("calendar")))
  1. Si la aplicación de notas sigue ejecutándose, utiliza make exitNotes para detenerla.

  2. Ejecuta make run para iniciar la aplicación de ejemplo.

  3. Envía una solicitud POST con el parámetro add_date:

    curl -X POST 'localhost:8080/notes?desc=hello_again&add_date=y'

  4. En el Trace Explorer, haz clic en esta última traza notes para ver una traza distribuida entre ambos servicios:

    Una gráfica de llamas para una traza distribuida.

Esta gráfica de llamas combina interacciones de múltiples aplicaciones:

  • El primer tramo es una solicitud POST enviada por el usuario y gestionada por el enrutador chi a través de la biblioteca go-chi compatible.
  • El segundo tramo es una función createNote que fue rastreada manualmente por la función makeSpanMiddleware. La función creó un tramo a partir del contexto de la solicitud HTTP.
  • El siguiente tramo es la solicitud enviada por la aplicación de notas utilizando la biblioteca http compatible y el cliente inicializado en el archivo main.go. Esta solicitud GET se envía a la aplicación de calendario. Los tramos de la aplicación de calendario aparecen en azul porque son servicios independientes.
  • Dentro de la aplicación de calendario, un enrutador go-chi gestiona la solicitud GET y la función GetDate se rastrea manualmente con su propio tramo bajo la solicitud GET.
  • Por último, la llamada db púrpura es su propio servicio de la biblioteca sql compatible. Aparece en el mismo nivel que la solicitud GET /Calendar porque ambas son llamadas por el tramo primario CreateNote.

Solucionar problemas

Si no recibes trazas como esperabas, configura el modo de depuración para el trazador de Go. Lee Activar el modo de depuración para obtener más información.

Leer más