我正在尝试在python中记录未捕获的异常。为此,我将sys.excepthook
中的__init__.py
设置如下。
import sys
import logging
import traceback
def log_except_hook(*exc_info):
logger = logging.getLogger(__name__)
text = "".join(traceback.format_exception(*exc_info))
logger.critical(f"Unhandled exception:\n{text}")
sys.excepthook = log_except_hook
我的问题是,当我运行一个进程并发生异常时,记录的异常中的模块名称是包含代码的文件夹的名称(在这种情况下为src
),而不是该名称。发生的功能(在此示例中为foo_produce_an_error
)。请在下面找到一个示例:
2019-10-09 18:55:48,638 src CRITICAL: Unhandled exception:
Traceback (most recent call last):
File "/Users/ivallesp/Projects/Project_Folder/main.py", line 109, in <module>
foo_function(7)
File "/Users/ivallesp/Projects/Project_Folder/src/new_module.py", line 8, in foo_function
foo_produce_an_error(x)
File "/Users/ivallesp/Projects/Project_Folder/src/new_module.py", line 12, in foo_produce_an_error
x / 0
ZeroDivisionError: division by zero
如何进行日志记录以显示第一行日志记录中发生错误的模块和函数名称?
答案 0 :(得分:1)
您没有提供足够的信息来回答这个问题-例如,如何配置日志记录(特别是使用的格式字符串/格式化程序)。我可以举一个例子来说明如何总体上达到期望的结果。假设模块failfunc
中的功能失败:
# failfunc.py
def the_failing_func():
1 / 0
然后,您的主脚本可能是:
# logtest_ue.py
import logging
import sys
from failfunc import the_failing_func
def log_except_hook(*exc_info):
logger = logging.getLogger(__name__)
tb = exc_info[-1]
# get the bottom-most traceback entry
while tb.tb_next:
tb = tb.tb_next
modname = tb.tb_frame.f_globals.get('__name__')
funcname = tb.tb_frame.f_code.co_name
logger.critical('Unhandled in module %r, function %r: %s',
modname, funcname, exc_info[1], exc_info=exc_info)
sys.excepthook = log_except_hook
def main():
the_failing_func()
if __name__ == '__main__':
logging.basicConfig(format='%(levelname)s %(message)s')
sys.exit(main())
运行时,它会打印
CRITICAL Unhandled in module 'failfunc', function 'the_failing_func': division by zero
Traceback (most recent call last):
File "logtest_ue.py", line 23, in <module>
sys.exit(main())
File "logtest_ue.py", line 19, in main
the_failing_func()
File "/home/vinay/projects/scratch/failfunc.py", line 2, in the_failing_func
1 / 0
ZeroDivisionError: division by zero
请注意,使用exc_info
关键字参数将追溯追溯到日志的方法稍微简单一些。还要注意,在这种情况下,正常的模块和函数名称(可以使用%(module)s
和%(funcName)s
在格式字符串中显示)将是sys.excepthook
指向的模块和函数名称,而不是实际发生异常的值。对于这些,您将必须按照我说明的方式使用traceback对象来获取最底层的帧(实际发生异常的位置)并从该帧获取模块和函数的名称。
答案 1 :(得分:0)
该模块很难获得,但是您可以拥有文件名和行号。它们包含在exc_info中,您无需自行格式化。您可以将它们传递给log函数,并使用格式化程序将其全部显示。这是一个示例代码,可让您了解如何完成此操作:
import sys
import logging
import traceback
def log_except_hook(*exc_info):
logger = logging.getLogger(__name__)
handler = logging.StreamHandler()
handler.setFormatter(logging.Formatter('%(asctime)s %(fname)s:%(lnum)s %(message)s %(exc_info)s'))
logger.addHandler(handler)
frame = traceback.extract_tb(exc_info[2])[-1]
fname = frame.filename
lnum = frame.lineno
logger.critical("Unhandled exception:", exc_info=exc_info, extra={'fname':fname, 'lnum':lnum})
sys.excepthook = log_except_hook