Skip to main content

Añadiendo OpenTelemetry

Una vez con el proyecto base en mano, podemos añadir la instrumentación de este código. Aquí tenemos un paso a paso de cómo usar el SDK de OTel con NodeJS.

En la carpeta del proyecto necesitamos instalar algunas dependencias.

npm install @opentelemetry/sdk-node \
@opentelemetry/api \
@opentelemetry/auto-instrumentations-node \
@opentelemetry/sdk-metrics \
@opentelemetry/sdk-trace-node

Esto actualizará el package.json que contiene todos los paquetes disponibles para el código cuando hacemos npm install que crea la carpeta node_modules que podemos usar en nuestro código.

Para no tener que poner esto en ambos códigos auth y todos vamos a crear el instrumentation.js que será el instrumentador y lo instanciaremos en auth y todos.

/*instrumentation.ts*/
// Importa los módulos necesarios de OpenTelemetry
// NodeSDK es el componente principal para configuración de la telemetría
import { NodeSDK } from '@opentelemetry/sdk-node';
// Proporciona instrumentación automática para módulos Node.js comunes
import { getNodeAutoInstrumentations } from '@opentelemetry/auto-instrumentations-node';
// Exportador de traces en formato OTLP (OpenTelemetry Protocol)
import {OTLPTraceExporter} from '@opentelemetry/exporter-trace-otlp-proto';

// Función que inicializa la instrumentación de OpenTelemetry
// Recibe el nombre del servicio como parámetro
function start(serviceName: string) {
// Configura el exportador para enviar traces a Jaeger
// a través del protocolo OTLP en el puerto 4318
const traceExporter = new OTLPTraceExporter({
url: 'http://jaeger:4318/v1/traces',
});

// Crea y configura una nueva instancia del SDK OpenTelemetry
const sdk = new NodeSDK({
traceExporter, // Exportador de traces configurado arriba
serviceName:serviceName, // Nombre del servicio para identificación
instrumentations: [getNodeAutoInstrumentations()] // Habilita instrumentación automática
});

// Inicia el SDK para comenzar a recolectar y exportar telemetría
sdk.start();
}

// Exporta la función start para ser usada en otros módulos
export default start

En este proyecto vamos a utilizar un exporter en lugar de utilizar un collector, o sea vamos a enviar directo a Jaeger que también levantaremos colocándolo en docker-compose.yml.

version: '3.8'

services:
todo:
build:
context: .
dockerfile: docker/Dockerfile.todo
volumes:
- .:/usr/src/app:rw
- /usr/src/app/node_modules
ports:
- 8081:8080
depends_on:
- redis

auth:
build:
context: .
dockerfile: docker/Dockerfile.auth
volumes:
- .:/usr/src/app:rw
- /usr/src/app/node_modules
ports:
- 8080:8080

redis:
image: redis:alpine
ports:
- '6380:6379'

jaeger:
image: jaegertracing/all-in-one
ports:
- 4318
- 16686:16686
environment:
COLLECTOR_OTLP_ENABLED: true

Sin embargo, es necesario iniciar este instrumentador en ambos servicios auth y todos antes de que los otros servicios inicien.

auth-service.ts

import start from './instrumentation';
start('auth-service')
// Resto del código...

todos-service.ts

import start from './instrumentation';
start('todo-service')
// Resto del código...

Cada aplicación necesita tener un nombre único para que podamos saber de dónde está viniendo y separar los sistemas. Si mantienes el mismo nombre mostrará todo de un único color en Jaeger después.

Ahora podemos levantar nuevamente el docker compose.

docker compose up --build

En el navegador accede localhost:8081/todos para observar la respuesta.

alt text

Y vamos a verificar qué sucedió en Jaeger que corre en localhost:16686. Ya tenemos nuestro primer trace.

alt text

Fíjate que los colores son diferentes (azul y amarillo) justamente porque estamos usando nombres diferentes en los exporters.

alt text

Esta parte del proyecto está en la branch base_com_otel.