Cuando tu API cae a las 3 de la mañana, abres los logs y ves: "Error processing request". Sin request ID, sin timestamp estandarizado, sin contexto de lo que estaba pasando. Ese log no ayuda a resolver nada.

El logging estructurado resuelve esto: cada log es un objeto JSON con campos estandarizados que las herramientas de observabilidad pueden indexar, filtrar y correlacionar.

El formato que funciona

Cada log debe ser una línea JSON con campos consistentes:

{
  "level": "error",
  "timestamp": "2026-12-18T14:30:00.123Z",
  "message": "Failed to process payment",
  "service": "payment-api",
  "request_id": "req_abc123",
  "user_id": "usr_xyz789",
  "error": {
    "name": "PaymentGatewayError",
    "message": "Card declined",
    "stack": "PaymentGateway.ts:45:12"
  },
  "context": {
    "amount": 15000,
    "currency": "BRL",
    "payment_method": "credit_card"
  }
}

Compáralo con el log no estructurado: "Error al procesar pago". El formato estructurado permite buscar "todos los errores de pago del usuario xyz789", o "errores de tarjeta rechazada en los últimos 5 minutos", o "cuál es la tasa de fallo del gateway X".

Los campos que importan

  • level: error, warn, info, debug. Estandarízalo. Nunca uses console.log en producción.
  • timestamp: ISO 8601, siempre en UTC. Evita problemas de timezone.
  • service: qué microservicio generó el log. Obligatorio en arquitectura distribuida.
  • request_id: ID único del request. Se propaga entre servicios. Permite correlacionar logs del mismo flujo.
  • user_id: cuando aplique, el ID del usuario afectado.
  • error: objeto con nombre, mensaje y stack trace.
  • context: datos específicos de la operación que ayudan en el debug.

Implementación con pino (Node.js)

Pino es el logger estándar para Node.js en producción. Rápido, estructurado y con soporte nativo de JSON:

import pino from 'pino'

const logger = pino({
  level: process.env.LOG_LEVEL || 'info',
  formatters: {
    level: (label) => ({ level: label }),
  },
  timestamp: pino.stdTimeFunctions.isoTime,
})

// Middleware de request
app.use((req, res, next) => {
  req.id = crypto.randomUUID()
  req.log = logger.child({
    request_id: req.id,
    method: req.method,
    url: req.url,
  })

  const start = Date.now()
  res.on('finish', () => {
    req.log.info({
      status_code: res.statusCode,
      duration_ms: Date.now() - start,
    }, 'Request completed')
  })

  next()
})

Request ID: el hilo conductor

El request_id es el campo más importante para debug en sistemas distribuidos. Necesita nacer en la primera capa y propagarse por todas las llamadas:

// Generar en el gateway/API
const requestId = req.headers['x-request-id'] || crypto.randomUUID()

// Propagar en llamadas internas
await fetch('http://user-service/api/users', {
  headers: { 'X-Request-Id': requestId }
})

Con herramientas como Datadog, Elasticsearch o Loki, puedes buscar todos los logs de un request_id específico y ver el flujo completo de un request, de punta a punta.

Qué loguear y qué no loguear

Loguear: errores, warnings, eventos de negocio importantes (pago aprobado, cuenta creada), métricas de performance (duración de queries, tiempo de respuesta).

No loguear: datos sensibles (contraseñas, tokens, datos de tarjeta), datos PII sin necesidad, flujo normal de operaciones (excesivo), variables de entorno.

// ❌ Nunca
logger.info({ password: user.password, token: jwt })

// ✅ Correcto
logger.info({ user_id: user.id, action: 'login', ip: req.ip })

Log levels en la práctica

Error: algo falló y necesita atención. Alerta inmediata.

Warn: algo inesperado pero no crítico. Merece investigación.

Info: eventos normales del sistema. Pago procesado, email enviado.

Debug: detalles para desarrollo. Deshabilitado en producción.

En producción, corre con level: 'info'. Activa debug temporalmente vía variable de entorno cuando necesites investigar algo específico.

Correlación con métricas

Logs estructurados combinados con métricas (Prometheus, Datadog) permiten dashboards que muestran: tasa de errores por endpoint, latencia percentil, throughput por servicio. El log da el qué pasó, la métrica da el cuánto.