正如mechmind所回答的那样,堆栈跟踪仅包括在引发异常的位置和
try
块的位置之间的帧。如果需要完整的堆栈跟踪,似乎您没什么办法。
除非从顶层到当前帧提取堆栈条目是显然可行的——
traceback.extract_stack
可以很好地处理它。问题是通过直接检查堆栈帧来获取的
traceback.extract_stack
的信息在任何时候都没有创建traceback对象,并且
logging
API需要一个traceback对象才能影响traceback输出。
幸运的是,
logging
不需要一个实际的traceback对象,它需要一个可以传递给
traceback
模块的格式化程序的对象。
traceback
也不关心——它只使用traceback的两个属性,帧和行号。因此,应该可以创建一个鸭子类型的伪traceback对象链表并将其作为traceback传递。
import sys
class FauxTb(object):
def __init__(self, tb_frame, tb_lineno, tb_next):
self.tb_frame = tb_frame
self.tb_lineno = tb_lineno
self.tb_next = tb_next
def current_stack(skip=0):
try: 1/0
except ZeroDivisionError:
f = sys.exc_info()[2].tb_frame
for i in xrange(skip + 2):
f = f.f_back
lst = []
while f is not None:
lst.append((f, f.f_lineno))
f = f.f_back
return lst
def extend_traceback(tb, stack):
"""Extend traceback with stack info."""
head = tb
for tb_frame, tb_lineno in stack:
head = FauxTb(tb_frame, tb_lineno, head)
return head
def full_exc_info():
"""Like sys.exc_info, but includes the full traceback."""
t, v, tb = sys.exc_info()
full_tb = extend_traceback(tb, current_stack(1))
return t, v, full_tb
有了这些功能,你的代码只需要进行微小的修改:
import logging
def func():
try:
raise Exception('Dummy')
except:
logging.error("Something awful happened!", exc_info=full_exc_info())
def func2():
func()
func2()
...以得到预期的输出:
ERROR:root:Something awful happened!
Traceback (most recent call last):
File "a.py", line 52, in <module>
func2()
File "a.py", line 49, in func2
func()
File "a.py", line 43, in func
raise Exception('Dummy')
Exception: Dummy
请注意,虚假回溯对象完全可用于内省 - 显示本地变量或作为
pdb.post_mortem()
的参数 - 因为它们包含对真实堆栈帧的引用。
exc_info = sys.exc_info()
,其中包含有问题的回溯信息,并将此信息传递给Sentry处理程序,后者解析它以检查每个帧中的本地变量。是的,我认为问题是相同的。 - warvariuc