400 Stimmen

Anzeige des Stacktrace einer laufenden Python-Anwendung

Ich habe diese Python-Anwendung, die von Zeit zu Zeit stecken bleibt und ich kann nicht herausfinden, wo.

Gibt es eine Möglichkeit, dem Python-Interpreter zu signalisieren, dass er Ihnen den genauen Code anzeigt, der gerade läuft?

Eine Art On-the-Fly-Stacktrace?

Verwandte Fragen:

353voto

Brian Punkte 112487

Ich habe ein Modul, das ich für solche Situationen verwende - wenn ein Prozess lange Zeit läuft, aber manchmal aus unbekannten und nicht reproduzierbaren Gründen stecken bleibt. Es ist ein bisschen hacky, und funktioniert nur auf Unix (erfordert Signale):

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

Rufen Sie einfach die listen()-Funktion zu einem bestimmten Zeitpunkt auf, wenn Ihr Programm startet (Sie könnten sie sogar in site.py einfügen, damit alle Python-Programme sie verwenden), und lassen Sie sie laufen. Zu jedem beliebigen Zeitpunkt senden Sie dem Prozess ein SIGUSR1-Signal, indem Sie kill oder in Python:

    os.kill(pid, signal.SIGUSR1)

Dies führt dazu, dass das Programm an dem Punkt, an dem es sich gerade befindet, in eine Python-Konsole umbricht, die Ihnen den Stack-Trace anzeigt und Ihnen die Möglichkeit gibt, die Variablen zu manipulieren. Verwenden Sie control-d (EOF), um die Ausführung fortzusetzen (beachten Sie jedoch, dass Sie wahrscheinlich alle E/A usw. an dem Punkt unterbrechen, an dem Sie das Signal geben, so dass es nicht völlig unauffällig ist.

Ich habe ein anderes Skript, das dasselbe tut, nur dass es mit dem laufenden Prozess über eine Pipe kommuniziert (um das Debuggen von Prozessen im Hintergrund usw. zu ermöglichen). Es ist ein bisschen groß, um es hier zu posten, aber ich habe es als python kochbuch rezept .

158voto

spiv Punkte 2990

Der Vorschlag, einen Signalhandler zu installieren, ist gut, und ich verwende ihn häufig. Zum Beispiel, bzr installiert standardmäßig einen SIGQUIT-Handler, der die pdb.set_trace() um Sie sofort in eine pdb (Siehe die bzrlib.breakin Quelle des Moduls für die genauen Details). Mit pdb können Sie nicht nur den aktuellen Stacktrace (mit der Option (w)here Befehl), sondern auch Variablen usw. überprüfen.

Manchmal muss ich jedoch einen Prozess debuggen, bei dem ich nicht in der Lage war, den Signalhandler zu installieren. Unter Linux kann man gdb an den Prozess anhängen und mit einigen gdb-Makros einen Python-Stacktrace erhalten. Setzen Sie http://svn.python.org/projects/python/trunk/Misc/gdbinit en ~/.gdbinit , dann:

  • gdb anhängen: gdb -p PID
  • Holen Sie sich den Python-Stacktrace: pystack

Es ist leider nicht ganz zuverlässig, aber es funktioniert meistens. Siehe auch https://wiki.python.org/moin/DebuggingWithGdb

Schließlich ist das Anbringen von strace kann Ihnen oft eine gute Vorstellung davon vermitteln, was ein Prozess tut.

81voto

haridsv Punkte 8019

Ich bin fast immer den Umgang mit mehreren Threads und Haupt-Thread ist in der Regel nicht viel tun, so was am interessantesten ist, um alle Stapel zu dumpen (das ist mehr wie die Java-Dump). Hier ist eine Implementierung basierend auf dieser Blog :

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)

60voto

Nickolay Punkte 29488

Abrufen einer Stapelverfolgung einer unvorbereitet python-Programm, das in einem Standard-Python-Programm läuft ohne Fehlersuchsymbole kann erfolgen mit Pyrasit . Funktionierte für mich unter Ubuntu Trusty wie ein Zauber:

$ 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

(Hut ab vor @Albert, der in seiner Antwort unter anderem auf dieses Tool verwiesen hat).

37voto

Torsten Marek Punkte 78610
>>> import traceback
>>> def x():
>>>    print traceback.extract_stack()

>>> x()
[('<stdin>', 1, '<module>', None), ('<stdin>', 2, 'x', None)]

Sie können den Stacktrace auch schön formatieren, siehe die docs .

bearbeiten : Um das Verhalten von Java zu simulieren, wie von @Douglas Leeder vorgeschlagen, fügen Sie dies hinzu:

import signal
import traceback

signal.signal(signal.SIGUSR1, lambda sig, stack: traceback.print_stack(stack))

in den Startup-Code Ihrer Anwendung einfügen. Dann können Sie den Stack drucken, indem Sie SIGUSR1 für den laufenden Python-Prozess.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X