python: czy można podłączyć konsolę do działającego procesu

81

Chcę tylko zobaczyć stan procesu, czy można dołączyć konsolę do procesu, abym mógł wywoływać funkcje wewnątrz procesu i zobaczyć niektóre zmienne globalne.

Lepiej, aby proces przebiegał bez wpływu (oczywiście wydajność może nieco spaść)

Bin Chen
źródło
7
więc w zasadzie debugger?
St0le
coś w rodzaju interpretera wiersza poleceń python.exe
Bin Chen
wersja pdb: stackoverflow.com/questions/25308847/…
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功

Odpowiedzi:

42

Jeśli masz dostęp do kodu źródłowego programu, możesz stosunkowo łatwo dodać tę funkcjonalność.

Patrz przepis 576515 :Debugging a running python process by interrupting and providing an interactive prompt (Python)

Cytować:

Zapewnia to kod umożliwiający przerwanie dowolnego programu w Pythonie, który go używa, w bieżącym momencie i komunikowanie się z nim za pośrednictwem zwykłej interaktywnej konsoli Pythona. Pozwala to na badanie lokalnych, globalnych i powiązanych stanów programu, a także wywoływanie dowolnych funkcji i klas.

Aby go użyć, proces powinien zaimportować moduł i wywołać funkcję Listen () w dowolnym momencie podczas uruchamiania. Aby przerwać ten proces, skrypt można uruchomić bezpośrednio, podając jako parametr identyfikator procesu do debugowania.


Kolejną implementację mniej więcej tej samej koncepcji zapewnia rconsole . Z dokumentacji:

rconsole to zdalna konsola Pythona z funkcją automatycznego uzupełniania, której można używać do sprawdzania i modyfikowania przestrzeni nazw uruchomionego skryptu.

Aby wywołać w skrypcie, wykonaj:

from rfoo.utils import rconsole
rconsole.spawn_server()

Aby dołączyć z muszli, wykonaj:

$ rconsole

Uwaga dotycząca bezpieczeństwa: odbiornik rconsole uruchomiony za pomocą spawn_server () akceptuje każde połączenie lokalne i dlatego może być niebezpieczny w użyciu we współdzielonym hostingu lub podobnych środowiskach!

fmark
źródło
2
To naprawdę bardzo fajny przepis. Używanie potoków i plików do wejścia i wyjścia jest naprawdę sprytne i myślę, że każdy przyzwoity projekt skorzystałby na takiej funkcjonalności.
erkmene
2
Jest to jednak bardzo niebezpieczne, więc używaj ostrożnie
fmark
Wypróbowałem przepis i zepsuło to moją instalację Pythona. Obiekt „moduł” nie ma atrybutu „getmro”
Victor „Chris” Cabral
Skompilowałem rozszerzenie cython, po dodaniu kodu do kodu i uruchomiłem serwer rpc, ale rconsole zawsze zepsuje haniebnie po każdej operacji. rfoo._rfoo.EofError: 0
Sajuuk,
60

Spowoduje to przerwanie procesu (chyba że uruchomisz go w wątku), ale możesz użyć codemodułu do uruchomienia konsoli Pythona:

import code
code.interact()

Będzie to blokowane, dopóki użytkownik nie wyjdzie z konsoli interaktywnej przez wykonanie exit().

codeModuł jest dostępny w co najmniej Python v2.6, prawdopodobnie innych.

Zwykle używam tego podejścia w połączeniu z sygnałami do mojej pracy w Linuksie (dla Windows, patrz poniżej). Klepię to u góry moich skryptów Pythona:

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

A następnie uruchom go z powłoki kill -SIGUSR2 <PID>, gdzie <PID>jest identyfikator procesu. Następnie proces zatrzymuje cokolwiek robi i przedstawia konsolę:

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

Generalnie stamtąd ładuję komponent po stronie serwera zdalnego debuggera, taki jak doskonały WinPDB .

Windows nie jest systemem operacyjnym zgodnym z POSIX , więc nie dostarcza takich samych sygnałów jak Linux. Jednak Python w wersji 2.2 i nowszych uwidacznia sygnał specyficzny dla systemu WindowsSIGBREAK (wyzwalany przez naciśnięcie CTRL+ Pause/Break). Ten sposób nie zakłócają normalnego CTRL+ C( SIGINT) operacji, a więc jest przydatny alternatywy.

Dlatego przenośna, ale nieco brzydka wersja powyższego to:

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

Zalety tego podejścia:

  • Brak zewnętrznych modułów (wszystkie standardowe rzeczy w Pythonie)
  • Ledwo zużywa zasoby, dopóki nie zostanie uruchomiony (import 2x)

Oto kod, którego używam w moim środowisku produkcyjnym, który załaduje stronę serwera WinPDB (jeśli jest dostępny) i wróci do otwierania konsoli Pythona.

# 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
RobM
źródło
Czy możesz podać więcej szczegółów na temat ładowania składnika WinPDB po stronie serwera, gdy masz konsolę Python?
Christian Long
1
Dodałem mój kod produkcyjny do odpowiedzi, ale zasadniczo wystarczy wprowadzić na konsoli tylko: '' import rpdb2; rpdb2.start_embedded_debugger ("foobar", True, True) '', a następnie uruchom GUI WinPDB z hasłem "foobar" po wyświetleniu monitu
RobM
26

Użyj powłoki pirasytu . Nie mogę uwierzyć, że działa tak dobrze, ale tak jest. „ Daj pid, zdobądź muszlę ”.

$ 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'

Powoduje to uruchomienie powłoki Pythona z dostępem do zmiennych globals () i locals () tego działającego procesu Pythona oraz innych wspaniałych rzeczy.

Testowałem to osobiście tylko na Ubuntu, ale wydaje się, że obsługuje również OSX.

Zaczerpnięte z tej odpowiedzi .

Uwaga: Linia wyłączająca ptrace_scopewłaściwość jest konieczna tylko w przypadku jąder / systemów, które zostały zbudowane z włączoną funkcją CONFIG_SECURITY_YAMA. Uważaj, mieszając z ptrace_scope w wrażliwych środowiskach, ponieważ może to wprowadzić pewne luki w zabezpieczeniach. Zobacz tutaj po szczegóły.

python1981
źródło
@Dirk Uważam, że ptrace_scope jest niezbędne, aby umożliwić jednemu procesowi śledzenie / interakcję z innym niepowiązanym procesem.
python1981
Oczywiście dotyczy to tylko systemów z YAMA. Zaproponowałem zmianę i usunąłem mój oryginalny komentarz. (Ten również będzie dostępny w ciągu jakiegoś czasu.)
Dirk
Zobacz tutaj, aby używać w Dockerze: stackoverflow.com/questions/37072468/…
Michael Steinberg,
4

Dlaczego po prostu nie skorzystać z modułu pdb ? Pozwala zatrzymać skrypt, sprawdzić wartości elementów i wykonać kod linia po linii. A ponieważ jest oparty na interpreterze języka Python, zapewnia również funkcje oferowane przez klasyczny interpreter. Aby go użyć, po prostu umieść te 2 wiersze w swoim kodzie, w miejscu, w którym chcesz go zatrzymać i sprawdzić:

import pdb
pdb.set_trace()
mdeous
źródło
3
czy wiesz, jak uruchomić go dla danego wątku threading.enumerate ()?
yucer
4

Inna możliwość, bez dodawania rzeczy do skryptów Pythona, jest opisana tutaj:

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

Niestety, to rozwiązanie również wymaga przemyślenia, przynajmniej do tego stopnia, że ​​musisz używać wersji Pythona z symbolami debugowania.

Joshua Richardson
źródło
W przypadku większości dystrybucji Linuksa Python jest zbudowany z symboli debugowania, ale symbole debugowania znajdują się w innym pakiecie. Pakiet symboli debugowania można zainstalować po uruchomieniu skryptu Pythona.
W.Mann
1

Używając PyCharm, nie udało mi się połączyć z procesem w Ubuntu. Rozwiązaniem tego problemu jest wyłączenie YAMA. Aby uzyskać więcej informacji, zobacz askubuntu

echo 0 | sudo tee /proc/sys/kernel/yama/ptrace_scope
shao.lo
źródło