Отображение трассировки стека из запущенного приложения Python
311 Seb [2008-09-25 11:06:00]
У меня есть приложение Python, которое время от времени застревает, и я не могу узнать, где.
Есть ли способ сигнализировать интерпретатору Python, чтобы показать вам точный код, который работает?
Какой-то тип "на лету"?
Связанные вопросы:
- Печать текущего стека вызовов из метода в коде Python
- Проверьте выполняемый процесс: трассируйте трассировку стека неинструментированной программы Python
python debugging stack-trace traceback
25 ответов
297 Решение Brian [2008-09-25 16:38:00]
У меня есть модуль, который я использую для ситуаций, подобных этому, - где процесс будет работать в течение длительного времени, но иногда застревает по неизвестным и непоправимым причинам. Он немного взломан и работает только на 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, используя kill или в python:
os.kill(pid, signal.SIGUSR1)
Это приведет к тому, что программа будет разбита на консоль python в точке, в которой она сейчас находится, показывая вам трассировку стека и позволяя вам манипулировать переменными. Используйте control-d (EOF) для продолжения работы (хотя обратите внимание, что вы, вероятно, прервите любой ввод-вывод и т.д. В момент, когда вы сигнализируете, поэтому он не является полностью неинтрузивным.
У меня есть еще один script, который делает то же самое, за исключением того, что он связывается с запущенным процессом через канал (чтобы разрешить отладку фоновых процессов и т.д.). Его немного больше, чтобы публиковать здесь, но я добавил его как рецепт кулинарной книги python.
139 spiv [2008-09-29 03:44:00]
Предложение по установке обработчика сигнала является хорошим, и я использую его много. Например, bzr по умолчанию устанавливает обработчик SIGQUIT, который вызывает pdb.set_trace()
, чтобы немедленно перевести вас в pdb. (Подробные сведения см. В источнике bzrlib.breakin). С помощью pdb вы можете не только получить текущую трассировку стека, но также проверить переменные и т.д..
Однако иногда мне нужно отлаживать процесс, в котором у меня не было предусмотрительности для установки обработчика сигналов. В linux вы можете присоединить gdb к процессу и получить трассировку стека python с помощью некоторых макросов gdb. Поместите http://svn.python.org/projects/python/trunk/Misc/gdbinit в ~/.gdbinit
, затем:
- Прикрепить gdb:
gdb -p
PID
- Получить трассировку стека python:
pystack
Он не полностью надежный, к сожалению, но он работает большую часть времени.
Наконец, добавление strace
часто может дать вам представление о том, что делает процесс.
63 haridsv [2010-04-03 02:23:00]
Я почти всегда имею дело с несколькими потоками, и основной поток, как правило, мало что делает, поэтому самое интересное - сбросить все стеки (что больше похоже на дамп 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)
41 Nickolay [2015-04-26 21:22:00]
Получение трассировки стека неподготовленной программы 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, ответ которой содержал указатель на это, среди других инструментов.)
33 Torsten Marek [2008-09-25 11:29:00]
>>> 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.
26 gulgi [2008-09-25 11:27:00]
Модуль traceback имеет несколько приятных функций, среди которых: print_stack:
import traceback
traceback.print_stack()
20 haypo [2013-04-27 01:18:00]
Вы можете попробовать модуль 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/
19 Gunnlaugur Briem [2009-03-06 15:49:00]
Что мне действительно помогло, это spiv tip (который я бы проголосовал и прокомментировал, если бы у меня были очки репутации) для получения трассировки стека из неподготовленного Python. Кроме того, что это не сработало, пока я не изменил gdbinit script. Итак:
-
скачать http://svn.python.org/projects/python/trunk/Misc/gdbinit и поместить его в
~/.gdbinit
-
отредактируйте его, изменив[edit: больше не нужно; связанный файл уже имеет это изменение с 2010-01-14]PyEval_EvalFrame
наPyEval_EvalFrameEx
-
Прикрепить gdb:
gdb -p PID
-
Получить трассировку стека python:
pystack
10 Konstantin Naryshkin [2011-03-31 19:30:00]
Я бы добавил это как комментарий к ответах 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)
10 Gustavo Rubio [2008-09-25 11:24:00]
python -dv yourscript.py
Это заставит интерпретатор работать в режиме отладки и дать вам представление о том, что делает интерпретатор.
Если вы хотите интерактивно отлаживать код, вы должны запускать его следующим образом:
python -m pdb yourscript.py
Это говорит интерпретатору python запускать ваш script с модулем "pdb", который является отладчиком python, если вы запустите его так, как интерпретатор будет выполнен в интерактивном режиме, подобно GDB
8 Matt Joiner [2012-01-26 16:57:00]
Взгляните на модуль faulthandler
, новый в Python 3.3. A faulthandler
backport для использования в Python 2 доступен в PyPI.
6 anatoly techtonik [2013-06-24 11:03:00]
Если вы находитесь в системе Linux, используйте удивительность gdb
с расширениями отладки Python (может быть в пакете python-dbg
или python-debuginfo
). Он также помогает в многопоточных приложениях, графических приложениях и модулях C.
Запустите свою программу с помощью
$ gdb -ex r --args python <programname>.py [arguments]
Это дает команду gdb
подготовить python <programname>.py <arguments>
и r
un it.
Теперь, когда вы запускаете программу, перейдите в консоль gdb
, нажмите Ctr+C и выполните:
(gdb) thread apply all py-list
Смотрите пример сеанса и более подробную информацию здесь и здесь.
6 Tim Foster [2011-08-29 00:30:00]
В 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.
5 Stefan [2012-04-15 23:28:00]
Я искал какое-то время для решения отладки моих потоков, и я нашел его здесь благодаря 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)
Для моих нужд я также фильтрую потоки по имени.
3 rcoup [2009-01-29 04:28:00]
Стоит посмотреть Pydb, "расширенную версию отладчика Python на основе набора команд gdb". Он включает в себя диспетчеры сигналов, которые могут позаботиться о запуске отладчика при отправке заданного сигнала.
Проект Summer of Code 2006 года рассмотрел возможность добавления удаленных отладочных функций в pydb в модуле mpdb.
3 Albert [2012-04-06 21:49:00]
Я взломал некоторый инструмент, который присоединяется к запущенному процессу Python и вводит некоторый код, чтобы получить оболочку Python.
Смотрите здесь: https://github.com/albertz/pydbattach
2 Dan Lecocq [2014-05-01 12:40:00]
pyringe - отладчик, который может взаимодействовать с запущенными процессами python, трассировать стеки стека, переменные и т.д. без какой-либо априорной настройки.
Хотя я часто использовал решение обработчика сигналов в прошлом, часто бывает сложно воспроизвести проблему в определенных средах.
1 asmeurer [2013-04-27 03:54:00]
Вы можете использовать PuDB, отладчик Python с интерфейсом curses для этого. Просто добавьте
from pudb import set_interrupt_handler; set_interrupt_handler()
к вашему коду и используйте Ctrl-C, когда вы хотите сломать. Вы можете продолжить с помощью c
и повторно пропустить несколько раз, если вы пропустите его и хотите попробовать еще раз.
1 Armin Ronacher [2008-09-25 12:09:00]
Невозможно подключиться к запущенному процессу python и получить разумные результаты. То, что я делаю, если процессы блокируются, зацепляется и пытается выяснить, что именно происходит.
К сожалению, часто сторонник является наблюдателем, который "исправляет" условия гонки, так что выход тоже бесполезен.
0 Douglas Leeder [2008-09-25 12:06:00]
Я не знаю ничего похожего на java-ответ на SIGQUIT, поэтому вам, возможно, придется встраивать его в ваше приложение. Может быть, вы могли бы сделать сервер в другом потоке, который может получить stacktrace для ответа на какое-то сообщение?
0 user7610 [2018-04-18 15:31:00]
Я нахожусь в лагере GDB с расширениями Python. Следуйте https://wiki.python.org/moin/DebuggingWithGdb, что означает
-
dnf install gdb python-debuginfo
илиsudo apt-get install gdb python2.7-dbg
-
gdb python <pid of running process>
-
py-bt
Также рассмотрите info threads
и thread apply all py-bt
.
0 jtatum [2014-12-14 05:16:00]
В Python 3 pdb автоматически установит обработчик сигнала при первом использовании c (onue (inue)) в отладчике. После этого нажатие Ctrl-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.
используйте модуль проверки.
импорт проверить помощь (inspect.stack) Справка по стеку функций в модуле:
стека (контекст = 1) Верните список записей для стека выше кадра вызывающего абонента.
Я считаю это очень полезным.
0 Michal Čihař [2015-04-28 09:15:00]
Если вам нужно сделать это с помощью uWSGI, он имеет Python Tracebacker, и это просто вопрос включения его в конфигурацию ( номер прикрепляется к имени для каждого рабочего):
py-tracebacker=/var/run/uwsgi/pytrace
Как только вы это сделаете, вы можете распечатать обратную трассировку, просто подключившись к сокету:
uwsgi --connect-and-read /var/run/uwsgi/pytrace1
0 jakvb [2019-01-16 23:47:00]
Как отладить любую функцию в консоли:
Создайте функцию, в которой вы используете 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)
Удачной отладки :)