# 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](https://hub.docker.com/r/otel/opentelemetry-collector-contrib) 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](https://hub.docker.com/r/jaegertracing/jaeger).

## Requisitos previos

[Docker Compose](/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:
```bash
mkdir otel-js-app
cd otel-js-app
```

```bash
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:

```bash
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:

```js
// 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):

```js
// 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:

```yaml
# 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`:

```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/`:

```dockerfile
# 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:

```bash
docker compose up --build
```

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

Visita tu aplicación en [http://localhost:3000](http://localhost:3000)

Verifica las trazas en [http://localhost:16686](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.

