给 FastAPI 加上请求 ID:让一次请求的日志串起来

举报
yd_297598480 发表于 2026/11/02 10:05:14 2026/11/02
【摘要】 用 FastAPI 中间件和 ContextVar 为请求生成 ID,并将其写入日志与响应头,快速关联一次请求的记录。

背景:排查一次请求为什么要翻很多日志?

线上出现超时或 500 错误时,日志常分散在入口、中间件和业务代码里。只按时间或用户搜索,容易把并发请求的记录混在一起。给每个 HTTP 请求分配一个 request ID,并将它写入日志和响应头,排查时就有了稳定的检索键。

本文使用 FastAPI HTTP 中间件生成请求 ID,用 ContextVar 在异步请求处理过程中传递它,再通过日志过滤器把 ID 加到日志记录里。FastAPI 官方文档的 Middleware 教程介绍了使用 @app.middleware(“http”) 编写请求前后的处理逻辑。

一、完整示例

import logging
from contextvars import ContextVar
from uuid import uuid4

from fastapi import FastAPI, Request

request_id_var = ContextVar("request_id", default="-")

class RequestIdFilter(logging.Filter):
    def filter(self, record: logging.LogRecord) -> bool:
        record.request_id = request_id_var.get()
        return True

logger = logging.getLogger("api")
logger.setLevel(logging.INFO)
logger.propagate = False
handler = logging.StreamHandler()
handler.addFilter(RequestIdFilter())
handler.setFormatter(logging.Formatter(
    "%(asctime)s %(levelname)s request_id=%(request_id)s %(message)s"
))
logger.addHandler(handler)

app = FastAPI()

@app.middleware("http")
async def attach_request_id(request: Request, call_next):
    # 由服务端生成 ID,避免把任意外部输入直接写入日志。
    request_id = uuid4().hex
    token = request_id_var.set(request_id)
    try:
        response = await call_next(request)
        response.headers["X-Request-ID"] = request_id
        return response
    finally:
        # 请求结束后恢复上下文,避免后续任务读到旧值。
        request_id_var.reset(token)

@app.get("/ping")
async def ping():
    logger.info("health check")
    return {"ok": True}

将代码保存为 Python 源文件。在本地开发环境安装并启动:

python -m pip install fastapi uvicorn
uvicorn main:app --reload

–reload 仅用于本地开发。

启动应用后执行以下命令,在响应头中查看 X-Request-ID,并确认终端日志包含相同的 request_id。连续请求两次会得到不同 ID;排查单次请求时,可复制响应头中的值搜索相关日志。

curl -i http://127.0.0.1:8000/ping

二、实现时要留意的细节

  1. 在 finally 中恢复上下文。 ContextVar 适合在异步调用链中保存请求范围的数据,但仍应在请求结束后恢复 token,避免上下文泄漏。
  2. 不要把 ID 当作身份凭据。 示例每次都由服务端生成随机 ID,它只用于关联记录,不能用于鉴权或证明请求来自可信用户。
  3. 需要跨服务追踪时制定信任边界。 如果网关已经生成并传入 ID,可以只在可信代理后接受请求头;对公网客户端提供的值应做长度和字符校验,或重新生成。跨多个服务的分布式追踪还应考虑标准化的 trace context 与 OpenTelemetry。
  4. 避免把敏感信息放进 ID。 ID 会进入响应和日志,应使用随机标识,不要包含手机号、邮箱、令牌或业务机密。
  5. 后台任务要显式传递关联信息。 请求上下文会在请求处理结束时恢复。如果任务在请求结束后运行,可将 request ID 作为任务参数写入消息,不要依赖请求上下文。

请求 ID 不能代替分布式追踪,但能为小型 API 提供轻量的日志关联方式。先让同一次请求的日志连起来,再根据系统规模逐步加入 trace、span 和结构化日志。

参考资料:FastAPI 官方文档《Middleware》教程。

【版权声明】本文为华为云社区用户原创内容,未经允许不得转载,如需转载请自行联系原作者进行授权。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。