Compartir comentarios
Las respuestas se generan en base a la documentación.

Instrumentar una aplicación JavaScript con OpenTelemetry

OpenTelemetry (OTel) es un framework de observabilidad de código abierto que proporciona un conjunto de APIs, SDKs y herramientas para recopilar datos de telemetría, como métricas, registros (logs) y trazas de aplicaciones. Con OpenTelemetry, los desarrolladores pueden obtener información valiosa sobre cómo rinden sus servicios en producción o durante el desarrollo local.

Un componente clave de OpenTelemetry es el OpenTelemetry Protocol (OTLP), un protocolo de propósito general e independiente del proveedor diseñado para transmitir datos de telemetría de manera eficiente y confiable. OTLP admite múltiples tipos de datos (trazas, métricas, logs) a través de HTTP o gRPC, lo que lo convierte en el protocolo predeterminado y recomendado para la comunicación entre aplicaciones instrumentadas, el OpenTelemetry Collector y backends como Jaeger o Prometheus.

Esta guía te acompaña en el proceso de instrumentar una aplicación Node.js simple con OpenTelemetry y ejecutar tanto la aplicación como un recolector usando Docker. Esta configuración es ideal para el desarrollo local y para probar la observabilidad antes de integrarla con plataformas de observabilidad externas como Prometheus, Jaeger o Grafana.

En esta guía, aprenderás a:

  • Configurar OpenTelemetry en una aplicación Node.js.
  • Ejecutar un OpenTelemetry Collector en Docker.
  • Visualizar trazas con Jaeger.
  • Usar Docker Compose para administrar la pila completa de observabilidad.

Uso de OpenTelemetry con Docker

La imagen oficial de Docker para OpenTelemetry proporciona una forma conveniente de desplegar y administrar instancias de Dex. OpenTelemetry está disponible para varias arquitecturas de CPU, incluidas amd64, armv7 y arm64, lo que garantiza la compatibilidad con diferentes dispositivos y plataformas. Lo mismo aplica para la imagen Docker de Jaeger.

Requisitos previos

Docker Compose: Recomendado para administrar aplicaciones Docker de múltiples contenedores.

Conocimiento básico de Node.js y Docker.

Estructura del proyecto

Crea el directorio del proyecto:

mkdir otel-js-app
cd otel-js-app
otel-js-app/
├── docker-compose.yaml
├── collector-config.yaml
├── app/
│   ├── package.json
│   ├── app.js
│   └── tracer.js

Crear una aplicación Node.js simple

Inicializa una aplicación Node.js básica:

mkdir app && cd app
npm init -y
npm install express @opentelemetry/api @opentelemetry/sdk-node \
            @opentelemetry/auto-instrumentations-node \
            @opentelemetry/exporter-trace-otlp-http

Ahora, agrega la lógica de la aplicación:

// app/app.js
const express = require('express');
require('./tracer'); // Inicializa OpenTelemetry

const app = express();

app.get('/', (req, res) => {
  res.send('Hello from OpenTelemetry demo app!');
});

const PORT = 3000;
app.listen(PORT, () => {
  console.log(`App listening at http://localhost:${PORT}`);
});

Configurar el rastreo (tracing) con OpenTelemetry

Crea el archivo de configuración del rastreador (tracer):

// app/tracer.js
const { NodeSDK } = require('@opentelemetry/sdk-node');
const { getNodeAutoInstrumentations } = require('@opentelemetry/auto-instrumentations-node');
const { OTLPTraceExporter } = require('@opentelemetry/exporter-trace-otlp-http');

const sdk = new NodeSDK({
  traceExporter: new OTLPTraceExporter({
    url: 'http://collector:4318/v1/traces',
  }),
  instrumentations: [getNodeAutoInstrumentations()],
});

sdk.start();

Configurar el OpenTelemetry Collector

Crea un archivo collector-config.yaml en la raíz:

# collector-config.yaml
receivers:
  otlp:
    protocols:
      http:

exporters:
  logging:
    loglevel: debug
  jaeger:
    endpoint: jaeger:14250
    tls:
      insecure: true

service:
  pipelines:
    traces:
      receivers: [otlp]
      exporters: [logging, jaeger]

Agregar la configuración de Docker Compose

Crea el archivo docker-compose.yaml:

version: '3.9'

services:
  app:
    build: ./app
    ports:
      - "3000:3000"
    environment:
      - NODE_ENV=development
    depends_on:
      - collector

  collector:
    image: otel/opentelemetry-collector:latest
    volumes:
      - ./collector-config.yaml:/etc/otelcol/config.yaml
    command: ["--config=/etc/otelcol/config.yaml"]
    ports:
      - "4318:4318" # OTLP

  jaeger:
    image: jaegertracing/all-in-one:latest
    ports:
      - "16686:16686" # UI
      - "14250:14250" # Recolector gRPC

Ahora, agrega el Dockerfile dentro de la carpeta app/:

# app/Dockerfile
FROM node:18

WORKDIR /usr/src/app
COPY . .
RUN npm install

CMD ["node", "app.js"]

Iniciar la pila

Inicia todos los servicios con Docker Compose:

docker compose up --build

Una vez que los servicios estén en ejecución:

Visita tu aplicación en http://localhost:3000

Verifica las trazas en http://localhost:16686 en la interfaz de usuario de Jaeger

Verificar trazas en Jaeger

Después de visitar el endpoint raíz de tu aplicación, abre la interfaz de usuario de Jaeger, busca el servicio (el valor predeterminado suele ser unknown_service a menos que se nombre explícitamente) y comprueba las trazas.

Deberías ver spans para la solicitud HTTP, el middleware y las bibliotecas autoinstrumentadas.

Conclusión

Ahora tienes una configuración de OpenTelemetry completamente funcional utilizando Docker Compose. Has instrumentado una aplicación JavaScript básica para exportar trazas y las has visualizado usando Jaeger. Esta arquitectura se puede extender para aplicaciones más complejas y canales de observabilidad utilizando Prometheus, Grafana o exportadores nativos de la nube.

Para temas avanzados como la creación de spans personalizados, métricas y registros (logs), consulta la documentación de OpenTelemetry para JavaScript.