python: чи можна приєднати консоль до запущеного процесу


81

Я просто хочу побачити стан процесу, чи можна приєднати до нього консоль, щоб я міг викликати функції всередині процесу і побачити деякі глобальні змінні.

Краще, щоб процес працював без впливу (звичайно, продуктивність може трохи знизитися)


7
так в основному, налагоджувач?
st0le

щось на зразок інтерпретатора командного рядка python.exe
Bin Chen

Відповіді:


42

Якщо у вас є доступ до вихідного коду програми, ви можете порівняно легко додати цю функціональність.

Див. Рецепт 576515 :Debugging a running python process by interrupting and providing an interactive prompt (Python)

Цитувати:

Це забезпечує код, який дозволяє будь-якій програмі python, яка використовує його, перериватися в поточній точці та обмінюватися даними через звичайну інтерактивну консоль python. Це дозволяє досліджувати місцеві жителі, глобальні регіони та пов'язаний стан програм, а також викликати довільні функції та класи.

Для використання процес повинен імпортувати модуль і викликати Listen () у будь-який момент під час запуску. Щоб перервати цей процес, скрипт можна запустити безпосередньо, даючи ідентифікатор процесу для налагодження як параметр.


Інша реалізація приблизно тієї ж концепції представлена rconsole . З документації:

rconsole - це віддалена консоль Python з автоматичним заповненням, яку можна використовувати для перевірки та модифікації простору імен запущеного сценарію.

Щоб викликати сценарій, виконайте:

from rfoo.utils import rconsole
rconsole.spawn_server()

Щоб прикріпити з оболонки:

$ rconsole

Примітка щодо безпеки: Слухач rconsole, запущений із spawn_server (), прийме будь-яке локальне підключення і, отже, може бути небезпечним для використання в спільному хостингу або подібних середовищах!


2
Це справді дуже приємний рецепт. Використовувати канали та файли для введення та виведення дійсно розумно, і я думаю, що будь-який гідний проект виграє від такої функціональності.
erkmene

2
Це дуже небезпечно, тому використовуйте обережно
fmark

Я спробував рецепт, і це зламало мою установку python. Об'єкт "модуль" не має атрибута "getmro"
Віктор "Кріс" Кабрал,

Я скомпілював розширення cython після додавання заглушки до коду та запуску сервера rpc, але rconsole завжди ганебно зламається при будь-якій операції. rfoo._rfoo.EofError: 0
Саджук

60

Це перерве ваш процес (якщо ви не запустите його в потоці), але ви можете використовувати codeмодуль для запуску консолі Python:

import code
code.interact()

Це буде блокувати, поки користувач не вийде з інтерактивної консолі, виконавши exit().

codeМодуль доступний принаймні , Python v2.6, ймовірно , інші.

Я схильний використовувати цей підхід у поєднанні з сигналами для моєї роботи в Linux (для Windows, див. Нижче). Я ляпаю це вгорі моїх скриптів Python:

import code
import signal
signal.signal(signal.SIGUSR2, lambda sig, frame: code.interact())

А потім запустити його з оболонки з kill -SIGUSR2 <PID>, де <PID>є ідентифікатор процесу. Потім процес зупиняє все, що він робить, і представляє консоль:

Python 2.6.2 (r262:71600, Oct  9 2009, 17:53:52)
[GCC 3.4.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>>

Як правило, звідти я завантажую серверний компонент віддаленого налагоджувача, як чудовий WinPDB .

Windows не є ОС, сумісною з POSIX , і тому не забезпечує тих самих сигналів, що і Linux. Однак Python v2.2 і вище виставляють специфічний для Windows сигналSIGBREAK (запускається натисканням CTRL+ Pause/Break). Це не заважає нормальній роботі CTRL+ C( SIGINT), а тому є зручною альтернативою.

Тому портативна, але трохи потворна версія вищезазначеного:

import code
import signal
signal.signal(
        vars(signal).get("SIGBREAK") or vars(signal).get("SIGUSR2"),
        lambda sig, frame: code.interact()
        )

Переваги такого підходу:

  • Відсутність зовнішніх модулів (усі стандартні матеріали Python)
  • Ледь споживає будь-які ресурси до спрацьовування (2x імпорт)

Ось код, який я використовую у своєму виробничому середовищі, який завантажує серверну сторону WinPDB (якщо є) і повертається до відкриття консолі Python.

# Break into a Python console upon SIGUSR1 (Linux) or SIGBREAK (Windows:
# CTRL+Pause/Break).  To be included in all production code, just in case.
def debug_signal_handler(signal, frame):
    del signal
    del frame

    try:
        import rpdb2
        print
        print
        print "Starting embedded RPDB2 debugger. Password is 'foobar'"
        print
        print
        rpdb2.start_embedded_debugger("foobar", True, True)
        rpdb2.setbreak(depth=1)
        return
    except StandardError:
        pass

    try:
        import code
        code.interact()
    except StandardError as ex:
        print "%r, returning to normal program flow" % ex

import signal
try:
    signal.signal(
            vars(signal).get("SIGBREAK") or vars(signal).get("SIGUSR1"),
            debug_signal_handler
            )
except ValueError:
    # Typically: ValueError: signal only works in main thread
    pass

Чи можете ви дати докладнішу інформацію про те, як ви завантажуєте серверний компонент WinPDB, коли у вас є консоль Python?
Крістіан Лонг

1
Я додав свій робочий код до відповіді, але по суті вам потрібно лише ввести наступне на консолі: '' import rpdb2; rpdb2.start_embedded_debugger ("foobar", True, True) '', а потім запустити графічний інтерфейс WinPDB з паролем "foobar", коли буде запропоновано
RobM 03.03.16

26

Використовуйте піразитову оболонку . Я не можу повірити, що це працює так добре, але це робить. Msgstr " Дайте йому під, отримайте оболонку ".

$ sudo pip install pyrasite
$ echo 0 | sudo tee /proc/sys/kernel/yama/ptrace_scope # If YAMA activated, see below.
$ pyrasite-shell 16262
Pyrasite Shell 2.0
Connected to 'python my_script.py'
Python 2.7.6 (default, Jun 22 2015, 17:58:13) 
[GCC 4.8.2] on linux2
Type "help", "copyright", "credits" or "license" for more information.

>>> globals()
>>> print(db_session)
>>> run_some_local_function()
>>> some_existing_local_variable = 'new value'

Це запускає оболонку python з доступом до змінних globals () та local () цього запущеного процесу python та інших чудових речей.

Лише тестував це особисто на Ubuntu, але, схоже, це також стосується OSX.

Адаптовано з цієї відповіді .

Примітка: Вимкнення ptrace_scopeвластивості рядка необхідно лише для ядер / систем, які були побудовані з CONFIG_SECURITY_YAMAon. Будьте обережні, возитися з ptrace_scope в чутливих середовищах, оскільки це може спричинити певні уразливості безпеки. Детальніше див. Тут .


@Dirk Я вважаю, що ptrace_scope має важливе значення, щоб дозволити одному процесу відстежувати / взаємодіяти з іншим не пов'язаним процесом.
python1981

Очевидно, що це лише в системах, які мають YAMA. Пропонував редагувати та видалив мій оригінальний коментар. (Цей також піде через деякий час.)
Дірк,

Дивіться тут для використання в Docker: stackoverflow.com/questions/37072468/…
Майкл Штейнберг

4

Чому б не просто використовувати модуль pdb ? Це дозволяє зупинити сценарій, перевірити значення елементів і виконати код за рядком. Оскільки він побудований на інтерпретаторі Python, він також надає функції класичного інтерпретатора. Щоб використовувати його, просто вставте ці 2 рядки у свій код, де ви хочете зупинитись та перевірити його:

import pdb
pdb.set_trace()

3
ви знаєте, як запустити його для заданого потоку threading.enumerate ()?
yucer

4

Інша можливість, без додавання матеріалів до скриптів python, описана тут:

https://wiki.python.org/moin/DebuggingWithGdb

На жаль, це рішення також вимагає певної продуманості, принаймні настільки, наскільки вам потрібно використовувати версію python із символами налагодження.


Для більшості дистрибутивів Linux python будується із символами налагодження, але символи налагодження містяться в іншому пакеті. Пакет символів налагодження можна встановити після того, як ваш скрипт python вже запущений.
W.Mann

1

Використовуючи PyCharm, мені не вдалося підключитися до процесу в Ubuntu. Вирішенням цього є вимкнення YAMA. Для отримання додаткової інформації див. Askubuntu

echo 0 | sudo tee /proc/sys/kernel/yama/ptrace_scope
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.