Node.js cookbook · Beginner
Structured logging with request IDs in Node.js
Produce fast JSON logs where every line from a request carries the same request ID.
Approach
Use pino with pino-http to log requests and attach a child logger (req.log) containing the request ID. Store the ID in AsyncLocalStorage so code deep in services can log with context without passing req around. Redact secrets.
Solution
import { AsyncLocalStorage } from "node:async_hooks";
import { randomUUID } from "node:crypto";
import pino from "pino";
import { pinoHttp } from "pino-http";
export const logger = pino({
level: process.env.LOG_LEVEL ?? "info",
redact: ["req.headers.authorization", "req.headers.cookie", "*.password"],
});
const context = new AsyncLocalStorage<{ requestId: string }>();
app.use(pinoHttp({
logger,
genReqId: (req, res) => {
const incoming = req.headers["x-request-id"];
const id = typeof incoming === "string" && /^[\w-]{8,64}$/.test(incoming) ? incoming : randomUUID();
res.setHeader("X-Request-ID", id);
return id;
},
autoLogging: { ignore: (req) => req.url === "/healthz" },
}));
app.use((req, _res, next) => context.run({ requestId: String(req.id) }, next));
// Anywhere in the call stack:
export function log() {
const store = context.getStore();
return store ? logger.child({ requestId: store.requestId }) : logger;
}
// log().info({ orderId }, "order placed");
Pitfalls
console.logwith string concatenation in production.- Synchronous, pretty logging in production (use pino-pretty only locally).
- Logging tokens and cookies.
Variations
- OpenTelemetry's pino instrumentation adds trace IDs automatically.
Further reading: pino API
Reference: https://getpino.io/#/docs/api
More Node.js recipes
- Add health and readiness endpoints to a Node.js service
- Add JWT authentication to an Express API
- Cache expensive lookups in Redis from Node.js
- Call external APIs with timeouts and retries in Node.js
- Centralize error handling in Express 5
- Hash passwords and implement login safely in Node.js
- Implement cursor pagination with PostgreSQL in Node.js
- Offload CPU-heavy work with worker threads