Python 中使用回溯记录异常
如何记录 Python 异常?
try:
do_something()
except:
# How can I log my exception here, complete with its traceback?
How can I log my Python exceptions?
try:
do_something()
except:
# How can I log my exception here, complete with its traceback?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(13)
在 < 中使用
logging.exception
code>except: 处理程序/块,用于记录当前异常以及跟踪信息,并在前面添加一条消息。现在查看日志文件
/tmp/logging_example.out
:Use
logging.exception
from within theexcept:
handler/block to log the current exception along with the trace information, prepended with a message.Now looking at the log file,
/tmp/logging_example.out
:使用
exc_info
选项可能会更好,仍然是警告或错误标题:Use
exc_info
options may be better, remains warning or error title:我的工作最近要求我记录应用程序中的所有回溯/异常。我尝试了其他人在网上发布的多种技术,例如上面的技术,但最终选择了一种不同的方法。重写
traceback.print_exception
。我在 http:// www.bbarrows.com/ 这会更容易阅读,但我也会将其粘贴到这里。
当负责记录我们的软件在野外可能遇到的所有异常时,我尝试了多种不同的技术来记录我们的 python 异常回溯。起初我认为 python 系统异常钩子 sys.excepthook 将是插入日志代码的完美位置。我正在尝试类似的操作:
这适用于主线程,但我很快发现我的 sys.excepthook 在我的进程启动的任何新线程中都不会存在。这是一个大问题,因为该项目中的大多数事情都发生在线程中。
在谷歌搜索并阅读大量文档之后,我发现最有用的信息来自 Python 问题跟踪器。
该线程的第一篇文章展示了 sys.excepthook 不跨线程持久化的工作示例(如下所示)。显然这是预期的行为。
这个 Python Issue 线程上的消息确实导致了 2 个建议的黑客攻击。要么子类
Thread
并将 run 方法包装在我们自己的 try except 块中,以便捕获并记录异常,要么使用猴子补丁threading.Thread.run
在您自己的 try except 中运行阻止并记录异常。在我看来,第一种子类化 Thread 的方法在您的代码中不太优雅,因为您必须在任何想要拥有日志记录线程的地方导入并使用自定义的 Thread 类。这最终变得很麻烦,因为我必须搜索整个代码库并用这个自定义
Thread
替换所有正常的Threads
。然而,这个Thread
正在做什么是很清楚的,并且如果自定义日志记录代码出现问题,人们可以更容易地诊断和调试。客户日志记录线程可能如下所示:猴子修补
threading.Thread.run
的第二种方法很好,因为我可以在__main__
之后运行它一次并检测我的日志记录所有异常中的代码。猴子补丁对于调试来说可能很烦人,因为它改变了某些东西的预期功能。 Python 问题跟踪器建议的补丁是:直到我开始测试异常日志记录,我才意识到我的做法完全错误。
放置了一个
为了测试我在代码中 。但是,包装调用此方法的方法是一个 try except 块,它打印出回溯并吞掉异常。这非常令人沮丧,因为我看到回溯打印到 STDOUT 但没有被记录。然后我决定记录回溯的一种更简单的方法就是对所有 python 代码用来打印回溯本身的方法进行猴子修补,traceback.print_exception。
我最终得到了类似于以下内容的结果:
此代码将回溯写入字符串缓冲区并将其记录到日志错误中。我有一个自定义日志记录处理程序设置了“customLogger”记录器,它获取错误级别日志并将其发送回家进行分析。
My job recently tasked me with logging all the tracebacks/exceptions from our application. I tried numerous techniques that others had posted online such as the one above but settled on a different approach. Overriding
traceback.print_exception
.I have a write up at http://www.bbarrows.com/ That would be much easier to read but Ill paste it in here as well.
When tasked with logging all the exceptions that our software might encounter in the wild I tried a number of different techniques to log our python exception tracebacks. At first I thought that the python system exception hook, sys.excepthook would be the perfect place to insert the logging code. I was trying something similar to:
This worked for the main thread but I soon found that the my sys.excepthook would not exist across any new threads my process started. This is a huge issue because most everything happens in threads in this project.
After googling and reading plenty of documentation the most helpful information I found was from the Python Issue tracker.
The first post on the thread shows a working example of the
sys.excepthook
NOT persisting across threads (as shown below). Apparently this is expected behavior.The messages on this Python Issue thread really result in 2 suggested hacks. Either subclass
Thread
and wrap the run method in our own try except block in order to catch and log exceptions or monkey patchthreading.Thread.run
to run in your own try except block and log the exceptions.The first method of subclassing
Thread
seems to me to be less elegant in your code as you would have to import and use your customThread
class EVERYWHERE you wanted to have a logging thread. This ended up being a hassle because I had to search our entire code base and replace all normalThreads
with this customThread
. However, it was clear as to what thisThread
was doing and would be easier for someone to diagnose and debug if something went wrong with the custom logging code. A custome logging thread might look like this:The second method of monkey patching
threading.Thread.run
is nice because I could just run it once right after__main__
and instrument my logging code in all exceptions. Monkey patching can be annoying to debug though as it changes the expected functionality of something. The suggested patch from the Python Issue tracker was:It was not until I started testing my exception logging I realized that I was going about it all wrong.
To test I had placed a
somewhere in my code. However, wrapping a a method that called this method was a try except block that printed out the traceback and swallowed the exception. This was very frustrating because I saw the traceback bring printed to STDOUT but not being logged. It was I then decided that a much easier method of logging the tracebacks was just to monkey patch the method that all python code uses to print the tracebacks themselves, traceback.print_exception.
I ended up with something similar to the following:
This code writes the traceback to a String Buffer and logs it to logging ERROR. I have a custom logging handler set up the 'customLogger' logger which takes the ERROR level logs and send them home for analysis.
您可以通过将处理程序分配给
sys 来记录主线程上所有未捕获的异常.excepthook
,也许使用Python 日志记录函数的 exc_info
参数:但是,如果您的程序使用线程,请注意使用
threading.Thread
在未捕获的异常时不会触发sys.excepthook
发生在它们内部,如 Python 问题跟踪器上的 问题 1230540 中所述。有人建议采用一些技巧来解决此限制,例如猴子修补Thread.__init__
以使用替代的run
方法覆盖self.run
它将原始内容包装在try
块中,并从except
块内部调用sys.excepthook
。或者,您可以自己手动将每个线程的入口点包装在try
/except
中。You can log all uncaught exceptions on the main thread by assigning a handler to
sys.excepthook
, perhaps using theexc_info
parameter of Python's logging functions:If your program uses threads, however, then note that threads created using
threading.Thread
will not triggersys.excepthook
when an uncaught exception occurs inside them, as noted in Issue 1230540 on Python's issue tracker. Some hacks have been suggested there to work around this limitation, like monkey-patchingThread.__init__
to overwriteself.run
with an alternativerun
method that wraps the original in atry
block and callssys.excepthook
from inside theexcept
block. Alternatively, you could just manually wrap the entry point for each of your threads intry
/except
yourself.您可以使用记录器在任何级别(DEBUG、INFO、...)获取回溯。请注意,使用
logging.exception
时,级别为 ERROR。编辑:
这也有效(使用 python 3.6)
You can get the traceback using a logger, at any level (DEBUG, INFO, ...). Note that using
logging.exception
, the level is ERROR.EDIT:
This works too (using python 3.6)
我在寻找什么:
请参阅:
What I was looking for:
See:
未捕获的异常消息将发送到 STDERR,因此您可以使用用于运行 Python 脚本的任何 shell 将 STDERR 发送到文件,而不是在 Python 本身中实现日志记录。在 Bash 脚本中,您可以通过输出重定向来执行此操作,如 中所述BASH 指南。
示例
将错误附加到文件,将其他输出附加到终端:
使用交错的 STDOUT 和 STDERR 输出覆盖文件:
Uncaught exception messages go to STDERR, so instead of implementing your logging in Python itself you could send STDERR to a file using whatever shell you're using to run your Python script. In a Bash script, you can do this with output redirection, as described in the BASH guide.
Examples
Append errors to file, other output to the terminal:
Overwrite file with interleaved STDOUT and STDERR output:
这是使用 sys.excepthook 的版本
Here is a version that uses sys.excepthook
我就是这样做的。
This is how I do it.
也许不那么时尚,但更容易:
maybe not as stylish, but easier:
为了避免其他人可能在这里迷失,在日志中捕获它的最佳方法是使用
traceback.format_exc()
调用,然后按顺序拆分每行的字符串在生成的日志文件中捕获:To key off of others that may be getting lost in here, the way that works best with capturing it in logs is to use the
traceback.format_exc()
call and then split this string for each line in order to capture in the generated log file:由于某种原因,简单地使用
log.exception(exc)
对我来说不起作用,我必须手动构建exc_info
参数,如 这个答案。For some reason simply using
log.exception(exc)
didn't work for me and I had to manually build theexc_info
param as in this answer.下面是一个取自 python 2.6 文档 的简单示例:
Heres a simple example taken from the python 2.6 documentation: