pino
Use o Pino para logging rápido de JSON estruturado em Node.js - child loggers para contexto de requisição, redação para segredos e impacto mínimo na event loop.
Busque em todas as páginas da documentação
Use o Pino para logging rápido de JSON estruturado em Node.js - child loggers para contexto de requisição, redação para segredos e impacto mínimo na event loop.
Cartão de receita de referência rápida - pronto para copiar e colar.
import pino from "pino";
export const logger = pino({
level: process.env.LOG_LEVEL ?? "info",
redact: ["req.headers.authorization", "password"],
});
logger.info({ orderId: "o_1" }, "pedido criado");Quando usar isso:
console.log para pipelines JSON.req por todas as funções.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 }, "início da cobrança");
try {
const result = await processCharge(req.body);
req.log.info({ chargeId: result.id }, "cobrança bem-sucedida");
res.status(201).json(result);
} catch (err) {
req.log.error({ err }, "falha na cobrança");
res.status(500).json({ error: "Internal Server Error" });
}
});
async function processCharge(body: { amount: number }) {
return { id: "ch_1", amount: body.amount };
}
app.listen(3000);O que isso demonstra:
base e timestamps ISO.requestId.finish registra a duração e o status sem bloquear a resposta.{ err } antes da resposta genérica 5xx.| Opção | Propósito |
|---|---|
level | Nível mínimo emitido |
base | Campos em cada linha (pid, hostname podem ser omitidos com base: null) |
redact | Caminhos a serem censurados |
serializers | Formas personalizadas de req, res, err |
transport | Impressão bonita apenas para desenvolvimento |
const logger = pino({
transport: process.env.NODE_ENV === "development"
? { target: "pino-pretty", options: { colorize: true } }
: undefined,
});pino-pretty em produção - bloqueia a thread principal.npm install nestjs-pino// app.module.ts
import { LoggerModule } from "nestjs-pino";
@Module({
imports: [LoggerModule.forRoot({ pinoHttp: { level: "info" } })],
})
export class AppModule {}req e res completos - linhas enormes, risco de PII. Correção: serializadores personalizados apenas com método, url, status.pino.destination({ sync: true }) bloqueia. Correção: destino assíncrono padrão.err ausente - log.error("msg", err) assinatura incorreta. Correção: log.error({ err }, "msg").LOG_LEVEL=info em produção; amostrar debug.requestId em camadas profundas. Correção: AsyncLocalStorage ou parâmetro explícito.| Alternativa | Usar Quando | Não Usar Quando |
|---|---|---|
| Pino | Logging JSON em produção no Node | Mandato da equipe apenas para transports Winston |
| Winston | Aplicações legadas com muitos transports personalizados | Fastify novo (Pino integrado) |
| Bunyan | Manutenção de serviços mais antigos | Novos projetos |
| OpenTelemetry logs | Traces + logs unificados | API simples que precisa apenas de logs de requisição |
Alocação mínima, flush assíncrono e nenhuma formatação pesada por padrão. Benchmarks importam mais acima de ~1k logs/segundo.
pino.destination({ dest: 1, sync: true }) para stdout em testes, ou pino-test para captura.
O Fastify incorpora o Pino. Configure via logger: { level, redact } no construtor.
Prefira stdout + agente sidecar. pino-datadog-transport adiciona latência e outro ponto de falha.
Envie mensagens para o pai ou crie um child logger com workerId em base. AsyncLocalStorage não cruza threads.
Plataformas de contêiner coletam stdout - nenhuma rotação de arquivo é necessária. VMs: use journald ou agente de log, não pino-roll no aplicativo.
Complementares. Pino para eventos; OTel para traces e métricas. Correlacione com trace_id compartilhado.
Pule o logging no middleware quando req.path === "/health" ou registre em debug com filtro de agregação.
requestIdVersões de Stack: Esta página foi escrita para Node.js 24.18.0 (Active LTS), npm 10+, TypeScript 5.6+, Express 5, Fastify 5 e NestJS 11.
Revisado por Chris St. John·Última atualização: 19 de jul. de 2026