Wenn ein Anwender eines Programmes einen Absturz oder einen Hänger meldet, kann man manchmal nur versuchen mehr Informationen zu Ablauf und Umgebung zu sammeln und ein Fehlerszenario zu entwerfen, um diesen zu reproduzieren. Selbst mit einem klaren Anwenderszenario, ist man als Entwickler oft wegen verschiedener Umgebungen -- verschiedene Betriebssysteme, Compiler und anderes -- nicht in der Lage den Fehler zu reproduzieren. Wenn man Glück hat, ist der Anwender in der Lage Debug-Werkzeuge zu installieren, aber meistens muss man darauf warten, dass eine andere Person mehr Informationen zum selben Problem liefert.
Fatale Fehler
Das, in Python 3.3 neue, Modul faulthandler soll bei diesem Problem helfen. faulthandler ermöglicht es den Python Traceback bei einem Fatalen Fehler wie ein Segmentation Fault, Division durch Null, Programmabbruch oder bus error, zu erhalten. Man kann das innerhalb eines Programmes mit faulthandler.enable(), durch Starten von Python mit der Programmoption -X faulthandler oder durch Setzen der Umgebungsvariable PYTHONFAULTHANDLER=1 aktivieren.
Beispielausgabe
Fatal Python error: Segmentation fault Current thread 0x00007f7babc6b700: File "Lib/test/crashers/gc_inspection.py", line 29 in g File "Lib/test/crashers/gc_inspection.py", line 32 in <module> Segmentation fault
Timeout
faulthandler kann auch bei Programmhängern Traceback-Informationen liefern. faulthandler.dump_tracebacks_later(timeout) aktiviert einen Timer, nach dessen Ablauf ein Traceback ausgegeben wird. Ein erneuerter Aufruf setzt den Timer zurück. faulthandler.cancel_dump_tracebacks_later() stoppt den Timer. Ausgabe:
Timeout (0:01:00)! Current thread 0x00007f987d459700: File "Lib/test/crashers/infinite_loop_re.py", line 20 in <module>
Mit der Option repeat=True wird der Traceback alle timeout Sekunden ausgegeben, mit exit=True wird das Programm unsicher beendet; unsicher bedeutet, dass z.B. Dateien nicht mehr auf die Platte geschrieben werden.
Anwender Signal
Wenn man Zugang zum Computer hat, auf dem das Programm läuft, kann man mit faulthandler.register(signal) einen Signalhandler installieren, sodass ein Traceback ausgegeben wird wenn das Programm das signal erhält. Auf Unix kann man zum Beispiel das Signal SIGUSR1 folgendermaßen an den Prozess mit Prozess-Id pid senden: kill -USR1 <pid>. Auf Windows ist diese Möglichkeit nicht vorhanden. Ausgabe:
Current thread 0x00007fdc3da74700: File "Lib/test/crashers/infinite_loop_re.py", line 19 in <module>
Eine andere Möglichkeit ist im Programmcode direkt faulthandler.dump_traceback() direkt aufzurufen.
Sicherheitsaspekte und Ausgabedatei
faulthandler ist standardmäßig aus Sicherheitsgründen nicht aktiviert, hauptsächlich weil es den Dateideskriptor sys.stderr speichert und die Traceback-Informationen in diesen schreibt. Wenn die Datei sys.stderr geschlossen wird und der Dateideskriptor vom System neu vergeben wird, kann dies ein Socket, eine Pipe, eine wichtige Datei oder anderes sein. Standardmäßig schreibt faulthandler Traceback-Information in sys.stderr, es ist aber möglich eine andere Datei anzugeben. Mehr dazu in der faulthandler Dokumentation.
Nachinstallierbare Version für ältere Python Versionen
faulthandler ist auch als Zusatzmodul für Python 2.5 bis 3.2 auf PyPI erhältlich. Der Hauptunterschied zwischen dem Python 3.3 Modul und der nachinstaliierbaren Version ist die Implementierung von dump_tracebacks_later(): Python 3.3 verwendet einen Thread mit einem Timeout auf einem Lock, die nachinstaliierbaren Version verwendet SIGALRM und alarm().
Der Timeout des Locks, ein neues Feature in Python 3.3, ist in Microsekunden aufgelöst, wohingegen der alarm() Timer nur in Sekunden angegeben werden kann. Daneben unterbricht das SIGALRM-Signal möglicherweise einen geraden aktiven Systemaufruf, was zu einem EINTR Fehler führt.
Erfolgsgeschichten
Das neue Modul hat bereits geholfen Race Conditions in unseren Buildbots zu finden. Wir hoffen, dass es auch Dir in Deinen Programmen hilft.
Keine Kommentare:
Kommentar veröffentlichen