";let n=document.getElementById("TableOfContents");n&&(n.innerHTML=e)}rerender(){this.renderFilterMenu(),this.renderPageContent(),this.populateRightNav(),this.runHooks("afterRerender")}renderPageContent(){let e={};Object.keys(this.ifFunctionsByRef).forEach(t=>{let s=this.ifFunctionsByRef[t],o=s.value,n=(0,h.reresolveFunctionNode)(s,{variables:this.selectedValsByTraitId});this.ifFunctionsByRef[t]=n,o!==n.value&&(e[t]=n.value)});let t=document.getElementsByClassName("cdoc__toggleable");for(let n=0;n{this.fitCustomizationMenuToScreen()})}addDropdownEventListeners(){let e=document.getElementsByClassName("cdoc-dropdown");for(let t=0;t{let t=e.target;for(;!t.classList.contains("cdoc-dropdown")&&t.parentElement;)t=t.parentElement;let n=t.classList.toggle("cdoc-dropdown__expanded");t.setAttribute("aria-expanded",n.toString())});document.addEventListener("keydown",e=>{if(e.key==="Enter"){let t=e.target;t.classList.contains("cdoc-filter__option")&&t.click()}}),document.addEventListener("click",t=>{for(let n=0;nthis.handleFilterSelectionChange(e));this.addDropdownEventListeners()}locateFilterSelectorEl(){let e=document.getElementById("cdoc-selector");return!!e&&(this.filterSelectorEl=e,!0)}applyFilterSelectionOverrides(){let s=Object.keys(this.selectedValsByTraitId),e=!1,t=this.browserStorage.getTraitVals();Object.keys(t).forEach(n=>{s.includes(n)&&this.selectedValsByTraitId[n]!==t[n]&&(this.selectedValsByTraitId[n]=t[n],e=!0)});let n=(0,j.getTraitValsFromUrl)({url:new URL(window.location.href),traitIds:s});return Object.keys(n).forEach(t=>{this.selectedValsByTraitId[t]!==n[t]&&(this.selectedValsByTraitId[t]=n[t],e=!0)}),e}updateEditButton(){let t=document.getElementsByClassName("toc-edit-btn")[0];if(!t)return;let e=t.getElementsByTagName("a")[0];e&&(e.href=e.href.replace(/\.md\/$/,".mdoc.md/"))}revealPage(){this.runHooks("beforeReveal"),this.filterSelectorEl&&(this.filterSelectorEl.style.position="sticky",this.filterSelectorEl.style.backgroundColor="white",this.filterSelectorEl.style.paddingTop="10px",this.filterSelectorEl.style.visibility="visible",this.filterSelectorEl.style.zIndex="1000");let e=document.getElementById("cdoc-content");e&&(e.style.visibility="visible"),this.runHooks("afterReveal")}renderFilterMenu(){if(!this.filterSelectorEl||!this.filtersManifest)throw new Error("Cannot render filter selector without filtersManifest and filterSelectorEl");let e=(0,l.resolveFilters)({filtersManifest:this.filtersManifest,valsByTraitId:this.selectedValsByTraitId});Object.keys(e).forEach(t=>{let n=e[t];this.selectedValsByTraitId[t]=n.currentValue});let t=(0,y.buildCustomizationMenuUi)(e);this.filterSelectorEl.innerHTML=t,this.fitCustomizationMenuToScreen(),this.addFilterSelectorEventListeners()}fitCustomizationMenuToScreen(){let e=document.getElementById(g);if(!e)return;let s=e.classList.contains(n),t=document.getElementById(v);if(!t)throw new Error("Dropdown menu not found");let o=document.getElementById(b);if(!o)throw new Error("Menu wrapper not found");let i=e.scrollWidth>o.clientWidth;!s&&i?(e.classList.add(n),t.classList.remove(n)):s&&!i&&(e.classList.remove(n),t.classList.add(n))}get cdocsState(){return{selectedValsByTraitId:this.selectedValsByTraitId,ifFunctionsByRef:this.ifFunctionsByRef,filtersManifest:this.filtersManifest,browserStorage:this.browserStorage,filterSelectorEl:this.filterSelectorEl}}};e.ClientFiltersManager=r,t=r,s={value:void 0}}),y=e(e=>{Object.defineProperty(e,"__esModule",{value:!0});var t=j();window.clientFiltersManager=t.ClientFiltersManager.instance}),y()})()Tutorial: Activación del rastreo de una aplicación Go y Datadog Agent en contenedores
Este tutorial te guiará a través de los pasos necesarios para activar el rastreo en una aplicación Go de ejemplo instalada en un contenedor. En este escenario, el Datadog Agent también está instalado en un contenedor.
Para otros escenarios, incluyendo la aplicación y el Agent en un host, la aplicación y el Agent en la infraestructura en la nube y en aplicaciones escritas en otros lenguajes, consulta los otros tutoriales de activación de rastreo.
Consulta Rastreo de aplicaciones Go para obtener documentación general sobre la configuración del rastreo para Go.
El repositorio contiene una aplicación Go multiservicio preconfigurada para ejecutarse dentro de contenedores de Docker. La aplicación de ejemplo consiste en una aplicación básica de notas y una aplicación de calendario, cada una con una API REST para añadir y cambiar datos. Los archivos YAML docker-compose se encuentran en el directorio docker.
Este tutorial utiliza el archivo all-docker-compose.yaml, que crea contenedores para las aplicaciones de notas y calendario y el Datadog Agent.
Inicio y ejecución de la aplicación de ejemplo
Crea los contenedores de la aplicación ejecutando:
docker-compose -f all-docker-compose.yaml build
Inicia los contenedores:
docker-compose -f all-docker-compose.yaml up -d
Comprueba que los contenedores se están ejecutando con el comando docker ps. Deberías ver algo como esto:
ID DE CONTENEDOR IMAGEN COMANDO CREADO ESTADO PUERTOS NOMBRES
0a4704ebed09 docker-notes "./cmd/notes/notes" About a minute ago Up About a minute 0.0.0.0:8080->8080/tcp notes
9c428d7f7ad1 docker-calendar "./cmd/calendar/cale..." About a minute ago Up About a minute 0.0.0.0:9090->9090/tcp calendar
b2c2bafa6b36 gcr.io/datadoghq/agent:latest "/bin/entrypoint.sh" About a minute ago Up About a minute (unhealthy) 8125/udp, 8126/tcp datadog-ag
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, apaga y elimina los contenedores y asegúrate de que se han eliminado:
docker-compose -f all-docker-compose.yaml down
docker-compose -f all-docker-compose.yaml rm
Activación del rastreo
A continuación, configura la aplicación Go para habilitar el rastreo. Dado que el Agent se ejecuta en un contenedor, no es necesario instalar nada.
Para activar el 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"// 1.x
chitrace"gopkg.in/DataDog/dd-trace-go.v1/contrib/go-chi/chi"// 1.x
httptrace"gopkg.in/DataDog/dd-trace-go.v1/contrib/net/http"// 1.x
"gopkg.in/DataDog/dd-trace-go.v1/ddtrace/tracer"// 1.x
// Si estás utilizando v2, las líneas se ven así:
// sqltrace "github.com/DataDog/dd-trace-go/contrib/database/sql/v2" // 2.x
// chitrace "github.com/DataDog/dd-trace-go/contrib/go-chi/chi/v2" // 2.x
// httptrace "github.com/DataDog/dd-trace-go/contrib/net/http/v2" // 2.x
// "github.com/DataDog/dd-trace-go/v2/ddtrace/tracer" // 2.x
En la función main(), descomenta las siguientes líneas:
Descomenta los campos depends_on para datadog-agent en el contenedor notes.
Fíjate que en la sección del servicio notes, la variable de entorno DD_AGENT_HOST está definida en el nombre de host del contenedor del Agent. Tu sección del contenedor notes debería tener el siguiente aspecto:
Más adelante, configurarás las secciones y variables de calendar en este tutorial.
Iniciar los contenedores para explorar la instrumentación automática
Ahora que la biblioteca de rastreo está instalada, reinicia tus contenedores de aplicación e inicia para empezar a recibir trazas. Ejecuta los siguientes comandos:
docker-compose -f all-docker-compose.yaml build
docker-compose -f all-docker-compose.yaml up -d
Para empezar a generar y recopilar trazas, inicia de nuevo la aplicación con make run.
Para saber si el Agent está funcionando, observa los resultados continuos en el terminal o abre el Explorador de eventos en Datadog y observa el evento de inicio del Agent:
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 Datadog. Ve a APM > Traces (APM > Trazas). La lista de trazas muestra algo como lo siguiente:
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 Trazas (a veces filtra por una variable de entorno como ENV que no estás utilizando).
Examinar 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 tardó cada tramo y qué otros tramos ocurrieron antes de que se completara un tramo. La barra de la parte superior del gráfico es el tramo que seleccionaste 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 tardó en completarse. Una barra más angosta representa un tramo que se completa durante el tiempo de vida de una barra de mayor ancho.
El gráfico de llamas de una traza POST tiene este aspecto:
Una traza GET /notes tiene este aspecto:
Configuración del rastreo
Puedes configurar la biblioteca de rastreo para añadir etiquetas (tags) 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:
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: chitracesqltrace y httptrace respectivamente:
cmd/notes/main.go
import(...sqltrace"gopkg.in/DataDog/dd-trace-go.v1/contrib/database/sql"// 1.x
chitrace"gopkg.in/DataDog/dd-trace-go.v1/contrib/go-chi/chi"// 1.x
httptrace"gopkg.in/DataDog/dd-trace-go.v1/contrib/net/http"// 1.x
// Si estás utilizando v2, las líneas se ven así:
// sqltrace "github.com/DataDog/dd-trace-go/contrib/database/sql/v2" // 2.x
// chitrace "github.com/DataDog/dd-trace-go/contrib/go-chi/chi/v2" // 2.x
// httptrace "github.com/DataDog/dd-trace-go/contrib/net/http/v2" // 2.x
...)
En cmd/notes/main.go, las bibliotecas de Datadog se inicializan con la opción WithService. Por ejemplo, la biblioteca chitrace se inicializa de la siguiente manera:
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 implementación para cada una de estas bibliotecas. Para ver una lista exhaustiva 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 en torno a la siguiente importación:
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
funcdoLongRunningProcess(ctxcontext.Context){childSpan,ctx:=tracer.StartSpanFromContext(ctx,"traceMethod1")childSpan.SetTag(ext.ResourceName,"NotesHelper.doLongRunningProcess")deferchildSpan.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
funcprivateMethod1(ctxcontext.Context){childSpan,_:=tracer.StartSpanFromContext(ctx,"manualSpan1",tracer.SpanType("web"),tracer.ServiceName("noteshelper"),)childSpan.SetTag(ext.ResourceName,"privateMethod1")deferchildSpan.Finish()time.Sleep(30*time.Millisecond)log.Println("Hello from the custom privateMethod1 in Notes")}
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 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:
Descomenta las siguientes líneas en cmd/calendar/main.go:
Abre docker/all-docker-compose.yaml y descomenta el servicio calendar para configurar el host del Agent y las etiquetas de servicio unificadas para la aplicación y para Docker:
En la sección del servicio notes, descomenta la variable de entorno CALENDAR_HOST y la entrada calendar en depends_on para establecer las conexiones necesarias entre ambas aplicaciones: Tu servicio de notas debería verse así:
En el Explorador de trazas, haz clic en esta última traza de notes para ver una traza distribuida entre ambos servicios:
Este gráfico 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 principal CreateNote.
Solucionar problemas
Si no recibes trazas como esperabas, configura el modo de depuración para el rastreador Go. Para obtener más información, consulta Habilitar el modo de depuración.