使用 Loguru 捕获并记录 Python 异常到日志文件

使用 Loguru 捕获并记录 Python 异常到日志文件
最新回答
苍山有井名为空

2022-11-09 19:19:48

使用 Loguru 捕获并记录 Python 异常到日志文件的核心方法是通过 @logger.catch 装饰器自动捕获未处理异常,结合日志接收器(sink)配置实现完整错误记录。以下是具体实现步骤和最佳实践:

一、核心实现步骤
  1. 配置日志接收器使用 logger.add() 指定日志文件路径、轮转规则和日志级别,确保异常信息能写入文件:

    from loguru import loggerlogger.add("error.log", rotation="500 MB", level="DEBUG") # 文件大小超过500MB时轮辩滚转
  2. 使用 @logger.catch 装饰器将装饰器应用于程序入口函数(如 main()),自动捕获函数内及调用的子函数中的未处理异常:

    @logger.catchdef main(): result = divide() # 若divide()未捕获异常,@logger.catch会捕获 logger.info(f"结果: {result}")
  3. 显式异常处理补充对可预见的异常,仍建议使用 try...except 结合 logger.exception() 记录详细信息:

    def divide(): try: return 1 / 0 except ZeroDivisionError as e: logger.exception("显式捕获除零错误") # 自动记录堆栈 return None
二、工作原理
  • 未捕获异常的默认行为:Python 解释器通过 sys.excepthook() 将异常输出到 sys.stderr,Loguru 默认竖塌不监听此流。
  • @logger.catch 的作用:在装饰的函数外层包余灶圆裹 try...except,捕获异常后调用 logger.exception(),将错误信息写入所有配置的 sinks(如文件、终端)。
三、日志文件内容示例

运行后 error.log 会包含两类信息:

  1. 显式记录的错误:2024-01-01 10:00:00.000000 | ERROR | __main__:divide:5 - 显式捕获除零错误
  2. 自动捕获的异常堆栈:2024-01-01 10:00:00.000000 | ERROR | __main__:main:11 - An exception was caught!Traceback (most recent call last): File "test.py", line 11, in main result = divide() File "test.py", line 5, in divide return 1 / 0ZeroDivisionError: division by zero
四、最佳实践
  1. 装饰入口函数将 @logger.catch 应用于 main() 或顶层函数,确保捕获全局未处理异常。

  2. 细粒度控制对关键函数单独使用 try...except + logger.exception(),例如:

    def critical_operation(): try: # 高风险操作 except Exception as e: logger.exception("关键操作失败") raise # 可选择重新抛出
  3. 多 sinks 配置同时输出到文件和终端,方便开发调试:

    logger.add("error.log", rotation="500 MB")logger.add(sys.stderr, level="WARNING") # 终端仅显示WARNING及以上级别
  4. 异常分类处理通过 @logger.catch(exceptions=SomeException) 指定捕获的异常类型,避免捕获无关错误。

五、完整代码示例from loguru import loggerimport sysdef divide(): try: return 1 / 0 except ZeroDivisionError as e: logger.exception("显式捕获除零错误") return None@logger.catchdef main(): result = divide() if result is not None: logger.info(f"结果: {result}") else: logger.warning("divide函数返回了None")if __name__ == "__main__": logger.add("error.log", rotation="500 MB", level="DEBUG") logger.add(sys.stderr, level="WARNING") main()六、注意事项
  • 装饰器位置:@logger.catch 需直接应用于函数定义上方,不能嵌套在其他装饰器内。
  • 性能影响:异常捕获会引入轻微开销,仅在调试或生产环境监控时使用。
  • 日志轮转:生产环境建议配置 rotation 和 retention 避免日志文件过大。

通过以上方法,可确保所有未处理异常和显式错误均被完整记录,显著提升问题排查效率。