如何在代码运行出错时将异常错误与堆栈跟踪打印到文件
可行性结论
该需求完全可以实现,不需要给每段业务代码单独套异常捕获,基于Python标准库自带的全局异常钩子能力就能搞定,所有未被捕获、会导致程序终止抛出的异常,都会自动走到你自定义的处理逻辑里,调用traceback.print_exception()写入指定文件即可。
具体实现方法
核心逻辑是替换sys模块内置的sys.excepthook,这个钩子是Python预留的全局异常出口,默认行为是把异常栈打印到控制台,我们可以重写它的逻辑,把异常信息输出到目标日志文件。
依赖说明
全程只用Python标准库,不需要安装任何第三方包,用到的模块为sys、traceback、pathlib(可选,用来处理文件路径更方便)。
完整示例代码
import sys import traceback from pathlib import Path # 这里替换成你要存储异常日志的目标文件路径 ERROR_LOG_PATH = Path("./runtime_error.log") def custom_excepthook(exc_type, exc_value, exc_tb): # 放行键盘中断异常,不记录手动按Ctrl+C终止程序的场景,不需要的话可以删掉这段判断 if issubclass(exc_type, KeyboardInterrupt): sys.__excepthook__(exc_type, exc_value, exc_tb) return # 以追加模式打开日志文件,指定utf-8编码避免中文乱码 with open(ERROR_LOG_PATH, mode="a", encoding="utf-8") as log_file: # 调用要求的traceback.print_exception,将异常栈输出到文件 traceback.print_exception(exc_type, exc_value, exc_tb, file=log_file) # 如果需要同时在控制台打印错误信息,放开下面这行注释即可 # traceback.print_exception(exc_type, exc_value, exc_tb) # 替换全局默认的异常钩子 sys.excepthook = custom_excepthook # --------------- 以下为测试逻辑 --------------- if __name__ == "__main__": print("程序启动") # 故意制造一个除零异常测试效果 test_val = 1 / 0
运行上面的测试代码,你会在脚本同目录下找到runtime_error.log文件,里面已经完整记录了除零异常的完整栈信息,和控制台默认打印的异常内容完全一致。
注意事项
- 全局钩子只能捕获未被业务代码主动捕获的异常,如果你的业务逻辑里写了
try/except把异常捕获后没有重新抛出,异常不会走到全局钩子,自然也不会被记录。 - 多线程场景下,
sys.excepthook默认只能捕获主线程的未捕获异常,子线程抛出的异常需要单独给线程实例设置excepthook属性,使用线程池/进程池的场景也要对应配置异常回调逻辑,不然子线程/子进程的错误会漏记。 - 日志文件打开模式一定要用追加模式
a,如果用覆盖写模式w,每次程序启动后触发的第一个异常会把之前所有的历史错误日志清空,不利于回溯问题。 - 如果是基于asyncio的异步程序,还需要额外设置
loop.set_exception_handler()来捕获异步协程里抛出的未处理异常,上面的同步逻辑对协程场景不生效。
内容的提问来源于stack exchange,提问作者Mayottasekaisen
相关产品推荐
相关产品推荐

