Wie kann ich meine Python-Fehler protokollieren?
try:
do_something()
except:
# How can I log my exception here, complete with its traceback?
ZEITX
Wie kann ich meine Python-Fehler protokollieren?
try:
do_something()
except:
# How can I log my exception here, complete with its traceback?
nosklo
Verwenden logging.exception
aus dem except:
Handler/Block, um die aktuelle Ausnahme zusammen mit den Ablaufverfolgungsinformationen zu protokollieren, denen eine Nachricht vorangestellt ist.
import logging
LOG_FILENAME = '/tmp/logging_example.out'
logging.basicConfig(filename=LOG_FILENAME, level=logging.DEBUG)
logging.debug('This message should go to the log file')
try:
run_my_stuff()
except:
logging.exception('Got exception on main handler')
raise
Wenn Sie sich jetzt die Protokolldatei ansehen, /tmp/logging_example.out
:
DEBUG:root:This message should go to the log file
ERROR:root:Got exception on main handler
Traceback (most recent call last):
File "/tmp/teste.py", line 9, in <module>
run_my_stuff()
NameError: name 'run_my_stuff' is not defined
Ich habe den Django-Code dafür durchgesehen, und ich nehme an, die Antwort ist nein, aber gibt es eine Möglichkeit, die Rückverfolgung auf eine bestimmte Menge von Zeichen oder Tiefe zu beschränken? Das Problem ist, dass es bei großen Rückverfolgungen ziemlich lange dauert.
– Eduard Lukas
21. Mai 2014 um 13:16 Uhr
Beachten Sie, dass wenn Sie einen Logger mit definieren logger = logging.getLogger('yourlogger')
Du musst schreiben logger.exception('...')
damit das funktioniert…
– 576i
5. Februar 2017 um 12:43 Uhr
Können wir dies so ändern, dass die Nachricht mit Protokollebene INFO gedruckt wird?
– NM
31. Oktober 2017 um 9:38 Uhr
Beachten Sie, dass für bestimmte externe Apps, z. B. Azure Insight, der Trackback nicht in den Protokollen gespeichert wird. Es ist dann notwendig, sie explizit an die Nachrichtenzeichenfolge zu übergeben, wie unten gezeigt.
– Edgar H
16. Juli 2020 um 7:55 Uhr
Ich hatte immer gedacht logging.exception(...)
(oder logger.exception(...)
wenn so konfiguriert) würde es tun. Aber ich bin ein bisschen verwirrt mit dieser Methode geworden exception
im Kontext eines Ausnahme-Hook-Handlers: Es scheint den Traceback in diesem Kontext nicht auszudrucken. Beginnen Sie zu vermuten, dass Ihr Anrufcode in einem sein muss except
blockieren, damit dies funktioniert.
– Mike Nagetier
10. April 2021 um 17:49 Uhr
Flycee
Verwenden exc_info
Optionen können besser sein, bleibt Warnung oder Fehlertitel:
try:
# coode in here
except Exception as e:
logging.error(e, exc_info=True)
Ich kann mich nie erinnern, was die exc_info=
kwarg heißt; Danke!
– Berto
31. Oktober 2017 um 15:00 Uhr
Dies ist identisch mit der Protokollierung.Ausnahme, mit der Ausnahme, dass der Typ zweimal redundant protokolliert wird. Verwenden Sie einfach “logging.exception”, es sei denn, Sie möchten eine andere Ebene als “Error”.
– Wyrmholz
17. November 2017 um 16:11 Uhr
@Wyrmwood, es ist nicht identisch, da Sie eine Nachricht übermitteln müssen logging.exception
– Peter Holz
21. April 2018 um 7:30 Uhr
Verwenden logging.error
kann man unangenehme Nachrichten wie vermeiden ''
oder ' '
zu logging.exception
.
– Nuklear03020704
16. April 2021 um 2:34 Uhr
Brad Barrows
Mein Job hat mich kürzlich damit beauftragt, alle Tracebacks/Ausnahmen aus unserer Anwendung zu protokollieren. Ich habe zahlreiche Techniken ausprobiert, die andere online gepostet hatten, wie die obige, aber mich für einen anderen Ansatz entschieden. Überschreiben traceback.print_exception
.
Ich habe ein Schreiben auf http://www.bbarrows.com/ Das wäre viel einfacher zu lesen, aber ich werde es auch hier einfügen.
Als ich damit beauftragt wurde, alle Ausnahmen zu protokollieren, auf die unsere Software in freier Wildbahn stoßen könnte, habe ich eine Reihe verschiedener Techniken ausprobiert, um unsere Python-Ausnahmerückverfolgungen zu protokollieren. Zuerst dachte ich, dass der Ausnahmehaken des Python-Systems, sys.excepthook, der perfekte Ort wäre, um den Protokollierungscode einzufügen. Ich habe etwas Ähnliches versucht:
import traceback
import StringIO
import logging
import os, sys
def my_excepthook(excType, excValue, traceback, logger=logger):
logger.error("Logging an uncaught exception",
exc_info=(excType, excValue, traceback))
sys.excepthook = my_excepthook
Dies funktionierte für den Hauptthread, aber ich stellte bald fest, dass my sys.excepthook in keinem neuen Thread vorhanden war, den mein Prozess gestartet hatte. Dies ist ein großes Problem, da fast alles in Threads in diesem Projekt passiert.
Nachdem ich viel Dokumentation gegoogelt und gelesen hatte, waren die hilfreichsten Informationen, die ich fand, aus dem Python Issue Tracker.
Der erste Beitrag im Thread zeigt ein funktionierendes Beispiel für die sys.excepthook
NICHT über Threads hinweg bestehen bleiben (wie unten gezeigt). Anscheinend ist dies ein erwartetes Verhalten.
import sys, threading
def log_exception(*args):
print 'got exception %s' % (args,)
sys.excepthook = log_exception
def foo():
a = 1 / 0
threading.Thread(target=foo).start()
Die Nachrichten in diesem Python-Problem-Thread führen wirklich zu 2 vorgeschlagenen Hacks. Entweder Unterklasse Thread
und packen Sie die run-Methode in unseren eigenen try except block, um Exceptions oder Monkey Patch abzufangen und zu protokollieren threading.Thread.run
in Ihrem eigenen Versuch auszuführen, außer zu blockieren und die Ausnahmen zu protokollieren.
Die erste Methode der Unterklassenbildung Thread
scheint mir in Ihrem Code weniger elegant zu sein, da Sie Ihre benutzerdefinierten importieren und verwenden müssten Thread
Klasse ÜBERALL, wo Sie einen Protokollierungsthread haben wollten. Dies war ein Ärgernis, da ich unsere gesamte Codebasis durchsuchen und alle normalen ersetzen musste Threads
mit diesem Brauch Thread
. Es war jedoch klar, worum es ging Thread
funktionierte und für jemanden einfacher zu diagnostizieren und zu debuggen wäre, wenn etwas mit dem benutzerdefinierten Protokollierungscode schief gelaufen wäre. Ein benutzerdefinierter Protokollierungsthread könnte folgendermaßen aussehen:
class TracebackLoggingThread(threading.Thread):
def run(self):
try:
super(TracebackLoggingThread, self).run()
except (KeyboardInterrupt, SystemExit):
raise
except Exception, e:
logger = logging.getLogger('')
logger.exception("Logging an uncaught exception")
Die zweite Methode des Monkey Patching threading.Thread.run
ist schön, weil ich es einfach mal direkt hinterher laufen lassen könnte __main__
und instrumentiere meinen Logging-Code in allen Ausnahmen. Das Debuggen von Monkey-Patches kann jedoch lästig sein, da es die erwartete Funktionalität von etwas ändert. Der vorgeschlagene Patch vom Python Issue Tracker war:
def installThreadExcepthook():
"""
Workaround for sys.excepthook thread bug
From
http://spyced.blogspot.com/2007/06/workaround-for-sysexcepthook-bug.html
(https://sourceforge.net/tracker/?func=detail&atid=105470&aid=1230540&group_id=5470).
Call once from __main__ before creating any threads.
If using psyco, call psyco.cannotcompile(threading.Thread.run)
since this replaces a new-style class method.
"""
init_old = threading.Thread.__init__
def init(self, *args, **kwargs):
init_old(self, *args, **kwargs)
run_old = self.run
def run_with_except_hook(*args, **kw):
try:
run_old(*args, **kw)
except (KeyboardInterrupt, SystemExit):
raise
except:
sys.excepthook(*sys.exc_info())
self.run = run_with_except_hook
threading.Thread.__init__ = init
Erst als ich anfing, meine Ausnahmeprotokollierung zu testen, wurde mir klar, dass ich alles falsch gemacht hatte.
Zum Testen hatte ich einen platziert
raise Exception("Test")
irgendwo in meinem Code. Das Umschließen einer Methode, die diese Methode aufrief, war jedoch ein Try-Except-Block, der das Traceback ausgab und die Ausnahme verschluckte. Das war sehr frustrierend, weil ich gesehen habe, dass der Traceback auf STDOUT gedruckt, aber nicht protokolliert wurde. Ich entschied dann, dass eine viel einfachere Methode zum Protokollieren der Tracebacks darin bestand, einfach die Methode zu patchen, die der gesamte Python-Code verwendet, um die Tracebacks selbst zu drucken, traceback.print_exception. Ich endete mit etwas Ähnlichem wie dem Folgenden:
def add_custom_print_exception():
old_print_exception = traceback.print_exception
def custom_print_exception(etype, value, tb, limit=None, file=None):
tb_output = StringIO.StringIO()
traceback.print_tb(tb, limit, tb_output)
logger = logging.getLogger('customLogger')
logger.error(tb_output.getvalue())
tb_output.close()
old_print_exception(etype, value, tb, limit=None, file=None)
traceback.print_exception = custom_print_exception
Dieser Code schreibt den Traceback in einen String-Puffer und protokolliert ihn zum Protokollieren von ERROR. Ich habe einen benutzerdefinierten Protokollierungs-Handler eingerichtet, der den Logger „customLogger“ eingerichtet hat, der die Protokolle der ERROR-Ebene nimmt und sie zur Analyse nach Hause sendet.
Ein durchaus interessanter Ansatz. Eine Frage – add_custom_print_exception
scheint sich nicht auf der Seite zu befinden, auf die Sie verlinkt haben, und stattdessen gibt es dort einen ganz anderen endgültigen Code. Welches ist Ihrer Meinung nach besser / endgültiger und warum? Vielen Dank!
– fantastisch
31. Juli 2014 um 0:53 Uhr
Danke, tolle Antwort!
– 101
12. Januar 2016 um 3:45 Uhr
Es gibt einen Ausschneide- und Einfügefehler. Beim delegierten Aufruf von old_print_exception sollten limit und file übergeben werden limit und file, nicht None — old_print_exception(etype, value, tb, limit, file)
– Marwin
27. Mai 2016 um 15:15 Uhr
Für Ihren letzten Codeblock können Sie einfach aufrufen, anstatt ein StringIO zu initialisieren und die Ausnahme davon auszugeben logger.error(traceback.format_tb())
(oder format_exc(), wenn Sie auch die Ausnahmeinformationen wünschen).
– James
6. Oktober 2018 um 21:01 Uhr
Ihr geteilter Link funktioniert jetzt nicht. Ich bin auch nicht in der Lage, das Traceback mit der obigen Methode zu protokollieren. Ich rief raise Exception
im Code und vor dem habe ich die von Ihnen definierte Methode aufgerufen. Nichts passiert. @Brad und @Christian
– Vaibhav Grover
19. April 2021 um 6:07 Uhr
Sie können alle nicht abgefangenen Ausnahmen im Hauptthread protokollieren, indem Sie einen Handler zuweisen sys.excepthook
vielleicht mit der exc_info
Parameter der Logging-Funktionen von Python:
import sys
import logging
logging.basicConfig(filename="/tmp/foobar.log")
def exception_hook(exc_type, exc_value, exc_traceback):
logging.error(
"Uncaught exception",
exc_info=(exc_type, exc_value, exc_traceback)
)
sys.excepthook = exception_hook
raise Exception('Boom')
Wenn Ihr Programm jedoch Threads verwendet, beachten Sie, dass Threads erstellt mit threading.Thread
Wille nicht Abzug sys.excepthook
wenn eine nicht abgefangene Ausnahme in ihnen auftritt, wie in angegeben Ausgabe 1230540 im Issue-Tracker von Python. Dort wurden einige Hacks vorgeschlagen, um diese Einschränkung zu umgehen, z. B. Monkey-Patching Thread.__init__
zu überschreiben self.run
mit Alternative run
Methode, die das Original in a umschließt try
blockieren und anrufen sys.excepthook
aus dem Inneren except
Block. Alternativ könnten Sie den Einstiegspunkt für jeden Ihrer Threads einfach manuell einschließen try
/except
dich selbst.
Was ich gesucht habe:
import sys
import traceback
exc_type, exc_value, exc_traceback = sys.exc_info()
traceback_in_var = traceback.format_tb(exc_traceback)
Sehen:
Sie können die Rückverfolgung mit einem Logger auf jeder Ebene (DEBUG, INFO, …) abrufen. Beachten Sie, dass mit logging.exception
der Pegel ist FEHLER.
# test_app.py
import sys
import logging
logging.basicConfig(level="DEBUG")
def do_something():
raise ValueError(":(")
try:
do_something()
except Exception:
logging.debug("Something went wrong", exc_info=sys.exc_info())
DEBUG:root:Something went wrong
Traceback (most recent call last):
File "test_app.py", line 10, in <module>
do_something()
File "test_app.py", line 7, in do_something
raise ValueError(":(")
ValueError: :(
BEARBEITEN:
Dies funktioniert auch (mit Python 3.6)
logging.debug("Something went wrong", exc_info=True)
Markus Amery
Nicht erfasste Ausnahmemeldungen werden an STDERR gesendet. Anstatt also Ihre Protokollierung in Python selbst zu implementieren, könnten Sie STDERR an eine Datei senden, indem Sie die Shell verwenden, die Sie zum Ausführen Ihres Python-Skripts verwenden. In einem Bash-Skript können Sie dies mit der Ausgabeumleitung tun, als im BASH-Leitfaden beschrieben.
Fehler an Datei anhängen, andere Ausgabe an das Terminal:
./test.py 2>> mylog.log
Datei mit verschachtelter STDOUT- und STDERR-Ausgabe überschreiben:
./test.py &> mylog.log