문제

이 파이썬 애플리케이션이 때때로 붙어 있으며 어디에 있는지 알 수 없습니다.

Python 통역사를 신호하여 실행중인 정확한 코드를 표시하는 방법이 있습니까?

일종의 비행 비행 스택 트레이스?

관련 질문 :

도움이 되었습니까?

해결책

나는 이와 같은 상황에 사용하는 모듈이 있습니다. 프로세스가 오랫동안 실행될 수 있지만 때로는 알려지지 않았고 돌이킬 수없는 이유로 갇히게됩니다. 약간 해킹되고 유닉스에서만 작동합니다 (신호 필요) :

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에 붙일 수도 있음) 실행하십시오. 언제든지 킬 또는 파이썬을 사용하여 프로세스를 sigusr1 신호를 보내십시오.

    os.kill(pid, signal.SIGUSR1)

이로 인해 현재 시점에서 프로그램이 파이썬 콘솔로 나뉘어 스택 추적을 보여주고 변수를 조작 할 수 있습니다. Control-D (EOF)를 사용하여 계속 실행을 계속하십시오 (그러나 신호 시점에서 I/O 등을 방해 할 수 있으므로 완전히 무관심하지는 않습니다.

파이프를 통해 런닝 프로세스와 통신하는 것을 제외하고는 같은 일을하는 또 다른 스크립트 (배경 프로세스를 디버깅 할 수 있도록). 여기에 게시하기에는 약간 큽니다. 그러나 나는 그것을 파이썬 요리 책 레시피.

다른 팁

신호 핸들러를 설치하라는 제안은 좋은 것이므로 많이 사용합니다. 예를 들어, BZR 기본적으로 호출되는 시그 퀴트 핸들러를 설치합니다 pdb.set_trace() 즉시 당신을 a로 떨어 뜨립니다 PDB 즉각적인. (참조 bzrlib.breakin 정확한 세부 사항에 대한 모듈 소스.) PDB를 사용하면 현재 스택 추적을 얻을 수있을뿐만 아니라 변수를 검사 할 수 있습니다.

그러나 때로는 신호 핸들러를 설치할 예측이없는 프로세스를 디버깅해야합니다. Linux에서는 GDB를 프로세스에 연결하고 일부 GDB 매크로로 Python 스택 추적을 얻을 수 있습니다. 놓다 http://svn.python.org/projects/python/trunk/misc/gdbinit 안에 ~/.gdbinit, 그 다음에:

  • 첨부 gdb : gdb -p PID
  • 파이썬 스택 추적을 얻으십시오. 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)

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

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

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

import traceback

traceback.print_stack()

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/

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

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)

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

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

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.

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.

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.

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.

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

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.

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.

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.

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

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?

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.

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.

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

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.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top