我想在不退出的情况下捕获和记录异常,例如,
try:
do_stuff()
except Exception as err:
print(Exception, err)
# I want to print the entire traceback here,
# not just the exception name and details
我想打印与抛出异常时打印的完全相同的输出,而不使用try/,只是拦截异常,并且我不希望它退出程序。
我想在不退出的情况下捕获和记录异常,例如,
try:
do_stuff()
except Exception as err:
print(Exception, err)
# I want to print the entire traceback here,
# not just the exception name and details
我想打印与抛出异常时打印的完全相同的输出,而不使用try/,只是拦截异常,并且我不希望它退出程序。
当前回答
您需要traceback模块。它将允许您像Python通常那样打印堆栈转储。特别是,print_last函数将打印最后一个异常和堆栈跟踪。
其他回答
我在其他答案中没有看到这个。如果你出于某种原因传递一个Exception对象……
在Python 3.5+中,您可以使用traceback.TracebackException.from_exception()从Exception对象获取跟踪。例如:
import traceback
def stack_lvl_3():
raise Exception('a1', 'b2', 'c3')
def stack_lvl_2():
try:
stack_lvl_3()
except Exception as e:
# raise
return e
def stack_lvl_1():
e = stack_lvl_2()
return e
e = stack_lvl_1()
tb1 = traceback.TracebackException.from_exception(e)
print(''.join(tb1.format()))
然而,上面的代码导致:
Traceback (most recent call last):
File "exc.py", line 10, in stack_lvl_2
stack_lvl_3()
File "exc.py", line 5, in stack_lvl_3
raise Exception('a1', 'b2', 'c3')
Exception: ('a1', 'b2', 'c3')
这只是堆栈的两层,而不是在stack_lvl_2()中引发异常而没有被拦截(取消注释# raise行)时在屏幕上打印的内容。
根据我的理解,这是因为异常在被引发时只记录堆栈的当前级别,在本例中是stack_lvl_3()。当它在堆栈中往回传递时,更多的层被添加到它的__traceback__中。但是我们在stack_lvl_2()中拦截了它,这意味着它只能记录级别3和2。要获得打印在stdout上的完整跟踪,我们必须在最高(最低?)级别捕获它:
import traceback
def stack_lvl_3():
raise Exception('a1', 'b2', 'c3')
def stack_lvl_2():
stack_lvl_3()
def stack_lvl_1():
stack_lvl_2()
try:
stack_lvl_1()
except Exception as exc:
tb = traceback.TracebackException.from_exception(exc)
print('Handled at stack lvl 0')
print(''.join(tb.stack.format()))
结果是:
Handled at stack lvl 0
File "exc.py", line 17, in <module>
stack_lvl_1()
File "exc.py", line 13, in stack_lvl_1
stack_lvl_2()
File "exc.py", line 9, in stack_lvl_2
stack_lvl_3()
File "exc.py", line 5, in stack_lvl_3
raise Exception('a1', 'b2', 'c3')
注意,堆栈打印是不同的,第一行和最后一行都不见了。因为它是不同的格式()。
在尽可能远离异常引发点的地方拦截异常,可以简化代码,同时提供更多信息。
要获得精确的堆栈跟踪(作为字符串),如果没有try/except进行跨步处理,则会引发该字符串,只需将其放置在捕获违规异常的except块中。
desired_trace = traceback.format_exc(sys.exc_info())
下面是如何使用它(假设定义了flaky_func,并且log调用您最喜欢的日志系统):
import traceback
import sys
try:
flaky_func()
except KeyboardInterrupt:
raise
except Exception:
desired_trace = traceback.format_exc(sys.exc_info())
log(desired_trace)
捕获并重新引发KeyboardInterrupts是个好主意,这样您仍然可以使用Ctrl-C终止程序。日志记录不在这个问题的范围之内,但是日志记录是一个很好的选择。sys和traceback模块的文档。
Traceback.format_exc()或sys.exc_info()将产生更多信息,如果这是你想要的。
import traceback
import sys
try:
do_stuff()
except Exception:
print(traceback.format_exc())
# or
print(sys.exc_info()[2])
Python 3解决方案
stacktrace_helper.py:
from linecache import getline
import sys
import traceback
def get_stack_trace():
exc_type, exc_value, exc_tb = sys.exc_info()
trace = traceback.format_stack()
trace = list(filter(lambda x: ("\\lib\\" not in x and "/lib/" not in x and "stacktrace_helper.py" not in x), trace))
ex_type = exc_type.__name__
ex_line = exc_tb.tb_lineno
ex_file = exc_tb.tb_frame.f_code.co_filename
ex_message = str(exc_value)
line_code = ""
try:
line_code = getline(ex_file, ex_line).strip()
except:
pass
trace.insert(
0, f'File "{ex_file}", line {ex_line}, line_code: {line_code} , ex: {ex_type} {ex_message}',
)
return trace
def get_stack_trace_str(msg: str = ""):
trace = list(get_stack_trace())
trace_str = "\n".join(list(map(str, trace)))
trace_str = msg + "\n" + trace_str
return trace_str
您需要traceback模块。它将允许您像Python通常那样打印堆栈转储。特别是,print_last函数将打印最后一个异常和堆栈跟踪。