FastAPI中修改sys.excepthook实现traceback单行输出适配云日志平台
FastAPI场景下单行traceback输出方案及sys.excepthook适配说明
sys.excepthook不生效原因
FastAPI基于Uvicorn、Hypercorn等ASGI服务器运行,请求处理全链路的异常会被ASGI服务器、FastAPI内置中间件提前捕获处理,不会触发Python全局sys.excepthook逻辑,因此直接修改该参数无法捕获请求链路内的异常。
是否可以修改sys模块专属参数
可以正常修改包括sys.excepthook在内的sys模块参数,修改操作本身是有效的,只是这类全局钩子不适配FastAPI的ASGI运行模式,仅会作用于主线程非请求链路抛出的未捕获异常(如服务启动阶段的异常),不会在请求处理阶段生效。
FastAPI实现单行traceback的可行方案
- 方案1:自定义FastAPI全局异常处理器
直接捕获所有路由层未处理异常,手动格式化traceback为单行输出,示例代码如下:
from fastapi import FastAPI, Request from fastapi.responses import JSONResponse import traceback import logging app = FastAPI() @app.exception_handler(Exception) async def global_exception_handler(request: Request, exc: Exception): # 格式化traceback为单行,替换换行符为自定义分隔符 tb_single_line = "".join(traceback.format_exception(type(exc), exc, exc.__traceback__)).replace("\n", " | ").strip() logging.error(f"path={request.url.path} | err_msg={str(exc)} | traceback={tb_single_line}") return JSONResponse(status_code=500, content={"detail": "服务内部错误"})
该方案可以覆盖所有FastAPI路由层抛出的未处理异常。
- 方案2:自定义logging Formatter全局统一处理
如需覆盖所有日志场景的异常输出格式,可直接修改logging的异常格式化逻辑,示例代码如下:
import logging class SingleLineExceptionFormatter(logging.Formatter): def formatException(self, exc_info): original_tb = super().formatException(exc_info) # 替换换行、回车符为指定分隔符 return original_tb.replace("\n", " | ").replace("\r", "").strip() # 配置全局日志处理器 stream_handler = logging.StreamHandler() stream_handler.setFormatter(SingleLineExceptionFormatter("%(asctime)s %(levelname)s %(message)s")) logging.root.addHandler(stream_handler) logging.root.setLevel(logging.INFO)
该方案会作用于所有调用logging.exception输出的异常,适用范围更广。
内容的提问来源于stack exchange,提问作者Downey J
相关产品推荐
相关产品推荐

