Fastapi中利用中间件实现日志记录
FastAPI 的「中间件」机制让你能够在 不改动现有路由函数 的前提下,为每一次请求/响应统一地写日志。下面给出一份可直接落地的最小示例。
日志中间件代码封装
logger_config.py文件内容如下:
import logging
import os
import time
import uuid
from logging.handlers import RotatingFileHandler
from fastapi import Request
# 日志目录路径
LOG_DIR = "logs"
# 确保日志目录存在,如果不存在则创建
os.makedirs(LOG_DIR, exist_ok=True)
# 日志格式:时间 - 名称 - 级别 - 消息
LOG_FORMAT = "%(asctime)s - %(name)s - %(levelname)s - %(message)s"
# 创建FastAPI应用日志记录器
logger = logging.getLogger("fastapi_app")
# 设置日志记录级别为INFO
logger.setLevel(logging.INFO)
# 创建文件处理器,用于将日志写入文件
# 设置日志文件最大为10MB,保留5个备份文件
file_handler = RotatingFileHandler(
os.path.join(LOG_DIR, "app.log"),
maxBytes=10 * 1024 * 1024,
backupCount=5,
encoding="utf-8"
)
# 设置日志格式
file_handler.setFormatter(logging.Formatter(LOG_FORMAT))
# 将文件处理器添加到日志记录器
logger.addHandler(file_handler)
def make_logging_middleware():
"""
创建日志中间件函数,用于记录请求和响应信息
Returns:
返回一个异步中间件函数
"""
async def logging_middleware(request: Request, call_next):
# 记录请求开始时间
start = time.time()
# 获取请求ID,如果不存在则生成一个UUID的前8位
rid = request.headers.get("x-request-id") or str(uuid.uuid4())[:8]
# 获取客户端真实IP,如果不存在则使用客户端主机地址
real_ip = request.headers.get("x-real-ip") or request.client.host
# 获取用户代理信息
ua = request.headers.get("user-agent", "-")
# 获取查询参数,如果没有则使用"-"
query = str(request.query_params) if request.query_params else "-"
# 记录请求信息:请求方法、路径、查询参数、客户端IP、用户代理和请求ID
logger.info(f"→ {request.method} {request.url.path} - "
f"query:{query} - Client:{real_ip} - ua:{ua} - rid:{rid}")
# 调用下一个中间件或路由处理函数
response = await call_next(request)
# 计算请求处理耗时(毫秒)
duration = round((time.time() - start) * 1000, 2)
# 记录响应信息:请求方法、路径、状态码、处理耗时和请求ID
logger.info(f"← {request.method} {request.url.path} - "
f"Status:{response.status_code} - Duration:{duration}ms - rid:{rid}")
# 返回响应
return response
return logging_middleware
使用方法
main.py中使用中间件,代码内容如下:
from fastapi import FastAPI
from logger_config import make_logging_middleware # 引入中间件工厂
app = FastAPI()
# 注册日志中间件(零侵入业务路由)
app.middleware("http")(make_logging_middleware())
# -----------------------
# 以下为示例业务路由
# -----------------------
@app.get("/")
def read_root():
return {"Hello": "World"}
运行示例
# 开发
uvicorn main:app --reload
# 生产
uvicorn main:app --host 0.0.0.0 --port 8080 --workers 4
# 您可以在使用 fastapi 或 uvicorn 命令时,通过 --workers CLI 选项启用多个工作进程(workers),以充分利用多核 CPU,以并行运行多个进程。
时间仓促,如有错误欢迎指出,欢迎在评论区讨论,如对您有帮助还请点个推荐、关注支持一下
作者:莫颀
出处:https://www.cnblogs.com/bokemoqi/p/18985581
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须在文章页面给出原文链接,否则保留追究法律责任的权利。
若内容有侵犯您权益的地方,请公告栏处联系本人,本人定积极配合处理解决。

浙公网安备 33010602011771号