You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

从Flask迁移至FastAPI时TimedRotatingFileHandler日志报错的解决方法

FastAPI日志配置报错:TimedRotatingFileHandler与Uvicorn Access Logger冲突问题

错误成因

你复用了uvicorn.access这个Logger实例,但Uvicorn为该Logger默认配置了AccessFormatter——这个格式化器专门用于解析HTTP请求的访问日志(格式需包含请求方法、路径、状态码等5个核心字段)。当你直接调用logger.debug("test")传入普通字符串时,不符合AccessFormatter的解析要求,导致格式化时抛出ValueError: not enough values to unpack (expected 5, got 0)。

修复方法

方案1:创建自定义业务日志Logger(推荐)

不要复用Uvicorn的访问日志Logger,独立创建业务Logger,完全自定义日志格式与处理器:

import logging
from logging.handlers import TimedRotatingFileHandler
from fastapi import FastAPI, Request

app = FastAPI()

# 创建自定义Logger,避免与Uvicorn日志冲突
logger = logging.getLogger("my_app")
logger.setLevel(logging.DEBUG)
logger.propagate = False  # 防止日志被Uvicorn根Logger重复处理

# 配置日志格式
logformat = logging.Formatter(
    "[%(asctime)s][%(filename)s:%(lineno)d][%(levelname)s][%(process)d][%(threadName)s] - %(message)s"
)

# 添加TimedRotatingFileHandler
debug_rotating_handler = TimedRotatingFileHandler(
    'pml_debug.log',
    when="midnight",
    interval=1,
    backupCount=15,
    encoding='utf-8'
)
debug_rotating_handler.setFormatter(logformat)
debug_rotating_handler.setLevel(logging.DEBUG)
logger.addHandler(debug_rotating_handler)


@app.get("/")
async def home(request: Request):
    logger.debug("test")
    return {"test": 1}

方案2:替换Uvicorn Access Logger的Formatter(不推荐)

若坚持复用uvicorn.access,需替换其默认Formatter,但会导致Uvicorn原生的请求访问日志格式被覆盖,丢失请求相关信息:

import logging
from logging.handlers import TimedRotatingFileHandler
from fastapi import FastAPI, Request

app = FastAPI()

logformat = logging.Formatter(
    "[%(asctime)s][%(filename)s:%(lineno)d][%(levelname)s][%(process)d][%(threadName)s] - %(message)s"
)
logger = logging.getLogger("uvicorn.access")

# 清空原有Handler与Formatter
for handler in logger.handlers[:]:
    logger.removeHandler(handler)

# 添加自定义Handler
debug_rotating_handler = TimedRotatingFileHandler(
    'pml_debug.log',
    when="midnight",
    interval=1,
    backupCount=15,
    encoding='utf-8'
)
debug_rotating_handler.setFormatter(logformat)
debug_rotating_handler.setLevel(logging.DEBUG)
logger.addHandler(debug_rotating_handler)
logger.setLevel(logging.DEBUG)


@app.get("/")
async def home(request: Request):
    logger.debug("test")
    return {"test": 1}

关于异步日志的必要性

  • 标准库TimedRotatingFileHandler是同步IO操作,在FastAPI的异步事件循环中,频繁日志写入会阻塞事件循环,降低并发性能。
  • 高QPS、大日志量场景:建议采用异步日志方案,比如用logging模块的QueueHandler+QueueListener将日志IO转移到独立线程/进程,或使用aiologger等原生异步日志库。
  • 低流量场景:同步日志的性能影响可忽略,直接使用TimedRotatingFileHandler即可。

内容的提问来源于stack exchange,提问作者Gui

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.15 08:55:18