pino
Usa Pino para un registro JSON estructurado rápido en Node.js: loggers hijos para el contexto de la solicitud, redacción para secretos y un impacto mínimo en el bucle de eventos.
Busca en todas las páginas de la documentación
Usa Pino para un registro JSON estructurado rápido en Node.js: loggers hijos para el contexto de la solicitud, redacción para secretos y un impacto mínimo en el bucle de eventos.
Tarjeta de receta de referencia rápida: lista para copiar y pegar.
import pino from "pino";
export const logger = pino({
level: process.env.LOG_LEVEL ?? "info",
redact: ["req.headers.authorization", "password"],
});
logger.info({ orderId: "o_1" }, "order created");Cuándo usarlo:
console.log para pipelines JSON.req por cada función.import pino from "pino";
import express from "express";
import { randomUUID } from "node:crypto";
const logger = pino({
level: process.env.LOG_LEVEL ?? "info",
base: { service: "billing-api" },
redact: {
paths: ["req.headers.authorization", "req.headers.cookie", "body.cardNumber"],
censor: "[REDACTED]",
},
timestamp: pino.stdTimeFunctions.isoTime,
});
const app = express();
app.use(express.json());
app.use((req, res, next) => {
const requestId = (req.headers["x-request-id"] as string) ?? randomUUID();
const start = process.hrtime.bigint();
(req as express.Request & { log: pino.Logger }).log = logger.child({ requestId });
res.on("finish", () => {
req.log.info({
event: "request_complete",
method: req.method,
path: req.path,
statusCode: res.statusCode,
durationMs: Number(process.hrtime.bigint() - start) / 1e6,
});
});
next();
});
app.post("/charges", async (req, res) => {
req.log.info({ amount: req.body.amount }, "charge started");
try {
const result = await processCharge(req.body);
req.log.info({ chargeId: result.id }, "charge succeeded");
res.status(201).json(result);
} catch (err) {
req.log.error({ err }, "charge failed");
res.status(500).json({ error: "Internal Server Error" });
}
});
async function processCharge(body: { amount: number }) {
return { id: "ch_1", amount: body.amount };
}
app.listen(3000);Lo que esto demuestra:
base y marcas de tiempo ISO.requestId.finish registra la duración y el estado sin bloquear la respuesta.{ err } antes de la respuesta genérica 5xx.| Opción | Propósito |
|---|---|
level | Nivel mínimo emitido |
base | Campos en cada línea (pid, hostname pueden omitirse con base: null) |
redact | Rutas a censurar |
serializers | Formas personalizadas de req, res, err |
transport | Impresión bonita solo para desarrollo |
const logger = pino({
transport: process.env.NODE_ENV === "development"
? { target: "pino-pretty", options: { colorize: true } }
: undefined,
});pino-pretty en producción - bloquea el hilo principal.npm install nestjs-pino// app.module.ts
import { LoggerModule } from "nestjs-pino";
@Module({
imports: [LoggerModule.forRoot({ pinoHttp: { level: "info" } })],
})
export class AppModule {}req y res completos - líneas enormes, riesgo de PII. Solución: serializadores personalizados con solo método, url, estado.pino-pretty en producción - colapso del rendimiento. Solución: JSON a stdout; bonito solo localmente.pino.destination({ sync: true }) bloquea. Solución: destino asíncrono predeterminado.log.error("msg", err) firma incorrecta. Solución: log.error({ err }, "msg").LOG_LEVEL=info en producción; muestrear depuración.| Alternativa | Usar cuándo | No usar cuándo |
|---|---|---|
| Pino | Registro JSON de producción en Node | El equipo solo exige transportes de Winston |
| Winston | Aplicaciones heredadas con muchos transportes personalizados | Fastify nuevo (Pino integrado) |
| Bunyan | Mantener servicios antiguos | Proyectos nuevos |
| Logs de OpenTelemetry | Trazas + logs unificados | API simple que solo necesita logs de solicitud |
Mínima asignación, vaciado asíncrono y sin formato pesado predeterminado. Los benchmarks importan más por encima de ~1k logs/seg.
pino.destination({ dest: 1, sync: true }) a stdout en pruebas, o pino-test para captura.
Fastify incrusta Pino. Configúralo a través de logger: { level, redact } en el constructor.
Prefiere stdout + sidecar de agente. pino-datadog-transport añade latencia y otro punto de fallo.
Publica mensajes al padre o crea un logger hijo con workerId en base. AsyncLocalStorage no cruza hilos.
Las plataformas de contenedores recopilan stdout - no se necesita rotación de archivos. VMs: usa journald o agente de logs, no pino-roll en la aplicación.
Complementarios. Pino para eventos; OTel para trazas y métricas. Correlaciona con trace_id compartido.
Omite el registro en el middleware cuando req.path === "/health" o registra en depuración con filtro de agregació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.
Revisado por Chris St. John·Última actualización: 19 jul 2026