Monitorización vs. observabilidad
Monitorizar es vigilar señales que ya sabes que importan (¿está vivo el servidor? ¿cuánta CPU usa?). Observabilidad es poder responder preguntas que no habías anticipado a partir de lo que el sistema emite. La diferencia práctica: cuando algo falla a las 3 de la madrugada, ¿tienes datos suficientes para entender por qué, sin desplegar código nuevo?
Esos datos se apoyan en tres pilares: logs, métricas y trazas. Son complementarios, no intercambiables.
1. Logs estructurados
Un log es un registro de un evento puntual. El error clásico es escribir
texto libre (console.log("usuario " + id + " hizo login")): legible para una
persona, inservible para una máquina. Un log estructurado es un objeto (que
se serializa a JSON) con campos consistentes:
{ "nivel": "info", "mensaje": "login", "usuarioId": 42, "ts": "2026-06-22T10:00:00Z", "requestId": "abc-123" }
Así puedes filtrar y agregar: "dame todos los error del usuarioId 42 en
la última hora". Cada log lleva un nivel que indica su gravedad y permite
silenciar el ruido en producción:
debug: detalle interno, solo en desarrollo.info: eventos normales esperados (una petición, un login).warn: algo raro pero recuperable (reintento, caché fría).error: una operación falló y alguien debería mirarlo.
2. Métricas
Una métrica es un número agregado en el tiempo, barato de almacenar (no guardas cada evento, sino su recuento o distribución). Tipos habituales:
- Contador (counter): solo sube. "Número de peticiones", "errores totales". Derivas la tasa (peticiones por segundo) a partir de su pendiente.
- Medidor (gauge): sube y baja. "Conexiones abiertas", "memoria usada".
- Histograma: agrupa muchas mediciones en buckets para ver su distribución. Es lo que usas para la latencia.
Sobre la latencia, nunca mires solo la media: una media de 100 ms puede esconder que 1 de cada 20 usuarios espera 3 segundos. Por eso se usan percentiles. El p95 es el valor por debajo del cual cae el 95 % de las peticiones: "el 95 % responde en menos de 200 ms". El p99 captura la cola, la peor experiencia. Mejorar el p95/p99 suele importar más que mejorar la media.
3. Trazas (distributed tracing)
En un sistema con varios servicios, una sola petición del usuario cruza muchos saltos: gateway → servicio de pedidos → base de datos → servicio de pagos. Una traza sigue esa petición de extremo a extremo. Cada salto es un span con su duración, y todos comparten un mismo request id (o trace id) que se propaga en las cabeceras. Así ves dónde se va el tiempo: si la petición tarda 800 ms, la traza te dice que 700 fueron en una consulta lenta a la BD.
Ese mismo requestId debe ir también en los logs: es el hilo que cose los
tres pilares. Con él saltas de "esta petición fue lenta" (traza) a "y además
registró este error" (log).
Lo que construyes encima
- Dashboards: gráficas de las métricas clave (tasa de errores, p95, tráfico).
- Alertas: reglas que avisan cuando una métrica cruza un umbral ("p95 > 1 s durante 5 min"). Una buena alerta es accionable: si nadie va a hacer nada al recibirla, es ruido.
- Health checks: un endpoint (
/health) que responde si el servicio está sano. El balanceador lo consulta para dejar de enviar tráfico a instancias caídas.
Regla práctica: instrumenta primero los golden signals — latencia, tráfico, errores y saturación. Cubren la mayoría de los incidentes.
Ejemplos
Un log estructurado en JSON, listo para indexar
function log(nivel, mensaje, contexto = {}) {
return JSON.stringify({
nivel,
mensaje,
ts: new Date().toISOString(),
...contexto,
});
}
console.log(log("error", "pago rechazado", { usuarioId: 42, requestId: "abc-123" }));
p95: el percentil 95 de una lista de latencias (ms)
function percentil(valores, p) {
const orden = [...valores].sort((a, b) => a - b);
const i = Math.ceil((p / 100) * orden.length) - 1;
return orden[Math.max(0, i)];
}
const latencias = [80, 90, 95, 100, 110, 120, 130, 140, 150, 900];
console.log("p95:", percentil(latencias, 95), "ms"); // la cola asoma