AsyncLocalStorage Correlation Logging

Tag every log line with a request correlation id using AsyncLocalStorage, letting deeply nested async code log without passing context.

TypescriptNodeResilience

Code

snippet
import { AsyncLocalStorage } from 'node:async_hooks';
import pino from 'pino';

interface RequestScope {
  requestId: string;
  userId?: string;
}

const storage = new AsyncLocalStorage<RequestScope>();

const logger = pino({
  level: 'info',
  mixin: () => {
    const scope = storage.getStore();
    return scope ? { requestId: scope.requestId, userId: scope.userId } : {};
  },
});

async function chargeCard(orderId: string) {
  logger.info({ orderId }, 'charging card'); // 自动带上请求上下文
  await new Promise((r) => setTimeout(r, 10));
}

async function handleCheckout(req) {
  await chargeCard('ord-5');
  await refundIfDuplicate('ord-5');
}

async function refundIfDuplicate(orderId: string) {
  logger.warn({ orderId }, 'duplicate detected');
}


async function entry(request) {
  const scope: RequestScope = {
    requestId: request.headers['x-request-id'] ?? crypto.randomUUID(),
    userId: request.headers['x-user-id'],
  };

  // 后续整条异步链路都在同一 scope 内执行
  return storage.run(scope, () => handleCheckout(request));
}

await entry({ headers: {} });