我想在不退出的情况下捕获和记录异常,例如,
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/,只是拦截异常,并且我不希望它退出程序。
当前回答
除了Aaron Hall的回答之外,如果您正在记录日志,但不想使用logging.exception()(因为它在ERROR级别记录日志),您可以使用更低的级别并传递exc_info=True。如。
try:
do_something_that_might_error()
except Exception:
logging.info('General exception noted.', exc_info=True)
其他回答
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])
要获得精确的堆栈跟踪(作为字符串),如果没有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模块的文档。
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
首先,不要使用打印来记录日志,有一个稳定的、经过验证的、经过深思熟虑的stdlib模块可以做到这一点:日志。你绝对应该用它来代替。
其次,当有原生的简单方法时,不要试图用不相关的工具搞得一团糟。下面就是:
log = logging.getLogger(__name__)
try:
call_code_that_fails()
except MyError:
log.exception('Any extra info you want to see in your logs')
就是这样。现在你完成了。
为任何对事物的工作原理感兴趣的人提供解释
什么日志。异常实际上所做的只是对日志的调用。error(即记录级别为error的事件),然后打印traceback。
为什么更好呢?
这里有一些注意事项:
它刚刚好; 这很简单; 这很简单。
为什么没有人应该使用exc_info=True的跟踪或调用记录器,或者用sys.exc_info弄脏他们的手?
嗯,就是因为!它们存在的目的各不相同。例如,traceback。Print_exc的输出与解释器本身产生的回溯略有不同。如果你使用它,你会让任何阅读你日志的人感到困惑,他们会用头去撞你的日志。
将exc_info=True传递给日志调用是不合适的。但是,当捕获可恢复的错误并且你想用回溯记录它们(使用,例如INFO级别)时,它是有用的,因为log。exception只产生一个级别的日志- ERROR。
而且你绝对应该避免和sys搞混。Exc_info。它不是一个公共接口,而是一个内部接口——如果你明确知道自己在做什么,你就可以使用它。它不仅仅用于打印异常。
你可以这样做:
try:
do_stuff()
except Exception, err:
print(Exception, err)
raise err