Dump所有活动线程的堆栈跟踪

38

我试图转储所有活动线程的列表,包括每个线程的当前堆栈。 我可以使用 threading.enumerate() 获取所有线程的列表,但我无法从那里找到获取堆栈的方法。

背景:Zope/Plone 应用程序会不时地出现问题,消耗了 100% 的 cpu,并且需要重新启动。 我有一种感觉,这是一个无法正常终止的循环,但是我无法在测试环境中重现它以进行验证。 我成功注册了一个信号处理程序,可以从外部触发,因此可以在情况再次发生时立即触发一些代码。 如果我能够转储所有活动线程的堆栈跟踪,那就可以给我一个线索,说明出了什么问题。整个应用程序都在 python 2.4 上运行...

有关如何追踪此类情况的任何想法都将不胜感激 :)

谢谢, Chriss

6个回答

43

正如jitter在早期答案中指出的那样,sys._current_frames()可以为v2.5+提供所需内容。对于懒惰的人来说,以下代码片段对我很有用,可能也能帮助你:

print >> sys.stderr, "\n*** STACKTRACE - START ***\n"
code = []
for threadId, stack in sys._current_frames().items():
    code.append("\n# ThreadID: %s" % threadId)
    for filename, lineno, name, line in traceback.extract_stack(stack):
        code.append('File: "%s", line %d, in %s' % (filename,
                                                    lineno, name))
        if line:
            code.append("  %s" % (line.strip()))

for line in code:
    print >> sys.stderr, line
print >> sys.stderr, "\n*** STACKTRACE - END ***\n"

39

对于Python 3.3及更高版本,有faulthandler.dump_traceback()方法。

下面的代码会生成类似的输出,但包括线程名称,并可增强以打印更多信息。

for th in threading.enumerate():
    print(th)
    traceback.print_stack(sys._current_frames()[th.ident])
    print()

2
注意:faulthandler代码在Python 3.9.4中出现了段错误(这是目前Ubuntu 21.04中的最新版本),而这个问题在大约两个月前已经在3.9.7 Python版本中修复。 - Anton Kraievyi

10
使用Zope时,您需要安装Products.signalstackmr.freeze;它们专门为此目的而设计!将USR1信号发送到Zope服务器,它将立即将所有线程的堆栈跟踪转储到控制台。即使所有Zope线程被锁定,它也会这样做。在幕后,这些包间接使用threadframes;对于Python版本2.5及以上版本,如果没有使用Zope,可以使用sys._current_frames()函数构建相同的功能以访问每个线程的堆栈帧。从Zope 2.12.5开始,此功能已集成到Zope本身中,不再需要安装其他软件包。

现在在Plone中,“不需要特殊的软件包”。http://stackoverflow.com/a/36633215/3046069 - Danimal
@Danimal:谢谢,已添加到帖子中。2.12.5是我写这个答案一年后发布的。 - Martijn Pieters
threadframes的链接现在已经失效了,但是无论如何,在Python 2.5中,您可以使用sys._current_frames() - Imran Rashid
@ImranRashid:是的,我的回答已经说明了你可以。我已经更换了坏掉的链接。 - Martijn Pieters

7

1

0

ASPN 上有一份适用的配方。您可以使用 threading.enumerate() 获取所有 tids,然后只需调用 _async_raise() 并附上一些合适的异常来强制生成堆栈跟踪。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接