FastAPI异常处理器正常返回响应但logging日志不输出问题
问题成因
这个问题的核心是日志配置时机不对,被uvicorn(运行FastAPI最常用的ASGI服务器)的默认日志规则覆盖了:
- 你当前写的日志初始化、启动测试日志的代码,都是在模块导入、FastAPI实例创建阶段执行的,这个阶段uvicorn还没加载自身的日志配置,所以
logger.debug("Logger created")、logger.debug('test')都能正常输出,很容易造成“日志配置已经生效”的错觉。 - 等uvicorn完成启动流程、开始接收请求前,会自动调用
logging.config.dictConfig加载内置的日志规则:这个操作会把所有未在它配置里明确定义的自定义logger的级别重置,默认对齐到根logger的WARNING级别,你之前调用basicConfig做的配置也会被覆盖。 - 当请求触发异常、进入你写的
handle_exception函数时,自定义的MyLANlogger级别已经被改成WARNING,logger.debug()输出的日志级别低于当前生效阈值,会被直接过滤,根本不会传到你绑定的文件handler、Discord handler里,自然没有输出。 - 由于异常返回逻辑和日志组件完全独立,所以你自定义的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
相关产品推荐
相关产品推荐

