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

我有这个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:


回答 0

我有用于以下情况的模块-进程将长时间运行,但有时由于未知且不可复制的原因而卡住。它有点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.


回答 1

安装信号处理程序的建议是一个不错的建议,我经常使用它。例如,默认情况下,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通常可以使您很好地了解流程在做什么。

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

Finally, attaching strace can often give you a good idea what a process is doing.


回答 2

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

回答 3

可以使用pyrasite来获取未经准备的 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.)


回答 4

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

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

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

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

import signal
import traceback

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

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

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


回答 5

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

import traceback

traceback.print_stack()

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

import traceback

traceback.print_stack()

回答 6

您可以尝试使用Faulthandler模​​块。使用安装pip install faulthandler并添加:

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/


回答 7

真正帮助我的是spiv的技巧(如果我没有信誉点,我会投票并提出评论),以获取未经准备的 Python进程的堆栈跟踪。直到我修改了gdbinit脚本起作用。所以:

  • 下载http://svn.python.org/projects/python/trunk/Misc/gdbinit并将其放入~/.gdbinit

  • 编辑它,更改PyEval_EvalFramePyEval_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 http://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


回答 8

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

回答 9

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


回答 10

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

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


回答 11

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

回答 12

如果您使用的是Linux系统,请结合使用gdbPython调试扩展(可以在包装中python-dbgpython-debuginfo打包中)使用。它还对多线程应用程序,GUI应用程序和C模块有帮助。

使用以下命令运行程序:

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

这指示gdb准备python <programname>.py <arguments>r取消准备。

现在,当程序挂起时,切换到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.


回答 13

我一直在寻找调试我的线程的解决方案,由于使用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.


回答 14

值得一看的是Pydb,“基于gdb命令集宽松地扩展了Python调试器的版本”。它包括信号管理器,该管理器可以在发送指定信号时负责启动调试器。

2006年夏天的Code项目研究了在名为mpdb的模块中向pydb添加远程调试功能。

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.


回答 15

我一起破解了一些附加到正在运行的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


回答 16

可以使用出色的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)  

回答 17

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.


回答 18

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


回答 19

您可以使用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.


回答 20

我在python扩展的GDB阵营中。跟随https://wiki.python.org/moin/DebuggingWithGdb,这意味着

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

同时考虑info threadsthread apply all 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.


回答 21

如何在控制台中调试任何功能:

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


回答 22

我不知道任何类似于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?


回答 23

使用检查模块。

导入检查帮助(inspect.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.


回答 24

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


回答 25

如果您需要使用uWSGI进行此操作,它内置了Python Tracebacker,只需在配置中启用它即可(每个工作人员的姓名均附有数字):

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

回答 26

在运行代码的那一点,您可以插入此小片段,以查看格式正确的打印堆栈跟踪。假定您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 --!

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。