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

FastAPI异常处理器正常返回响应但logging日志不输出问题

问题成因

这个问题的核心是日志配置时机不对,被uvicorn(运行FastAPI最常用的ASGI服务器)的默认日志规则覆盖了:

  1. 你当前写的日志初始化、启动测试日志的代码,都是在模块导入、FastAPI实例创建阶段执行的,这个阶段uvicorn还没加载自身的日志配置,所以logger.debug("Logger created")、logger.debug('test')都能正常输出,很容易造成“日志配置已经生效”的错觉。
  2. 等uvicorn完成启动流程、开始接收请求前,会自动调用logging.config.dictConfig加载内置的日志规则:这个操作会把所有未在它配置里明确定义的自定义logger的级别重置,默认对齐到根logger的WARNING级别,你之前调用basicConfig做的配置也会被覆盖。
  3. 当请求触发异常、进入你写的handle_exception函数时,自定义的MyLAN logger级别已经被改成WARNING,logger.debug()输出的日志级别低于当前生效阈值,会被直接过滤,根本不会传到你绑定的文件handler、Discord handler里,自然没有输出。
  4. 由于异常返回逻辑和日志组件完全独立,所以你自定义的500响应可以正常返回,全程也不会抛出任何可定位问题的报错。

你可以临时把异常处理器里的日志改成logger.warning("Something's brokey")测试,这条日志肯定能正常输出,可以直接实锤是日志级别被重置导致的问题。

解决方案

任选以下一种方案修复即可,优先推荐第一种:

方案1:将日志初始化逻辑移到应用启动钩子中

不要在模块顶层直接写日志配置,全部放到FastAPI的startup生命周期事件里执行,这个时间点uvicorn已经完成自身日志配置加载,不会再覆盖你的自定义设置:

import logging
from fastapi import FastAPI, Response
# 其余导入省略

app = FastAPI()
logger = logging.getLogger("MyLAN")

@app.on_event("startup")
def init_log_config():
    # 强制重置根日志配置,屏蔽uvicorn默认规则的干扰
    logging.basicConfig(
        filename='mylan.log',
        level=logging.DEBUG,
        force=True
    )
    # 初始化Discord日志处理器
    discord_handler = DiscordHandler(
        webhook_url, 
        agent, 
        notify_users=notify_users, 
        emit_as_code_block=False, 
        max_size=2000
    )
    discord_handler.setLevel(logging.DEBUG)
    discord_handler.setFormatter(FORMAT)
    
    # 清空logger上可能被uvicorn自动绑定的默认handler
    logger.handlers.clear()
    logger.setLevel(logging.DEBUG)
    logger.addHandler(discord_handler)
    # 关闭日志向根logger传播,避免被根logger级别规则过滤、重复打印
    logger.propagate = False
    
    logger.debug("Logger init complete")

@app.exception_handler(Exception)
def handle_exception(req, exc):
    logger.debug("Something's brokey")
    return Response("Internal Server Error Test", status_code=500)

方案2:启动uvicorn时显式指定全局日志级别

启动服务时追加参数将全局日志级别设为DEBUG,保证DEBUG级别的日志不会被过滤:

uvicorn 你的模块名:app --log-level debug

使用这个方案需要在初始化logger时加上logger.propagate = False,否则同一条日志会被uvicorn的默认控制台handler重复输出。

方案3:禁用uvicorn的自动日志配置

启动时追加参数让uvicorn不加载自身的日志规则,完全使用你自定义的配置:

# Linux/macOS
uvicorn 你的模块名:app --no-access-log --log-config /dev/null
# Windows
uvicorn 你的模块名:app --no-access-log --log-config nul

提示:只要是用uvicorn/gunicorn这类服务器部署Python Web服务,都不要在模块顶层直接初始化日志,服务器启动阶段几乎都会默认修改日志配置,放到启动生命周期钩子中初始化是稳定性最高的做法。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 17:24:21