Busca en todas las páginas de la documentación
Structured logging and correlation IDs make Node services debuggable in production without SSH and grep of unstructured strings.
Quick-reference recipe card - copy-paste ready.
import pino from "pino";
import { randomUUID } from "node:crypto";
export const logger = pino({ level: process.env.LOG_LEVEL ?? "info" });
app.use((req, res, next) => {
const requestId = req.headers["x-request-id"]?.toString() ?? randomUUID();
res.setHeader("X-Request-Id", requestId);
req.log = logger.child({ requestId });
next();
});When to reach for this:
// src/logging/logger.ts
import pino from "pino";
export const rootLogger = pino({
level: process.env.LOG_LEVEL ?? "info",
redact: ["req.headers.authorization", "password", "creditCard"],
});
export type AppLogger// src/middleware/request-context.ts
import { randomUUID } from "node:crypto";
import type { Request, Response, NextFunction } from "express";
import { rootLogger } from "../logging/logger.js";
declare global {
namespace Express {
interface Request {
log:
// src/services/billing.ts
export async function charge(log: AppLogger, customerId: string, cents: number) {
log.info({ customerId, cents }, "charge started");
// ...
log.info({ customerId }, "charge completed");
What this demonstrates:
X-Request-Id respected; generated if absent.requestId through service layer.error for failures needing action, warn for degraded, info for request lifecycle, debug dev-only.| Field | Source |
|---|---|
requestId | Header or UUID |
level | Pino default |
msg | Human-readable event |
time | ISO timestamp automatic |
service | name in logger config |
req.log augmentation for Express; Fastify uses built-in req.log with pino integration.req.body - log ids and action names only.no-console in src/.requestId in job payload from HTTP handler.LOG_LEVEL=info default; debug via dynamic toggle with expiry.| Alternative | Use When | Don't Use When |
|---|---|---|
| OpenTelemetry traces | Full distributed tracing | Tiny single service MVP |
| Winston | Team legacy standard | Greenfield (Pino faster on Node) |
| AsyncLocalStorage context | Implicit requestId without req.log | Simple Express apps (middleware enough) |
No, but JSON structured logging is required. Pino is the common Node 24 choice; Fastify integrates natively.
await fetch(url, { headers: { "X-Request-Id": requestId } });Use nestjs-pino or OTel; same correlation header rules apply.
Yes in error logs server-side; never return stacks to API clients in production.
Sample debug/info on high-RPS health checks; never sample error logs.
Same JSON schema with jobId and requestId fields for trace join.
Metrics for SLO dashboards; logs for incident debugging. Both required for mature ops.
Org policy; typically 30-90 days hot, longer cold archive for audit domains.
Yes in Kubernetes - collectors scrape stdout; no file rotation in container.
Do not log every /health at info in prod; use debug or exclude path in middleware.
Stack versions: This page was written for Node.js 24.18.0 (Active LTS), npm 10+, TypeScript 5.6+, Express 5, Fastify 5, and NestJS 11.