如何将捕获的异常(其描述和堆栈跟踪)转换为外部使用的str ?
try:
method_that_can_raise_an_exception(params)
except Exception as e:
print(complete_exception_description(e))
如何将捕获的异常(其描述和堆栈跟踪)转换为外部使用的str ?
try:
method_that_can_raise_an_exception(params)
except Exception as e:
print(complete_exception_description(e))
当前回答
>>> import sys
>>> import traceback
>>> try:
... 5 / 0
... except ZeroDivisionError as e:
... type_, value_, traceback_ = sys.exc_info()
>>> traceback.format_tb(traceback_)
[' File "<stdin>", line 2, in <module>\n']
>>> value_
ZeroDivisionError('integer division or modulo by zero',)
>>> type_
<type 'exceptions.ZeroDivisionError'>
>>>
>>> 5 / 0
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ZeroDivisionError: integer division or modulo by zero
您可以使用sys.exc_info()收集信息,并使用traceback模块中的函数对其进行格式化。 下面是一些格式化的例子。
整个异常字符串位于:
>>> ex = traceback.format_exception(type_, value_, traceback_)
>>> ex
['Traceback (most recent call last):\n', ' File "<stdin>", line 2, in <module>\n', 'ZeroDivisionError: integer division or modulo by zero\n']
其他回答
在Python 3中,以下代码将格式化Exception对象,与使用traceback.format_exc()获得的结果完全相同:
import traceback
try:
method_that_can_raise_an_exception(params)
except Exception as ex:
print(''.join(traceback.format_exception(etype=type(ex), value=ex, tb=ex.__traceback__)))
这样做的好处是只需要Exception对象(多亏了记录的__traceback__属性),因此可以更容易地将其作为参数传递给另一个函数进行进一步处理。
如果你的目标是让异常和stacktrace消息看起来与python抛出错误时完全一样,那么以下代码在python 2+3中都适用:
import sys, traceback
def format_stacktrace():
parts = ["Traceback (most recent call last):\n"]
parts.extend(traceback.format_stack(limit=25)[:-2])
parts.extend(traceback.format_exception(*sys.exc_info())[1:])
return "".join(parts)
# EXAMPLE BELOW...
def a():
b()
def b():
c()
def c():
d()
def d():
assert False, "Noooh don't do it."
print("THIS IS THE FORMATTED STRING")
print("============================\n")
try:
a()
except:
stacktrace = format_stacktrace()
print(stacktrace)
print("THIS IS HOW PYTHON DOES IT")
print("==========================\n")
a()
它的工作原理是从堆栈中删除最后一个format_stacktrace()调用,并加入其余的调用。当运行时,上面的示例给出以下输出:
THIS IS THE FORMATTED STRING
============================
Traceback (most recent call last):
File "test.py", line 31, in <module>
a()
File "test.py", line 12, in a
b()
File "test.py", line 16, in b
c()
File "test.py", line 20, in c
d()
File "test.py", line 24, in d
assert False, "Noooh don't do it."
AssertionError: Noooh don't do it.
THIS IS HOW PYTHON DOES IT
==========================
Traceback (most recent call last):
File "test.py", line 38, in <module>
a()
File "test.py", line 12, in a
b()
File "test.py", line 16, in b
c()
File "test.py", line 20, in c
d()
File "test.py", line 24, in d
assert False, "Noooh don't do it."
AssertionError: Noooh don't do it.
让我们创建一个相当复杂的stacktrace,以演示我们得到完整的stacktrace:
def raise_error():
raise RuntimeError('something bad happened!')
def do_something_that_might_error():
raise_error()
记录完整的堆栈跟踪
最佳实践是为您的模块设置一个记录器。它将知道模块的名称,并且能够更改级别(在其他属性中,例如处理程序)
import logging
logging.basicConfig(level=logging.DEBUG)
logger = logging.getLogger(__name__)
我们可以使用这个日志来获取错误:
try:
do_something_that_might_error()
except Exception as error:
logger.exception(error)
日志:
ERROR:__main__:something bad happened!
Traceback (most recent call last):
File "<stdin>", line 2, in <module>
File "<stdin>", line 2, in do_something_that_might_error
File "<stdin>", line 2, in raise_error
RuntimeError: something bad happened!
所以我们得到的输出和我们有错误时是一样的:
>>> do_something_that_might_error()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "<stdin>", line 2, in do_something_that_might_error
File "<stdin>", line 2, in raise_error
RuntimeError: something bad happened!
只获取字符串
如果你真的只想要字符串,使用回溯。取而代之的是Format_exc函数,在这里演示了记录字符串:
import traceback
try:
do_something_that_might_error()
except Exception as error:
just_the_string = traceback.format_exc()
logger.debug(just_the_string)
日志:
DEBUG:__main__:Traceback (most recent call last):
File "<stdin>", line 2, in <module>
File "<stdin>", line 2, in do_something_that_might_error
File "<stdin>", line 2, in raise_error
RuntimeError: something bad happened!
>>> import sys
>>> import traceback
>>> try:
... 5 / 0
... except ZeroDivisionError as e:
... type_, value_, traceback_ = sys.exc_info()
>>> traceback.format_tb(traceback_)
[' File "<stdin>", line 2, in <module>\n']
>>> value_
ZeroDivisionError('integer division or modulo by zero',)
>>> type_
<type 'exceptions.ZeroDivisionError'>
>>>
>>> 5 / 0
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ZeroDivisionError: integer division or modulo by zero
您可以使用sys.exc_info()收集信息,并使用traceback模块中的函数对其进行格式化。 下面是一些格式化的例子。
整个异常字符串位于:
>>> ex = traceback.format_exception(type_, value_, traceback_)
>>> ex
['Traceback (most recent call last):\n', ' File "<stdin>", line 2, in <module>\n', 'ZeroDivisionError: integer division or modulo by zero\n']
如果你想将你的回溯转换为dict的列表(适用于python > 3.5):
from traceback import TracebackException
def list_traceback(exc_value: BaseException):
result = list()
# get previous fails, so errors are appended by order of execution
if exc_value.__context__:
result += list_traceback(exc_value.__context__)
# convert Exception into TracebackException
tbe = TracebackException.from_exception(exc_value)
# get stacktrace (cascade methods calls)
error_lines = list()
for frame_summary in tbe.stack:
summary_details = {
'filename': frame_summary.filename,
'method' : frame_summary.name,
'lineno' : frame_summary.lineno,
'code' : frame_summary.line
}
error_lines.append(summary_details)
# append error, by order of execution
result.append({"error_lines": error_lines,
"type" : tbe.exc_type.__name__,
"message" : str(tbe)})
return result
这将是结果(一个例子):
[
{
"error_lines": [
{
"filename": "/home/demo/file2.py",
"method": "do_error_2",
"lineno": 18,
"code": "a=1/0"
}
],
"type": "ZeroDivisionError",
"message": "division by zero"
},
{
"error_lines": [
{
"filename": "/home/demo/file_main.py",
"method": "demo2",
"lineno": 50,
"code": "file2.DEMO().do_error_2()"
},
{
"filename": "/home/demo/file2.py",
"method": "do_error_2",
"lineno": 20,
"code": "raise AssertionError(\"Raised inside the except, after division by zero\")"
}
],
"type": "AssertionError",
"message": "Raised inside the except, after division by zero"
}
]