Registro con Pino
Configura Pino a través de Fastify para obtener registros JSON estructurados con contexto de solicitud y rendimiento listo para producción.
Receta
Tarjeta de receta de referencia rápida: lista para copiar y pegar.
import Fastify from "fastify";
const app = Fastify({
logger: {
level: process.env.LOG_LEVEL ?? "info",
redact: ["req.headers.authorization", "req.body.password"],
serializers: {
req(req) {
return { method: req.method, url: req.url, id: req.id };
},
},
},
});
app.get("/users", async (req) => {
req.log.info({ action: "list_users" });
return [];
});Cuándo usar esto: En cada servicio de Fastify. Pino es la opción predeterminada y la correcta para el registro JSON en producción.
Ejemplo funcional
import Fastify from "fastify";
const app = Fastify({
logger: {
level: "info",
timestamp: () => `,"time":"${new Date().toISOString()}"`,
redact: {
paths: ["req.headers.authorization", "req.headers.cookie", "body.password"],
censor: "[REDACTED]",
},
},
genReqId: (req) => req.headers["x-request-id"] as string ?? crypto.randomUUID(),
requestIdLogLabel: "requestId",
});
app.addHook("onRequest", async (req) => {
req.log.info({ event: "request_start" });
});
app.addHook("onResponse", async (req, reply) => {
req.log.info({
event: "request_complete",
statusCode: reply.statusCode,
responseTime: reply.elapsedTime,
});
});
app.get("/users/:id", async (req) => {
req.log.info({ userId: req.params.id, action: "get_user" });
return { id: (req.params as { id: string }).id };
});Lo que esto demuestra:
- Registros JSON estructurados con propagación de ID de solicitud
- Redacción de encabezados y campos de cuerpo sensibles
- Registro del ciclo de vida de la solicitud a través de hooks
reply.elapsedTimepara el tiempo de respuesta
Análisis profundo
Cómo funciona
- Pino escribe líneas JSON en stdout (un registro por línea)
req.loges un registrador hijo vinculado al ID de la solicitud- Pino es asíncrono: serializa en un hilo de trabajador (impacto mínimo en el hilo principal)
- Los agregadores de registros (Datadog, Loki, CloudWatch) analizan las líneas JSON de forma nativa
Niveles de registro
| Nivel | Usar para |
|---|---|
fatal | El proceso es inutilizable |
error | Errores manejados, operaciones fallidas |
warn | Estado degradado, reintentos |
info | Ciclo de vida de la solicitud, eventos de negocio |
debug | Diagnóstico de desarrollo |
trace | Internos detallados |
Impresión bonita para desarrollo
const app = Fastify({
logger: {
transport: process.env.NODE_ENV === "development"
? { target: "pino-pretty", options: { colorize: true } }
: undefined,
},
});Nunca uses pino-pretty en producción. Bloquea el hilo principal.
Errores comunes
- Registrar
req.bodycompleto - Información de identificación personal (PII) en el almacenamiento de registros. Solución: redactar rutas; registrar solo los campos necesarios. pino-prettyen producción - mata el rendimiento y bloquea el bucle de eventos. Solución: JSON a stdout solamente.- ID de solicitud faltante - no se pueden correlacionar los registros entre servicios. Solución:
genReqIddesde el encabezadox-request-id. console.logjunto con Pino - registros no estructurados mezclados con JSON. Solución: prohibirconsole.logen las reglas de lint.- Registro dentro de bucles cerrados - el volumen de registros explota. Solución: muestrear o agregar.
- No registrar el contexto de error -
log.error(err)sin el serializadorerrpierde la pila. Solución:req.log.error({ err }, "mensaje").
Alternativas
| Alternativa | Cuándo usar | Cuándo NO usar |
|---|---|---|
| Pino independiente | Aplicación Express o Node pura | Ya en Fastify (integrado) |
| Winston | Mandato del equipo para transportes de Winston | Fastify nuevo (Pino es más rápido) |
| Registros de OpenTelemetry | Trazas + registros + métricas unificadas | API simple que solo necesita registros de solicitud |
| morgan (Express) | Solo registros de acceso de Express | Proyecto Fastify |
Preguntas frecuentes
¿Por qué Fastify usa Pino por defecto?
Pino es el registrador JSON de Node más rápido. Se alinea con el enfoque de rendimiento de Fastify y produce registros estructurados sin configuración.
¿Cómo añado el ID de usuario a cada registro?
En un hook onRequest después de la autenticación: req.log = req.log.child({ userId: req.user.id }).
¿Puedo enviar registros a Datadog?
Registra JSON en stdout; usa el agente de Datadog para recopilar registros de contenedores. O usa pino-datadog-transport (añade latencia).
¿Cómo se relaciona esto con AsyncLocalStorage?
El ID de solicitud a través de genReqId cubre el contexto HTTP. Para trabajadores no HTTP, usa AsyncLocalStorage. Consulta AsyncLocalStorage para el contexto.
¿Debo registrar los cuerpos de las solicitudes?
Solo en desarrollo, con redacción. Producción: registra el método, la ruta, el estado, la duración y el ID de la solicitud.
¿Cómo silencio los registros de verificación de estado?
disableRequestLogging personalizado por ruta o filtrar en onResponse cuando la ruta es /health.
¿NestJS usa Pino?
A través del paquete nestjs-pino. El adaptador de Fastify se integra de forma natural.
¿Qué pasa con la correlación con los servicios descendentes?
Reenvía x-request-id en las llamadas HTTP salientes. Registra el mismo ID en ambos servicios.
Relacionado
- Conceptos básicos de registro - principios de registro estructurado
- ID de correlación de solicitudes - trazado distribuido
- Redacción y cumplimiento de PII - reglas de redacción
- Conceptos básicos de Fastify - configuración del registrador
- Mejores prácticas de Fastify - lista de verificación de la sección
Versiones de la pila: Esta página fue escrita para Node.js 24.18.0 (LTS activa), npm 10+, TypeScript 5.6+, Express 5, Fastify 5 y NestJS 11.