javascript 50 lines · 8 steps

Per-request logging context in Express

Use AsyncLocalStorage to thread a request ID through every log line without passing it around.

Explained by highlit
1const express = require('express');
2const { AsyncLocalStorage } = require('async_hooks');
3const { randomUUID } = require('crypto');
4 
5const requestContext = new AsyncLocalStorage();
6 
7function getRequestId() {
8 const store = requestContext.getStore();
9 return store ? store.requestId : undefined;
10}
11 
12function log(level, message, meta = {}) {
13 const entry = {
14 timestamp: new Date().toISOString(),
15 level,
16 requestId: getRequestId(),
17 message,
18 ...meta,
19 };
20 process.stdout.write(JSON.stringify(entry) + '\n');
21}
22 
23function requestContextMiddleware(req, res, next) {
24 const requestId = req.get('x-request-id') || randomUUID();
25 res.setHeader('x-request-id', requestId);
26 
27 requestContext.run({ requestId }, () => {
28 const startedAt = process.hrtime.bigint();
29 
30 log('info', 'request received', {
31 method: req.method,
32 path: req.originalUrl,
33 ip: req.ip,
34 });
35 
36 res.on('finish', () => {
37 const durationMs = Number(process.hrtime.bigint() - startedAt) / 1e6;
38 log('info', 'request completed', {
39 method: req.method,
40 path: req.originalUrl,
41 status: res.statusCode,
42 durationMs: Math.round(durationMs * 100) / 100,
43 });
44 });
45 
46 next();
47 });
48}
49 
50module.exports = { requestContextMiddleware, getRequestId, log };
01 / 01
STEP 01

Walkthrough

Space play step click any line
Three takeaways
  1. 1AsyncLocalStorage carries per-request state across async boundaries so deep code can read context without explicit argument plumbing.
  2. 2Wrapping the rest of the request in a single run() call scopes the store to exactly that request's async chain.
  3. 3Emitting structured JSON logs with a shared request ID makes correlating a request's lines trivial in aggregation tools.

Related explainers

Share this explainer

Here's the card — post it anywhere.

Per-request logging context in Express — share card
Made with highlit — turn any snippet into a walkthrough like this in about a minute.
Explain your code