02 · Fundamentos de Observabilidad

Mapa rápido del tool‑chain (¿qué es cada cosa y para qué sirve?)

Herramienta
Rol en el stack
¿Por qué la elegimos en 2025?

Prometheus

Base de datos de series temporales (TSDB). Scrapea métricas vía HTTP y da un potente lenguaje de consulta (PromQL).

Estándar CNCF, pull‑based → menos overhead, enorme ecosistema de exporters y rules reutilizables.

Grafana

UI unificada: dashboards, alertas, exploración de métricas/logs/trazas.

Abstrae múltiples back‑ends; paneles listos, alertas visuales y enlaces cruzados.

Loki

Almacén de logs indexados por etiquetas en vez de por texto completo.

Consumir logs baratos (S3, local), mismo modelo de etiquetas que Prometheus ⇒ consultas coherentes.

Tempo

Almacén de trazas distribuido y altamente escalable (sucesor de Jaeger/Zipkin).

Soporta OTLP nativo, sin necesidad de índices costosos; se integra directo en Grafana.

OpenTelemetry (OTEL)

Estándar vendor‑neutral para instrumentar aplicaciones (API + SDK + spec).

"Instrumenta una vez, exporta a cualquiera"; comunidad activa, versión 1.0 estable.

Promtail

Agente daemon que lee ficheros de log y los envía a Loki con etiquetas.

Config YAML sencilla, sin sidecar pesado (a diferencia de Logstash o Fluend).

OTEL Collector (opcional)

Proxy/roteador que recibe telemetría, transforma y re‑exporta a uno o varios back‑ends.

Desacopla tu app de la infraestructura de observabilidad; centraliza sampling, batching y seguridad.

Docker Compose

Orquestador local para levantar todo el stack rápidamente.

Nada de instalar cada pieza a mano; reproducible por los alumnos en cualquier OS.

0.1 Cómo se relacionan entre sí

spinner
  • Prometheus tira de las métricas cada N segundos; Loki y Tempo reciben push desde los agentes/SDK.

  • Grafana no almacena datos; sólo los visualiza y correlaciona.

Objetivo General: Al finalizar esta clase queremos comprender los conceptos fundamentales de la observabilidad, cómo instrumentar aplicaciones Node.js con OpenTelemetry y utilizar herramientas como Grafana, Loki y Prometheus para monitorear, depurar y analizar el comportamiento de microservicios.

Parte 1: Fundamentos de la Observabilidad

1. Introducción a la Observabilidad

¿Qué es la Observabilidad y por qué es crucial?

  • Diferencias clave entre Monitoreo Clásico vs. Observabilidad Moderna.

    • Monitoreo: Sabemos qué preguntas hacer (¿Está el servidor arriba?).

    • Observabilidad: Capacidad de hacer preguntas nuevas y desconocidas sobre el sistema sin necesidad de redeployar código (¿Por qué este usuario específico experimenta latencia solo en este endpoint?).

    • Desafíos en arquitecturas de microservicios: Complejidad, debugging distribuido, fallos en cascada, "unknown unknowns".

    • Beneficios: Reducción del MTTR (Mean Time To Resolution), mejora de la fiabilidad, comprensión proactiva del sistema.

  • Caso real de estudio: El E-commerce en Black Friday.

    • Escenario: Picos de tráfico, errores intermitentes en el checkout, quejas de usuarios.

    • Pregunta: ¿Cómo correlacionamos un aumento en http_server_requests_seconds_count{status="500"} con las trazas específicas que fallaron y los logs detallados del error para identificar que un servicio de inventario aguas abajo estaba fallando por timeouts?

spinner

Explicación: Un timeout en la BD de Productos causa que el Servicio de Productos falle, lo que a su vez hace que el Servicio de Órdenes falle, impactando al usuario. Sin observabilidad, encontrar la causa raíz (D) es un desafío.

  • Discusión Rápida:

    • ¿Habeis enfrentado problemas similares y cómo los resolvieron?

    • ¿Qué herramientas usan actualmente para monitorear sus aplicaciones?

2. Los Pilares de la Observabilidad: Logs, Métricas y Trazas

Introducción a los 3 Pilares: La base para entender el comportamiento del sistema.

Logs (Registros):

  • ¿Qué son? Eventos discretos, inmutables y con marca de tiempo. Útiles para información detallada y errores específicos.

  • Buenas prácticas: Logs estructurados (JSON), niveles de log (INFO, WARN, ERROR), incluir contexto relevante (IDs de correlación, IDs de usuario).

  • Herramientas Comunes: Loki, ELK Stack (Elasticsearch, Logstash, Kibana).

Métricas:

  • ¿Qué son? Agregaciones numéricas medibles en el tiempo (contadores, medidores, histogramas). Útiles para dashboards, alertas y entender tendencias.

  • Tipos comunes: Tasa de errores, latencia (percentiles P95, P99), throughput (RPS), uso de CPU/memoria.

  • Herramientas Comunes: Prometheus, DataDog, Dynatrace.

Trazas (Tracing Distribuido):

  • ¿Qué son? Representan el flujo de una solicitud a través de múltiples servicios. Compuestas por "spans" (unidades de trabajo).

  • Beneficios: Identificar cuellos de botella, entender dependencias entre servicios, depurar errores en sistemas distribuidos.

  • Conceptos Clave: traceId, `spanId

  • Herramientas Comunes: Jaeger, Tempo (parte de Grafana Stack), Zipkin, DataDog APM, Dynatrace.

  • Correlación entre Pilares: La magia ocurre cuando se usan juntos. Ejemplo: Una alerta de métrica (alta latencia P99) te lleva a una traza específica, donde un span anómalo te permite ver los logs de ese servicio y span particular para encontrar el error.

spinner

Explicación: La aplicación emite los tres tipos de señales, que son recolectadas por sus respectivos backends y luego visualizadas y correlacionadas en Grafana.

Ejercicio Práctico: Preparando el Entorno con Docker

docker-compose.yml:

promtail-local-config.yml:

prometheus.yml:

  1. Levantar el Stack:

  1. Verificar Servicios:

  • Grafana: http://localhost:3000

  • Prometheus: http://localhost:9090

  • Loki (API, no UI por defecto): http://localhost:3100/ready (debería dar "ready"). Puede tardar hasta 15 segundos en estar listo. Probar con curl -i http://localhost:3100/ready

  1. Generar Logs de Ejemplo:

Crear un archivo example-log-generator.ts:

Configurar promtail para que recolecte logs de app.log:

  1. Explorar Logs en Grafana:

  • Ir a Grafana (http://localhost:3000).

  • Sección "Explore".

  • Seleccionar "Loki" como datasource (puede requerir configuración inicial si no está auto-detectado: URL http://loki:3100).

    • Probar query: filename = "app.log" o similar.


3. OpenTelemetry: El Estándar de la Trazabilidad Moderna

¿Qué es OpenTelemetry (OTEL)?

  • Un conjunto de APIs, SDKs, herramientas y especificaciones agnósticas al proveedor.

  • Objetivo: Estandarizar la forma en que se recolecta y exporta la telemetría (logs, métricas, trazas).

  • Incubado por la CNCF (Cloud Native Computing Foundation).

Componentes Clave de OTEL:

  • API (Application Programming Interface): Define cómo instrumentar el código (crear spans, registrar métricas). Tu código interactúa con la API.

  • SDK (Software Development Kit): Implementación concreta de la API. Gestiona el muestreo (sampling), procesamiento y exportación de datos.

  • Exporters: Envían datos a diferentes backends (Jaeger, Prometheus, Loki, OTLP Collector, DataDog, etc.).

  • Collector (Opcional pero recomendado): Un proxy que recibe telemetría, la procesa/filtra y la reenvía a uno o más backends. Desacopla la app del backend.

spinner

Instrumentación en Node.js:

  • Automática: Librerías que "parchean" módulos comunes (HTTP, Express, gRPC, clientes de BD) para generar spans y métricas automáticamente.

    • Ej: @opentelemetry/auto-instrumentations-node

  • Manual: Crear spans y métricas explícitamente en tu código para lógica de negocio específica.

  • Demo en vivo (conceptual): Mostrar una traza compleja en Jaeger o Tempo, explicando la jerarquía de spans, tags, logs en spans, y cómo ayuda a identificar cuellos de botella.

Ejercicio Práctico: Instrumentación Básica con OTEL en Node.js (15m):

(Asumir una app Express simple en ejercicio2-otel-node/app.js dentro del repo clonado).

  1. Navegar al directorio del ejercicio:

  1. Instalar dependencias de OTEL:

  1. Crear archivo tracing.ts (o similar) para configurar el SDK:

  1. Crear app.ts para cargar tracing.ts al inicio:

  1. Añadir Tempo al docker-compose.yml (si no estaba):

Y un tempo-config.yaml simple:

  1. Reiniciar Docker Compose:

docker compose up -d --force-recreate

  1. Ejecutar la app Node.js:

node app.ts (o configurar para que corra en Docker).

  1. Ver Trazas en Grafana/Tempo:

  • En Grafana, ir a "Explore".

  • Seleccionar "Tempo" como datasource (URL http://tempo:3200).

  • En la pestaña "Search", buscar trazas (puede tardar unos segundos en aparecer). Puedes filtrar por service.name="my-node-app".

  • Analizar una traza, especialmente la de /slow.


Parte 2: Implementación Práctica y Casos de Uso

4. Métricas de Aplicación y Negocio + Dashboards

Más allá de las Métricas de Infraestructura: No solo CPU/Memoria. Necesitamos métricas que reflejen la salud de la aplicación y el impacto en el negocio.

Métricas GOLD (Google SRE): Latency, Errors, Traffic, Saturation. Aplicables a servicios.

Métricas de Negocio (KPIs):

  • Derivadas de eventos del dominio: UserSignedUp, OrderCreated, PaymentProcessed, PaymentFailed.

  • Ejemplos: Tasa de conversión (ej. PaymentSuccess / PaymentAttempt), número de carritos abandonados, valor promedio de orden (AOV).

  • ¿Cómo instrumentarlas? Contadores, Gauges.

Diagrama Mermaid: Customer Journey y Métricas Relevantes

spinner

Explicación: Cada paso del journey puede generar métricas que ayudan a entender el embudo y los puntos de fricción.

Ejercicio Práctico: Instrumentar Métricas Custom y Crear Dashboard (20m):

  1. Instalar exportador de Prometheus para OTEL (si no se hizo):

  1. Modificar tracing.ts para añadir el exportador de métricas:

Nota: La configuración de métricas con OTEL puede ser un poco más compleja de integrar con NodeSDK que las trazas. Para el ejercicio, la configuración del PrometheusExporter y MeterProvider es clave. El NodeSDK debería idealmente manejar la inicialización del MeterProvider. Si no, el MeterProvider debe ser configurado y sus Meters usados explícitamente.

  1. Instrumentar una métrica de negocio en app.js:

  1. Configurar Prometheus para scrapear la app Node.js:

  • Añadir un nuevo job a prometheus.yml (del ejercicio1-docker-stack o crear uno nuevo). Asumiendo que la app Node.js está en la misma red Docker que Prometheus y se llama my_node_app:

  • Importante: Si la app Node.js corre fuera de Docker (ej. node app.js en tu host), y Prometheus dentro de Docker, host.docker.internal es el DNS para acceder al host desde un contenedor Docker (en Mac/Windows). Para Linux, sería la IP del docker0 bridge o la IP principal del host. Si Node.js también está en un contenedor, usa el nombre del servicio y puerto interno.

  1. Reiniciar docker-compose y la app Node.js.

  2. Generar algunas órdenes:

  1. Crear un Dashboard Básico en Grafana:

  • Ir a Grafana (http://localhost:3000).

  • Asegurar que Prometheus es un datasource (URL http://prometheus:9090).

    • Crear un nuevo Dashboard.

    • Añadir panel > "Time series" o "Stat".

    • Query (Total Órdenes): sum(orders_total) o sum(rate(complex_operation_success_total[5m])) by (outcome) para tasa.


5. Alertas Automatizadas y Notificaciones

¿Por qué Alertas? Notificación proactiva de problemas antes de que los usuarios los reporten (o a gran escala).

Tipos de Alertas:

  • Basadas en Métricas: Umbrales (CPU > 80%), tasas de error (errores 5xx > 5%), anomalías. (Prometheus + Alertmanager).

  • Basadas en Logs: Patrones de error específicos en logs (Loki puede generar alertas o Grafana sobre Loki).

  • Basadas en Trazas (Menos común para alertas directas): Más para investigación, pero se pueden derivar métricas de trazas (ej. % de trazas con error).

Buenas Prácticas para Alertas:

  • Accionables: Cada alerta debe llevar a una acción o investigación clara.

  • Evitar Fatiga por Alertas ("Alert Fatigue"): No alertar por todo. Agrupar, usar severidades, definir bien los umbrales y duraciones (for: en Prometheus).

  • Documentación (Runbooks): ¿Qué hacer cuando salta esta alerta?

  • Canales de Notificación: Slack, PagerDuty, email, etc.

Ejercicio Práctico: Configurar Alerta en Prometheus y Notificación:

  1. Configurar Alertmanager (si no está en docker-compose.yml):

Y un alertmanager.yml básico (para Slack, necesitarás un webhook URL real):

  1. Indicar a Prometheus dónde está Alertmanager (prometheus.yml):

  1. Crear archivo alert.rules.yml:

(Nota: http_server_requests_seconds_count es una métrica estándar que OTEL podría generar para instrumentación HTTP. Asegúrate que los nombres de métricas y labels coincidan con lo que tu app exporta).

  1. Reiniciar docker-compose (Prometheus y Alertmanager).

  2. Simular Errores para Disparar la Alerta:

  • Generar varias peticiones que fallen al endpoint /checkout de tu app Node.js:

  • O si tienes un endpoint /error que siempre da 500:

  1. Verificar Alertas:

  • En Prometheus UI (http://localhost:9090/alerts). Debería pasar de PENDING a FIRING.

  • En Alertmanager UI (http://localhost:9093).

  • En tu canal de Slack (si lo configuraste).


6. Ejercicio Integrado: Debugging Distribuido de un Problema Real

Escenario del Problema (Guiado por el instructor):

  • "Los usuarios reportan que el endpoint /api/v1/user/:id/profile está extremadamente lento a veces, e incluso da timeouts."

    • Este endpoint en el ServicioA (Node.js) internamente llama a:

      • ServicioB (Node.js) para obtener datos básicos del usuario (/users/:id).

      • ServicioC (Node.js) para obtener el historial de compras (/users/:id/orders).

      • ServicioD (externo, legacy) para obtener preferencias de marketing (/marketing/:email/prefs).

        • Todos los servicios están instrumentados con OpenTelemetry y envían trazas a Tempo, métricas a Prometheus y logs a Loki.

Pasos para los Alumnos (trabajando juntos o individualmente):

  1. Identificar la Métrica Afectada (Grafana/Prometheus):

  • ¿Qué métrica buscarían? (Ej: http_server_requests_seconds_bucket{path="/api/v1/user/:id/profile", service_name="servicio-a"}).

  • Visualizar P95 o P99 de latencia. Confirmar el problema.

  • Buscar correlación con tasas de error si las hay.

  1. Encontrar Trazas Relevantes (Grafana/Tempo):

  • Desde el dashboard de métricas, ¿cómo pivotarían a trazas? (Idealmente, un dashboard que linkee traceIDs o permita filtrar por tiempo y servicio).

  • Si no hay link directo, usar el explorador de Tempo. Buscar trazas para service_name="servicio-a" con http.target="/api/v1/user/:id/profile" que sean lentas (ordenar por duración) o tengan errores.

  1. Analizar la Traza (Grafana/Tempo):

  • Identificar el "critical path" de la traza.

  • ¿Qué span está tomando más tiempo? ¿Es en ServicioA, B, C o D?

  • ¿Hay errores marcados en algún span? ¿Atributos (tags) útiles?

  • Suposición para el ejercicio: El span de la llamada a ServicioD (externo) es el que muestra una latencia muy alta y variable.

  1. Correlacionar con Logs (Grafana/Loki):

  • De la traza/span problemático, obtener el trace_id (y span_id si es útil).

  • Ir a Loki en Grafana y buscar logs con ese trace_id: {service_name="servicio-a", trace_id="<valor_del_trace_id>"}.

  • ¿Qué dicen los logs del ServicioA justo antes y después de llamar a ServicioD? (Ej: "INFO: Calling Marketing Service D", "WARN: Marketing Service D call took 3500ms").

  • ¿Hay logs de timeout o de reintentos?

  1. Crear un Dashboard Ad-Hoc (Opcional, si hay tiempo):

  • Un dashboard rápido en Grafana que muestre:

    • Latencia P99 del endpoint /api/v1/user/:id/profile.

    • Latencia P99 de la llamada externa a ServicioD (si se tiene una métrica específica para ello, ej. http_client_requests_seconds_bucket{peer_service="servicio-d"}).

    • Logs filtrados por trace_id para investigaciones rápidas.

  1. Proponer un Fix o Mitigación (Discusión):

  • Basado en el hallazgo (ej. ServicioD es lento):

    • Corto plazo: Implementar un timeout más agresivo y un circuit breaker para ServicioD. Cachear respuestas de ServicioD si los datos no son ultra-críticos en tiempo real. ¿Carga condicional de datos de marketing?

    • Largo plazo: Hablar con el equipo de ServicioD para que mejoren su rendimiento o provean una API más eficiente. ¿Reemplazar ServicioD?

Última actualización