显示正在运行的Python应用程序的堆栈跟踪
我有这个不时被卡住的Python应用程序,我找不到在哪里。
有没有什么方法可以告诉Python解释器显示正在运行的确切代码?
某种即时堆栈跟踪?
相关问题:
- 从Python代码中的方法打印当前的调用堆栈
- 检查一个正在运行的进程正在做什么:打印一个未经修补的Python程序的堆栈跟踪
我有这样的情况使用模块 – 在一个进程将运行很长一段时间,但有时卡住了未知和不可重复的原因。 它有点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控制台,向您显示堆栈跟踪,并让您操作variables。 使用control-d(EOF)继续运行(尽pipe请注意,您可能会在您发出信号的时候中断任何I / O等,因此它不是完全非侵入式的。
我有另外一个脚本可以做同样的事情,除了通过pipe道与正在运行的进程通信(以便debugging后台进程等)。 这里有点大,但我已经把它作为一个python食谱食谱添加 。
build议安装一个信号处理程序是一个很好的build议,我使用它很多。 例如,默认情况下, bzr会安装一个调用pdb.set_trace()
立即将您放入pdb提示符的SIGQUIT处理程序。 (具体细节见bzrlib.breakin模块的源代码。)使用pdb,您不仅可以获取当前的堆栈跟踪,还可以检查variables等。
但是,有时我需要debugging一个我没有先见之明的进程来安装信号处理程序。在linux上,可以将gdb附加到进程中,并使用一些gdbmacros来获取python堆栈跟踪。 把http://svn.python.org/projects/python/trunk/Misc/gdbinit放入;~/.gdbinit
,然后:
- 附加gdb:
gdb -p
PID
- 获取python堆栈跟踪:
pystack
不幸的是,这不是完全可靠的,但大多数情况下它是有效的。
最后,附加strace
通常会给你一个好主意,一个过程在做什么。
我几乎总是处理多个线程,主线程一般没有太多的工作,所以最有意思的是转储所有的堆栈(这更像是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)
>>> import traceback >>> def x(): >>> print traceback.extract_stack() >>> x() [('<stdin>', 1, '<module>', None), ('<stdin>', 2, 'x', None)]
您也可以很好地格式化堆栈跟踪,请参阅文档 。
编辑 :按照@Douglas Leeder的build议来模拟Java的行为,添加:
import signal import traceback signal.signal(signal.SIGUSR1, lambda sig, stack: traceback.print_stack(stack))
到应用程序中的启动代码。 然后,您可以通过将SIGUSR1
发送到正在运行的Python进程来打印堆栈。
获取一个没有准备 好的 python程序的堆栈跟踪,在没有debugging符号的情况下运行在stock 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
(给@Albert的提示,其答案包含一个指向这个的指针,以及其他工具。)
回溯模块有一些很好的function,其中包括:print_stack:
import traceback traceback.print_stack()
这里真正帮助我的是spiv的提示 (我会投票并评论是否有声望点),以便从无准备的 Python进程中获取堆栈跟踪。 除非我修改了gdbinit脚本,否则不行 。 所以:
-
下载http://svn.python.org/projects/python/trunk/Misc/gdbinit并将其放入;
~/.gdbinit
-
编辑它,将[编辑:不再需要; 链接的文件已经有这个变化了2010-01-14]PyEval_EvalFrame
更改为PyEval_EvalFrameEx
-
附加gdb:
gdb -p PID
-
获取python堆栈跟踪:
pystack
您可以尝试error handling程序模块 。 使用pip install faulthandler
安装它,并添加:
import faulthandler, signal faulthandler.register(signal.SIGUSR1)
在你的节目开始。 然后将SIGUSR1发送到您的进程(例如kill -USR1 42
),以显示所有线程的Python回溯到标准输出。 阅读文档以获取更多选项(例如:login文件)以及其他方式显示回溯。
该模块现在是Python 3.3的一部分。 对于Python 2,请参阅http://faulthandler.readthedocs.org/
python -dv yourscript.py
这将使解释器运行在debugging模式,并给你一个解释器正在做什么的踪迹。
如果你想交互debugging代码,你应该像这样运行它:
python -m pdb yourscript.py
这就告诉python解释器使用pythondebugging器的模块“pdb”来运行你的脚本,如果你运行它,解释器将以交互模式执行,就像GDB
我会加上这个作为haridsv的回应评论,但我缺乏这样做的声誉:
我们中的一些人仍然坚持Python 2.6以上版本(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)
看一看Python 3.3中的new faulthandler
模块。 PyPI上提供了Python 2中使用的faulthandler
backport 。
在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.
如果你使用的是Linux系统,那么使用Pythondebugging扩展(可以在python-dbg
或python-debuginfo
软件包中)使用gdb
。 它也有助于multithreading应用程序,GUI应用程序和C模块。
运行你的程序:
$ gdb -ex r --args python <programname>.py [arguments]
这指示gdb
准备python <programname>.py <arguments>
和r
un它。
现在当你编程挂起时,切换到gdb
控制台,按Ctr + C并执行:
(gdb) thread apply all py-list
看到例子会议和更多的信息在这里和这里 。
我正在寻找一个解决scheme来debugging我的线程,我发现它在这里感谢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)
为了我的需要,我也按名称过滤线程。
值得一提的是Pydb ,“松散地基于gdb命令集的Pythondebugging器的扩展版本”。 它包括信号pipe理器,可以在指定的信号发送时负责启动debugging器。
2006年的Code of Summer项目研究了在一个名为mpdb的模块中为pydb添加远程debuggingfunction。
我一起攻击了一个附加到正在运行的Python进程中的工具,并注入了一些代码来获得一个Python shell。
看到这里: https : //github.com/albertz/pydbattach
pyringe是一个debugging器,可以与运行python进程,打印堆栈跟踪,variables等进行交互,无需任何先验设置。
尽pipe过去我经常使用信号处理器解决scheme,但在特定的环境中再现问题通常也很困难。
没有办法挂钩到正在运行的Python进程,并获得合理的结果。 如果进程locking,我所做的就是将strace放在一边,试图弄清究竟发生了什么。
不幸的是,观察员往往会“修正”竞赛条件,以至于输出也是无用的。
您可以使用带有curses接口的Pythondebugging器PuDB来执行此操作。 只需添加
from pudb import set_interrupt_handler; set_interrupt_handler()
到你的代码,当你想要打破时使用Ctrl-C。 如果你错过了并且想再试一次,你可以继续使用c
并多次再次分手。
我不知道类似于java对SIGQUIT的响应 ,所以你可能需要将它构build到你的应用程序中。 也许你可以在另一个线程,可以得到一个堆栈跟踪回应某种消息的服务器?
使用检查模块。
导入检查帮助(inspect.stack)模块中function堆栈的帮助检查:
stack(context = 1)返callback用者框架上方堆栈的logging列表。
我觉得这非常有用。
在Python 3中,pdb会在debugging器中首次使用c(ont(inue))时自动安装信号处理程序。 之后按下Control-C会将你放回原处。 在Python 2中,这是一个应该在相对较旧的版本中工作的单线程(在2.7中进行了testing,但是我检查了Python源代码到2.4,看起来没问题):
import pdb, signal signal.signal(signal.SIGINT, lambda sig, frame: pdb.Pdb().set_trace(frame))
如果您花费任何时间debuggingPython,pdb值得学习。 界面有些呆板,但对于使用类似工具(比如gdb)的人来说应该是很熟悉的。
如果你需要使用uWSGI来做到这一点,它内置了Python Tracebacker ,只需要在configuration中启用它(数字附加到每个worker的名字):
py-tracebacker=/var/run/uwsgi/pytrace
完成此操作后,只需连接到套接字即可打印回溯:
uwsgi --connect-and-read /var/run/uwsgi/pytrace1