如何在不停止程序的情况下打印完整的回溯?

我正在编写一个程序,分析10个网站,查找数据文件,保存文件,然后parsing它们,使数据在NumPy库中很容易使用。 这个文件通过错误的链接,糟糕的XML,缺less的条目以及其他我尚未分类的东西遇到了大量的错误。 我最初做这个程序来处理这样的错误:

try: do_stuff() except: pass 

但是现在我想logging错误:

 try: do_stuff() except Exception, err: print Exception, err 

注意这是打印到一个日志文件供以后检查。 这通常打印非常无用的数据。 我想要的是打印完全相同的行打印错误触发时没有try-except拦截exception,但我不希望它停止我的程序,因为它嵌套在一系列for循环,我想看完成。

还有一些答案已经指出了追溯模块。

请注意,在print_exc ,在某些情况下,您将无法获得您期望的结果。 在Python 2.x中:

 import traceback try: raise TypeError("Oups!") except Exception, err: try: raise TypeError("Again !?!") except: pass traceback.print_exc() 

…将显示最后一个exception的回溯:

 Traceback (most recent call last): File "e.py", line 7, in <module> raise TypeError("Again !?!") TypeError: Again !?! 

如果您确实需要访问原始回溯,则解决scheme是caching从局部variables中exc_info返回的exception信息 ,并使用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! 

很less有这样的缺陷:

  • sys_info的文档:

    将追踪返回值分配给处理exception的函数中的局部variables将导致循环引用 。 这将防止在同一个函数中由局部variables引用的任何东西,或者通过回溯被垃圾收集。 […] 如果你确实需要追踪,确保在使用后删除它 (最好用try … finally语句完成)

  • 但是,从相同的文档:

    从Python 2.2开始,当启用垃圾回收并且无法访问时, 会自动回收这些循环 ,但是避免创build循环会更有效。


另一方面,通过允许你访问exception相关的回溯,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!") 

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]) 

如果你正在debugging,只想看到当前的堆栈跟踪,你可以简单地调用:

traceback.print_stack()

没有必要手动提出exception,只是为了再次捕捉它。

如何在不停止程序的情况下打印完整的回溯?

当你不想在错误中停止你的程序时,你需要用try / except来处理这个错误:

 try: do_something_that_might_error() except Exception as error: handle_the_error(error) 

为了提取完整的回溯,我们将使用标准库中的traceback模块:

 import traceback 

并创build一个体面复杂的堆栈跟踪,以certificate我们得到完整的堆栈跟踪:

 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! 

比打印更好,日志logging:

但是,最好的做法是为您的模块设置一个logging器。 它将知道模块的名称,并能够更改级别(以及其他属性,例如处理程序)

 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! 

或者你只是想要string,在这种情况下,你会想要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! 

为了得到精确的堆栈跟踪,作为一个string,如果没有尝试/除了在那里,那么就把它提出来,只要把它放在除了得到有问题的exception的块外就可以了。

 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不在问题的范围之内,但是日志logging是一个很好的select。 sys和traceback模块的文档。

你将需要把尝试/除了内部错误可能发生的最内层,即

 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 

… 等等

换句话说,您将需要在尽可能包含尽可能具体的情况下尽可能在最内层循环中包装可能失败的语句。

你想要回溯模块。 它会让你打印像Python一样的堆栈转储。 特别是, print_last函数将打印最后一个exception和一个堆栈跟踪。