簡體   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