显示正在运行的Python应用程序的堆栈跟踪

Seb*_*Seb 330 python debugging stack-trace traceback

我有这个Python应用程序不时被卡住,我无法找到在哪里.

有没有办法告诉Python解释器向您显示正在运行的确切代码?

某种即时堆栈跟踪?

相关问题:

Bri*_*ian 306

我有这样的情况下使用的模块 - 一个进程将运行很长时间,但有时会因未知和不可复制的原因而卡住.它有点hacky,只适用于unix(需要信号):

import code, traceback, signal

def debug(sig, frame):
    """Interrupt running process, and provide a python prompt for
    interactive debugging."""
    d={'_frame':frame}         # Allow access to frame object.
    d.update(frame.f_globals)  # Unless shadowed by global
    d.update(frame.f_locals)

    i = code.InteractiveConsole(d)
    message  = "Signal received : entering python shell.\nTraceback:\n"
    message += ''.join(traceback.format_stack(frame))
    i.interact(message)

def listen():
    signal.signal(signal.SIGUSR1, debug)  # Register handler
Run Code Online (Sandbox Code Playgroud)

要使用,只需在程序启动时调用listen()函数(你甚至可以将它粘贴在site.py中让所有python程序都使用它),并让它运行.在任何时候,使用kill或python发送进程SIGUSR1信号:

    os.kill(pid, signal.SIGUSR1)
Run Code Online (Sandbox Code Playgroud)

这将导致程序在当前所处的位置中断到python控制台,向您显示堆栈跟踪,并让您操作变量.使用control-d(EOF)继续运行(但请注意,您可能会在发出信号的位置中断任何I/O等,因此它不是完全非侵入式的.

我有另一个脚本执行相同的操作,除了它通过管道与正在运行的进程通信(以允许调试后台进程等).它有点大,可以在这里发布,但我已将其添加为python cookbook配方.

  • 如果应用程序卡住,Python解释器循环可能无法运行来处理信号.使用`faulthandler`模块(及其在PyPI上找到的后端)用于C级信号处理程序,它将打印Python堆栈而不需要解释器循环响应. (10认同)
  • PDB不这样做吗? (3认同)
  • 我现在已将它发布在python cookbook网站上 - 链接已添加. (2认同)
  • 棒极了!这也可以将信号发送到包含"mypythonapp"一词的所有进程:pkill -SIGUSR1 -f mypythonapp (2认同)

spi*_*piv 144

安装信号处理程序的建议很好,我经常使用它.例如,bzr默认安装一个SIGQUIT处理程序,该处理程序调用pdb.set_trace()立即将您放入pdb提示符.(有关详细信息,请参阅bzrlib.breakin模块的源代码.)使用pdb,您不仅可以获取当前堆栈跟踪,还可以检查变量等.

但是,有时我需要调试一个我没有远见来安装信号处理程序的进程.在linux上,你可以将gdb附加到进程并获得带有一些gdb宏的python堆栈跟踪.将http://svn.python.org/projects/python/trunk/Misc/gdbinit放入~/.gdbinit,然后:

  • 附上gdb: gdb -p PID
  • 获取python堆栈跟踪: pystack

不幸的是,它并不完全可靠,但它大部分时间都有效.

最后,附加strace通常可以让您很好地了解流程正在做什么.

  • 次要更新:这个gdb技术(和更新的代码)记录在http://wiki.python.org/moin/DebuggingWithGdb这方面有一些开发,记录在该URL,显然gdb 7有一些Python支持. (25认同)
  • 据我所知,这只有在编译成python二进制文件的调试符号时才有效 - 例如:你用python2-dbg运行程序(在Ubuntu上,这是在一个单独的包`python-dbg`中).没有这些符号,您似乎没有获得太多有用的信息. (7认同)
  • gdb 7+ --with-python支持由python-gdb.py提供.更多细节:https://chezsoi.org/lucas/blog/2014/11/07/en-gdb-python-macros/ (6认同)
  • 辉煌!pystack命令有时会锁定,但是在执行此操作之前,它无需使用任何准备即可在python代码行中为我提供该过程的完整堆栈跟踪。 (2认同)

har*_*dsv 71

我几乎总是处理多个线程,主线程通常没有做太多,所以最有趣的是转储所有堆栈(这更像是Java的转储).以下是基于此博客的实现:

import threading, sys, traceback

def dumpstacks(signal, frame):
    id2name = dict([(th.ident, th.name) for th in threading.enumerate()])
    code = []
    for threadId, stack in sys._current_frames().items():
        code.append("\n# Thread: %s(%d)" % (id2name.get(threadId,""), 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()))
    print "\n".join(code)

import signal
signal.signal(signal.SIGQUIT, dumpstacks)
Run Code Online (Sandbox Code Playgroud)


Nic*_*lay 50

获得一个没有准备的 python程序的堆栈跟踪,在没有调试符号的股票python中运行可以使用pyrasite完成.在Ubuntu Trusty上像我一样的魅力:

$ sudo pip install pyrasite
$ echo 0 | sudo tee /proc/sys/kernel/yama/ptrace_scope
$ sudo pyrasite 16262 dump_stacks.py # dumps stacks to stdout/stderr of the python program
Run Code Online (Sandbox Code Playgroud)

(帽子提示@Albert,其答案中包含指向此的工具,以及其他工具.)

  • 重要提示:在运行pyrasite之前运行`apt-get install gdb python-dbg`(或等效的),否则它将无声地失败.如果像魅力一样工作! (11认同)
  • 这对我很有用,其中`dump_stacks.py`只是`import traback; traceback.print_stack()` (5认同)
  • `traceback -l`为您提供了一个可以使用的预定义python脚本列表,`dump_stacks.py`就是其中之一.如果您使用自己的(例如将堆栈跟踪写入文件),使用其他名称可能是明智的. (2认同)
  • Pyrasite 的最后一次发布是 [2012 年](https://pypi.org/project/pyrasite/#history) (2认同)

Tor*_*rek 35

>>> import traceback
>>> def x():
>>>    print traceback.extract_stack()

>>> x()
[('<stdin>', 1, '<module>', None), ('<stdin>', 2, 'x', None)]
Run Code Online (Sandbox Code Playgroud)

您还可以很好地格式化堆栈跟踪,请参阅文档.

编辑:为了模拟Java的行为,正如@Douglas Leeder所建议的那样,添加:

import signal
import traceback

signal.signal(signal.SIGUSR1, lambda sig, stack: traceback.print_stack(stack))
Run Code Online (Sandbox Code Playgroud)

到应用程序中的启动代码.然后,您可以通过发送SIGUSR1到正在运行的Python进程来打印堆栈.

  • 这只会打印主线程的回溯。我还没有找到一个解决方案来查看所有线程的痕迹。实际上,python 似乎缺少从 Thread 对象检索堆栈的 API,尽管 threading.enumerate() 可以访问所有 Thread 对象。 (2认同)

gul*_*lgi 27

回溯模块有一些不错的功能,其中包括:print_stack:

import traceback

traceback.print_stack()
Run Code Online (Sandbox Code Playgroud)

  • 要将堆栈跟踪写出到文件中,请使用:`import traceback; f = open('/tmp/stack-trace.log', 'w') traceback.print_stack(file=f) f.close()` (2认同)
  • +1 给@gulgi,因为他的答案很简单。对于我从脚本函数获取调用堆栈跟踪的简单任务来说,其他一些答案看起来非常复杂。 (2认同)

hay*_*ypo 24

您可以尝试faulthandler模​​块.使用pip install faulthandler并添加以下命令:

import faulthandler, signal
faulthandler.register(signal.SIGUSR1)
Run Code Online (Sandbox Code Playgroud)

在你的程序的开头.然后将SIGUSR1发送到您的进程(例如:),kill -USR1 42以显示所有线程到标准输出的Python回溯.阅读文档以获取更多选项(例如:登录文件)以及显示回溯的其他方法.

该模块现在是Python 3.3的一部分.对于Python 2,请参阅http://faulthandler.readthedocs.org/


Gun*_*iem 20

在这里真正帮助我的是spiv的提示(我会投票并评论我是否有声望点)从一个毫无准备的 Python进程中获取堆栈跟踪.除非在我修改gdbinit脚本之前它不起作用.所以:

  • 不,它没有 - 我不清楚,对不起,因为这条线出现在三个地方.我链接的补丁显示了当我看到这项工作时我改变了哪一个. (2认同)
  • 就像@spiv的回答一样,这需要程序在使用调试符号编译的python下运行.否则你只会在当前的背景下得到"无符号"co (2认同)

Kon*_*kiy 12

我想将此作为对haridsv的回应的评论,但我缺乏这样做的声誉:

我们中的一些人仍然坚持使用早于2.6的Python版本(Thread.ident需要),所以我在Python 2.5中使用了代码(尽管没有显示线程名称):

import traceback
import sys
def dumpstacks(signal, frame):
    code = []
    for threadId, stack in sys._current_frames().items():
            code.append("\n# Thread: %d" % (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()))
    print "\n".join(code)

import signal
signal.signal(signal.SIGQUIT, dumpstacks)
Run Code Online (Sandbox Code Playgroud)


Gus*_*bio 11

python -dv yourscript.py

这将使解释器以调试模式运行,并为您提供解释器正在执行的操作的跟踪.

如果您想以交互方式调试代码,您应该像这样运行它:

python -m pdb yourscript.py

这告诉python解释器使用模块"pdb"运行你的脚本,这是python调试器,如果你运行它就像解释器将以交互模式执行,就像GDB一样


Mat*_*ner 10

看一下faulthandlerPython 3.3中的新模块.一个faulthandler反向移植了在Python 2使用可PyPI上.

  • @haypo的最新答案对此进行了更详细的介绍。我不确定通常如何在SO上进行处理,但是有两个本质上重复的答案感觉不对... (2认同)

小智 7

在Solaris上,您可以使用pstack(1)不需要更改python代码.例如.

# pstack 16000 | grep : | head
16000: /usr/bin/python2.6 /usr/lib/pkg.depotd --cfg svc:/application/pkg/serv
[ /usr/lib/python2.6/vendor-packages/cherrypy/process/wspbus.py:282 (_wait) ]
[ /usr/lib/python2.6/vendor-packages/cherrypy/process/wspbus.py:295 (wait) ]
[ /usr/lib/python2.6/vendor-packages/cherrypy/process/wspbus.py:242 (block) ]
[ /usr/lib/python2.6/vendor-packages/cherrypy/_init_.py:249 (quickstart) ]
[ /usr/lib/pkg.depotd:890 (<module>) ]
[ /usr/lib/python2.6/threading.py:256 (wait) ]
[ /usr/lib/python2.6/Queue.py:177 (get) ]
[ /usr/lib/python2.6/vendor-packages/pkg/server/depot.py:2142 (run) ]
[ /usr/lib/python2.6/threading.py:477 (run)
etc.
Run Code Online (Sandbox Code Playgroud)

  • 似乎有一个Debian/Ubuntu程序``pstack``做同样的事情 (2认同)

saa*_*aaj 7

它可以通过优秀的py-spy来完成。它是Python 程序的采样分析器,因此它的工作是附加到 Python 进程并对其调用堆栈进行采样。因此,py-spy dump --pid $SOME_PID您只需转储$SOME_PID进程中所有线程的调用堆栈即可。通常它需要提升权限(读取目标进程的内存)。

下面是一个关于线程 Python 应用程序的示例。

$ sudo py-spy dump --pid 31080
Process 31080: python3.7 -m chronologer -e production serve -u www-data -m
Python v3.7.1 (/usr/local/bin/python3.7)

Thread 0x7FEF5E410400 (active): "MainThread"
    _wait (cherrypy/process/wspbus.py:370)
    wait (cherrypy/process/wspbus.py:384)
    block (cherrypy/process/wspbus.py:321)
    start (cherrypy/daemon.py:72)
    serve (chronologer/cli.py:27)
    main (chronologer/cli.py:84)
    <module> (chronologer/__main__.py:5)
    _run_code (runpy.py:85)
    _run_module_as_main (runpy.py:193)
Thread 0x7FEF55636700 (active): "_TimeoutMonitor"
    run (cherrypy/process/plugins.py:518)
    _bootstrap_inner (threading.py:917)
    _bootstrap (threading.py:885)
Thread 0x7FEF54B35700 (active): "HTTPServer Thread-2"
    accept (socket.py:212)
    tick (cherrypy/wsgiserver/__init__.py:2075)
    start (cherrypy/wsgiserver/__init__.py:2021)
    _start_http_thread (cherrypy/process/servers.py:217)
    run (threading.py:865)
    _bootstrap_inner (threading.py:917)
    _bootstrap (threading.py:885)
...
Thread 0x7FEF2BFFF700 (idle): "CP Server Thread-10"
    wait (threading.py:296)
    get (queue.py:170)
    run (cherrypy/wsgiserver/__init__.py:1586)
    _bootstrap_inner (threading.py:917)
    _bootstrap (threading.py:885)  
Run Code Online (Sandbox Code Playgroud)


kma*_*ork 7

您可以使用hypno包,如下所示:

hypno <pid> "import traceback; traceback.print_stack()"
Run Code Online (Sandbox Code Playgroud)

这会将堆栈跟踪打印到程序的标准输出中。

或者,如果您不想将任何内容打印到标准输出,或者您无权访问它(例如守护进程),您可以使用 madbg 包,它一个 python 调试器,允许您附加到正在运行的程序python 程序并在当前终端中对其进行调试。它类似于pyrasitepyringe,但更新,不需要 gdb,并用于IPython调试器(这意味着颜色和自动完成)。

要查看正在运行的程序的堆栈跟踪,您可以运行:

madbg attach <pid>
Run Code Online (Sandbox Code Playgroud)

然后在调试器 shell 中输入: bt

免责声明 - 这两个包都是我写的


Ste*_*fan 6

我正在寻找一段时间来调试我的线程,我在这里找到了感谢haridsv.我使用traceback.print_stack()使用稍微简化的版本:

import sys, traceback, signal
import threading
import os

def dumpstacks(signal, frame):
  id2name = dict((th.ident, th.name) for th in threading.enumerate())
  for threadId, stack in sys._current_frames().items():
    print(id2name[threadId])
    traceback.print_stack(f=stack)

signal.signal(signal.SIGQUIT, dumpstacks)

os.killpg(os.getpgid(0), signal.SIGQUIT)
Run Code Online (Sandbox Code Playgroud)

为了我的需要,我也按名称过滤线程.


ana*_*nik 6

如果您使用的是Linux系统,请使用gdbPython调试扩展的强大功能(可以在python-dbgpython-debuginfo包中).它还有助于多线程应用程序,GUI应用程序和C模块.

运行程序:

$ gdb -ex r --args python <programname>.py [arguments]
Run Code Online (Sandbox Code Playgroud)

这指示gdb准备python <programname>.py <arguments>r解除它.

现在当程序挂起时,切换到gdb控制台,按下Ctr+C并执行:

(gdb) thread apply all py-list
Run Code Online (Sandbox Code Playgroud)

请参阅示例会话以及此处此处的更多信息.


归档时间:

查看次数:

120505 次

最近记录:

6 年,8 月 前