显示正在运行的 Python 应用程序的堆栈跟踪
我有一个 Python 应用程序,它时不时地卡住,而且我不知道在哪里。
有什么方法可以向 Python 解释器发出信号,向您显示正在运行的确切代码吗?
某种即时堆栈跟踪?
相关问题
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
我有一个 Python 应用程序,它时不时地卡住,而且我不知道在哪里。
有什么方法可以向 Python 解释器发出信号,向您显示正在运行的确切代码吗?
某种即时堆栈跟踪?
相关问题
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
接受
或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
发布评论
评论(29)
我几乎总是处理多个线程,而主线程通常不做太多事情,所以最有趣的是转储所有堆栈(这更像是Java的转储)。 以下是基于此博客的实现:
I am almost always dealing with multiple threads and main thread is generally not doing much, so what is most interesting is to dump all the stacks (which is more like the Java's dump). Here is an implementation based on this blog:
获取一个未准备的Python程序的堆栈跟踪,在一个库存Python中运行没有调试符号可以通过黄铁矿。 在 Ubuntu Trusty 上对我来说就像一个魅力:(
向 @Albert 致敬,他的答案包含了指向这个的指针以及其他工具。)
Getting a stack trace of an unprepared python program, running in a stock python without debugging symbols can be done with pyrasite. Worked like a charm for me in on Ubuntu Trusty:
(Hat tip to @Albert, whose answer contained a pointer to this, among other tools.)
安装信号处理程序的建议很好,我经常使用它。 例如,bzr 默认情况下会安装一个调用
pdb.set_trace()
的 SIGQUIT 处理程序立即将您带入 pdb 提示符。 (请参阅 bzrlib.breakin< /a> 模块的源代码以获取确切的详细信息。)使用 pdb,您不仅可以获得当前的堆栈跟踪(使用(w)here
命令),还可以检查变量等。但是,有时我需要调试一个我没有先见之明安装信号处理程序的进程。在 Linux 上,您可以将 gdb 附加到进程并使用一些 gdb 宏获取 python 堆栈跟踪。 把 http://svn.python.org/projects/python/trunk/Misc/ gdbinit 位于
~/.gdbinit
中,然后:gdb -p
PID
不幸的是,它并不完全可靠,但它在大多数情况下都有效。 另请参阅 https://wiki.python.org/moin/DebuggingWithGdb
最后,附加
strace 通常可以让您很好地了解进程正在做什么。
The suggestion to install a signal handler is a good one, and I use it a lot. For example, bzr by default installs a SIGQUIT handler that invokes
pdb.set_trace()
to immediately drop you into a pdb prompt. (See the bzrlib.breakin module's source for the exact details.) With pdb you can not only get the current stack trace (with the(w)here
command) but also inspect variables, etc.However, sometimes I need to debug a process that I didn't have the foresight to install the signal handler in. On linux, you can attach gdb to the process and get a python stack trace with some gdb macros. Put http://svn.python.org/projects/python/trunk/Misc/gdbinit in
~/.gdbinit
, then:gdb -p
PID
pystack
It's not totally reliable unfortunately, but it works most of the time. See also https://wiki.python.org/moin/DebuggingWithGdb
Finally, attaching
strace
can often give you a good idea what a process is doing.您还可以很好地格式化堆栈跟踪,请参阅文档。
编辑:要按照 @Douglas Leeder 的建议模拟 Java 的行为,请将以下内容添加
到应用程序的启动代码中。 然后,您可以通过向正在运行的 Python 进程发送
SIGUSR1
来打印堆栈。You can also nicely format the stack trace, see the docs.
Edit: To simulate Java's behavior, as suggested by @Douglas Leeder, add this:
to the startup code in your application. Then you can print the stack by sending
SIGUSR1
to the running Python process.这可以通过优秀的 py-spy 来完成。 它是 Python 程序的采样分析器,因此它的工作是附加到 Python 进程并对其调用堆栈进行采样。 因此,您只需使用 py-spy dump --pid $SOME_PID 即可转储 $SOME_PID 进程中所有线程的调用堆栈。 通常它需要升级权限(以读取目标进程的内存)。
下面是一个线程 Python 应用程序的示例。
It can be done with excellent py-spy. It's a sampling profiler for Python programs, so its job is to attach to a Python processes and sample their call stacks. Hence,
py-spy dump --pid $SOME_PID
is all you need to do to dump call stacks of all threads in the$SOME_PID
process. Typically it needs escalated privileges (to read the target process' memory).Here's an example of how it looks like for a threaded Python application.
您可以尝试faulthandler 模块。 使用
pip install failurehandler
安装它并在程序开头添加:。 然后将 SIGUSR1 发送到您的进程(例如:
kill -USR1 42
)以将所有线程的 Python 回溯显示到标准输出。 阅读文档以获取更多选项(例如:登录到文件)以及显示回溯的其他方法。该模块现在是 Python 3.3 的一部分。 对于 Python 2,请参阅 http://faulthandler.readthedocs.org/
You can try the faulthandler module. Install it using
pip install faulthandler
and add:at the beginning of your program. Then send SIGUSR1 to your process (ex:
kill -USR1 42
) to display the Python traceback of all threads to the standard output. Read the documentation for more options (ex: log into a file) and other ways to display the traceback.The module is now part of Python 3.3. For Python 2, see http://faulthandler.readthedocs.org/
traceback 模块有一些不错的功能,其中他们: print_stack:
The traceback module has some nice functions, among them: print_stack:
您可以使用 PuDB(带有 curses 接口的 Python 调试器)来执行此操作。 只需添加
到您的代码中并在您想要中断时使用 Ctrl-C 即可。 如果您错过了并想重试,可以使用
c
继续并多次中断。You can use PuDB, a Python debugger with a curses interface to do this. Just add
to your code and use Ctrl-C when you want to break. You can continue with
c
and break again multiple times if you miss it and want to try again.pyringe 是一个调试器,可以与正在运行的 python 进程交互、打印堆栈跟踪、变量等,无需任何操作先验设置。
虽然我过去经常使用信号处理程序解决方案,但在某些环境中重现问题通常仍然很困难。
pyringe is a debugger that can interact with running python processes, print stack traces, variables, etc. without any a priori setup.
While I've often used the signal handler solution in the past, it can still often be difficult to reproduce the issue in certain environments.
从 Austin 3.3 开始,您可以使用
-w/--where
选项发出当前堆栈跟踪。 请参阅 https://stackoverflow.com/a/70905181/1838793如果您想要查看正在运行的 Python 应用程序,以类似顶部的方式查看“实时”调用堆栈,您可以使用 austin-tui (https://github.com/p403n1x87/austin-tui)。 您可以使用例如从 PyPI 安装它,请
注意,它需要 austin 二进制文件才能工作(https://github.com/ p403n1x87/austin),但是你可以使用以下命令附加到正在运行的 Python 进程
Since Austin 3.3, you can use the
-w/--where
option to emit the current stack trace. See https://stackoverflow.com/a/70905181/1838793If you want to peek at a running Python application to see the "live" call stack in a top-like fashon you can use austin-tui (https://github.com/p403n1x87/austin-tui). You can install it from PyPI with e.g.
Note that it requires the austin binary to work (https://github.com/p403n1x87/austin), but then you can attach to a running Python process with
我编写了一些工具,将其附加到正在运行的 Python 进程中,并注入一些代码来获取 Python shell。
请参阅此处:https://github.com/albertz/pydbattach
I hacked together some tool which attaches into a running Python process and injects some code to get a Python shell.
See here: https://github.com/albertz/pydbattach
值得一看 Pydb,“松散地基于 gdb 命令集的 Python 调试器的扩展版本”。 它包括信号管理器,可以在发送指定信号时负责启动调试器。
2006 年 Summer of Code 项目着眼于在名为 的模块中向 pydb 添加远程调试功能mpdb。
It's worth looking at Pydb, "an expanded version of the Python debugger loosely based on the gdb command set". It includes signal managers which can take care of starting the debugger when a specified signal is sent.
A 2006 Summer of Code project looked at adding remote-debugging features to pydb in a module called mpdb.
我一直在寻找一个解决方案来调试我的线程,多亏了haridsv,我在这里找到了它。 我使用稍微简化的版本,使用traceback.print_stack():
根据我的需要,我还按名称过滤线程。
I was looking for a while for a solution to debug my threads and I found it here thanks to haridsv. I use slightly simplified version employing the traceback.print_stack():
For my needs I also filter threads by name.
如果您使用的是 Linux 系统,请将
gdb
的强大功能与 Python 调试扩展结合使用(可以位于python-dbg
或python-debuginfo
中)包裹)。 它还有助于多线程应用程序、GUI 应用程序和 C 模块。运行您的程序:
这指示 gdb 准备 python.py 并
r
un 它。现在,当您的程序挂起时,切换到
gdb
控制台,按 Ctr+C 并执行:请参阅 示例会话和更多信息此处 和此处。
If you're on a Linux system, use the awesomeness of
gdb
with Python debug extensions (can be inpython-dbg
orpython-debuginfo
package). It also helps with multithreaded applications, GUI applications and C modules.Run your program with:
This instructs
gdb
to preparepython <programname>.py <arguments>
andr
un it.Now when you program hangs, switch into
gdb
console, press Ctr+C and execute:See example session and more info here and here.
在 Solaris 上,您可以使用 pstack(1) 无需更改 python 代码。 例如。
On Solaris, you can use pstack(1) No changes to the python code are necessary. eg.
真正对我有帮助的是 spiv 的提示 (如果我有声誉点,我会投票并发表评论)从未准备的Python进程中获取堆栈跟踪。 但直到我 修改 gdbinit 脚本。 所以:
下载https://svn.python.org/projects/ python/trunk/Misc/gdbinit 并将其放入
~/.gdbinit
编辑它,将PyEval_EvalFrame
更改为PyEval_EvalFrameEx
[编辑:不再需要; 截至 2010 年 1 月 14 日,链接文件已进行此更改]附加 gdb:
gdb -p PID
获取 python 堆栈跟踪:
pystack
What really helped me here is spiv's tip (which I would vote up and comment on if I had the reputation points) for getting a stack trace out of an unprepared Python process. Except it didn't work until I modified the gdbinit script. So:
download https://svn.python.org/projects/python/trunk/Misc/gdbinit and put it in
~/.gdbinit
edit it, changing[edit: no longer needed; the linked file already has this change as of 2010-01-14]PyEval_EvalFrame
toPyEval_EvalFrameEx
Attach gdb:
gdb -p PID
Get the python stack trace:
pystack
python -dv yourscript.py
这将使解释器在调试模式下运行,并让您跟踪解释器正在做什么。
如果你想交互式地调试代码,你应该像这样运行它:
python -m pdb yourscript.py
这告诉 python 解释器使用模块“pdb”运行你的脚本,该模块是 python 调试器,如果你像这样运行它,解释器将以交互模式执行,就像 GDB 一样
python -dv yourscript.py
That will make the interpreter to run in debug mode and to give you a trace of what the interpreter is doing.
If you want to interactively debug the code you should run it like this:
python -m pdb yourscript.py
That tells the python interpreter to run your script with the module "pdb" which is the python debugger, if you run it like that the interpreter will be executed in interactive mode, much like GDB
我会将其作为评论添加到 haridsv 的响应,但我缺乏这样做的声誉:
我们中的一些人仍然停留在 2.6 之前的 Python 版本上(Thread.ident 需要),所以我让代码在 Python 2.5 中工作(尽管没有线程名称)显示)如下:
I would add this as a comment to haridsv's response, but I lack the reputation to do so:
Some of us are still stuck on a version of Python older than 2.6 (required for Thread.ident), so I got the code working in Python 2.5 (though without the thread name being displayed) as such:
看一下
faulthandler
模块, Python 3.3 中的新功能。 PyPI 上提供了用于 Python 2 的faulthandler
向后移植。Take a look at the
faulthandler
module, new in Python 3.3. Afaulthandler
backport for use in Python 2 is available on PyPI.您可以使用 hypno 包,如下所示:
这会将堆栈跟踪打印到程序的标准输出中。
或者,如果您不想将任何内容打印到标准输出,或者您无权访问它(例如守护进程),您可以使用 madbg 包,它是一个 python 调试器,允许您附加到正在运行的 python 程序并在当前终端中对其进行调试。 它类似于
pyrasite
和pyringe
,但更新,不需要 gdb,并使用IPython
作为调试器(这意味着颜色和自动完成) )。要查看正在运行的程序的堆栈跟踪,您可以运行:
在调试器 shell 中输入:
bt
免责声明 - 这两个包都是我写的
You can use the hypno package, like so:
This would print a stack trace into the program's stdout.
Alternatively, if you don't want to print anything to stdout, or you don't have access to it (a daemon for example), you could use the madbg package, which is a python debugger that allows you to attach to a running python program and debug it in your current terminal. It is similar to
pyrasite
andpyringe
, but newer, doesn't require gdb, and usesIPython
for the debugger (which means colors and autocomplete).To see the stack trace of a running program, you could run:
And in the debugger shell, enter:
bt
Disclaimer - I wrote both packages
我属于 GDB 阵营,有 python 扩展。 关注 https://wiki.python.org/moin/DebuggingWithGdb,即
dnf install gdb python-debuginfo
或sudo apt-get install gdb python2.7-dbg
gdb python <运行进程的pid>
py- bt
还要考虑
信息线程
和线程应用所有py-bt
。I am in the GDB camp with the python extensions. Follow https://wiki.python.org/moin/DebuggingWithGdb, which means
dnf install gdb python-debuginfo
orsudo apt-get install gdb python2.7-dbg
gdb python <pid of running process>
py-bt
Also consider
info threads
andthread apply all py-bt
.如何在控制台中调试任何函数:
创建函数,在其中使用 pdb.set_trace(),然后调用您想要调试的函数。
然后调用创建的函数:
快乐调试:)
How to debug any function in console:
Create function where you use pdb.set_trace(), then function you want debug.
Then call created function:
Happy debugging :)
如果您需要使用 uWSGI 执行此操作,它内置了 Python Tracebacker -in ,只需在配置中启用它即可(数字附加到每个工作人员的名称上):
完成此操作后,您可以通过连接到套接字来简单地打印回溯:
In case you need to do this with uWSGI, it has Python Tracebacker built-in and it's just matter of enabling it in the configuration (number is attached to the name for each worker):
Once you have done this, you can print backtrace simply by connecting to the socket:
使用检查模块。
stack(context=1)
返回调用者框架上方堆栈的记录列表。
我发现它确实非常有帮助。
use the inspect module.
stack(context=1)
Return a list of records for the stack above the caller's frame.
I find it very helpful indeed.
在 Python 3 中,第一次在调试器中使用 c(ont(inue)) 时,pdb 将自动安装信号处理程序。 之后按 Control-C 会让你回到那里。 在 Python 2 中,这里有一个单行代码,即使在相对较旧的版本中也应该可以工作(在 2.7 中进行了测试,但我检查了 Python 源代码回到 2.4,它看起来还不错):
如果您花大量时间调试 Python,pdb 是值得学习的。 该界面有点迟钝,但使用过类似工具(例如 gdb)的任何人都应该熟悉。
In Python 3, pdb will automatically install a signal handler the first time you use c(ont(inue)) in the debugger. Pressing Control-C afterwards will drop you right back in there. In Python 2, here's a one-liner which should work even in relatively old versions (tested in 2.7 but I checked Python source back to 2.4 and it looked okay):
pdb is worth learning if you spend any amount of time debugging Python. The interface is a bit obtuse but should be familiar to anyone who has used similar tools, such as gdb.
我不知道有什么类似于 java 对 SIGQUIT 的响应,因此您可能必须将其构建到您的应用程序中。 也许您可以在另一个线程中创建一个服务器,该服务器可以获得对某种消息的响应的堆栈跟踪?
I don't know of anything similar to java's response to SIGQUIT, so you might have to build it in to your application. Maybe you could make a server in another thread that can get a stacktrace on response to a message of some kind?
没有办法挂钩正在运行的 python 进程并获得合理的结果。 如果进程锁定,我要做的就是连接 strace 并尝试找出到底发生了什么。
不幸的是,strace 通常是“修复”竞争条件的观察者,因此输出在那里也毫无用处。
There is no way to hook into a running python process and get reasonable results. What I do if processes lock up is hooking strace in and trying to figure out what exactly is happening.
Unfortunately often strace is the observer that "fixes" race conditions so that the output is useless there too.
在代码运行时,您可以插入这个小片段来查看格式良好的打印堆栈跟踪。 它假设您的项目根目录中有一个名为
logs
的文件夹。At the point where the code is run, you can insert this small snippet to see a nicely formatted printed stack trace. It assumes that you have a folder called
logs
at your project's root directory.我有一个用于这种情况的模块 - 一个进程将运行很长时间,但有时会因未知和不可重现的原因而卡住。 它有点hacky,并且仅适用于unix(需要信号):
要使用,只需在程序启动时调用listen()函数(您甚至可以将其粘贴在site.py中以使所有python程序都使用它),然后让它运行。 在任何时候,使用kill或在python中向进程发送SIGUSR1信号:
这将导致程序在当前所在的位置中断到python控制台,向您显示堆栈跟踪,并让您操作变量。 使用 control-d (EOF) 继续运行(但请注意,您可能会在发出信号时中断任何 I/O 等,因此它并不是完全非侵入性的。
我有另一个脚本可以执行相同的操作,除了它通过管道与正在运行的进程进行通信(以允许调试后台进程等)之外,在此处发布它有点大,但我已将其添加为 Python 食谱。
I have module I use for situations like this - where a process will be running for a long time but gets stuck sometimes for unknown and irreproducible reasons. Its a bit hacky, and only works on unix (requires signals):
To use, just call the listen() function at some point when your program starts up (You could even stick it in site.py to have all python programs use it), and let it run. At any point, send the process a SIGUSR1 signal, using kill, or in python:
This will cause the program to break to a python console at the point it is currently at, showing you the stack trace, and letting you manipulate the variables. Use control-d (EOF) to continue running (though note that you will probably interrupt any I/O etc at the point you signal, so it isn't fully non-intrusive.
I've another script that does the same thing, except it communicates with the running process through a pipe (to allow for debugging backgrounded processes etc). Its a bit large to post here, but I've added it as a python cookbook recipe.