Python自定义异常日志:异常钩子返回错误函数信息的解决
解决sys.excepthook日志显示异常抛出位置的问题
问题原因
当你在自定义的sys.excepthook函数中直接调用logging.error()等方法时,logging模块默认会捕捉当前函数(即exception_hook)的调用栈信息,因此日志里显示的是这个函数的文件名、行号,而非原异常抛出的真实位置。
解决方法
方法1:用logging.exception自动捕获异常栈
logging.exception()会自动附带完整的异常栈追踪,并且能正确指向原异常的抛出位置,是最简便的解决方案:
import sys import logging # 配置日志格式,包含文件名、函数名、行号 logging.basicConfig( format='%(asctime)s - %(levelname)s - %(filename)s:%(funcName)s:%(lineno)d - %(message)s', level=logging.INFO ) def exception_hook(exc_type, exc_value, exc_traceback): # 用exception方法记录,自动包含异常栈,位置信息会指向原异常抛出点 logging.exception("未捕获异常", exc_info=(exc_type, exc_value, exc_traceback)) sys.excepthook = exception_hook # 测试代码 def trigger_error(): raise ValueError("测试自定义异常日志格式") trigger_error()
方法2:手动提取原异常的栈帧信息
如果需要更精细控制日志内容,可以通过exc_traceback提取原异常的栈帧数据,用extra参数覆盖logging默认的位置字段:
import sys import logging import traceback logging.basicConfig( format='%(asctime)s - %(levelname)s - %(filename)s:%(funcName)s:%(lineno)d - %(message)s', level=logging.INFO ) def exception_hook(exc_type, exc_value, exc_traceback): if exc_traceback is None: logging.error(f"未捕获异常: {exc_value}") return # 获取原异常的栈帧信息,跳过hook函数的层级 tb_frame = exc_traceback.tb_frame.f_back filename = tb_frame.f_code.co_filename func_name = tb_frame.f_code.co_name line_no = exc_traceback.tb_lineno # 手动传入原异常的位置信息 logging.error( f"未捕获异常: {exc_value}", exc_info=(exc_type, exc_value, exc_traceback), extra={ 'filename': filename, 'funcName': func_name, 'lineno': line_no } ) sys.excepthook = exception_hook # 测试代码 def trigger_error(): raise ValueError("测试自定义异常日志格式") trigger_error()
方法3:自定义Logger修改栈查找深度
通过继承logging.Logger,修改findCaller方法的栈查找层级,跳过exception_hook函数的栈帧:
import sys import logging class CustomLogger(logging.Logger): def findCaller(self, stack_info=False, stacklevel=1): # 额外跳过1层栈帧(对应exception_hook函数) return super().findCaller(stack_info, stacklevel + 1) # 设置全局Logger类为自定义类 logging.setLoggerClass(CustomLogger) logging.basicConfig( format='%(asctime)s - %(levelname)s - %(filename)s:%(funcName)s:%(lineno)d - %(message)s', level=logging.INFO ) def exception_hook(exc_type, exc_value, exc_traceback): logging.error( f"未捕获异常: {exc_value}", exc_info=(exc_type, exc_value, exc_traceback) ) sys.excepthook = exception_hook # 测试代码 def trigger_error(): raise ValueError("测试自定义异常日志格式") trigger_error()
注意事项
- 若需要完整的异常栈追踪,优先用方法1;若只需显示原异常位置信息,方法2或3更灵活。
- 实际使用中建议对
exc_traceback做非空判断,避免极端场景下报错。
内容的提问来源于stack exchange,提问作者qalis
相关产品推荐
相关产品推荐

