Python-Exception-Logging: Traceback und ausreichenden Anforderungskontext beibehalten
Verwenden Sie einen benannten Logger, konfigurieren Sie die Anwendung einmal und fügen Sie sicheren Kontext hinzu, ohne jeden Fehler zu duplizieren.
Auf dieser Seite
Die kurze Antwort
In einem Exception-Handler zeichnet logger.exception ein ERROR-Ereignis mit den aktuellen Exception-Informationen auf. Konfigurieren Sie Handler im Einstiegspunkt der Anwendung und verwenden Sie getLogger(__name__) in einzelnen Modulen. Fügen Sie einen sicheren Vorgangs- oder Anforderungsbezeichner hinzu, damit der Traceback dem fehlerhaften Vorgang zugeordnet werden kann. Das Logging zeichnet den Fehler auf; das Programm muss separat entscheiden, ob es wiederhergestellt wird, ein Fehler zurückgegeben oder die Exception erneut ausgelöst wird.
Lesen Sie ein vollständiges kleines Beispiel
Dieses konstruierte eigenständige Skript übergibt absichtlich einen nicht-numerischen String an int. Die erwartete Protokollausgabe enthält eine ERROR-Meldung mit request_id=demo1 und Exception-Informationen, die mit ValueError enden. Exakte Traceback-Pfade und Zeilennummern hängen davon ab, wo das Skript gespeichert ist, daher wird kein fester vollständiger Traceback versprochen. Das Beispiel veranschaulicht einen Logging-Aufruf; seine abgefangene Exception wird nicht automatisch an den Aufrufer weitergegeben.
Entscheiden Sie, wer das finale Fehlerprotokoll besitzt
Wenn eine untere Schicht eine Exception protokolliert und erneut auslöst und eine obere Schicht sie ebenfalls protokolliert, kann ein Fehler zweimal erscheinen. Entscheiden Sie, welche Schicht genug Kontext hat, um das operative Protokoll zu erstellen. Eine untere Schicht kann Informationen hinzufügen, indem sie eine geeignete Exception auslöst, während die Grenze den endgültigen Fehler protokolliert. Dies ist eine Entwurfsentscheidung, keine Anforderung, dass jede Exception überall genau einmal protokolliert werden muss.
Diagnostizieren Sie sich wiederholende Ausgaben über Handler
Auftretende Duplikate können auch daraus resultieren, dass ein Handler an einen untergeordneten Logger angehängt wird, während die Weiterleitung an einen Vorfahren mit einem weiteren Handler erlaubt bleibt. Prüfen Sie die Logger-Hierarchie und die Handler-Konfiguration, bevor Sie Anwendungsereignisse entfernen. Logger- und Handler-Ebenen können beide beeinflussen, ob Ausgaben erscheinen. Das Unterdrücken der Weiterleitung ohne Kenntnis der Zielorte kann Protokolle von einem zentralen Senke genauso verbergen wie eine doppelte Konsolenzeile entfernen.
Halten Sie sensible Kontextinformationen aus dem Protokoll heraus
Verwenden Sie einen undurchsichtigen Anforderungsbezeichner oder einen sorgfältig ausgewählten Vorgangsnamen. Schließen Sie keine Passwörter, Autorisierungsheader, API-Schlüssel oder eine gesamte ungefilterte Anforderungspayload ein. Exception-Nachrichten selbst können Benutzereingaben oder Verbindungsdetails enthalten, daher ist ein sicherer Logging-Aufruf kein Beweis, dass jeder resultierende Traceback sicher aufbewahrt werden kann. Wenden Sie Zugriffs-, Aufbewahrungs- und Redaktionsrichtlinien an, die für die tatsächliche Anwendung und das Protokollziel geeignet sind.
import logging
logging.basicConfig(level=logging.INFO, format="%(levelname)s %(name)s %(message)s")
logger = logging.getLogger(__name__)
request_id = "demo1"
try:
int("bad")
except ValueError:
logger.exception("Could not parse quantity; request_id=%s", request_id)
Trennen Sie Diagnostik von Programmverhalten
Ein Logging-Aufruf wiederholt den Vorgang weder noch wählt die an einen Client zurückgegebene Antwort. Nach dem Aufzeichnen des Ereignisses entscheiden Sie bewusst, ob mit einem gültigen Fallback fortgefahren, ein dokumentierter Fehler zurückgegeben oder die Exception erneut ausgelöst wird. Dokumentieren Sie die Entscheidung nahe der Fehlergrenze. Wenn das Programm fortfährt, vermeiden Sie, dass späterer Code von einem Wert abhängt, der von der fehlerhaften Anweisung nie erfolgreich erstellt wurde.
Wählen Sie das Ereignis, das Sie aufzeichnen müssen
Ein Exception-Objekt und ein operatives Ereignis beantworten unterschiedliche Fragen. Die Exception beschreibt, was fehlgeschlagen ist; das Ereignis kann identifizieren, welcher Vorgang im Gange war. Bevor Sie Logging hinzufügen, entscheiden Sie, wer den Eintrag lesen wird und was er zur Untersuchung benötigt. Eine kurze Meldung, die den Vorgang benennt, und ein nicht-geheimer Korrelationsbezeichner sind normalerweise nützlicher als das Wiederholen eines gesamten Anforderungskörpers oder das Ausgeben jeder lokalen Variable.
Konfigurieren Sie das Logging an der Anwendungsgrenze
Für ein eigenständiges Skript konfigurieren Sie das Logging, bevor die Anwendung mit der Arbeit beginnt. Das untenstehende Beispiel verwendet basicConfig einmal und holt einen benannten Logger. Eine größere Anwendung kann einen anderen Konfigurationsmechanismus verwenden, aber der Besitz sollte weiterhin klar sein. Eine wiederverwendbare Bibliothek sollte benannte Logger bereitstellen und dem Aufrufer überlassen, Handler, Zielorte und Ebenen zu wählen, statt die Anwendungskonfiguration bedingungslos zu ersetzen.
Nutzen Sie Exception-Informationen innerhalb des Handlers
logger.exception ist für einen Exception-Handler gedacht, in dem die aktuellen Exception-Informationen verfügbar sind. Der Aufruf von logger.error mit nur dem Exception-Text lässt den Traceback weg, es sei denn, Exception-Informationen werden explizit angefordert. Umgekehrt erfordert das Schreiben eines Tracebacks nicht, jede wiederherstellbare Bedingung als fatalen Anwendungsfehler zu behandeln. Wählen Sie die Ereignisebene und die Wiederherstellungspolitik gemäß dem Vorgang, nicht allein gemäß dem Namen der Exception-Klasse.
Was Sie prüfen sollten
- Handler in der Anwendung konfigurieren, nicht in jedem Modul.
- Exception-Informationen nutzen, während die Exception behandelt wird.
- Sicheren Korrelationsbezeichner einschließen.
- Handler und Weiterleitung prüfen, wenn Ausgaben sich wiederholen.
- Wiederherstellung oder Weitergabe separat vom Logging definieren.
Geltungsbereich
Das Skript veranschaulicht das Logging aus der Standardbibliothek und einen abgefangenen ValueError. Es ist keine vollständige Produktions-Logging-Konfiguration und zeigt keinen bereitgestellten Log-Zielort, automatische Redaktion, Wiederholungen oder einen ausgeführten Anwendungstest.