我正在编写一个程序来解析10个网站,查找数据文件,保存文件,然后解析它们以生成可以在NumPy库中使用的数据。此文件通过错误链接,格式错误,缺少条目以及我尚未分类的其他内容遇到吨错误。我最初制作这个程序来处理这样的错误:
try:
do_stuff()
except:
pass
但现在我想记录错误:
try:
do_stuff()
except Exception, err:
print Exception, err
请注意,这是打印到日志文件以供日后查看。这通常会打印非常无用的数据。我想要的是打印错误触发时打印的完全相同的行没有try-except拦截异常,但我不希望它停止我的程序,因为它嵌套在一系列for循环中我想看完了。
答案 0 :(得分:614)
traceback.format_exc()
或sys.exc_info()
会产生更多信息,如果这就是你想要的。
import traceback
import sys
try:
do_stuff()
except Exception:
print(traceback.format_exc())
# or
print(sys.exc_info()[0])
答案 1 :(得分:428)
其他一些答案已经指出了traceback模块。
请注意,对于print_exc
,在某些极端情况下,您将无法获得所期望的内容。在Python 2.x中:
import traceback
try:
raise TypeError("Oups!")
except Exception, err:
try:
raise TypeError("Again !?!")
except:
pass
traceback.print_exc()
...将显示 last 例外的追溯:
Traceback (most recent call last):
File "e.py", line 7, in <module>
raise TypeError("Again !?!")
TypeError: Again !?!
如果您确实需要访问原始的追踪 ,一个解决方案是缓存从exc_info
返回的异常信息一个局部变量并使用print_exception
显示它:
import traceback
import sys
try:
raise TypeError("Oups!")
except Exception, err:
try:
exc_info = sys.exc_info()
# do you usefull stuff here
# (potentially raising an exception)
try:
raise TypeError("Again !?!")
except:
pass
# end of useful stuff
finally:
# Display the *original* exception
traceback.print_exception(*exc_info)
del exc_info
产:
Traceback (most recent call last):
File "t.py", line 6, in <module>
raise TypeError("Oups!")
TypeError: Oups!
尽管如此,很少有陷阱:
来自sys_info
的文档:
将traceback返回值分配给处理异常的函数中的局部变量将导致循环引用。这将阻止同一函数中的局部变量或回溯引用的任何内容被垃圾回收。 [...] 如果您确实需要回溯,请务必在使用后将其删除(最好使用try ... finally语句完成)
但是,来自同一个文档:
从Python 2.2开始,当启用垃圾收集并且它们无法访问时,这些周期会自动回收,但是避免创建周期仍然会更有效。
另一方面,通过允许您访问与异常相关联的追溯,Python 3产生了一个不太令人惊讶的结果:
import traceback
try:
raise TypeError("Oups!")
except Exception as err:
try:
raise TypeError("Again !?!")
except:
pass
traceback.print_tb(err.__traceback__)
...将显示:
File "e3.py", line 4, in <module>
raise TypeError("Oups!")
答案 2 :(得分:197)
答案 3 :(得分:74)
如何在不停止程序的情况下打印完整的回溯?
如果您不想在错误时暂停程序,则需要尝试使用try / except来处理该错误:
try:
do_something_that_might_error()
except Exception as error:
handle_the_error(error)
要提取完整的追溯,我们将使用标准库中的traceback
模块:
import traceback
创建一个相当复杂的堆栈跟踪来证明我们得到了完整的堆栈跟踪:
def raise_error():
raise RuntimeError('something bad happened!')
def do_something_that_might_error():
raise_error()
要打印完整的追溯,请使用traceback.print_exc
方法:
try:
do_something_that_might_error()
except Exception as error:
traceback.print_exc()
打印哪些:
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 logging
logging.basicConfig(level=logging.DEBUG)
logger = logging.getLogger(__name__)
在这种情况下,您将需要logger.exception
功能:
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!
或许你只想要字符串,在这种情况下,你会想要traceback.format_exc
函数:
try:
do_something_that_might_error()
except Exception as error:
logger.debug(traceback.format_exc())
哪些日志:
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!
对于所有三个选项,我们看到输出与输出错误时相同:
>>> 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!
答案 4 :(得分:11)
首先,不要使用print
进行日志记录,有一个稳定,可靠且经过深思熟虑的stdlib模块可以执行此操作:logging
。您肯定应该使用它。
第二,如果有本机且简单的方法,请不要尝试使用不相关的工具进行混乱。在这里:
log = logging.getLogger(__name__)
try:
call_code_that_fails()
except MyError:
log.exception('Any extra info you want to see in your logs')
就是这样。现在完成了。
log.exception
实际所做的只是对log.error
的调用(即,记录级别为ERROR
的事件),然后打印回溯。 >
嗯,这是一些注意事项:
traceback
或用exc_info=True
呼叫记录器,或者为什么不使用sys.exc_info
弄脏手?好吧,只是因为!它们全都出于不同的目的而存在。例如,traceback.print_exc
的输出与解释器本身产生的回溯有些不同。如果您使用它,则会使任何人阅读您的日志感到困惑,他们会朝着他们的头撞。
传递exc_info=True
来记录通话是不合适的。 但是,它在捕获可恢复错误时非常有用,并且您还希望使用回溯记录它们(例如,使用INFO
级别),因为log.exception
仅生成一个级别的日志-ERROR
。
您绝对应该尽可能避免与sys.exc_info
发生混乱。它不是一个公共接口,而是一个内部接口-如果您确实知道自己在做什么,则可以 使用它。它不仅仅用于打印异常。
答案 5 :(得分:7)
除了@Aaron Hall的回答之外,如果您正在记录,但又不想使用logging.exception()
(因为它以ERROR级别登录),您可以使用较低级别并传递{{1} }。 e.g。
exc_info=True
答案 6 :(得分:6)
您需要将try / except放在可能发生错误的最内圈内,即
for i in something:
for j in somethingelse:
for k in whatever:
try:
something_complex(i, j, k)
except Exception, e:
print e
try:
something_less_complex(i, j)
except Exception, e:
print e
......等等
换句话说,您需要在尽可能具体的情况下尽可能地包装尽可能在try / except中失败的语句。
答案 7 :(得分:6)
要获得精确堆栈跟踪,作为字符串,如果没有尝试/除了它,那么将被引发,只需将其置于除了捕获违规例外的块。
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)
抓住并重新加注KeyboardInterrupt
是一个好主意,这样你仍然可以使用Ctrl-C杀死程序。记录超出了问题的范围,但一个好的选择是logging。 sys和traceback模块的文档。
答案 8 :(得分:4)
关于this answer的评论:print(traceback.format_exc())
对我来说比traceback.print_exc()
更好。对于后者,hello
有时会与回溯文本奇怪地“混合”,例如,如果两者都想同时写入stdout或stderr,则会产生奇怪的输出(至少在文本编辑器内部和在“构建结果”面板中查看输出)。
回溯(最近通话最近):
中的文件“ C:\ Users \ User \ Desktop \ test.py”,第7行 地狱 do_stuff()
do_stuff中的文件“ C:\ Users \ User \ Desktop \ test.py”,第4行
1/0
ZeroDivisionError:整数除法或以零为模
o
[以0.1秒完成]
所以我用:
import traceback, sys
def do_stuff():
1/0
try:
do_stuff()
except Exception:
print(traceback.format_exc())
print('hello')
答案 9 :(得分:3)
您需要traceback模块。它可以让你像Python一样打印堆栈转储。特别是,print_last函数将打印最后一个异常和堆栈跟踪。
答案 10 :(得分:0)
使用traceback.format_exception
如果只有异常对象,则可以使用以下命令从Python 3中代码的任何点以字符串形式获取回溯:
import traceback
''.join(traceback.format_exception(None, exc_obj, exc_obj.__traceback__))
完整示例:
#!/usr/bin/env python3
import traceback
def f():
g()
def g():
raise Exception('asdf')
try:
g()
except Exception as e:
exc = e
tb_str = ''.join(traceback.format_exception(None, exc_obj, exc_obj.__traceback__))
print(tb_str)
输出:
Traceback (most recent call last):
File "./main.py", line 12, in <module>
g()
File "./main.py", line 9, in g
raise Exception('asdf')
Exception: asdf
文档:https://docs.python.org/3.7/library/traceback.html#traceback.format_exception
另请参阅:Extract traceback info from an exception object
在Python 3.7.3中进行了测试。
答案 11 :(得分:0)
我在其他任何答案中都没有提到这一点。如果出于某种原因要传递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')
请注意,堆栈打印有所不同,缺少第一行和最后一行。因为它是different format()
。
在离异常产生的地方越远的地方截获该异常将使代码更简单,同时还提供更多信息。
答案 12 :(得分:0)
如果您已经有一个Error对象,并且想要打印整个内容,则需要进行此稍微尴尬的调用:
import traceback
traceback.print_exception(type(err), err, err.__traceback__)
是的,print_exception
接受三个位置参数:异常的类型,实际的异常对象以及异常自身的内部回溯属性。
在python 3.5或更高版本中,type(err)
是可选的...但是它是一个位置参数,因此您仍然必须在其位置显式传递None。
traceback.print_exception(None, err, err.__traceback__)
我不知道为什么所有这些不只是traceback.print_exception(err)
。为什么您要打印出错误以及与该错误无关的回溯,这超出了我的范围。
答案 13 :(得分:0)
这是将错误写入日志文件以及控制台的解决方案:
<video controls width="400" height="300">
<source src={Video} type="video/mp4"></source>
</video>
答案 14 :(得分:0)
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
答案 15 :(得分:-1)
你可以这样做:
try:
do_stuff()
except Exception, err:
print(Exception, err)
raise err