Módulo 3: Observability As Sli Input

1. Introducción: observabilidad al servicio de una pregunta, no de un dashboard

Descripción

El Módulo 2 cerró con SLO.md: un SLI definido con precisión, un SLO de 99,9% mensual elegido con evidencia, y un presupuesto de 43,2 minutos medido —pero medido sobre un dataset fijo, committeado a mano, no sobre datos que salen de process-shipment-manifest en este mismo instante—. SLO.md fue explícito sobre esa limitación, en su propia sección "Consequences": "not a live number [...] but the evidence this SLO was chosen with, not guessed at". Este módulo existe para resolver exactamente esa frase: construir el pipeline mínimo que convierte invocaciones reales del Lambda heredado en los mismos dos números que compute_sli() necesita —eventos válidos, eventos buenos—, usando los tres pilares clásicos de observabilidad: métricas, logs y trazas.

La palabra clave de esa frase es mínimo. Este módulo no es un curso de instrumentación. No vas a aprender qué es un contador frente a un histograma, ni a instrumentar una aplicación desde cero, ni a diseñar un dashboard de organización completo. Vas a aprender exactamente lo que hace falta para que una pregunta muy específica —¿el SLI de process-shipment-manifest se está cumpliendo?— tenga una respuesta con datos reales detrás, no con un dataset de ejemplo. Todo lo que este módulo instrumenta está al servicio de esa pregunta; nada más.

Conexión con el módulo

Las ocho lecciones de este módulo siguen el mismo patrón que ya usaste en el Módulo 2: primero el marco (lección 2, los tres pilares con lente de SRE), después la ejecución real, pilar por pilar (lecciones 3 a 6: métricas, logs, trazas, y el stack Prometheus/Grafana que el mercado pide), y al final el cierre del hilo (lección 7: la calculadora del Módulo 2 corriendo, por primera vez, con telemetría real de este módulo en vez del dataset fijo). La lección 8 documenta el pipeline completo como el primer artefacto operativo de observabilidad de Andes Cargo.


La frontera que este módulo respeta: instrumentar es un medio, no el fin

Este ecosistema ya tiene una guía dedicada a observabilidad como disciplina completa: monitoring-observability-guide. Esa guía —no esta— es el lugar donde se enseña qué es un contador frente a un histograma, cómo instrumentar una aplicación desde cero, y cómo diseñar dashboards de organización a fondo. aws-serverless-and-containers-guide/DISENO.md ya delegó esa disciplina ahí, explícitamente, antes de que esta guía existiera.

Este módulo hace algo distinto y más angosto: toma la pregunta exacta que SLO.md dejó abierta —¿hay datos reales detrás de este SLI?— e instrumenta lo mínimo indispensable para contestarla. Cada lección de este módulo, sin excepción, se puede resumir con la misma pregunta: ¿esto me deja calcular un SLI de verdad? Nunca: "¿cómo se instrumenta una aplicación en general?". Esa pregunta más amplia sigue siendo, con toda intención, terreno de monitoring-observability-guide — este módulo no la contesta, y no debería.

La diferencia se nota en la profundidad, no en las herramientas: vas a usar Prometheus, Grafana, CloudWatch, OpenTelemetry y Jaeger —las mismas herramientas que usaría un curso de observabilidad completo—, pero vas a usarlas para producir exactamente dos números (eventos válidos, eventos buenos) y para que la calculadora del Módulo 2 los reciba. Ningún panel de este módulo existe "porque se ve bien en un dashboard"; cada uno existe porque alimenta, directa o indirectamente, compute_sli().


El mapa de este módulo: las 8 lecciones

   MODULO 3 — OBSERVABILIDAD COMO INSUMO DEL SLI
   de SLO.md con un dataset fijo a SLO.md medido con datos reales

   M3.1  Introduccion (esta leccion)              la frontera, la pregunta unica del modulo
   M3.2  Los tres pilares, con lente de SRE         que pregunta contesta cada uno
   M3.3  Metricas reales del Lambda heredado         REPRESENTATIVO: awslocal cloudwatch
   M3.4  Logs reales con jq                          REPRESENTATIVO + REAL: jq sobre logs reales
   M3.5  Trazas con OpenTelemetry y Jaeger            REAL: OTel -> Jaeger v2, corriendo
   M3.6  Prometheus y Grafana, el stack del mercado    REAL: docker compose, panel real
   M3.7  De telemetria cruda a un SLI medido           REAL: la calculadora del M2.4, datos reales
   M3.8  Proyecto: el pipeline de observabilidad-a-SLI  REAL: runbook + panel guardado
#LecciónQué construye
1Introducción (esta)La frontera con monitoring-observability-guide; la pregunta única del módulo
2Los tres pilares, con lente de SREQué pregunta responde cada pilar cuando la pregunta es "¿mi SLI se cumple?"
3Métricas reales del Lambda heredadoRepresentativo: awslocal cloudwatch get-metric-statistics sobre un batch fijo de 20 invocaciones
4Logs reales con jqRepresentativo (awslocal) + real (jq) — extraer las 3 invocaciones fallidas por requestId
5Trazas con OpenTelemetry y JaegerReal: dos trazas, upload → Lambda → DynamoDB, corriendo contra Jaeger v2 local
6Prometheus y Grafana, el stack del mercadoReal: docker compose up, un panel de Grafana con la misma métrica de éxito/error
7De telemetría cruda a un SLI medidoReal: error_budget_calculator.py corre con datos de este módulo, no el dataset del M2.4
8Proyecto: el pipeline de observabilidad-a-SLIReal: el runbook corto + el panel de Grafana guardado como dashboard.json

El hilo determinista de este módulo: un solo batch, tres lentes

A diferencia del Módulo 2 —donde cada lección corría sobre un dataset distinto (30 días de tráfico, después una semana mala)—, este módulo corre sobre un único batch fijo de 20 invocaciones de process-shipment-manifest, con 3 malformadas a propósito en posiciones fijas (5, 12 y 17), nunca elegidas con random. Ese mismo batch aparece leído con tres instrumentos distintos:

  • La lección 3 lo lee como conteo agregado (AWS/Lambda/Invocations/Errors): 20 invocaciones, 3 errores.
  • La lección 4 lo lee como detalle por invocación (logs): qué requestId falló, y por qué —el mismo error de validación que ya conoces de aws-serverless-and-containers-guide, no uno inventado para esta guía.
  • La lección 5 lo lee como una invocación específica, seguida de punta a punta (una traza): la número 17, con el punto exacto donde el flujo upload → Lambda → DynamoDB se corta.

Tres preguntas distintas sobre el mismo evento real, no tres eventos distintos —exactamente la idea que la lección 2 desarrolla con la analogía completa de este módulo.


Honestidad de este módulo: qué corre de verdad, qué queda representativo, y por qué

Este módulo tiene la distribución real/representativo más matizada de toda la guía, y vale la pena verla completa antes de la primera lección técnica:

HerramientaEstado en este móduloRazón técnica exacta
awslocal cloudwatch get-metric-statistics (lección 3)RepresentativoSin LOCALSTACK_AUTH_TOKEN exportado en este entorno de escritura, el contenedor de LocalStack no arranca. CloudWatch sí está confirmado en el plan Hobby de LocalStack —la salida que vas a leer es la que produciría ese comando contra la infraestructura real, reconstruida campo por campo, nunca inventada.
awslocal logs filter-log-events (lección 4)Representativo, misma razónIgual que arriba: el comando existe, es correcto, y correría contra LocalStack Hobby con el token exportado.
jq (lección 4)Realjq no depende de LocalStack. Corre contra un archivo JSON de logs de ejemplo —el mismo formato que produciría el comando awslocal de arriba— y produce la salida literal de esta lección, verificada corriendo el binario de verdad.
OpenTelemetry SDK + Jaeger v2 (lección 5)Realinstrument_manifest_flow.py corre con python3, envía spans por OTLP/HTTP a un contenedor Jaeger v2 real, corriendo con docker run. La traza que vas a ver en la UI de Jaeger es la que ese script produjo, verificada en este entorno.
Prometheus + Grafana (lección 6)Realdocker compose up levanta ambos contenedores de verdad; el panel de Grafana consulta Prometheus con PromQL real, sobre una métrica real expuesta por un exportador Python real.
error_budget_calculator.py (lección 7)RealLa misma calculadora del Módulo 2, corriendo con python3, esta vez con los números de este módulo.
AWS X-Ray (nombrado en lección 5)Representativo, nombrado, no ejecutado"Included in Plans: Ultimate" — ausente del plan Hobby de LocalStack. Es la razón exacta por la que esta lección usa OpenTelemetry + Jaeger en vez de X-Ray.

La regla que gobierna toda esta guía se mantiene sin excepción: si un comando aparece en una lección, corrió para escribirla. Lo que no corrió de verdad —los dos comandos awslocal— queda etiquetado en el momento exacto en que aparece, con la razón técnica precisa, nunca con un genérico "esto debería funcionar".


Errores comunes

Esperar que este módulo enseñe observabilidad "en general" (de confundir el alcance). Qué pasa: alguien llega a este módulo esperando aprender, por ejemplo, cómo instrumentar cualquier aplicación con OpenTelemetry, o cómo diseñar un dashboard de Grafana desde cero para cualquier sistema. Cómo detectarlo: si tu pregunta al terminar una lección de este módulo es "¿pero cómo haría esto para OTRO sistema, con otras métricas?" en vez de "¿esto alimenta el SLI de process-shipment-manifest?". Cómo corregirlo: ese alcance más amplio es, con toda intención, el terreno de monitoring-observability-guide —una guía completa dedicada a esa pregunta—. Este módulo instrumenta lo mínimo para un caso específico, con un SLI ya definido de antemano; no es un curso general de la disciplina.

Tratar los dos comandos awslocal de este módulo como si fueran menos reales que los demás (de subestimar lo representativo). Qué pasa: alguien lee "representativo" y asume que esa parte de la lección es menos confiable, o que se puede saltar. Cómo detectarlo: si tu plan es "ya voy a las partes reales, esto lo salteo". Cómo corregirlo: representativo no significa inventado —significa reconstruido campo por campo a partir de comportamiento ya confirmado (CloudWatch en el plan Hobby de LocalStack, documentación oficial de AWS), con la única variable siendo que este entorno específico de escritura no tiene el token de LocalStack exportado. Si corres estas lecciones con tu propio LOCALSTACK_AUTH_TOKEN, deberías obtener resultados equivalentes.

Pensar que las lecciones 3, 4 y 5 miden tres eventos distintos (de perder el hilo determinista). Qué pasa: alguien llega a la lección 5 pensando que la traza de Jaeger es de un evento nuevo, sin relación con los conteos de la lección 3 ni con el requestId extraído en la lección 4. Cómo detectarlo: si no puedes decir qué posición del batch de 20 invocaciones corresponde a la traza de error que la lección 5 muestra en Jaeger. Cómo corregirlo: las tres lecciones leen el mismo batch fijo de 20 invocaciones —la traza de error de la lección 5 es, específicamente, la invocación número 17, la misma que la lección 4 extrae por requestId con jq. Es un solo batch, leído con tres instrumentos, no tres batches distintos.


Ejercicios

Ejercicio 1 — Explica, sin mirar atrás, qué frase exacta de SLO.md (Módulo 2, lección 8) este módulo existe para resolver. Cita la sección de SLO.md donde aparece, y explica en una frase qué cambia entre esa sección y el final de este módulo.

Ver solución

La frase vive en la sección "Consequences" de SLO.md: "not a live number [...] but the evidence this SLO was chosen with, not guessed at", refiriéndose a los 4,23 minutos de presupuesto restante medidos sobre el dataset fijo del Módulo 2, lección 4. Lo que cambia al final de este módulo: la lección 7 corre exactamente la misma calculadora (compute_sli(), budget_report()) con datos que vienen de una fuente real de telemetría —Prometheus, alimentado por invocaciones reales del batch de este módulo— en vez del dataset committeado a mano. El SLI sigue siendo el mismo definido en SLO.md; lo que cambia es de dónde vienen los números que se le dan a la fórmula.

Ejercicio 2 — Clasifica una tarea hipotética: ¿pertenece a este módulo, o a monitoring-observability-guide? Un compañero de equipo propone instrumentar process-shipment-manifest con un histograma de latencia por percentil (p50, p95, p99), pensando en un dashboard de rendimiento general del Lambda, sin conectarlo a ningún SLI específico todavía. ¿Esa tarea entra en el alcance de este módulo?

Ver solución

No entra en el alcance de este módulo, tal como está descrita. La pregunta que gobierna cada lección de este módulo es "¿esto me deja calcular un SLI de verdad?" —y un histograma de latencia por percentil, sin ninguna conexión declarada a un SLI o un SLO específico, es exactamente el tipo de instrumentación general que monitoring-observability-guide cubre. Si la misma propuesta se reformulara como "necesitamos la latencia p99 porque el SLO de este módulo depende de que ninguna invocación exceda el Timeout: 10", entonces sí entraría —porque ahora la métrica está al servicio de una pregunta de SRE concreta, no de un dashboard de rendimiento en general. La diferencia no es la herramienta (un histograma es una herramienta legítima en ambos casos); es si existe, o no, una pregunta de SLI detrás.

Ejercicio 3 — Sin leer todavía la lección 2, predice qué pregunta va a contestar cada uno de los tres pilares (métricas, logs, trazas) cuando la pregunta central es "¿mi SLI se cumple?". Escribe una frase por pilar, usando lo que ya sabes de la definición de SLI del Módulo 2 (eventos buenos ÷ eventos válidos).

Ver solución

No hay una única respuesta correcta antes de leer la lección 2, pero una predicción razonable, usando la fórmula del SLI: métricas contestarían "¿cuántos eventos válidos hubo, y cuántos de esos fueron buenos?" —el conteo agregado que alimenta directamente el numerador y el denominador de compute_sli()—. Logs contestarían "¿cuáles, específicamente, fueron los eventos malos, y por qué?" —el detalle que las métricas agregadas no dan, necesario para actuar, no solo para medir—. Trazas contestarían "¿en qué punto exacto del flujo se rompió una invocación específica?" —la vista de una sola invocación seguida de punta a punta, útil para diagnosticar una falla puntual, no para calcular el SLI del mes—. La lección 2 formaliza esta misma intuición con la analogía completa del módulo.


Resumen y siguiente paso

Esta lección instaló la frontera que gobierna las siete lecciones que siguen: este módulo no enseña observabilidad como disciplina general —eso es monitoring-observability-guide—, instrumenta lo mínimo indispensable para que una pregunta específica, la que SLO.md dejó abierta, tenga una respuesta con datos reales. Viste el mapa de las 8 lecciones, el hilo determinista que las conecta (un solo batch de 20 invocaciones, leído con tres instrumentos distintos), y la tabla completa de honestidad de este módulo: qué corre de verdad (jq, OpenTelemetry, Jaeger, Prometheus, Grafana, la calculadora) y qué queda representativo, con su razón técnica exacta (los dos comandos awslocal).

Antes de avanzar deberías poder: explicar en una frase la diferencia entre "instrumentar como fin" y "instrumentar como medio", citando la frase exacta de SLO.md que este módulo resuelve; nombrar las 8 lecciones en orden; y explicar por qué las lecciones 3, 4 y 5 no son tres eventos distintos, sino tres lentes sobre el mismo batch fijo.

La lección 2 formaliza los tres pilares —métricas, logs, trazas— con la analogía completa de este módulo: tres formas de investigar por qué un tren llegó tarde.

Recursos

  1. Este mismo repositorio, Módulo 2, lección 8 (08-project-andes-cargos-slo-md.md) — SLO.md, con la sección "Consequences" que este módulo resuelve.
  2. aws-serverless-and-containers-guide (NIEVA), Módulo 2 — la versión de process-shipment-manifest (handler.py, validate_manifest()) que este módulo lee con instrumentación, sin reescribirla.
  3. monitoring-observability-guide (NIEVA) — la guía hermana que posee la observabilidad como disciplina general; la frontera declarada en esta lección.
  4. Google SRE Book, Capítulo 6 — Monitoring Distributed Systems — el marco de monitoreo que la lección 2 aplica con lente de SRE.
  5. LocalStack Docs — CloudWatch — confirmación del plan Hobby, la fuente de la etiqueta "representativo" de las lecciones 3 y 4.