繁体   English   中英

在 Python FastAPI 中根据 API 请求记录 UUID

[英]Logging UUID per API request in Python FastAPI

我有一个纯 python 包(我们称它为 main),它具有一些用于管理基础结构的功能。 此外,我还创建了一个 FastAPI 服务,可以根据需要调用主模块来调用功能。

对于日志记录,我正在使用loguru 启动时的 API 创建一个 loguru 实例,应用设置并设置通用 UUID(即 [main])。 对于 API 的每个传入请求,pre_request function 都会生成一个新的 UUID 并调用 loguru 以使用该 UUID 进行配置。 在请求结束时,UUID 被设置回默认 UUID [main]。

我面临的问题是并发请求,新的 UUID 接管并且所有日志现在都使用最新配置的 UUID 写入。 有没有一种方法可以在每个请求上实例化 loguru 模块,并确保并行处理的 API 请求不会发生交叉日志记录?

执行:

在主package的 init.py 中:

from loguru import logger 
logger.remove() #to delete all existing default loggers 
logger.add(filename, format, level, retention, rotation)  #format
logger.configure(extra={"uuid": "main"}) 

在所有模块中,记录器被导入为

from loguru import logger 

在 api/ package - 在每个新请求中,我都有下面的代码块:

uuid = get_uuid() #calling util func to get a new uuid
logger.configure(uuid=uuid) 
# Here onwards, all log messages contain this uuid 
# At the end of the request, I configure it back to default uuid (i.e. "main") 

配置方法正在更新根记录器,我尝试使用绑定方法,根据 loguru 文档,它可用于将额外的记录属性上下文化,但它似乎没有任何效果(我仍然看到默认的 UUID,即“主要”,仅当我使用.configure UUID 设置时)。

关于我 go 应该如何设置 UUID 的任何想法,以便对 API 的所有并发请求都有自己的 UUID? 由于有多个子模块被调用来为一个 API 请求提供服务,并且所有子模块都有一些登录信息,因此我需要 UUID 为每个请求的所有模块保留。 似乎我需要每个 API 请求都有一个记录器实例,但我不确定如何正确实例化它以使其工作。

如果 API 正在服务一个请求,则当前实现有效,但在服务超过 1 个调用时记录中断(因为记录的 UUID 是配置的最后一个)

我创建了这个中间件,它在路由调用之前使用上下文管理器的用户使用 UUID 配置记录器实例:

from loguru import logger
from contextvars import ContextVar
from starlette.middleware.base import BaseHTTPMiddleware

_request_id = ContextVar("request_id", default=None)


def get_request_id():
    return _request_id.get()

class ContextualizeRequest(BaseHTTPMiddleware):
    async def dispatch(self, request, call_next):
        uuid = get_uuid()
        request_id = _request_id.set(uuid)  # set uuid to context variable
        with logger.contextualize(uuid=get_request_id()):
            try:
                response = await call_next(request)
            except Exception:
                logger.error("Request failed")
            finally:
                _request_id.reset()
                return response

唯一需要注意的是,如果您使用多线程、多处理或创建新的事件循环(在内部调用中),该块中的记录器实例将没有此 UUID。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM