背景

在一次仿真测试过程中,测试人员反馈系统启动异常,我通过查看日志文件,认为进程卡在了某个位置,但通过查看控制台日志,发现该程序抛出了未捕获的异常,但该异常信息没有在日志文件里。

于是开始寻找将非捕获的异常输出到 logging 的办法。

解决方案

参考了 《捕获全局异常,并且把异常信息打印到日志中》 这篇文章,经过验证后发现可行。

他的原理是修改全局的 exception钩子,将其指向自定义的异常处理函数,在该函数内,统一将异常输出到 logger 中。

import logging
import sys
 
logging.basicConfig(level=logging.DEBUG,
                    format='%(asctime)s %(levelname)s %(message)s',
                    filename='exception.log',
                    filemode='a+')
 
# 定义一个异常捕获函数
def handle_exception(exc_type, exc_obj, exc_traceback):
    """异常捕获函数
 
    Args:
        exc_type (type): 异常类型
        exc_obj (Error): 异常对象
        exc_traceback (traceback): traceback对象
    """
    
    # 将Ctrl+C异常抛出到默认except钩子,不做处理
    if issubclass(exc_type, KeyboardInterrupt):
        sys.__excepthook__(exc_type, exc_obj, exc_traceback)
        return
    logging.exception("Unhandled Exception", exc_info=(exc_type, exc_obj, exc_traceback))
    
# 为sys的except钩子设置异常捕获函数
sys.excepthook = handle_exception
 
# 抛出一系列异常
 
# raise NameError('test')
# raise KeyboardInterrupt("")

在执行时,可以发现对于 KeyboardInterrupt 日志不会捕获,而其他的异常会正常捕获并输出到日志文件:

2025-02-14 14:34:57,299 ERROR Unhandled Exception
Traceback (most recent call last):
  File "/home/wzq/python_test/exception_catch.py", line 29, in <module>
    raise NameError('test')
NameError: test