MÓDULO 18 · CI/CD + MONITORING EN PRODUCCIÓN · 30 MIN

Logs, métricas y trazas: tres preguntas distintas

Los tres pilares no son tres formatos del mismo dato: son tres respuestas a tres preguntas que no se pueden intercambiar. Las métricas dicen cuánto, los logs dicen qué pasó exactamente, las trazas dicen por dónde pasó. Empezar un incidente por el pilar equivocado es la causa habitual de que una investigación de diez minutos acabe durando cuatro horas.
01 — El orden de uso
Métrica, luego log, luego traza
01 · Métricas
¿Cuánto? ¿Cuándo?
La latencia p99 pasó de 200 ms a 3 s a las 14:00. Hay un problema.
02 · Logs
¿Qué pasó exactamente?
Filtras por level=ERROR service=checkout: «Redis connection timeout». Falla Redis.
03 · Trazas
¿Por dónde pasó?
API 10 ms → Auth 25 ms → Checkout 50 ms → Redis 2500 ms → Pago 100 ms. Ahí está.
MétricasLogsTrazas
FormatoNúmeros agregadosEventos discretosSpans con tiempos
CardinalidadBajaAltaMedia
Volumen y costeBajoAltoMedio (con muestreo)
Retención típicaMeses o añosDías o semanasDías
Uso principalAlertas, panelesDepuración, auditoríaCuello de botella

Ir directo a los logs sin haber mirado una métrica es buscar sin saber qué se busca. Y la cardinalidad de la tabla explica por qué no se pueden intercambiar: meter un identificador de usuario como etiqueta de una métrica multiplica las series por el número de usuarios y revienta la factura. Ese dato pertenece a un log.

02 — El pilar que más se descuida
El log estructurado

No estructurado, imposible de agregar:

Error processing payment for john@email.com - amount $99.99 failed with code 402

Estructurado, consultable:

{
  "timestamp":   "2026-01-19T15:30:00.123Z",
  "level":       "ERROR",
  "service":     "payment-api",
  "version":     "2.3.1",
  "environment": "production",
  "request_id":  "req_abc123",
  "trace_id":    "4bf92f3577b34da6a3ce929d0e0e4736",
  "user_id":     "user_456",
  "event":       "payment_failed",
  "error_code":  "CARD_DECLINED",
  "message":     "Payment processing failed due to insufficient funds"
}
No estructuradoEstructurado
BúsquedaRegex frágillevel="ERROR" AND user_id="user_456"
AgregaciónManualAutomática: errores por hora y servicio
AlertasSobre textoSobre campos concretos
CorrelaciónImposiblePor trace_id

El campo que lo cambia todo es trace_id. Sin él tienes líneas sueltas de cinco servicios que hablan del mismo incidente sin saberlo. Con él, los logs dejan de ser un pilar aparte y pasan a colgar de la traza — que es lo que convierte tres herramientas en un sistema.

// un log sin trace_id es una frase suelta; con él, es una línea de un diálogo
03 — El almacén que nadie protege
Qué no se loggea nunca
NuncaEn su lugar
ContraseñasNada, tampoco el hash
Tokens y API keysapi_key: "sk_***redacted***"
Números de tarjetaLos últimos cuatro: ****1234
Datos personales sin necesidadEl ID del usuario, no su email

Los logs se replican, se archivan, se exportan a un tercero y los consulta muchísima más gente que la base de datos. Un log es un almacén de datos con los permisos más laxos del sistema, y casi nadie lo trata como tal.

04 — Qué medir
RED, USE y los cuatro tipos de métrica

RED, para servicios y APIs: Rate (peticiones por segundo), Errors (tasa de fallos), Duration (latencia). USE, para recursos e infraestructura: Utilization, Saturation, Errors. Uno mira lo que el usuario experimenta; el otro, lo que la máquina sufre.

TipoQué haceEjemplo
CounterSolo subeTotal de peticiones, total de errores
GaugeSube y bajaMemoria en uso, conexiones activas
HistogramReparte los valores en cubosLatencia — permite calcular p95 después
SummaryPercentiles precalculadosDuración por cuantil

El error clásico es medir latencia con un gauge o guardando la media. Un histograma existe justamente para poder preguntar por percentiles después, sin haber decidido de antemano cuáles — y esa pregunta es la única que describe la experiencia real de los usuarios.

05 — El cuarto pilar de facto
Error tracking no es logging
LoggingError tracking
UnidadLa líneaEl issue agrupado
El mismo fallo 847 veces847 líneas1 issue con contador
ContextoLo que escribiste túStack trace, usuario, navegador, breadcrumbs
VersiónHay que deducirlaAsociada al release

La agrupación es la función principal, no un extra. Ver «847 ocurrencias, 12 usuarios afectados, primera vez hace dos días, release v2.3.1» convierte una avalancha de ruido en un dato accionable: cuánta gente, desde cuándo, y con qué despliegue empezó. Esa última columna es la que cierra el círculo con el módulo de CI/CD.

Auditoría Sobre el código de Sentry. La guía fija @sentry/node en ^7.91.0 y usa Sentry.Handlers.requestHandler() y new Sentry.Integrations.Express({ app }) en el backend, pero en el frontend escribe Sentry.browserTracingIntegration() y replayIntegration(), que es la forma funcional de las integraciones. ¿Pertenecen las dos formas a la misma versión mayor del SDK, o hay un salto de v7 a v8 mezclado dentro del mismo capítulo? Conviene resolverlo antes de copiar nada: si son de versiones distintas, el resultado no es un aviso de deprecación sino un error en el arranque. Y una segunda: la guía cita «OWASP A09:2025 — Logging & Alerting Failures» como referencia estable. ¿Es esa la numeración definitiva del Top 10 de 2025, o la de un borrador que todavía podía cambiar? Es el tipo de cita que en una entrevista invita a una repregunta.
Para hacer
Convertir un console.log y chocar con lo difícil

Coge un console.log real de un proyecto tuyo y reescríbelo como JSON con los ocho campos: timestamp, level, service, version, environment, request_id, event y message. Es mecánico y tarda cinco minutos.

Y ahora la pregunta incómoda, que es el ejercicio de verdad: ¿de dónde sacas el request_id si ese log está en una función a la que no llega el objeto de la petición? Propagar el contexto sin ensuciar todas las firmas es la parte difícil de la instrumentación, y llega mucho antes que la decisión de qué herramienta comprar.