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ść)
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ść)
Odpowiedzi:
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!
rfoo._rfoo.EofError: 0
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:
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
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.
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()
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.