← 中文资源

简体中文版本

在日志中传递请求 ID

生成或接受可校验的请求 ID,把它附加到每条日志和响应,并传递到下游调用,从而端到端追踪一次用户操作。

阅读英文原文

一个 ID 贯穿所有层

目标是:用户报告错误后,一次搜索就能找到请求、下游调用和相关日志。为此需要在入口生成或接受 ID,存入请求上下文,返回给客户端,并转发给下游。

app.use((req, res, next) => {
  const id = safeRequestId(req.get('x-request-id')) ?? randomUUID();
  res.set('x-request-id', id);
  storage.run({ requestId: id }, next);
});

app.get('/orders', async (req, res) => {
  const { requestId } = storage.getStore();
  logger.info({ requestId, path: req.path }, 'handling request');
  res.json({ ok: true });
});

步骤

  1. 接受 W3C traceparent 或经过校验的 x-request-id,否则生成 UUID;拒绝包含控制字符或超长的值。
  2. 用 AsyncLocalStorage 或框架请求上下文保存 ID,并在响应头返回。
  3. 输出结构化日志,包含 requestId、方法、路径、状态码和耗时;不要记录 Authorization 头或含密钥的请求体。
  4. 把 ID 转发给出站 HTTP 调用,并在错误响应中包含它;发送请求后通过返回的 ID 搜索日志验证。

验证

  • 响应包含 x-request-id。
  • 该请求的所有日志行包含相同 ID。
  • 出站调用收到该 ID。
  • 非法或超长的入站 ID 被替换,而不是被信任。
  • 错误响应包含 ID,便于用户报告。

常见陷阱

模块级变量会在并发请求之间泄漏 ID。记录完整头或请求体可能暴露凭据。把请求 ID 用作指标标签会造成无界基数。ID 应保持不透明、长度受限,并与认证信息分离。