Ir al contenido
angel.library

Logging de requests

Saber qué requests llegaron, con qué status respondieron y cuánto tardaron es la base para depurar cualquier problema en producción — sin logs, un bug reportado como “la API no anda” no tiene ningún rastro de qué pasó.

Ventana de terminal
pnpm add morgan
app.ts
import express from "express"
import morgan from "morgan"
const app = express()
app.use(morgan("dev")) // formato compacto y coloreado, pensado para desarrollo
GET /usuarios 200 12.345 ms - 348
POST /usuarios 201 45.102 ms - 89
GET /usuarios/xyz 404 3.210 ms - 28
app.use(morgan("tiny")) // el más compacto
app.use(morgan("dev")) // compacto + colores, para desarrollo
app.use(morgan("combined")) // formato estilo Apache, más completo, para producción
app.use(morgan(":method :url :status :response-time ms - :res[content-length]"))
import { createWriteStream } from "node:fs"
import path from "node:path"
const accessLogStream = createWriteStream(
path.join(process.cwd(), "access.log"),
{ flags: "a" }
)
app.use(morgan("combined", { stream: accessLogStream }))

{ flags: 'a' } (append) es importante — sin eso, el stream sobrescribiría el archivo en cada reinicio del servidor en vez de agregar al final.

Cuando morgan no alcanza: structured logging

Sección titulada «Cuando morgan no alcanza: structured logging»

Para producción real, sobre todo con múltiples servicios, un logger que emite JSON estructurado (en vez de texto plano) es más fácil de indexar y buscar en herramientas como Datadog, CloudWatch o similares.

Ventana de terminal
pnpm add pino pino-http
import pinoHttp from "pino-http"
app.use(pinoHttp())
{
"level": 30,
"time": 1723800000,
"req": { "method": "GET", "url": "/usuarios" },
"res": { "statusCode": 200 },
"responseTime": 12
}

pino es uno de los loggers más rápidos del ecosistema Node (diseñado para agregar el mínimo overhead posible) y emite JSON por defecto — el formato que la mayoría de las plataformas de observabilidad esperan.

Loguear dentro de la lógica de negocio, no solo requests

Sección titulada «Loguear dentro de la lógica de negocio, no solo requests»

morgan/pino-http loguean automáticamente cada request — pero eventos de negocio (un pago procesado, un usuario eliminado) necesitan su propio log explícito, en el lugar donde pasan:

import { logger } from "./lib/logger"
// instancia de pino, configurada una vez
async function eliminarUsuario(id: string) {
await prisma.user.delete({ where: { id } })
logger.info({ userId: id }, "Usuario eliminado")
}
HerramientaPara qué
morgan('dev')Log de cada request, formato legible, desarrollo
morgan('combined')Formato más completo, estilo Apache, producción
pino + pino-httpJSON estructurado, alto rendimiento, para observabilidad real
Logs propios en la lógica de negocioEventos que importan más allá de “llegó una request”
  • Loguear el body completo de cada request (incluyendo passwords, tokens, datos de tarjetas) es un riesgo de seguridad — cualquier logging automático debería excluir explícitamente campos sensibles.
  • console.log a secas funciona para desarrollo local, pero no estructura nada ni tiene niveles (info/warn/error) — no reemplaza un logger real en producción.