显示正在运行的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脚本,否则不行 。 所以:

您可以尝试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-dbgpython-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