Python: Ist es möglich, eine Konsole an einen laufenden Prozess anzuhängen?

81

Ich möchte nur den Status des Prozesses sehen. Ist es möglich, eine Konsole an den Prozess anzuhängen, damit ich Funktionen innerhalb des Prozesses aufrufen und einige der globalen Variablen sehen kann?

Es ist besser, wenn der Prozess ohne Beeinträchtigung ausgeführt wird (natürlich kann die Leistung etwas nachlassen).

Bin Chen
quelle
7
Also im Grunde ein Debugger?
st0le
so etwas wie der Kommandozeileninterpreter python.exe
Bin Chen
pdb version: stackoverflow.com/questions/25308847/…
Ciro Santilli 4 冠状 病. 事件 4

Antworten:

42

Wenn Sie Zugriff auf den Quellcode des Programms haben, können Sie diese Funktionalität relativ einfach hinzufügen.

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

Zitieren:

Dies bietet Code, mit dem jedes Python-Programm, das es verwendet, zum aktuellen Zeitpunkt unterbrochen und über eine normale interaktive Python-Konsole kommuniziert werden kann. Auf diese Weise können die Einheimischen, Globalen und der zugehörige Programmstatus untersucht und beliebige Funktionen und Klassen aufgerufen werden.

Zur Verwendung sollte ein Prozess das Modul importieren und zu jedem Zeitpunkt während des Starts listen () aufrufen. Um diesen Prozess zu unterbrechen, kann das Skript direkt ausgeführt werden, wobei die Prozess-ID des zu debuggenden Prozesses als Parameter angegeben wird.


Eine weitere Implementierung von ungefähr demselben Konzept bietet rconsole . Aus der Dokumentation:

rconsole ist eine Remote-Python-Konsole mit automatischer Vervollständigung, mit der der Namespace eines laufenden Skripts überprüft und geändert werden kann.

So rufen Sie ein Skript auf:

from rfoo.utils import rconsole
rconsole.spawn_server()

So befestigen Sie von einer Shell aus:

$ rconsole

Sicherheitshinweis: Der mit spawn_server () gestartete rconsole-Listener akzeptiert alle lokalen Verbindungen und kann daher in Shared Hosting oder ähnlichen Umgebungen unsicher sein!

fmark
quelle
2
Das ist wirklich ein sehr schönes Rezept. Die Verwendung von Pipes und Dateien für die Ein- und Ausgabe ist wirklich clever, und ich denke, jedes anständige Projekt würde von einer solchen Funktionalität profitieren.
erkmene
2
Es ist jedoch sehr unsicher, also
vorsichtig
Ich habe versucht, Rezept und es brach meine Python-Installation. 'Modul' Objekt hat kein Attribut 'getmro'
Victor 'Chris' Cabral
Ich habe die Cython-Erweiterung kompiliert, nachdem ich den Stub zum Code hinzugefügt und den RPC-Server gestartet habe, aber die Rconsole wird bei jeder Operation immer schändlich kaputt gehen. rfoo._rfoo.EofError: 0
Sajuuk
60

Dies unterbricht Ihren Prozess (es sei denn, Sie starten ihn in einem Thread), aber Sie können das codeModul verwenden, um eine Python-Konsole zu starten:

import code
code.interact()

Dies wird blockiert, bis der Benutzer die interaktive Konsole durch Ausführen verlässt exit().

Das codeModul ist mindestens in Python v2.6 verfügbar, wahrscheinlich auch in anderen.

Ich neige dazu, diesen Ansatz in Kombination mit Signalen für meine Linux-Arbeit zu verwenden (für Windows siehe unten). Ich schlage dies oben in meine Python-Skripte:

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

Und dann lösen Sie es aus einer Shell mit kill -SIGUSR2 <PID>, wo <PID>ist die Prozess-ID. Der Prozess stoppt dann alles, was er tut, und zeigt eine Konsole an:

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

Im Allgemeinen lade ich von dort aus die serverseitige Komponente eines Remote-Debuggers wie die ausgezeichnete WinPDB .

Windows ist kein POSIX- kompatibles Betriebssystem und liefert daher nicht die gleichen Signale wie Linux. Allerdings Python v2.2 und über ein Windows-spezifisches Signal aussetzenSIGBREAK (ausgelöst durch Drücken CTRL+ Pause/Break). Dies gilt nicht bei normalen stören CTRL+ C( SIGINT) Betrieb, und so ist eine praktische Alternative.

Daher ist eine tragbare, aber etwas hässliche Version der oben genannten:

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

Vorteile dieses Ansatzes:

  • Keine externen Module (alles Standard-Python-Zeug)
  • Verbraucht bis zur Auslösung kaum Ressourcen (2x Import)

Hier ist der Code, den ich in meiner Produktionsumgebung verwende, der die Serverseite von WinPDB (falls verfügbar) lädt und auf das Öffnen einer Python-Konsole zurückgreift.

# 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
quelle
Können Sie weitere Details zum Laden der serverseitigen Komponente von WinPDB angeben, sobald Sie eine Python-Konsole haben?
Christian Long
1
Ich habe der Antwort meinen Produktionscode hinzugefügt, aber im Wesentlichen müssen Sie an einer Konsole nur Folgendes eingeben: '' import rpdb2; rpdb2.start_embedded_debugger ("foobar", True, True) '' und starten Sie dann die WinPDB-GUI mit dem Passwort "foobar", wenn Sie dazu aufgefordert werden
RobM
26

Verwenden Sie eine Pyrasitschale . Ich kann nicht glauben, dass es so gut funktioniert, aber es funktioniert. " Gib ihm eine Pid, ​​hol eine Muschel ".

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

Dadurch wird die Python-Shell mit Zugriff auf die Variablen globals () und local () des ausgeführten Python-Prozesses und andere wunderbare Dinge gestartet.

Habe dies nur persönlich unter Ubuntu getestet, scheint aber auch für OSX zu sorgen.

Angepasst an diese Antwort .

Hinweis: Die Leitung, die die ptrace_scopeEigenschaft ausschaltet, ist nur für Kernel / Systeme erforderlich, die mit CONFIG_SECURITY_YAMAon erstellt wurden. Achten Sie darauf, dass Sie in sensiblen Umgebungen mit ptrace_scope herumspielen, da dies zu bestimmten Sicherheitslücken führen kann. Siehe hier für Details.

python1981
quelle
@Dirk Ich glaube, ptrace_scope ist wichtig, damit ein Prozess einen anderen nicht verwandten Prozess verfolgen / mit ihm interagieren kann.
Python1981
Dies gilt natürlich nur für Systeme mit YAMA. Vorgeschlagene Bearbeitung und entfernte meinen ursprünglichen Kommentar. (Dieser auch innerhalb einiger Zeit zu gehen.)
Dirk
Siehe hier für die Verwendung in Docker: stackoverflow.com/questions/37072468/…
Michael Steinberg
5

Warum nicht einfach das pdb- Modul verwenden? Sie können ein Skript stoppen, Elementwerte überprüfen und den Code zeilenweise ausführen. Und da es auf dem Python-Interpreter basiert, bietet es auch die Funktionen des klassischen Interpreters. Um es zu verwenden, fügen Sie einfach diese 2 Zeilen in Ihren Code ein, wo Sie anhalten und es überprüfen möchten:

import pdb
pdb.set_trace()
mdeous
quelle
3
Wissen Sie, wie Sie es für einen bestimmten Thread von threading.enumerate () starten können?
Yucer
4

Eine andere Möglichkeit, ohne den Python-Skripten etwas hinzuzufügen, wird hier beschrieben:

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

Leider erfordert diese Lösung auch einige Überlegungen, zumindest in dem Maße, in dem Sie eine Python-Version mit Debugging-Symbolen verwenden müssen.

Joshua Richardson
quelle
Bei den meisten Linux-Distributionen wird Python mit Debugging-Symbolen erstellt, die Debugging-Symbole befinden sich jedoch in einem anderen Paket. Das Debugging-Symbolpaket kann installiert werden, nachdem Ihr Python-Skript bereits gestartet wurde.
W. Mann
1

Bei Verwendung von PyCharm konnte ich keine Verbindung zum Prozess in Ubuntu herstellen. Die Lösung hierfür ist das Deaktivieren von YAMA. Für weitere Informationen siehe askubuntu

echo 0 | sudo tee /proc/sys/kernel/yama/ptrace_scope
shao.lo
quelle