Observabilidad¶
De un vistazo
Materia: Transversal (aplica en todas las capas) · Tiempo de lectura: ~28 min · Requisitos previos: Sistemas distribuidos y Performance ayudan, pero no son imprescindibles.
En una frase: una vez desplegado, tu sistema es una caja negra en marcha y tú estás fuera; la observabilidad es el conjunto de decisiones de diseño que te permiten preguntarle qué está pasando por dentro sin volver a desplegar —porque en producción no puedes poner un var_dump().
Por qué esto importa¶
En local eres omnisciente. Pones un dd(), un breakpoint, lees el error en pantalla, reproduces el fallo mil veces. Depurar es fácil porque tú controlas la ejecución.
En producción no controlas nada de eso. El fallo ocurrió hace tres minutos, en la petición de un usuario que no conoces, en uno de seis contenedores, y ya no está pasando. No puedes reproducirlo a voluntad. No puedes poner un breakpoint. No puedes leer la pantalla del servidor. Y el clásico "pues meto un var_dump y redespliego" tiene tres problemas: tarda minutos, el bug puede no volver a aparecer, y estás modificando el sistema que intentas diagnosticar.
Las preguntas que aparecen en producción son de otra naturaleza:
- El checkout va lento para algunos usuarios. ¿Cuáles? ¿Desde cuándo? ¿Qué tienen en común?
- Ha habido un pico de errores 500 a las 03:14. Ya no pasa. ¿Qué fue?
- Una petición cruza cinco servicios. Tarda 4 segundos. ¿Cuál de los cinco se come el tiempo?
- Un cliente dice que "no le llegó el email de confirmación". ¿Se envió? ¿Falló? ¿Se envió a otro sitio?
Ninguna de estas se responde con más código. Se responden con datos que el sistema tuvo que ir dejando por el camino mientras ocurría el problema. Si no los dejó, la información se perdió para siempre y estás adivinando. Por eso la frase que sostiene la lección:
Si no lo puedes ver, no lo puedes arreglar. Y solo puedes ver lo que diseñaste para ser visible.
La observabilidad no es una herramienta que instalas al final. Es una propiedad del sistema que se decide mientras lo construyes, igual que la seguridad o el rendimiento.
Intuición primero: el avión y la caja negra¶
Un piloto no ve el motor. Va sentado en una cabina, físicamente separado de las miles de piezas que hacen volar el avión. Y sin embargo sabe en todo momento la altitud, la velocidad, la temperatura de cada motor, el nivel de combustible, si un alerón responde. ¿Cómo? Porque el avión se diseñó lleno de sensores que emiten esos datos continuamente, y la cabina los agrega en instrumentos legibles.
Tu sistema en producción es el avión; tú eres el piloto. No estás dentro del proceso. Solo sabes lo que los instrumentos te cuentan. Un sistema sin observabilidad es un avión sin cuadro de mandos: vuela, hasta que deja de volar y no tienes ni idea de por qué.
graph LR
SIS["Sistema en producción<br/>(la caja negra:<br/>no lo ves por dentro)"]
SIS -->|"emite señales"| INST["Instrumentos<br/>logs · métricas · trazas"]
INST -->|"agregadas y consultables"| TU["Tú, fuera<br/>haciendo preguntas"]
Dos ideas que van dentro de esta imagen y que hay que separar bien:
- El avión emite las señales (eso lo hace tu código: instrumentación).
- Los instrumentos las recogen y te dejan preguntar (eso lo hacen las herramientas: Grafana, Kibana, Jaeger...).
La observabilidad de verdad empieza en la primera parte. Ninguna herramienta puede mostrarte una señal que tu código no emitió.
El detalle¶
1. Observabilidad no es monitorización¶
Se usan como sinónimos y no lo son. La diferencia es sutil pero cambia cómo diseñas.
Monitorizar es vigilar un conjunto conocido y finito de cosas que ya sabes que pueden fallar. Defines de antemano las preguntas —"¿la CPU pasa del 80%?", "¿hay más de 10 errores por minuto?", "¿el disco está lleno?"— y montas paneles y alarmas para esas preguntas concretas. Es imprescindible, pero solo te avisa de los problemas que anticipaste.
Observar es tener el sistema instrumentado de forma que puedas hacer preguntas que no anticipaste, después de que el problema aparezca, sin tocar el código. "Vale, hay errores... ¿solo para usuarios de Android? ¿Solo con este método de pago? ¿Solo cuando el carrito tiene más de 20 líneas?". Esa capacidad de cortar los datos por dimensiones que no habías previsto es lo que distingue un sistema observable de uno meramente monitorizado.
La regla para distinguirlas
Monitorización responde preguntas conocidas de antemano (known-unknowns: sé que la CPU puede subir, vigilo la CPU). Observabilidad responde preguntas nuevas (unknown-unknowns: no imaginé que fallaría solo para carritos con cupón caducado, pero puedo descubrirlo). La monitorización es un subconjunto: el mínimo. La observabilidad es la capacidad general.
En la práctica no eliges una u otra: monitorizas lo crítico conocido y diseñas para poder observar lo desconocido. Lo segundo es lo que casi todo el mundo se salta.
2. Los tres pilares y qué responde cada uno¶
La observabilidad se construye sobre tres tipos de señal. No son intercambiables: cada una responde una clase distinta de pregunta, y las tres juntas se refuerzan.
graph TB
subgraph OBS["Tres pilares de la observabilidad"]
L["<b>LOGS</b><br/>¿QUÉ pasó?<br/>eventos discretos,<br/>con detalle"]
M["<b>MÉTRICAS</b><br/>¿CUÁNTO / con qué tendencia?<br/>números agregados<br/>en el tiempo"]
T["<b>TRAZAS</b><br/>¿DÓNDE se fue el tiempo?<br/>una petición a través<br/>de varios servicios"]
end
- Logs — el qué pasó. Eventos discretos con contexto: "usuario 42 intentó pagar y el gateway devolvió
card_declined". Mucho detalle, un evento cada vez. - Métricas — el cuánto y hacia dónde. Números agregados en el tiempo: "peticiones por segundo", "latencia media", "% de errores". Baratas, tendencias, alarmas.
- Trazas — el dónde. El recorrido de una sola petición cruzando todos los servicios, con el tiempo que pasó en cada uno.
Vamos una por una.
3. Logs: qué pasó (y cómo no arruinarlos)¶
Un log es un registro de un evento concreto. El problema no es logear —todo el mundo logea— sino logear de forma que luego puedas buscar y filtrar. Y aquí hay una decisión de diseño enorme: texto plano vs. estructurado.
Un log de texto plano es una frase para humanos:
Se lee bien... cuando hay diez. Cuando hay diez millones, es inservible: no puedes preguntar "dame todos los pagos rechazados del usuario 42 en la última hora" sin torturar un grep con expresiones regulares frágiles.
Un log estructurado es el mismo evento como datos (típicamente JSON), con campos consultables:
{
"timestamp": "2026-07-13T03:14:07Z",
"level": "warning",
"message": "Pago rechazado",
"event": "payment.declined",
"user_id": 42,
"order_id": 8891,
"gateway_reason": "card_declined",
"amount_cents": 4990
}
Ahora sí puedes preguntar: filtra por event = payment.declined, agrupa por gateway_reason, cuenta por user_id. El log deja de ser prosa y pasa a ser una base de datos de eventos. Esta es la diferencia entre un sistema observable y uno que solo genera ruido.
En Symfony esto es Monolog con un formateador JSON y contexto explícito:
use Psr\Log\LoggerInterface;
final class PaymentService
{
public function __construct(private LoggerInterface $logger) {}
public function charge(Order $order): void
{
try {
$this->gateway->charge($order);
// El segundo argumento es CONTEXTO estructurado: campos, no texto interpolado.
$this->logger->info('Pago aceptado', [
'event' => 'payment.accepted',
'order_id' => $order->getId(),
'user_id' => $order->getUserId(),
'amount_cents'=> $order->getAmountCents(),
]);
} catch (CardDeclined $e) {
$this->logger->warning('Pago rechazado', [
'event' => 'payment.declined',
'order_id' => $order->getId(),
'user_id' => $order->getUserId(),
'gateway_reason'=> $e->getReason(),
]);
throw $e;
}
}
}
Contexto en los campos, no en el mensaje
Regla de oro: el message debe ser constante ("Pago rechazado"), y todo lo variable va en el array de contexto. Si escribes "Pago rechazado del pedido $id", has vuelto al texto plano: cada log es una cadena distinta y no puedes agrupar. Mensaje fijo + campos = agrupable y buscable.
Los niveles son la primera dimensión de filtrado. No decoran: te dicen a qué prestar atención.
| Nivel | Cuándo | ¿Despierta a alguien? |
|---|---|---|
debug |
Detalle fino, solo en desarrollo | No |
info |
Algo normal ocurrió (petición servida, pago aceptado) | No |
warning |
Algo raro pero manejado (reintento, cache fallida) | No, pero se vigila |
error |
Una operación falló (excepción no esperada) | Quizá |
critical |
El sistema o una parte clave está caído | Sí, ya |
Un error clásico es logear todo como error "por si acaso": entonces el nivel deja de significar nada y nadie mira los logs. El nivel es una promesa sobre la gravedad; si la inflas, la rompes.
Lo que NUNCA debe entrar en un log
Un log es texto que se copia, se reenvía, se indexa en un sistema de terceros y se guarda meses. Nunca metas datos sensibles: contraseñas, tokens de sesión o API, números de tarjeta completos, PII innecesaria (DNI, direcciones), el cuerpo entero de peticiones que pueda contenerlos. Logea identificadores (user_id: 42), no datos personales (email, nombre). Un var_dump($request) en un log es a la vez una fuga de rendimiento y una brecha de seguridad y probablemente una infracción de RGPD. Filtra en el origen: Monolog tiene procesadores para redactar campos.
4. Métricas: números agregados en el tiempo¶
Un log es un evento; una métrica es un número medido repetidamente a lo largo del tiempo. "En este minuto se sirvieron 3.400 peticiones, con latencia media de 120 ms y 12 errores". No guardas cada petición: guardas agregados, lo que las hace baratísimas de almacenar y perfectas para gráficas y alarmas.
La pregunta útil no es "¿qué métricas puedo sacar?" (infinitas y casi todas ruido) sino "¿qué mido?". Hay dos plantillas que llevas contigo y casi nunca te fallan.
RED — para servicios que atienden peticiones (una API, una web):
- Rate — peticiones por segundo. ¿Cuánto tráfico entra?
- Errors — cuántas de ellas fallan. ¿Qué proporción va mal?
- Duration — cuánto tardan. ¿Va rápido o lento?
Con esas tres sabes la salud de cualquier endpoint: cuánto le piden, cuánto falla, cuánto tarda.
USE — para recursos (CPU, disco, un pool de conexiones, una cola):
- Utilization — % de tiempo que el recurso está ocupado.
- Saturation — cuánto trabajo hay esperando (la cola). El aviso temprano.
- Errors — errores del recurso.
graph LR
subgraph SERV["Servicio → mides RED"]
R1["Rate<br/>peticiones/s"]
E1["Errors<br/>% fallos"]
D1["Duration<br/>latencia"]
end
subgraph REC["Recurso → mides USE"]
U2["Utilization<br/>% ocupado"]
S2["Saturation<br/>cola de espera"]
E2["Errors"]
end
La media miente: usa percentiles
"Latencia media 120 ms" suena bien y esconde el desastre. Si 95 de cada 100 peticiones tardan 50 ms y 5 tardan 3 segundos, la media sigue baja, pero 1 de cada 20 usuarios está sufriendo. Por eso se mide en percentiles: el p50 (mediana) es el usuario típico; el p99 es "el 1% peor". La experiencia real de tus peores usuarios vive en el p99, y es donde se esconden los timeouts. Conecta con Performance: optimizar la cola de latencia es distinto de optimizar la media.
Una métrica bien pensada tiene dimensiones (etiquetas): latencia por endpoint, por método, por código de respuesta. Ahí es donde la métrica roza la observabilidad: puedes cortar "latencia" por "endpoint = /checkout" y descubrir que solo ese va lento. Cuidado, eso sí, con la cardinalidad: etiquetar por user_id (millones de valores) hace explotar el sistema de métricas. Alta cardinalidad es territorio de logs y trazas, no de métricas.
5. Trazas distribuidas: seguir UNA petición por todo el sistema¶
Aquí es donde la observabilidad se vuelve imprescindible y donde conecta de lleno con Sistemas distribuidos. En un monolito, una petición entra y sale del mismo proceso: un log te cuenta la historia. En una arquitectura de varios servicios, una sola petición del usuario puede desatar una cascada: el gateway llama a pedidos, que llama a inventario y a pagos, que llama a un banco externo, que...
El checkout tarda 4 segundos. Miras los logs de pedidos: rápido. Los de inventario: rápido. Los de pagos: rápido. Cada servicio jura que él va bien, y sin embargo la suma tarda 4 segundos. Ningún log local ve el conjunto. Necesitas seguir esa petición concreta por todos los servicios y ver dónde se fue el tiempo.
Eso es una traza distribuida. La idea mecánica es sencilla y potente:
- Cuando la petición entra por la puerta, se le asigna un
trace_idúnico. - Ese
trace_idviaja con la petición a cada servicio que toca (en una cabecera HTTP, típicamentetraceparent). - Cada tramo de trabajo (una llamada, una consulta a BD) genera un span: un intervalo con inicio, fin y a qué servicio pertenece, etiquetado con el mismo
trace_id. - Al final, juntando todos los spans con el mismo
trace_id, reconstruyes el recorrido completo en una cascada temporal.
graph TB
A["Gateway<br/>trace_id: abc-123<br/>[▓▓▓▓▓▓▓▓▓▓] 4000 ms"]
B["pedidos<br/>[▓▓] 200 ms"]
C["inventario<br/>[▓] 100 ms"]
D["pagos → banco externo<br/>[▓▓▓▓▓▓▓▓] 3600 ms ← AQUÍ"]
A --> B
A --> C
A --> D
De un vistazo: el culpable es la llamada al banco externo dentro de pagos, 3,6 de los 4 segundos. Ningún servicio individual "iba lento"; el problema era una dependencia concreta en el recorrido, y solo la traza lo hace visible. Este tipo de diagnóstico es, en la práctica, imposible sin trazas en un sistema distribuido.
El estándar que evita reinventar la rueda
Propagar el trace_id a mano por cabeceras HTTP es tedioso y frágil. OpenTelemetry (OTel) es el estándar de facto: librerías que instrumentan tu framework, propagan el contexto automáticamente y exportan spans a herramientas como Jaeger, Tempo o Datadog. La decisión de diseño no es "¿trazo o no?", sino "¿adopto OTel desde el día uno o me arrepiento cuando el monolito se parta en servicios?". Empezar sin trazas y añadirlas después significa reinstrumentar todo bajo presión, durante un incidente.
6. Correlación: los tres pilares son uno¶
El error de principiante es tratar logs, métricas y trazas como tres herramientas separadas con tres pestañas distintas. La observabilidad de verdad aparece cuando saltas de una a otra siguiendo un hilo:
graph LR
M["MÉTRICA<br/>pico de errores<br/>a las 03:14"] -->|"¿qué peticiones?"| T["TRAZA<br/>petición lenta<br/>trace_id abc-123"]
T -->|"¿qué pasó dentro?"| L["LOGS<br/>eventos con<br/>trace_id abc-123"]
L -->|"causa raíz"| CR["'gateway_reason:<br/>timeout banco'"]
El flujo real de una investigación: una métrica te avisa (los errores subieron); una traza te enseña dónde (la petición se atasca en pagos); los logs de esa traza te dan el detalle (gateway_reason: timeout). Métrica → traza → log: de lo agregado a lo concreto.
Para que ese salto funcione, la pieza de pegamento es incluir el trace_id en cada log. En Symfony, un procesador de Monolog que lo inyecta en todos los registros:
use Monolog\LogRecord;
final class TraceIdProcessor
{
public function __construct(private TraceContext $trace) {}
public function __invoke(LogRecord $record): LogRecord
{
// Cada log llevará el trace_id de la petición que lo generó.
$record->extra['trace_id'] = $this->trace->currentTraceId();
return $record;
}
}
Con esto, desde un span lento en la traza copias el trace_id, lo pegas en el buscador de logs, y ves exactamente los eventos de esa petición y de ninguna otra. Sin ese campo compartido, tienes tres silos que no se hablan.
7. Alertas útiles y fatiga de alertas¶
Tener datos no basta; alguien tiene que enterarse cuando importa. Ahí entran las alertas, y ahí casi todo el mundo se equivoca en la misma dirección: alertan de demasiado.
Una alerta que salta y no requiere acción es peor que inútil: entrena al equipo a ignorar las alertas. Es la fatiga de alertas. Cuando el móvil de guardia pita cuarenta veces al día por cosas que se arreglan solas, el ingeniero silencia el canal, y la vez que pita por algo real —el checkout caído— nadie mira. Demasiadas alertas es funcionalmente idéntico a no tener ninguna.
La regla es dura y clara:
Una alerta debe ser accionable y urgente: si salta, una persona tiene que dejar lo que está haciendo y hacer algo ahora. Si no cumple las dos, no es una alerta: es un panel que miras cuando quieras, o ruido que hay que borrar.
Alerta sobre síntomas, no sobre causas
Tentación: "avísame si la CPU pasa del 90%". Pero a nadie le importa la CPU en sí —importa si el usuario sufre. La CPU puede estar al 95% y el servicio ir perfecto. Alerta sobre el síntoma que nota el usuario (la latencia del checkout se disparó, los errores superan el umbral), no sobre la causa mecánica interna. Las causas las investigas después de que la alerta de síntoma te despierte, usando los tres pilares. Alertar por causas genera pitidos constantes que no correlacionan con dolor real.
8. SLI, SLO y el nivel de servicio que prometes¶
Para alertar sobre síntomas necesitas decidir qué nivel de servicio es "suficientemente bueno". Esto se formaliza con tres siglas que, quitada la jerga, son sentido común.
- SLI (Indicator) — la medida concreta de salud desde la óptica del usuario. Ej.: "% de peticiones al checkout que responden en menos de 500 ms y sin error". Es un número real, medible.
- SLO (Objective) — el objetivo que te pones sobre ese SLI. Ej.: "el 99,9% de las peticiones cumplen el SLI cada mes". Es la promesa interna.
- SLA (Agreement) — el SLO escrito en un contrato con el cliente, con penalización si se incumple. El SLA es el SLO con abogados.
La idea que lo cambia todo es el presupuesto de error (error budget). Un SLO del 99,9% dice que el 0,1% de las peticiones pueden fallar y seguir cumpliendo. Ese 0,1% no es un fracaso: es un presupuesto que puedes gastar. Mientras te sobre presupuesto, puedes desplegar rápido y arriesgar. Si te lo estás fundiendo, congela cambios y estabiliza. Convierte la fiabilidad de una discusión de opiniones ("¿desplegamos el viernes?") en una decisión con un número detrás.
El 100% es el objetivo equivocado
Perseguir el 100% de disponibilidad es una trampa: cada "nueve" adicional (99,9% → 99,99%) cuesta muchísimo más que el anterior y tus usuarios probablemente no notan la diferencia porque su propia red ya falla más que eso. El SLO correcto es el más bajo con el que los usuarios están contentos, no el más alto imaginable. Un SLO demasiado estricto te paraliza; uno realista te da margen para moverte rápido. Esto conecta con Sistemas distribuidos: en un sistema con muchas piezas, algo siempre está fallando un poco, y el diseño asume ese fallo en vez de negarlo.
Cómo se ve en la práctica¶
Un incidente real, de principio a fin, con los tres pilares trabajando juntos.
03:14. Una alerta salta: el SLI del checkout (peticiones OK bajo 500 ms) ha caído del 99,9% al 96% en cinco minutos. Es un síntoma que nota el usuario y se está comiendo el presupuesto de error a velocidad de crucero. Despierta al de guardia. Correcto: es accionable y urgente.
03:16. Abre el panel de métricas (RED del checkout). El rate es normal —no es un pico de tráfico—. Los errors subieron y la duration p99 pasó de 400 ms a 3 s. Algo va lento y falla, sin más carga. Descarta "nos han dado un aluvión de visitas".
03:18. Coge una traza de una petición lenta. La cascada canta: 2,8 de los 3 segundos están en un span pagos → gateway externo. Copia el trace_id.
03:19. Pega el trace_id en los logs. Filtra. Ahí está el detalle:
{"level":"error","event":"payment.timeout","trace_id":"abc-123",
"gateway":"stripe","waited_ms":3000,"order_id":8891}
Causa raíz en cinco minutos: el gateway de pago externo está lento y las peticiones agotan el timeout. No es culpa de su código; es una dependencia externa degradada. La acción inmediata (subir el timeout con reintento, o activar el gateway de respaldo) es evidente porque pudo ver. Sin observabilidad, esos mismos cinco minutos habrían sido horas de "a mí me funciona" mirando servicios de uno en uno a ciegas.
Fíjate en el orden: alerta → métrica → traza → log. Cada pilar hizo su trabajo y el trace_id fue el hilo que los cosió.
Lo que sacrificas / errores comunes¶
- La observabilidad cuesta: CPU para instrumentar, red para exportar, dinero para almacenar. Logear en
debugtodo en producción, o guardar el 100% de las trazas de un servicio con millones de peticiones, se paga en factura. Por eso existe el muestreo (sampling): guardas, por ejemplo, 1 de cada 100 trazas —y todas las que fallan—. Es un tradeoff consciente entre coste y visibilidad, no un descuido. - Añadirla al final: el error mayor. Un sistema construido sin instrumentar no se vuelve observable con un plugin; hay que ir metiendo
trace_id, contexto y spans por todo el código, y siempre acaba haciéndose a medias, bajo presión, durante un incidente. Se diseña desde el principio o se sufre. - Confundir "tengo logs" con "soy observable": gigabytes de texto plano no consultable son ruido caro, no observabilidad. Si no puedes preguntar y filtrar, no ves nada.
- Métricas de vanidad: paneles preciosos que nadie mira y que no corresponden a ningún dolor del usuario. Si una gráfica no cambia una decisión, sobra.
- Fugar datos sensibles en logs: repetido a propósito. Es el error con peores consecuencias legales de toda la lección.
- Alertar de todo: ya visto. La fatiga de alertas convierte tu sistema de aviso en ruido de fondo, y el día del incidente real nadie mira.
Resumen¶
- Una vez desplegado, tu sistema es una caja negra: solo ves lo que diseñaste para ser visible. En producción no hay
var_dump. Si no lo puedes ver, no lo puedes arreglar. - Monitorizar responde preguntas conocidas de antemano; observar te deja hacer preguntas nuevas que no anticipaste, cortando los datos por dimensiones no previstas.
- Tres pilares: logs (qué pasó, eventos discretos y estructurados), métricas (cuánto y con qué tendencia; RED para servicios, USE para recursos), trazas (dónde se fue el tiempo en una petición que cruza varios servicios).
- El valor real está en la correlación: el
trace_idcompartido cose métrica → traza → log en una sola investigación. Los tres pilares son un sistema, no tres pestañas. - Alertas accionables y urgentes, sobre síntomas del usuario, no sobre causas; y un SLO con presupuesto de error convierte la fiabilidad en una decisión con un número. La observabilidad se diseña, no se añade al final.
Ejercicios socráticos¶
No busques la respuesta fuera. Razónala con el modelo de esta lección. Si te atascas, la pista está en el texto.
- Un compañero dice: "ya tenemos observabilidad, logeamos todo con
error_log()a un fichero". Con lo que sabes de estructurado vs. plano y de los tres pilares, dile por qué eso no es observabilidad y qué le falta para poder responder "¿cuántos pagos rechazó el usuario 42 hoy?". - Tienes un pico de errores 500 que ya pasó y no se repite. ¿Por qué una métrica sola no te basta para la causa raíz, y por qué un log sin
trace_idtampoco, en un sistema de cinco servicios? ¿Qué pilar y qué campo lo resuelven? - La latencia media del checkout es 90 ms y el jefe está contento. ¿Por qué podrías tener a un 3% de usuarios sufriendo timeouts de 5 segundos sin que la media se inmute? ¿Qué medirías en su lugar?
- Diseña un SLO para el login de tu app: enuncia el SLI (medible, desde la óptica del usuario), pon un objetivo y explica qué es su presupuesto de error y para qué te sirve tenerlo. ¿Por qué no lo pones al 100%?
- El canal de alertas del equipo recibe 50 avisos al día y la gente lo ha silenciado. Sin tocar el código de la app, ¿cómo decides qué alertas borrar y cuáles conservar? Da el criterio de las dos condiciones que debe cumplir una alerta.
Repaso espaciado¶
Pasa estas a Anki (
repasos.md). Formato: pregunta que obligue a razonar, no a reconocer.
- [ ] ¿En qué se diferencian monitorizar y observar? Da un ejemplo de una pregunta que solo la observabilidad puede responder.
- [ ] Nombra los tres pilares y la pregunta concreta que responde cada uno. ¿Por qué no son intercambiables?
- [ ] ¿Qué gana un log estructurado frente a uno de texto plano, y por qué el
messagedebe ser constante? Nombra dos cosas que NUNCA deben ir en un log. - [ ] ¿Qué es un
trace_id, cómo viaja entre servicios y por qué es el pegamento que correlaciona los tres pilares? ¿Qué diagnóstico se vuelve imposible sin trazas? - [ ] Define SLI, SLO y presupuesto de error. ¿Por qué una buena alerta es sobre síntomas del usuario y no sobre causas como "CPU al 90%"?
Para seguir tirando del hilo¶
- Site Reliability Engineering (Google, gratis online) — capítulos de SLO, presupuesto de error y alertas. La referencia sobre cómo prometer y medir fiabilidad.
- Observability Engineering (Majors, Fong-Jones, Miranda; O'Reilly) — la distinción observar vs. monitorizar y el papel de la alta cardinalidad, con rigor.
- Documentación de OpenTelemetry — el estándar de instrumentación; empieza por los conceptos de trace, span y context propagation.
- Método RED (Tom Wilkie) y método USE (Brendan Gregg) — dos artículos cortos que te dan para siempre "qué mido" en servicios y en recursos.
- Experimento: coge cualquier proyecto Symfony tuyo, mete Monolog con formateador JSON y un procesador que inyecte un
request_id, y observa cómo cambia tu capacidad de buscar cuando los logs son datos y no prosa.