fastapi日志全链路追踪

fastapi 协程方式运行,日志无法通过线程号区分请求,使用 contextvars 管理一个 request-id 上下文带入日志。这里日志模块用的 loguru。

1. 在全局位置声明

import contextvars  # noqa

request_id_context = contextvars.ContextVar("request-id", default="-")
request_id_context.set("-")

2. 添加一个中间件,在处理请求前生成一个 uuid 赋值给 request_id_context,处理过之后再恢复默认

@app.middleware("http")
async def extra_process(request: Request, call_next):
    start_time = time.time()
    request_id = uuid.uuid4().hex
    request_id_context.set(request_id)
    response: Response = await call_next(request)
    ptime = time.time() - start_time
    logger.info(f"process time [{ptime}s]: {response.status_code}-{request.url}")
    request_id_context.set("-")
    return response

3. 把该 request-id 加进日志信息里

def _filter(record):
    record["extra"] = {"traceid": request_id_context.get("request-id")}
    return True


# 日志简单配置
logger.add(
    log_sink, rotation="50 MB", enqueue=True, level="INFO", encoding="utf-8",
    format=("<green>{time:YYYY-MM-DD HH:mm:ss.SSS}</green> | "
            "<level>{level: <8}</level> | "
            "<level>{extra[traceid]: <32}</level> | "
            "<cyan>{name}</cyan>:<cyan>{function}</cyan>:<cyan>{line}</cyan> - <level>{message}</level>"),
    filter=_filter
)

4. 至此会有一个问题,contextvars 线程隔离,对于使用 loop.run_in_executor 包过的使用线程池执行的方法中的日志访问不到第1步声明的这个上下文,需要重新定义一下线程池。这里用的Python3.8版本,Python3.9好像有更简单的解决方案,可参考 fastapi_issues_2776

class ContextSafeThreadPoolExecutor(ThreadPoolExecutor):

    def submit(self, fn: Callable, *args, **kwargs):
        ctx = contextvars.copy_context()
        return super().submit(partial(ctx.run, partial(fn, *args, **kwargs)))


def sync_to_async(func: Callable) -> Callable:
    """
    将同步函数转换成异步,协程使用
    :param func: 同步函数
    :return: 异步函数
    """

    @wraps(func)
    async def run_in_executor(*args, **kwargs):
        loop = asyncio.get_event_loop()
        p_func = partial(func, *args, **kwargs)
        return await loop.run_in_executor(ContextSafeThreadPoolExecutor(), p_func)

    return run_in_executor

参考:

FastAPI 全链路日志追踪

Context vars set in an async dependency are visible for sync routes but not for sync functions run inside ThreadPoolExecutor · Issue #2776 · tiangolo/fastapi · GitHub

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下为 FastAPI套教程: 1. FastAPI 简介 FastAPI 是一个现代化的 Python Web 框架,它使用了 Python 3.6+ 的新特性,如类型注释、异步和协程等。它提供了高性能、易于使用和易于扩展的 API 开发体验。 FastAPI 的主要特点: - 快速:FastAPI 有着非常快的性能,可以达到甚至超过其他 Python Web 框架的速度。 - 易于使用:FastAPIAPI 代码可读性非常高,开发者可以快速理解和使用。 - 自动文档:FastAPI 自动生成 API 文档,并支持交互式 API 文档界面。 - 异步支持:FastAPI 内置支持异步和协程,可以实现非阻塞 IO 和高并发。 - 安性:FastAPI 内置了安性功能,包括数据验证、身份验证和授权等。 2. 安装 FastAPI 安装 FastAPI 的最简单方法是使用 pip 包管理器: ```bash pip install fastapi ``` 安装完成后,您可以使用以下命令来检查 FastAPI 的版本: ```bash pip show fastapi ``` 3. 第一个 FastAPI 应用程序 创建一个名为 "main.py" 的文件,在其中编写以下代码: ```python from fastapi import FastAPI app = FastAPI() @app.get("/") def read_root(): return {"Hello": "World"} ``` 运行该应用程序: ```bash uvicorn main:app --reload ``` 打开浏览器,输入 http://localhost:8000,您将看到以下输出: ```json {"Hello": "World"} ``` 4. 定义请求参数 FastAPI 支持多种类型的请求参数,包括路径参数、查询参数、请求体等。以下是一个示例: ```python from fastapi import FastAPI app = FastAPI() @app.get("/items/{item_id}") def read_item(item_id: int, q: str = None): return {"item_id": item_id, "q": q} ``` 使用以下 URL 来测试该应用程序: ``` http://localhost:8000/items/42?q=test ``` 您将看到以下输出: ```json {"item_id": 42, "q": "test"} ``` 5. 定义响应模型 FastAPI 可以自动将响应数据转换为指定的模型类。以下是一个示例: ```python from fastapi import FastAPI from pydantic import BaseModel class Item(BaseModel): name: str price: float is_offer: bool = None app = FastAPI() @app.post("/items/") async def create_item(item: Item): return item ``` 使用以下命令来测试该应用程序: ```bash curl -X POST "http://localhost:8000/items/" \ -H "accept: application/json" \ -H "Content-Type: application/json" \ -d '{"name":"test item","price":9.99}' ``` 您将看到以下输出: ```json {"name": "test item", "price": 9.99, "is_offer": null} ``` 6. 自动文档 FastAPI 可以自动生成 API 文档,并支持交互式 API 文档界面。只需在浏览器中打开以下 URL 即可: ``` http://localhost:8000/docs ``` 您将看到自动生成的文档和交互式界面。 7. 部署 FastAPI 应用程序 FastAPI 应用程序可以通过多种方式部署,包括使用服务器软件(如 Nginx、Apache)、使用容器技术(如 Docker)等。 以下是使用 Docker 部署 FastAPI 应用程序的示例: 创建一个名为 "Dockerfile" 的文件,包含以下内容: ```dockerfile FROM tiangolo/uvicorn-gunicorn-fastapi:python3.8 COPY ./app /app ``` 在同一目录下创建一个名为 "app" 的目录,将 "main.py" 文件放在其中。 构建 Docker 镜像: ```bash docker build -t fastapi-app . ``` 运行 Docker 容器: ```bash docker run -d --name fastapi-container -p 8000:80 fastapi-app ``` 现在,您可以使用以下 URL 来访问 FastAPI 应用程序: ``` http://localhost:8000 ``` 以上就是 FastAPI套教程,希望对您有所帮助。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值