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

发布于 2024-07-05 07:38:29 字数 498 浏览 12 评论 0 原文

我有一个 Python 应用程序,它时不时地卡住,而且我不知道在哪里。

有什么方法可以向 Python 解释器发出信号,向您显示正在运行的确切代码吗?

某种即时堆栈跟踪?

相关问题

I have this Python application that gets stuck from time to time and I can't find out where.

Is there any way to signal Python interpreter to show you the exact code that's running?

Some kind of on-the-fly stacktrace?

Related questions:

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(29

一场春暖 2024-07-12 07:38:30

我几乎总是处理多个线程,而主线程通常不做太多事情,所以最有趣的是转储所有堆栈(这更像是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)

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:

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)
鱼窥荷 2024-07-12 07:38:30

获取一个未准备的Python程序的堆栈跟踪,在一个库存Python中运行没有调试符号可以通过黄铁矿。 在 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

向 @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:

$ 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

(Hat tip to @Albert, whose answer contained a pointer to this, among other tools.)

风筝在阴天搁浅。 2024-07-12 07:38:30

安装信号处理程序的建议很好,我经常使用它。 例如,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 中,然后:

  • Attach gdb: gdb -p PID
  • 获取python 堆栈跟踪:

不幸的是,它并不完全可靠,但它在大多数情况下都有效。 另请参阅 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:

  • Attach gdb: gdb -p PID
  • Get the python stack trace: 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.

川水往事 2024-07-12 07:38:30
>>> import traceback
>>> def x():
>>>    print traceback.extract_stack()

>>> x()
[('<stdin>', 1, '<module>', None), ('<stdin>', 2, 'x', None)]

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

编辑:要按照 @Douglas Leeder 的建议模拟 Java 的行为,请将以下内容添加

import signal
import traceback

signal.signal(signal.SIGUSR1, lambda sig, stack: traceback.print_stack(stack))

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

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

>>> x()
[('<stdin>', 1, '<module>', None), ('<stdin>', 2, 'x', None)]

You can also nicely format the stack trace, see the docs.

Edit: To simulate Java's behavior, as suggested by @Douglas Leeder, add this:

import signal
import traceback

signal.signal(signal.SIGUSR1, lambda sig, stack: traceback.print_stack(stack))

to the startup code in your application. Then you can print the stack by sending SIGUSR1 to the running Python process.

任谁 2024-07-12 07:38:30

这可以通过优秀的 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)  

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.

$ 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)  
日裸衫吸 2024-07-12 07:38:30

您可以尝试faulthandler 模块。 使用 pip install failurehandler 安装它并

import faulthandler, signal
faulthandler.register(signal.SIGUSR1)

在程序开头添加:。 然后将 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:

import faulthandler, signal
faulthandler.register(signal.SIGUSR1)

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/

单身情人 2024-07-12 07:38:30

traceback 模块有一些不错的功能,其中他们: print_stack:

import traceback

traceback.print_stack()

The traceback module has some nice functions, among them: print_stack:

import traceback

traceback.print_stack()
断念 2024-07-12 07:38:30

您可以使用 PuDB(带有 curses 接口的 Python 调试器)来执行此操作。 只需添加

from pudb import set_interrupt_handler; set_interrupt_handler()

到您的代码中并在您想要中断时使用 Ctrl-C 即可。 如果您错过了并想重试,可以使用 c 继续并多次中断。

You can use PuDB, a Python debugger with a curses interface to do this. Just add

from pudb import set_interrupt_handler; set_interrupt_handler()

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.

停顿的约定 2024-07-12 07:38:30

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.

岛歌少女 2024-07-12 07:38:30

从 Austin 3.3 开始,您可以使用 -w/--where 选项发出当前堆栈跟踪。 请参阅 https://stackoverflow.com/a/70905181/1838793

在此处输入图像描述

如果您想要查看正在运行的 Python 应用程序,以类似顶部的方式查看“实时”调用堆栈,您可以使用 austin-tui (https://github.com/p403n1x87/austin-tui)。 您可以使用例如从 PyPI 安装它,请

pipx install austin-tui

注意,它需要 austin 二进制文件才能工作(https://github.com/ p403n1x87/austin),但是你可以使用以下命令附加到正在运行的 Python 进程

austin-tui -p <pid>

Since Austin 3.3, you can use the -w/--where option to emit the current stack trace. See https://stackoverflow.com/a/70905181/1838793

enter image description here

If 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.

pipx install austin-tui

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

austin-tui -p <pid>
还在原地等你 2024-07-12 07:38:30

我编写了一些工具,将其附加到正在运行的 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

死开点丶别碍眼 2024-07-12 07:38:30

值得一看 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.

冷…雨湿花 2024-07-12 07:38:30

我一直在寻找一个解决方案来调试我的线程,多亏了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)

根据我的需要,我还按名称过滤线程。

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():

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)

For my needs I also filter threads by name.

一世旳自豪 2024-07-12 07:38:30

如果您使用的是 Linux 系统,请将 gdb 的强大功能与 Python 调试扩展结合使用(可以位于 python-dbgpython-debuginfo 中)包裹)。 它还有助于多线程应用程序、GUI 应用程序和 C 模块。

运行您的程序:

$ gdb -ex r --args python <programname>.py [arguments]

这指示 gdb 准备 python .py run 它。

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

(gdb) thread apply all py-list

请参阅 示例会话和更多信息此处此处

If you're on a Linux system, use the awesomeness of gdb with Python debug extensions (can be in python-dbg or python-debuginfo package). It also helps with multithreaded applications, GUI applications and C modules.

Run your program with:

$ gdb -ex r --args python <programname>.py [arguments]

This instructs gdb to prepare python <programname>.py <arguments> and run it.

Now when you program hangs, switch into gdb console, press Ctr+C and execute:

(gdb) thread apply all py-list

See example session and more info here and here.

我也只是我 2024-07-12 07:38:30

在 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.

On Solaris, you can use pstack(1) No changes to the python code are necessary. eg.

# 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.
治碍 2024-07-12 07:38:30

真正对我有帮助的是 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 PyEval_EvalFrame to PyEval_EvalFrameEx [edit: no longer needed; the linked file already has this change as of 2010-01-14]

  • Attach gdb: gdb -p PID

  • Get the python stack trace: pystack

秉烛思 2024-07-12 07:38:30

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

半衾梦 2024-07-12 07:38:30

我会将其作为评论添加到 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)

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:

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)
青瓷清茶倾城歌 2024-07-12 07:38:30

看一下 faulthandler 模块, Python 3.3 中的新功能。 PyPI 上提供了用于 Python 2 的 faulthandler 向后移植

Take a look at the faulthandler module, new in Python 3.3. A faulthandler backport for use in Python 2 is available on PyPI.

蓝天白云 2024-07-12 07:38:30

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

hypno <pid> "import traceback; traceback.print_stack()"

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

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

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

madbg attach <pid>

在调试器 shell 中输入:
bt

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

You can use the hypno package, like so:

hypno <pid> "import traceback; traceback.print_stack()"

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 and pyringe, but newer, doesn't require gdb, and uses IPython for the debugger (which means colors and autocomplete).

To see the stack trace of a running program, you could run:

madbg attach <pid>

And in the debugger shell, enter:
bt

Disclaimer - I wrote both packages

不离久伴 2024-07-12 07:38:30

我属于 GDB 阵营,有 python 扩展。 关注 https://wiki.python.org/moin/DebuggingWithGdb,即

  1. dnf install gdb python-debuginfosudo apt-get install gdb python2.7-dbg
  2. gdb python <运行进程的pid>
  3. py- bt

还要考虑信息线程线程应用所有py-bt

I am in the GDB camp with the python extensions. Follow https://wiki.python.org/moin/DebuggingWithGdb, which means

  1. dnf install gdb python-debuginfo or sudo apt-get install gdb python2.7-dbg
  2. gdb python <pid of running process>
  3. py-bt

Also consider info threads and thread apply all py-bt.

一曲爱恨情仇 2024-07-12 07:38:30

如何在控制台中调试任何函数:

创建函数,在其中使用 pdb.set_trace(),然后调用您想要调试的函数。

>>> import pdb
>>> import my_function

>>> def f():
...     pdb.set_trace()
...     my_function()
... 

然后调用创建的函数:

>>> f()
> <stdin>(3)f()
(Pdb) s
--Call--
> <stdin>(1)my_function()
(Pdb) 

快乐调试:)

How to debug any function in console:

Create function where you use pdb.set_trace(), then function you want debug.

>>> import pdb
>>> import my_function

>>> def f():
...     pdb.set_trace()
...     my_function()
... 

Then call created function:

>>> f()
> <stdin>(3)f()
(Pdb) s
--Call--
> <stdin>(1)my_function()
(Pdb) 

Happy debugging :)

吹泡泡o 2024-07-12 07:38:30

如果您需要使用 uWSGI 执行此操作,它内置了 Python Tracebacker -in ,只需在配置中启用它即可(数字附加到每个工作人员的名称上):

py-tracebacker=/var/run/uwsgi/pytrace

完成此操作后,您可以通过连接到套接字来简单地打印回溯:

uwsgi --connect-and-read /var/run/uwsgi/pytrace1

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

py-tracebacker=/var/run/uwsgi/pytrace

Once you have done this, you can print backtrace simply by connecting to the socket:

uwsgi --connect-and-read /var/run/uwsgi/pytrace1
青衫负雪 2024-07-12 07:38:30

使用检查模块。

<块引用>
<块引用>

导入检查
帮助(检查.stack)
模块检查中函数堆栈的帮助:


stack(context=1)
返回调用者框架上方堆栈的记录列表。

我发现它确实非常有帮助。

use the inspect module.

import inspect
help(inspect.stack)
Help on function stack in module inspect:

stack(context=1)
Return a list of records for the stack above the caller's frame.

I find it very helpful indeed.

北凤男飞 2024-07-12 07:38:30

在 Python 3 中,第一次在调试器中使用 c(ont(inue)) 时,pdb 将自动安装信号处理程序。 之后按 Control-C 会让你回到那里。 在 Python 2 中,这里有一个单行代码,即使在相对较旧的版本中也应该可以工作(在 2.7 中进行了测试,但我检查了 Python 源代码回到 2.4,它看起来还不错):

import pdb, signal
signal.signal(signal.SIGINT, lambda sig, frame: pdb.Pdb().set_trace(frame))

如果您花大量时间调试 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):

import pdb, signal
signal.signal(signal.SIGINT, lambda sig, frame: pdb.Pdb().set_trace(frame))

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.

回眸一遍 2024-07-12 07:38:30

我不知道有什么类似于 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?

未蓝澄海的烟 2024-07-12 07:38:30

没有办法挂钩正在运行的 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.

泪痕残 2024-07-12 07:38:30

在代码运行时,您可以插入这个小片段来查看格式良好的打印堆栈跟踪。 它假设您的项目根目录中有一个名为 logs 的文件夹。

# DEBUG: START DEBUG -->
import traceback

with open('logs/stack-trace.log', 'w') as file:
    traceback.print_stack(file=file)
# DEBUG: END DEBUG --!

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.

# DEBUG: START DEBUG -->
import traceback

with open('logs/stack-trace.log', 'w') as file:
    traceback.print_stack(file=file)
# DEBUG: END DEBUG --!
感悟人生的甜 2024-07-12 07:38:29

我有一个用于这种情况的模块 - 一个进程将运行很长时间,但有时会因未知和不可重现的原因而卡住。 它有点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

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

    os.kill(pid, signal.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):

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

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:

    os.kill(pid, signal.SIGUSR1)

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文