Отображение трассировки стека из запущенного приложения Python
У меня есть это приложение Python, которое время от времени застревает, и я не могу узнать, где.
есть ли способ сигнализировать интерпретатору Python, чтобы показать вам точный код, который работает?
какой-то на лету stacktrace?
вопросы:
- печать текущего стека вызовов из метода в коде Python
- проверьте, что делает запущенный процесс: печать трассировка стека программы неинструментальный на Python
24 ответов:
у меня есть модуль, который я использую для таких ситуаций - где процесс будет работать в течение длительного времени, но иногда застревает по неизвестным и невоспроизводимым причинам. Его немного хаки, и работает только на 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 использовали его), и пусть он работает. В любой момент, отправить процессу сигнал SIGUSR1, используя убивать, или в питон:
os.kill(pid, signal.SIGUSR1)это приведет к тому, что программа выйдет на консоль python в точке, в которой она находится в данный момент, показывая вам трассировку стека и позволяя вам манипулировать переменными. Используйте control-d (EOF) для продолжения работы (хотя обратите внимание, что вы, вероятно, прервете любой ввод-вывод и т. д. В точке, которую вы сигнализируете, поэтому он не является полностью ненавязчивым.
у меня есть другой скрипт, который делает то же самое, за исключением того, что он взаимодействует с запущенным процессом через канал (чтобы разрешить отладка фоновых процессов и т. д.). Его немного большой, чтобы разместить здесь, но я добавил его как рецепт поваренной книги питона.
предложение установить обработчик сигналов является хорошим, и я использую его много. Например, bzr по умолчанию устанавливается обработчик SIGQUIT, который вызывает
pdb.set_trace()чтобы сразу же бросить вас в pdb запрос. (См. bzrlib.ломать источник модуля для точных деталей.) С pdb вы можете не только получить текущую трассировку стека, но и проверить переменные и т. д.однако иногда мне нужно отладить процесс, который у меня не был предусмотрительность для установки обработчика сигналов. В linux вы можете присоединить gdb к процессу и получить трассировку стека python с некоторыми макросами gdb. Поставить http://svn.python.org/projects/python/trunk/Misc/gdbinit в
~/.gdbinit, тогда:
- прикрепить gdb:
gdb -pPID- получить трассировку стека 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)
получение трассировки стека неприготовленные программа python, работающая на складе 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(Hat tip to @Albert, чей ответ содержал указатель на это, среди других инструментов.)
>>> import traceback >>> def x(): >>> print traceback.extract_stack() >>> x() [('<stdin>', 1, '<module>', None), ('<stdin>', 2, 'x', None)]вы также можете красиво отформатировать трассировку стека, см. docs.
Edit: чтобы имитировать поведение Java, как предложил @Douglas Leeder, добавьте это:
import signal import traceback signal.signal(signal.SIGUSR1, lambda sig, stack: traceback.print_stack(stack))к коду запуска в вашем приложении. Затем вы можете распечатать стек, отправив
SIGUSR1к запущенному процессу Python.
на traceback модуль имеет некоторые хорошие функции, среди них: print_stack:
import traceback traceback.print_stack()
что действительно помогло мне вот это фарцовщика подсказка (который я бы проголосовал и прокомментировал, если бы у меня были очки репутации) для получения трассировки стека из неприготовленные процесс Python. Но это не сработало, пока я изменен скрипт gdbinit. Итак:
скачать http://svn.python.org/projects/python/trunk/Misc/gdbinit и положить его в
~/.gdbinit
редактировать, изменение[edit: больше не требуется; связанный файл уже имеет это изменение по состоянию на 2010-01-14]PyEval_EvalFrametoPyEval_EvalFrameExприкрепить gdb:
gdb -p PIDполучить трассировку стека python:
pystack
вы можете попробовать модуль 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/
python-dv yourscript.py
Это заставит интерпретатор работать в режиме отладки и дать вам трассировку того, что делает интерпретатор.
Если вы хотите интерактивно отлаживать код, который вы должны запустить его так:
python-m pdb yourscript.py
Это говорит интерпретатору python, чтобы запустить ваш скрипт с модулем "pdb", который является отладчиком python, если вы запустите его так, что интерпретатор будет выполняется в интерактивном режиме, как и GDB
Я бы добавил Это в качестве комментария к haridsv это, но мне не хватает репутации, чтобы сделать так:
некоторые из нас все еще застряли на версии Python старше 2.6 (требуется для резьбы.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)
посмотри
faulthandlerмодуль, новый в Python 3.3. Аfaulthandlerbackport для использования в Python 2 доступен на PyPI.
на 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, используйте удивительность
gdbс расширениями отладки Python (может быть вpython-dbgилиpython-debuginfoпакет). Он также помогает с многопоточными приложениями, графическими приложениями и модулями C.запустите программу с помощью:
$ gdb -ex r --args python <programname>.py [arguments]таким образом
gdbдля подготовкиpython <programname>.py <arguments>иrООН.теперь, когда программа зависает, переключает в
Я искал некоторое время для решения для отладки моих потоков, и я нашел его здесь благодаря haridsv. Я использую немного упрощенную версию, используя трассировку.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, "Расширенная версия отладчика Python, свободно основанная на наборе команд gdb". Он включает в себя диспетчеры сигналов, которые могут позаботиться о запуске отладчика при отправке указанного сигнала.
летом 2006 года проект кода посмотрел на добавление функций удаленной отладки в pydb в модуле под названием mpdb.
я взломал какой-то инструмент, который подключается к запущенному процессу Python и вводит некоторый код, чтобы получить оболочку Python.
смотрите здесь: https://github.com/albertz/pydbattach
pyringe - это отладчик, который может взаимодействовать с запущенными процессами python, трассировками стека печати, переменными и т. д. без какой-либо априорной установки.
хотя я часто использовал решение обработчика сигналов в прошлом, все еще может быть трудно воспроизвести проблему в определенных средах.
нет никакого способа подключиться к запущенному процессу python и получить разумные результаты. То, что я делаю, если процессы блокируются, подключает strace и пытается выяснить, что именно происходит.
к сожалению, часто strace является наблюдателем, который" фиксирует " условия гонки, так что выход там тоже бесполезен.
можно использовать PuDB, отладчик Python с интерфейсом curses для этого. Просто добавьте
from pudb import set_interrupt_handler; set_interrupt_handler()к вашему коду и использовать Ctrl-C, когда вы хотите, чтобы сломать. Вы можете продолжить с
cи перерыв снова несколько раз, если вы пропустите его и хотите попробовать еще раз.
Я не знаю ничего похожего на для Java-на которых он слушал, поэтому вам, возможно, придется встроить его в свое приложение. Может быть, вы могли бы сделать сервер в другом потоке, который может получить stacktrace на ответ на какое-то сообщение?
используйте модуль проверки.
импорт проверить помогите (осмотрите.стек) Справка по стеку функций в модуле inspect:
стек(контекст=1) Возвращает список записей для стека над кадром вызывающего объекта.
Я действительно нахожу это очень полезным.
в Python 3 pdb автоматически установит обработчик сигнала при первом использовании c(ont (inue)) в отладчике. Нажатие Control-C после этого отбросит вас прямо туда. В Python 2 Вот один лайнер, который должен работать даже в относительно старых версиях (протестирован в 2.7, но я проверил источник Python до 2.4, и он выглядел нормально):
import pdb, signal signal.signal(signal.SIGINT, lambda sig, frame: pdb.Pdb().set_trace(frame))pdb стоит изучить, если вы тратите какое-то количество времени на отладку Python. Интерфейс немного тупой, но должен быть знакомым для всех, кто использовал подобные инструменты, такие как gdb.
в случае, если вам нужно сделать это с uWSGI, он имеет Python Tracebacker встроенный и это просто вопрос включения его в конфигурации (номер прилагается к имени для каждого работника):
py-tracebacker=/var/run/uwsgi/pytraceпосле того, как вы сделали это, вы можете распечатать backtrace просто подключившись к сокету:
uwsgi --connect-and-read /var/run/uwsgi/pytrace1
Я нахожусь в лагере GDB с расширениями python. Следуйте https://wiki.python.org/moin/DebuggingWithGdb, что означает
dnf install gdb python-debuginfoилиsudo apt-get install gdb python2.7-dbggdb python <pid of running process>py-btтакже считают
info threadsиthread apply all py-bt.
Comments