Logging HOWTO¶
- Autor:
Vinay Sajip <vinay_sajip at red-dove dot com>
Diese Seite enthält Tutorial-Informationen. Links zu Referenzinformationen und einem Protokollierungs-Kochbuch finden Sie unter Weitere Ressourcen.
Einsteiger-Tutorial zur Protokollierung¶
Protokollierung ist eine Methode zur Verfolgung von Ereignissen, die während der Ausführung von Software auftreten. Der Entwickler der Software fügt Protokollierungsaufrufe in seinen Code ein, um anzuzeigen, dass bestimmte Ereignisse aufgetreten sind. Ein Ereignis wird durch eine beschreibende Meldung dargestellt, die optional variable Daten enthalten kann (d. h. Daten, die sich potenziell bei jedem Auftreten des Ereignisses unterscheiden). Ereignisse haben auch eine Wichtigkeit, die der Entwickler dem Ereignis zuordnet; die Wichtigkeit kann auch als Stufe oder Schweregrad bezeichnet werden.
Wann sollte Protokollierung verwendet werden¶
Sie können auf Protokollierungsfunktionalität zugreifen, indem Sie einen Logger über logger = getLogger(__name__) erstellen und dann die Methoden debug(), info(), warning(), error() und critical() des Loggers aufrufen. Um zu entscheiden, wann Protokollierung verwendet werden soll und welche Logger-Methoden Sie wann verwenden sollten, siehe die folgende Tabelle. Sie gibt für jede einer Reihe gängiger Aufgaben das beste Werkzeug für diese Aufgabe an.
Aufgabe, die Sie ausführen möchten |
Das beste Werkzeug für die Aufgabe |
|---|---|
Konsolenausgabe für normale Verwendung eines Kommandozeilenskripts oder -programms anzeigen |
|
Ereignisse melden, die während des normalen Betriebs eines Programms auftreten (z. B. zur Statusüberwachung oder Fehleruntersuchung) |
Die Methode |
Eine Warnung bezüglich eines bestimmten Laufzeitereignisses ausgeben |
Die Methode |
Einen Fehler bezüglich eines bestimmten Laufzeitereignisses melden |
Eine Ausnahme auslösen |
Unterdrückung eines Fehlers melden, ohne eine Ausnahme auszulösen (z. B. Fehlerbehandlung in einem langlebigen Serverprozess) |
Die Methode |
Die Logger-Methoden sind nach der Stufe oder dem Schweregrad der Ereignisse benannt, die sie zur Verfolgung verwenden. Die Standardstufen und ihre Anwendbarkeit werden nachstehend beschrieben (in aufsteigender Reihenfolge des Schweregrads)
Stufe |
Wann sie verwendet wird |
|---|---|
|
Detaillierte Informationen, die in der Regel nur bei der Diagnose von Problemen von Interesse sind. |
|
Bestätigung, dass die Dinge wie erwartet funktionieren. |
|
Ein Hinweis darauf, dass etwas Unerwartetes passiert ist, oder ein Hinweis auf ein Problem in naher Zukunft (z. B. „Festplattenspeicher gering“). Die Software funktioniert weiterhin wie erwartet. |
|
Aufgrund eines schwerwiegenderen Problems konnte die Software eine Funktion nicht ausführen. |
|
Ein schwerwiegender Fehler, der darauf hinweist, dass das Programm selbst möglicherweise nicht weiterlaufen kann. |
Die Standardstufe ist WARNING, was bedeutet, dass nur Ereignisse dieser Schwere und höher verfolgt werden, es sei denn, das Protokollierungspaket ist anders konfiguriert.
Verfolgte Ereignisse können unterschiedlich behandelt werden. Die einfachste Methode zur Behandlung von verfolgten Ereignissen ist deren Ausgabe auf der Konsole. Eine weitere übliche Methode ist das Schreiben in eine Disk-Datei.
Ein einfaches Beispiel¶
Ein sehr einfaches Beispiel ist
import logging
logging.warning('Watch out!') # will print a message to the console
logging.info('I told you so') # will not print anything
Wenn Sie diese Zeilen in ein Skript eingeben und es ausführen, sehen Sie
WARNING:root:Watch out!
auf der Konsole ausgegeben. Die Meldung INFO erscheint nicht, da die Standardstufe WARNING ist. Die ausgegebene Meldung enthält die Angabe der Stufe und die Beschreibung des Ereignisses, die im Protokollierungsaufruf angegeben wurde, d. h. „Watch out!“. Die tatsächliche Ausgabe kann recht flexibel formatiert werden, wenn Sie dies benötigen; Formatierungsoptionen werden ebenfalls später erläutert.
Beachten Sie, dass wir in diesem Beispiel Funktionen direkt auf dem Modul logging verwenden, z. B. logging.debug, anstatt einen Logger zu erstellen und Funktionen auf diesem aufzurufen. Diese Funktionen arbeiten mit dem Stamm-Logger, können aber nützlich sein, da sie basicConfig() für Sie aufrufen, wenn es noch nicht aufgerufen wurde, wie in diesem Beispiel. In größeren Programmen möchten Sie die Protokollierungskonfiguration jedoch normalerweise explizit steuern – daher und aus anderen Gründen ist es besser, Logger zu erstellen und deren Methoden aufzurufen.
Protokollierung in eine Datei¶
Eine sehr häufige Situation ist die Aufzeichnung von Protokollierungsereignissen in einer Datei, also schauen wir uns das als Nächstes an. Stellen Sie sicher, dass Sie das Folgende in einer neu gestarteten Python-Umgebung ausprobieren und nicht einfach von der oben beschriebenen Sitzung fortfahren
import logging
logger = logging.getLogger(__name__)
logging.basicConfig(filename='example.log', encoding='utf-8', level=logging.DEBUG)
logger.debug('This message should go to the log file')
logger.info('So should this')
logger.warning('And this, too')
logger.error('And non-ASCII stuff, too, like Øresund and Malmö')
Geändert in Version 3.9: Das Argument encoding wurde hinzugefügt. In früheren Python-Versionen oder wenn es nicht angegeben wird, ist die verwendete Kodierung der Standardwert, der von open() verwendet wird. Obwohl im obigen Beispiel nicht gezeigt, kann jetzt auch ein errors-Argument übergeben werden, das bestimmt, wie Kodierungsfehler behandelt werden. Verfügbare Werte und den Standard finden Sie in der Dokumentation für open().
Und wenn wir nun die Datei öffnen und uns ansehen, was wir haben, sollten wir die Protokollmeldungen finden
DEBUG:__main__:This message should go to the log file
INFO:__main__:So should this
WARNING:__main__:And this, too
ERROR:__main__:And non-ASCII stuff, too, like Øresund and Malmö
Dieses Beispiel zeigt auch, wie Sie die Protokollierungsstufe festlegen können, die als Schwellenwert für die Verfolgung dient. In diesem Fall wurden alle Meldungen gedruckt, da wir den Schwellenwert auf DEBUG gesetzt haben.
Wenn Sie die Protokollierungsstufe über eine Kommandozeilenoption wie
--log=INFO
und Sie den Wert des Parameters für --log in einer Variablen loglevel haben, können Sie
getattr(logging, loglevel.upper())
verwenden, um den Wert zu erhalten, den Sie über das Argument level an basicConfig() übergeben. Möglicherweise möchten Sie Benutzereingaben auf Fehler überprüfen, vielleicht wie im folgenden Beispiel
# assuming loglevel is bound to the string value obtained from the
# command line argument. Convert to upper case to allow the user to
# specify --log=DEBUG or --log=debug
numeric_level = getattr(logging, loglevel.upper(), None)
if not isinstance(numeric_level, int):
raise ValueError('Invalid log level: %s' % loglevel)
logging.basicConfig(level=numeric_level, ...)
Der Aufruf von basicConfig() sollte vor allen Aufrufen der Methoden eines Loggers wie debug(), info() usw. erfolgen. Andernfalls wird das Protokollierungsereignis möglicherweise nicht wie gewünscht behandelt.
Wenn Sie das obige Skript mehrmals ausführen, werden die Meldungen aufeinanderfolgender Ausführungen an die Datei example.log angehängt. Wenn jede Ausführung frisch beginnen soll, ohne sich an Meldungen früherer Ausführungen zu erinnern, können Sie das Argument filemode angeben, indem Sie den Aufruf im obigen Beispiel ändern zu
logging.basicConfig(filename='example.log', filemode='w', level=logging.DEBUG)
Die Ausgabe ist dieselbe wie zuvor, aber an die Protokolldatei wird nicht mehr angehängt, sodass die Meldungen früherer Ausführungen verloren gehen.
Protokollierung variabler Daten¶
Um variable Daten zu protokollieren, verwenden Sie eine Formatzeichenfolge für die Ereignisbeschreibungsnachricht und hängen Sie die variablen Daten als Argumente an. Zum Beispiel
import logging
logging.warning('%s before you %s', 'Look', 'leap!')
wird anzeigen
WARNING:root:Look before you leap!
Wie Sie sehen können, verwendet die Zusammenführung variabler Daten in der Ereignisbeschreibungsnachricht die alte %-Formatierung. Dies dient der Abwärtskompatibilität: Das Protokollierungspaket existiert vor neueren Formatierungsoptionen wie str.format() und string.Template. Diese neueren Formatierungsoptionen werden unterstützt, aber deren Untersuchung liegt außerhalb des Rahmens dieses Tutorials: weitere Informationen finden Sie unter Verwendung bestimmter Formatierungsstile in Ihrer Anwendung.
Ändern des Formats angezeigter Meldungen¶
Um das für die Anzeige von Meldungen verwendete Format zu ändern, müssen Sie das gewünschte Format angeben
import logging
logging.basicConfig(format='%(levelname)s:%(message)s', level=logging.DEBUG)
logging.debug('This message should appear on the console')
logging.info('So should this')
logging.warning('And this, too')
was drucken würde
DEBUG:This message should appear on the console
INFO:So should this
WARNING:And this, too
Beachten Sie, dass das „root“, das in früheren Beispielen erschien, verschwunden ist. Eine vollständige Liste der Dinge, die in Formatzeichenfolgen erscheinen können, finden Sie in der Dokumentation für LogRecord-Attribute, aber für eine einfache Verwendung benötigen Sie nur den levelname (Schweregrad), die message (Ereignisbeschreibung, einschließlich variabler Daten) und vielleicht die Anzeige, wann das Ereignis aufgetreten ist. Dies wird im nächsten Abschnitt beschrieben.
Anzeige von Datum/Zeit in Meldungen¶
Um das Datum und die Uhrzeit eines Ereignisses anzuzeigen, würden Sie „%(asctime)s“ in Ihre Formatzeichenfolge einfügen
import logging
logging.basicConfig(format='%(asctime)s %(message)s')
logging.warning('is when this event was logged.')
was etwa so ausgeben sollte
2010-12-12 11:41:42,612 is when this event was logged.
Das Standardformat für die Datum/Zeit-Anzeige (wie oben gezeigt) ist ähnlich wie ISO8601 oder RFC 3339. Wenn Sie mehr Kontrolle über die Formatierung des Datums/der Uhrzeit benötigen, übergeben Sie ein datefmt-Argument an basicConfig, wie in diesem Beispiel
import logging
logging.basicConfig(format='%(asctime)s %(message)s', datefmt='%m/%d/%Y %I:%M:%S %p')
logging.warning('is when this event was logged.')
was ungefähr so ausgeben würde
12/12/2010 11:46:36 AM is when this event was logged.
Das Format des datefmt-Arguments ist dasselbe wie das, das von time.strftime() unterstützt wird.
Nächste Schritte¶
Damit ist das grundlegende Tutorial abgeschlossen. Es sollte ausreichen, um Ihnen den Einstieg in die Protokollierung zu ermöglichen. Das Protokollierungspaket bietet noch viel mehr, aber um das Beste daraus zu machen, müssen Sie etwas mehr Zeit in das Lesen der folgenden Abschnitte investieren. Wenn Sie bereit dafür sind, holen Sie sich Ihr Lieblingsgetränk und machen Sie weiter.
Wenn Ihre Protokollierungsanforderungen einfach sind, verwenden Sie die obigen Beispiele, um die Protokollierung in Ihre eigenen Skripte zu integrieren. Wenn Sie auf Probleme stoßen oder etwas nicht verstehen, stellen Sie bitte eine Frage im Hilfe-Bereich des Python-Diskussionsforums und Sie sollten bald Hilfe erhalten.
Immer noch hier? Sie können die nächsten Abschnitte weiterlesen, die ein etwas fortgeschritteneres/detaillierteres Tutorial als das obige Grundtutorial bieten. Danach können Sie sich das Logging Cookbook ansehen.
Fortgeschrittenes Tutorial zur Protokollierung¶
Die Protokollierungsbibliothek verfolgt einen modularen Ansatz und bietet mehrere Komponentenkategorien: Logger, Handler, Filter und Formatter.
Logger stellen die Schnittstelle bereit, die der Anwendungscode direkt verwendet.
Handler senden die Protokollsätze (die von Loggern erstellt wurden) an das entsprechende Ziel.
Filter bieten eine feinere Granularität zur Bestimmung, welche Protokollsätze ausgegeben werden sollen.
Formatter legen das Layout von Protokollsätzen in der endgültigen Ausgabe fest.
Die Protokollereignisinformationen werden zwischen Loggern, Handlern, Filtern und Formatter in einer LogRecord-Instanz übergeben.
Die Protokollierung erfolgt durch Aufrufen von Methoden auf Instanzen der Klasse Logger (im Folgenden Logger genannt). Jede Instanz hat einen Namen und sie sind konzeptionell in einer Namensraumhierarchie angeordnet, wobei Punkte als Trennzeichen verwendet werden. Beispielsweise ist ein Logger namens ‚scan‘ der Elternteil der Logger ‚scan.text‘, ‚scan.html‘ und ‚scan.pdf‘. Logger-Namen können alles sein, was Sie möchten, und geben den Bereich einer Anwendung an, in dem eine protokollierte Meldung ihren Ursprung hat.
Eine gute Konvention bei der Benennung von Loggern ist die Verwendung eines Modul-weiten Loggers in jedem Modul, das Protokollierung verwendet, wie folgt benannt
logger = logging.getLogger(__name__)
Das bedeutet, dass die Logger-Namen die Paket-/Modulhierarchie verfolgen und es intuitiv offensichtlich ist, wo Ereignisse nur anhand des Logger-Namens protokolliert werden.
Die Wurzel der Logger-Hierarchie wird als Stamm-Logger bezeichnet. Dies ist der Logger, der von den Funktionen debug(), info(), warning(), error() und critical() verwendet wird, die einfach die gleichnamige Methode des Stamm-Loggers aufrufen. Die Funktionen und Methoden haben die gleichen Signaturen. Der Name des Stamm-Loggers wird in der Protokollausgabe als ‚root‘ angezeigt.
Es ist natürlich möglich, Meldungen an verschiedene Ziele zu protokollieren. Die Unterstützung für das Schreiben von Protokollmeldungen in Dateien, HTTP-GET/POST-Orte, E-Mails über SMTP, generische Sockets, Warteschlangen oder betriebssystemspezifische Protokollierungsmechanismen wie Syslog oder das Windows NT-Ereignisprotokoll ist im Paket enthalten. Ziele werden von Handler-Klassen bedient. Sie können Ihre eigene Protokollzielklasse erstellen, wenn Sie spezielle Anforderungen haben, die von keiner der integrierten Handler-Klassen erfüllt werden.
Standardmäßig ist kein Ziel für Protokollmeldungen festgelegt. Sie können ein Ziel (wie Konsole oder Datei) festlegen, indem Sie basicConfig() wie in den Tutorial-Beispielen verwenden. Wenn Sie die Funktionen debug(), info(), warning(), error() und critical() aufrufen, prüfen diese, ob kein Ziel gesetzt ist; und wenn eines nicht gesetzt ist, setzen sie ein Ziel der Konsole (sys.stderr) und ein Standardformat für die angezeigte Meldung, bevor sie an den Stamm-Logger delegieren, um die eigentliche Meldungsausgabe durchzuführen.
Das von basicConfig() gesetzte Standardformat für Meldungen ist
severity:logger name:message
Sie können dies ändern, indem Sie eine Formatzeichenfolge mit dem Schlüsselwortargument format an basicConfig() übergeben. Alle Optionen zur Erstellung einer Formatzeichenfolge finden Sie unter Formatter-Objekte.
Protokollierungsablauf¶
Der Ablauf der Protokollereignisinformationen in Loggern und Handlern ist im folgenden Diagramm dargestellt.
Logger¶
Logger-Objekte haben eine dreifache Aufgabe. Erstens stellen sie mehrere Methoden der Anwendung bereit, damit Anwendungen Meldungen zur Laufzeit protokollieren können. Zweitens bestimmen Logger-Objekte, welche Protokollmeldungen basierend auf dem Schweregrad (die standardmäßige Filterfunktion) oder Filterobjekten bearbeitet werden sollen. Drittens leiten Logger-Objekte relevante Protokollmeldungen an alle interessierten Protokoll-Handler weiter.
Die am häufigsten verwendeten Methoden für Logger-Objekte fallen in zwei Kategorien: Konfiguration und Meldungsversand.
Dies sind die gängigsten Konfigurationsmethoden
Logger.setLevel()gibt die Protokollmeldung mit der niedrigsten Schwere an, die ein Logger verarbeitet. Debug ist die niedrigste integrierte Schweregradstufe und Critical die höchste integrierte Schweregradstufe. Wenn beispielsweise die Schweregradstufe INFO ist, verarbeitet der Logger nur INFO-, WARNING-, ERROR- und CRITICAL-Meldungen und ignoriert DEBUG-Meldungen.Logger.addHandler()undLogger.removeHandler()fügen Handler-Objekte zum Logger-Objekt hinzu und entfernen sie. Handler werden in Handler detaillierter behandelt.Logger.addFilter()undLogger.removeFilter()fügen Filter-Objekte zum Logger-Objekt hinzu und entfernen sie. Filter werden in Filter-Objekte detaillierter behandelt.
Sie müssen diese Methoden nicht immer für jeden von Ihnen erstellten Logger aufrufen. Siehe die letzten beiden Absätze dieses Abschnitts.
Nachdem das Logger-Objekt konfiguriert ist, erstellen die folgenden Methoden Protokollmeldungen
Logger.debug(),Logger.info(),Logger.warning(),Logger.error()undLogger.critical()erstellen Protokollsätze mit einer Meldung und einer Stufe, die den entsprechenden Methodennamen entspricht. Die Meldung ist eigentlich eine Formatzeichenfolge, die die Standard-Zeichenfolgensubstitutionssyntax von%s,%d,%fusw. enthalten kann. Der Rest ihrer Argumente ist eine Liste von Objekten, die den Substitutionsfeldern in der Meldung entsprechen. In Bezug auf**kwargskümmert sich das Logging-Methode nur um ein Schlüsselwort namensexc_infound verwendet es, um zu bestimmen, ob Ausnahmeinformationen protokolliert werden sollen.Logger.exception()erstellt eine Protokollmeldung ähnlich wieLogger.error(). Der Unterschied besteht darin, dassLogger.exception()zusätzlich einen Stack-Trace ausgibt. Rufen Sie diese Methode nur aus einem Ausnahmebehandler auf.Logger.log()nimmt eine Protokollstufe als explizites Argument. Dies ist etwas umständlicher zum Protokollieren von Meldungen als die oben genannten Komfortmethoden für Protokollstufen, aber so protokolliert man auf benutzerdefinierten Protokollstufen.
getLogger() gibt eine Referenz auf eine Logger-Instanz mit dem angegebenen Namen zurück, falls vorhanden, oder root, falls nicht. Die Namen sind durch Punkte getrennte hierarchische Strukturen. Mehrere Aufrufe von getLogger() mit demselben Namen geben eine Referenz auf dasselbe Logger-Objekt zurück. Logger, die weiter unten in der hierarchischen Liste stehen, sind Kinder von Loggern höher in der Liste. Zum Beispiel sind für einen Logger mit dem Namen foo Logger mit den Namen foo.bar, foo.bar.baz und foo.bam alle Nachkommen von foo.
Logger haben ein Konzept des effektiven Niveaus. Wenn einem Logger kein Niveau explizit zugewiesen wird, wird stattdessen das Niveau seines übergeordneten Elements als sein effektives Niveau verwendet. Wenn das übergeordnete Element keine explizite Stufe eingestellt hat, wird dessen übergeordnetes Element untersucht und so weiter – alle Vorfahren werden durchsucht, bis eine explizit eingestellte Stufe gefunden wird. Der Stamm-Logger hat immer eine explizit eingestellte Stufe (standardmäßig WARNING). Bei der Entscheidung, ob ein Ereignis verarbeitet werden soll, wird das effektive Niveau des Loggers verwendet, um zu bestimmen, ob das Ereignis an die Handler des Loggers weitergeleitet wird.
Kind-Logger leiten Meldungen an die Handler weiter, die mit ihren übergeordneten Loggern verbunden sind. Aus diesem Grund ist es nicht notwendig, Handler für alle von einer Anwendung verwendeten Logger zu definieren und zu konfigurieren. Es reicht aus, Handler für einen Top-Level-Logger zu konfigurieren und bei Bedarf Kind-Logger zu erstellen. (Sie können die Weiterleitung jedoch deaktivieren, indem Sie das Attribut propagate eines Loggers auf False setzen.)
Handler¶
Handler-Objekte sind dafür verantwortlich, die geeigneten Protokollmeldungen (basierend auf dem Schweregrad der Protokollmeldungen) an das vom Handler angegebene Ziel zu senden. Logger-Objekte können null oder mehr Handler-Objekte über eine addHandler()-Methode zu sich selbst hinzufügen. Als Beispielszenario möchte eine Anwendung möglicherweise alle Protokollmeldungen in eine Protokolldatei senden, alle Protokollmeldungen ab der Stufe ERROR oder höher an stdout und alle Meldungen ab der Stufe CRITICAL an eine E-Mail-Adresse. Dieses Szenario erfordert drei einzelne Handler, wobei jeder Handler für das Senden von Meldungen eines bestimmten Schweregrads an einen bestimmten Speicherort zuständig ist.
Die Standardbibliothek enthält ziemlich viele Handler-Typen (siehe Nützliche Handler); die Tutorials verwenden hauptsächlich StreamHandler und FileHandler in ihren Beispielen.
Es gibt nur sehr wenige Methoden in einem Handler, mit denen sich Anwendungsentwickler befassen müssen. Die einzigen Handler-Methoden, die für Anwendungsentwickler relevant zu sein scheinen, die die integrierten Handler-Objekte verwenden (d. h. keine benutzerdefinierten Handler erstellen), sind die folgenden Konfigurationsmethoden
Die Methode
setLevel()gibt, genau wie bei Logger-Objekten, die niedrigste Schweregradstufe an, die an das entsprechende Ziel gesendet wird. Warum gibt es zweisetLevel()-Methoden? Die im Logger eingestellte Stufe bestimmt, welche Schweregradstufen von Meldungen an seine Handler weitergegeben werden. Die in jedem Handler eingestellte Stufe bestimmt, welche Meldungen dieser Handler weiterleitet.setFormatter()wählt ein Formatter-Objekt für diesen Handler aus.addFilter()undremoveFilter()konfigurieren bzw. dekonfigurieren Filter-Objekte auf Handlern.
Anwendungscode sollte keine Instanzen von Handler direkt instanziieren und verwenden. Stattdessen ist die Klasse Handler eine Basisklasse, die die Schnittstelle definiert, die alle Handler haben sollten, und einige Standardverhaltensweisen festlegt, die Kindklassen verwenden (oder überschreiben) können.
Formatter¶
Formatter-Objekte konfigurieren die endgültige Reihenfolge, Struktur und den Inhalt der Protokollmeldung. Im Gegensatz zur Basisklasse logging.Handler kann Anwendungscode Formatierklassen instanziieren, obwohl Sie die Formatierklasse wahrscheinlich unterordnen könnten, wenn Ihre Anwendung ein spezielles Verhalten benötigt. Der Konstruktor nimmt drei optionale Argumente entgegen – eine Meldungsformatzeichenfolge, eine Datumsformatzeichenfolge und ein Stil-Indikator.
- logging.Formatter.__init__(fmt=None, datefmt=None, style='%')¶
Wenn keine Meldungsformatzeichenfolge vorhanden ist, wird standardmäßig die rohe Meldung verwendet. Wenn keine Datumsformatzeichenfolge vorhanden ist, ist das Standard-Datumsformat
%Y-%m-%d %H:%M:%S
mit den Millisekunden am Ende angehängt. Der style ist einer von '%', '{' oder '$'. Wenn keiner davon angegeben ist, wird '%' verwendet.
Wenn der style auf '%' gesetzt ist, verwendet die Nachrichtenformatzeichenfolge die zeichenfolgenbasierte Ersetzung %(<dictionary key>)s; die möglichen Schlüssel sind in LogRecord-Attribute dokumentiert. Wenn der Stil '{' ist, wird angenommen, dass die Nachrichtenformatzeichenfolge mit str.format() (mit Schlüsselwortargumenten) kompatibel ist, während wenn der Stil '$' ist, die Nachrichtenformatzeichenfolge mit dem übereinstimmen sollte, was von string.Template.substitute() erwartet wird.
Geändert in Version 3.2: Der Parameter style wurde hinzugefügt.
Die folgende Nachrichtenformatzeichenfolge protokolliert die Zeit in einem lesbaren Format, die Schwere der Nachricht und den Inhalt der Nachricht, in dieser Reihenfolge
'%(asctime)s - %(levelname)s - %(message)s'
Formatierer verwenden eine vom Benutzer konfigurierbare Funktion, um die Erstellungszeit eines Datensatzes in ein Tupel umzuwandeln. Standardmäßig wird time.localtime() verwendet; um dies für eine bestimmte Formatiererinstanz zu ändern, setzen Sie das Attribut converter der Instanz auf eine Funktion mit derselben Signatur wie time.localtime() oder time.gmtime(). Um dies für alle Formatierer zu ändern, z.B. wenn Sie möchten, dass alle Protokollierungszeiten in GMT angezeigt werden, setzen Sie das Attribut converter in der Klasse Formatter (auf time.gmtime für GMT-Anzeige).
Protokollierung konfigurieren¶
Programmierer können die Protokollierung auf drei Arten konfigurieren
Explizites Erstellen von Loggern, Handlern und Formatierern mit Python-Code, der die oben genannten Konfigurationsmethoden aufruft.
Erstellen einer Protokollkonfigurationsdatei und Lesen dieser mit der Funktion
fileConfig().Erstellen eines Wörterbuchs mit Konfigurationsinformationen und Übergeben dieses an die Funktion
dictConfig().
Für die Referenzdokumentation zu den beiden letzteren Optionen siehe Konfigurationsfunktionen. Das folgende Beispiel konfiguriert einen sehr einfachen Logger, einen Konsolenhandler und einen einfachen Formatierer mithilfe von Python-Code
import logging
# create logger
logger = logging.getLogger('simple_example')
logger.setLevel(logging.DEBUG)
# create console handler and set level to debug
ch = logging.StreamHandler()
ch.setLevel(logging.DEBUG)
# create formatter
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
# add formatter to ch
ch.setFormatter(formatter)
# add ch to logger
logger.addHandler(ch)
# 'application' code
logger.debug('debug message')
logger.info('info message')
logger.warning('warn message')
logger.error('error message')
logger.critical('critical message')
Das Ausführen dieses Moduls von der Befehlszeile aus ergibt die folgende Ausgabe
$ python simple_logging_module.py
2005-03-19 15:10:26,618 - simple_example - DEBUG - debug message
2005-03-19 15:10:26,620 - simple_example - INFO - info message
2005-03-19 15:10:26,695 - simple_example - WARNING - warn message
2005-03-19 15:10:26,697 - simple_example - ERROR - error message
2005-03-19 15:10:26,773 - simple_example - CRITICAL - critical message
Das folgende Python-Modul erstellt einen Logger, einen Handler und einen Formatierer, die fast identisch mit denen im obigen Beispiel sind, wobei der einzige Unterschied die Namen der Objekte sind
import logging
import logging.config
logging.config.fileConfig('logging.conf')
# create logger
logger = logging.getLogger('simpleExample')
# 'application' code
logger.debug('debug message')
logger.info('info message')
logger.warning('warn message')
logger.error('error message')
logger.critical('critical message')
Hier ist die Datei logging.conf
[loggers]
keys=root,simpleExample
[handlers]
keys=consoleHandler
[formatters]
keys=simpleFormatter
[logger_root]
level=DEBUG
handlers=consoleHandler
[logger_simpleExample]
level=DEBUG
handlers=consoleHandler
qualname=simpleExample
propagate=0
[handler_consoleHandler]
class=StreamHandler
level=DEBUG
formatter=simpleFormatter
args=(sys.stdout,)
[formatter_simpleFormatter]
format=%(asctime)s - %(name)s - %(levelname)s - %(message)s
Die Ausgabe ist fast identisch mit der des beispielbasierten Nicht-Konfigurationsdateibeispiels
$ python simple_logging_config.py
2005-03-19 15:38:55,977 - simpleExample - DEBUG - debug message
2005-03-19 15:38:55,979 - simpleExample - INFO - info message
2005-03-19 15:38:56,054 - simpleExample - WARNING - warn message
2005-03-19 15:38:56,055 - simpleExample - ERROR - error message
2005-03-19 15:38:56,130 - simpleExample - CRITICAL - critical message
Sie können sehen, dass der Ansatz mit Konfigurationsdateien einige Vorteile gegenüber dem Ansatz mit Python-Code hat, hauptsächlich die Trennung von Konfiguration und Code und die Möglichkeit für Nicht-Programmierer, die Protokollierungseigenschaften einfach zu ändern.
Warnung
Die Funktion fileConfig() nimmt einen Standardparameter, disable_existing_loggers, der aus Gründen der Abwärtskompatibilität standardmäßig auf True gesetzt ist. Dies ist möglicherweise nicht das, was Sie möchten, da dadurch alle nicht-root-Logger, die vor dem Aufruf von fileConfig() existieren, deaktiviert werden, es sei denn, sie (oder ein Vorfahre) sind explizit in der Konfiguration aufgeführt. Bitte beachten Sie die Referenzdokumentation für weitere Informationen und geben Sie für diesen Parameter False an, wenn Sie dies wünschen.
Das an dictConfig() übergebene Wörterbuch kann ebenfalls einen booleschen Wert mit dem Schlüssel disable_existing_loggers angeben, der, wenn er nicht explizit im Wörterbuch angegeben ist, ebenfalls standardmäßig als True interpretiert wird. Dies führt zu dem oben beschriebenen Verhalten der Logger-Deaktivierung, was möglicherweise nicht erwünscht ist. In diesem Fall geben Sie den Schlüssel explizit mit dem Wert False an.
Beachten Sie, dass die in Konfigurationsdateien referenzierten Klassennamen entweder relativ zum Protokollierungsmodul sein müssen oder absolute Werte, die über normale Importmechanismen aufgelöst werden können. Somit könnten Sie entweder WatchedFileHandler (relativ zum Protokollierungsmodul) oder mypackage.mymodule.MyHandler (für eine Klasse, die im Paket mypackage und Modul mymodule definiert ist, wobei mypackage auf dem Python-Importpfad verfügbar ist) verwenden.
In Python 3.2 wurde eine neue Methode zur Konfiguration der Protokollierung eingeführt, die Wörterbücher zur Speicherung von Konfigurationsinformationen verwendet. Diese bietet eine Obermenge der Funktionalität des oben dargestellten Konfigurationsdateibasierten Ansatzes und ist die empfohlene Konfigurationsmethode für neue Anwendungen und Bereitstellungen. Da ein Python-Wörterbuch zur Speicherung von Konfigurationsinformationen verwendet wird und Sie dieses Wörterbuch auf verschiedene Arten füllen können, haben Sie mehr Optionen für die Konfiguration. Sie können beispielsweise eine Konfigurationsdatei im JSON-Format verwenden oder, wenn Sie Zugriff auf YAML-Verarbeitungsfunktionen haben, eine Datei im YAML-Format, um das Konfigurationswörterbuch zu füllen. Oder natürlich können Sie das Wörterbuch in Python-Code erstellen, es in gepickelter Form über einen Socket empfangen oder welchen Ansatz auch immer für Ihre Anwendung sinnvoll ist.
Hier ist ein Beispiel für dieselbe Konfiguration wie oben, im YAML-Format für den neuen wörterbuchbasierten Ansatz
version: 1
formatters:
simple:
format: '%(asctime)s - %(name)s - %(levelname)s - %(message)s'
handlers:
console:
class: logging.StreamHandler
level: DEBUG
formatter: simple
stream: ext://sys.stdout
loggers:
simpleExample:
level: DEBUG
handlers: [console]
propagate: no
root:
level: DEBUG
handlers: [console]
Weitere Informationen zur Protokollierung mit einem Wörterbuch finden Sie unter Konfigurationsfunktionen.
Was passiert, wenn keine Konfiguration bereitgestellt wird¶
Wenn keine Protokollierungskonfiguration bereitgestellt wird, kann es zu einer Situation kommen, in der ein Protokollierungsereignis ausgegeben werden muss, aber keine Handler gefunden werden können, um das Ereignis auszugeben.
Das Ereignis wird über einen "Handler letzter Instanz" ausgegeben, der in lastResort gespeichert ist. Dieser interne Handler ist keinem Logger zugeordnet und verhält sich wie ein StreamHandler, der die Ereignisbeschreibungsnachricht an den aktuellen Wert von sys.stderr schreibt (und somit alle geltenden Umleitungen respektiert). Es erfolgt keine Formatierung der Nachricht – es wird nur die reine Ereignisbeschreibungsnachricht gedruckt. Die Stufe des Handlers ist auf WARNING eingestellt, sodass alle Ereignisse dieser und höherer Schweregrade ausgegeben werden.
Geändert in Version 3.2: Für Python-Versionen vor 3.2 gilt Folgendes:
Wenn
raiseExceptionsaufFalsegesetzt ist (Produktionsmodus), wird das Ereignis stillschweigend verworfen.Wenn
raiseExceptionsaufTruegesetzt ist (Entwicklungsmodus), wird einmalig eine Meldung "No handlers could be found for logger X.Y.Z" ausgegeben.
Um das Verhalten vor Version 3.2 zu erhalten, kann lastResort auf None gesetzt werden.
Protokollierung für eine Bibliothek konfigurieren¶
Wenn Sie eine Bibliothek entwickeln, die Protokollierung verwendet, sollten Sie sorgfältig dokumentieren, wie die Bibliothek Protokollierung verwendet – zum Beispiel die Namen der verwendeten Logger. Auch ihre Protokollierungskonfiguration muss bedacht werden. Wenn die verwendende Anwendung keine Protokollierung verwendet und der Bibliotheks-Code Protokollaufrufe tätigt, dann (wie im vorherigen Abschnitt beschrieben) werden Ereignisse der Schweregrad WARNING und höher auf sys.stderr ausgegeben. Dies gilt als bestes Standardverhalten.
Wenn aus irgendeinem Grund diese Meldungen nicht ausgegeben werden sollen, wenn keine Protokollierungskonfiguration vorhanden ist, können Sie einen "do-nothing"-Handler an den Top-Level-Logger Ihrer Bibliothek anhängen. Dies vermeidet die Ausgabe der Meldung, da für die Ereignisse der Bibliothek immer ein Handler gefunden wird: er erzeugt nur keine Ausgabe. Wenn der Bibliotheksbenutzer Protokollierung für die Anwendungskonfiguration konfiguriert, wird diese Konfiguration wahrscheinlich einige Handler hinzufügen, und wenn die Pegel entsprechend konfiguriert sind, werden die in der Bibliotheks-Code ausgeführten Protokollaufrufe normal an diese Handler gesendet.
Ein "do-nothing"-Handler ist im Protokollierungspaket enthalten: NullHandler (seit Python 3.1). Eine Instanz dieses Handlers könnte an den Top-Level-Logger des von der Bibliothek verwendeten Protokollierungs-Namensraums angehängt werden (wenn Sie verhindern möchten, dass die von Ihrer Bibliothek protokollierten Ereignisse in Abwesenheit einer Protokollierungskonfiguration an sys.stderr ausgegeben werden). Wenn die gesamte Protokollierung durch eine Bibliothek *foo* mit Loggern erfolgt, deren Namen "foo.x", "foo.x.y" usw. entsprechen, dann sollte der Code
import logging
logging.getLogger('foo').addHandler(logging.NullHandler())
den gewünschten Effekt erzielen. Wenn eine Organisation eine Reihe von Bibliotheken produziert, kann der angegebene Logger-Name "orgname.foo" anstelle von nur "foo" lauten.
Hinweis
Es wird dringend davon abgeraten, in Ihrer Bibliothek an den Stamm-Logger zu protokollieren. Verwenden Sie stattdessen einen Logger mit einem eindeutigen und leicht identifizierbaren Namen, wie z.B. __name__ für das Top-Level-Paket oder Modul Ihrer Bibliothek. Die Protokollierung an den Stamm-Logger macht es für den Anwendungsentwickler schwierig oder unmöglich, die Protokollierungsvorbereitung oder die Handler Ihrer Bibliothek nach Wunsch zu konfigurieren.
Hinweis
Es wird dringend davon abgeraten, an die Logger Ihrer Bibliothek andere Handler als NullHandler anzuhängen. Dies liegt daran, dass die Konfiguration von Handlern das Vorrecht des Anwendungsentwicklers ist, der Ihre Bibliothek verwendet. Der Anwendungsentwickler kennt seine Zielgruppe und weiß, welche Handler für seine Anwendung am besten geeignet sind: Wenn Sie "hinter den Kulissen" Handler hinzufügen, können Sie seine Fähigkeit, Unit-Tests durchzuführen und Protokolle zu liefern, die seinen Anforderungen entsprechen, beeinträchtigen.
Protokollierungsstufen¶
Die numerischen Werte der Protokollierungsstufen sind in der folgenden Tabelle aufgeführt. Diese sind hauptsächlich von Interesse, wenn Sie Ihre eigenen Stufen definieren möchten und ihnen bestimmte Werte im Verhältnis zu den vordefinierten Stufen zuweisen müssen. Wenn Sie eine Stufe mit demselben numerischen Wert definieren, überschreibt dies den vordefinierten Wert; der vordefinierte Name geht verloren.
Stufe |
Numerischer Wert |
|---|---|
|
50 |
|
40 |
|
30 |
|
20 |
|
10 |
|
0 |
Stufen können auch mit Loggern verknüpft werden, entweder vom Entwickler festgelegt oder durch Laden einer gespeicherten Protokollierungskonfiguration. Wenn eine Protokollierungsmethode für einen Logger aufgerufen wird, vergleicht der Logger seine eigene Stufe mit der Stufe, die dem Methodenaufruf zugeordnet ist. Wenn die Stufe des Loggers höher ist als die des Methodenaufrufs, wird keine Protokollnachricht generiert. Dies ist der grundlegende Mechanismus zur Steuerung der Ausführlichkeit der Protokollausgabe.
Protokollnachrichten werden als Instanzen der Klasse LogRecord kodiert. Wenn ein Logger entscheidet, ein Ereignis tatsächlich zu protokollieren, wird eine Instanz von LogRecord aus der Protokollnachricht erstellt.
Protokollnachrichten werden durch die Verwendung von *Handlern* einem Dispatch-Mechanismus unterworfen, die Instanzen von Unterklassen der Klasse Handler sind. Handler sind dafür verantwortlich, sicherzustellen, dass eine protokollierte Nachricht (in Form eines LogRecord) an einem bestimmten Ort (oder an einer Menge von Orten) landet, der für die Zielgruppe dieser Nachricht nützlich ist (wie Endbenutzer, Support-Mitarbeiter, Systemadministratoren, Entwickler). Handlern werden LogRecord-Instanzen übergeben, die für bestimmte Ziele bestimmt sind. Jeder Logger kann null, einen oder mehrere Handler haben (über die Methode addHandler() von Logger). Zusätzlich zu allen direkt einem Logger zugeordneten Handlern werden *alle Handlern, die allen Vorfahren des Loggers zugeordnet sind*, aufgerufen, um die Nachricht zu verteilen (es sei denn, das Flag *propagate* eines Loggers ist auf einen falschen Wert gesetzt, woraufhin die Weitergabe an Vorfahren-Handler stoppt).
Ähnlich wie bei Loggern können Handlern Stufen zugeordnet werden. Die Stufe eines Handlers fungiert auf die gleiche Weise als Filter wie die Stufe eines Loggers. Wenn ein Handler ein Ereignis tatsächlich weiterleitet, wird die Methode emit() verwendet, um die Nachricht an ihr Ziel zu senden. Die meisten vom Benutzer definierten Unterklassen von Handler müssen diese emit() überschreiben.
Benutzerdefinierte Stufen¶
Das Definieren eigener Stufen ist möglich, sollte aber nicht notwendig sein, da die vorhandenen Stufen auf Basis praktischer Erfahrung gewählt wurden. Wenn Sie jedoch davon überzeugt sind, dass Sie benutzerdefinierte Stufen benötigen, sollten Sie dabei mit großer Sorgfalt vorgehen, und es ist möglicherweise *eine sehr schlechte Idee, benutzerdefinierte Stufen zu definieren, wenn Sie eine Bibliothek entwickeln*. Denn wenn mehrere Bibliotheksautoren ihre eigenen benutzerdefinierten Stufen definieren, besteht die Möglichkeit, dass die Protokollausgabe solcher mehreren gemeinsam verwendeten Bibliotheken für den entwickelnden Benutzer schwer zu kontrollieren und/oder zu interpretieren ist, da ein bestimmter numerischer Wert für verschiedene Bibliotheken unterschiedliche Bedeutungen haben könnte.
Nützliche Handler¶
Zusätzlich zur Basisklasse Handler werden viele nützliche Unterklassen bereitgestellt
StreamHandlerInstanzen senden Nachrichten an Streams (dateiahnliche Objekte).FileHandlerInstanzen senden Nachrichten an Dateidateien.BaseRotatingHandlerist die Basisklasse für Handler, die Protokolldateien an einem bestimmten Punkt rotieren. Sie ist nicht dazu bestimmt, direkt instanziiert zu werden. Verwenden Sie stattdessenRotatingFileHandleroderTimedRotatingFileHandler.RotatingFileHandlerInstanzen senden Nachrichten an Dateidateien, mit Unterstützung für maximale Dateigrößen und Rotation von Protokolldateien.TimedRotatingFileHandlerInstanzen senden Nachrichten an Dateidateien und rotieren die Protokolldatei in bestimmten Zeitintervallen.SocketHandlerInstanzen senden Nachrichten an TCP/IP-Sockets. Seit 3.4 werden auch Unix-Domain-Sockets unterstützt.DatagramHandlerInstanzen senden Nachrichten an UDP-Sockets. Seit 3.4 werden auch Unix-Domain-Sockets unterstützt.SMTPHandlerInstanzen senden Nachrichten an eine bestimmte E-Mail-Adresse.SysLogHandlerInstanzen senden Nachrichten an einen Unix-Syslog-Daemon, möglicherweise auf einem entfernten Computer.NTEventLogHandlerInstanzen senden Nachrichten an ein Windows NT/2000/XP-Ereignisprotokoll.MemoryHandlerInstanzen senden Nachrichten an einen Puffer im Speicher, der geleert wird, sobald bestimmte Kriterien erfüllt sind.HTTPHandlerInstanzen senden Nachrichten an einen HTTP-Server unter Verwendung vonGEToderPOSTSemantik.WatchedFileHandlerInstanzen beobachten die Datei, in die sie protokollieren. Wenn sich die Datei ändert, wird sie geschlossen und mit dem Dateinamen neu geöffnet. Dieser Handler ist nur auf Unix-ähnlichen Systemen nützlich; Windows unterstützt den zugrunde liegenden Mechanismus nicht.QueueHandlerInstanzen senden Nachrichten an eine Warteschlange, wie sie in den Modulenqueueodermultiprocessingimplementiert sind.NullHandlerInstanzen tun nichts mit Fehlermeldungen. Sie werden von Bibliotheksentwicklern verwendet, die Protokollierung verwenden möchten, aber die Meldung "No handlers could be found for logger XXX" vermeiden möchten, die angezeigt werden kann, wenn der Benutzer der Bibliothek die Protokollierung nicht konfiguriert hat. Siehe Protokollierung für eine Bibliothek konfigurieren für weitere Informationen.
Hinzugefügt in Version 3.1: Die Klasse NullHandler.
Hinzugefügt in Version 3.2: Die Klasse QueueHandler.
Die Klassen NullHandler, StreamHandler und FileHandler sind im Kern-Protokollierungsmodul definiert. Die anderen Handler sind in einem Untermodul, logging.handlers, definiert. (Es gibt auch ein weiteres Untermodul, logging.config, für Konfigurationsfunktionalität.)
Protokollierte Nachrichten werden zur Präsentation über Instanzen der Klasse Formatter formatiert. Sie werden mit einer für die Verwendung mit dem %-Operator geeigneten Formatzeichenfolge und einem Wörterbuch initialisiert.
Für die Formatierung mehrerer Nachrichten in einem Stapel können Instanzen von BufferingFormatter verwendet werden. Zusätzlich zur Formatzeichenfolge (die auf jede Nachricht im Stapel angewendet wird) gibt es Platz für Kopf- und Fußzeilen-Formatzeichenfolgen.
Wenn die Filterung basierend auf der Logger-Stufe und/oder Handler-Stufe nicht ausreicht, können Instanzen von Filter sowohl zu Logger- als auch zu Handler-Instanzen hinzugefügt werden (über ihre Methode addFilter()). Bevor entschieden wird, eine Nachricht weiter zu verarbeiten, konsultieren sowohl Logger als auch Handler alle ihre Filter um Erlaubnis. Wenn ein Filter einen falschen Wert zurückgibt, wird die Nachricht nicht weiterverarbeitet.
Die grundlegende Filter-Funktionalität ermöglicht die Filterung nach einem bestimmten Logger-Namen. Wenn diese Funktion verwendet wird, werden Nachrichten, die an den benannten Logger und seine Kinder gesendet werden, durch den Filter gelassen und alle anderen verworfen.
Beim Protokollieren ausgelöste Ausnahmen¶
Das Protokollierungspaket ist so konzipiert, dass Ausnahmen, die während der Protokollierung in der Produktion auftreten, unterdrückt werden. Dies geschieht, damit Fehler, die bei der Behandlung von Protokollierungsereignissen auftreten – wie z. B. fehlerhafte Protokollkonfiguration, Netzwerk- oder ähnliche Fehler – die Anwendung, die die Protokollierung verwendet, nicht vorzeitig beenden.
SystemExit und KeyboardInterrupt Ausnahmen werden niemals unterdrückt. Andere Ausnahmen, die während der Methode emit() einer Unterklasse von Handler auftreten, werden an ihre Methode handleError() übergeben.
Die Standardimplementierung von handleError() in Handler prüft, ob eine Modulvariable, raiseExceptions, gesetzt ist. Wenn sie gesetzt ist, wird ein Traceback auf sys.stderr gedruckt. Wenn sie nicht gesetzt ist, wird die Ausnahme unterdrückt.
Hinweis
Der Standardwert von raiseExceptions ist True. Dies liegt daran, dass Sie während der Entwicklung in der Regel über alle aufgetretenen Ausnahmen benachrichtigt werden möchten. Es wird empfohlen, raiseExceptions für den Produktionseinsatz auf False zu setzen.
Verwendung beliebiger Objekte als Nachrichten¶
In den vorherigen Abschnitten und Beispielen wurde davon ausgegangen, dass die beim Protokollieren des Ereignisses übergebene Nachricht eine Zeichenfolge ist. Dies ist jedoch nicht die einzige Möglichkeit. Sie können ein beliebiges Objekt als Nachricht übergeben, und seine __str__()-Methode wird aufgerufen, wenn das Protokollierungssystem es in eine Zeichenfolgenrepräsentation konvertieren muss. Tatsächlich können Sie, wenn Sie möchten, die Berechnung einer Zeichenfolgenrepräsentation ganz vermeiden – zum Beispiel emittiert der SocketHandler ein Ereignis, indem er es pickelt und über das Netzwerk sendet.
Optimierung¶
Die Formatierung von Nachrichtenargumenten wird aufgeschoben, bis sie nicht mehr vermieden werden kann. Die Berechnung der an die Protokollierungsmethode übergebenen Argumente kann jedoch ebenfalls teuer sein, und Sie möchten dies vermeiden, wenn der Logger Ihr Ereignis einfach verwirft. Um zu entscheiden, was zu tun ist, können Sie die Methode isEnabledFor() aufrufen, die ein Stufenargument entgegennimmt und true zurückgibt, wenn das Ereignis vom Logger für diese Stufe des Aufrufs erstellt würde. Sie können Code wie diesen schreiben
if logger.isEnabledFor(logging.DEBUG):
logger.debug('Message with %s, %s', expensive_func1(),
expensive_func2())
so dass, wenn die Schwelle des Loggers über DEBUG eingestellt ist, die Aufrufe von expensive_func1 und expensive_func2 nie erfolgen.
Hinweis
In einigen Fällen kann isEnabledFor() selbst teurer sein, als Sie möchten (z. B. für tief verschachtelte Logger, bei denen eine explizite Stufe nur hoch in der Logger-Hierarchie festgelegt ist). In solchen Fällen (oder wenn Sie das Aufrufen einer Methode in engen Schleifen vermeiden möchten) können Sie das Ergebnis eines Aufrufs von isEnabledFor() in einer lokalen oder Instanzvariable speichern und diese anstelle des wiederholten Aufrufs der Methode verwenden. Ein solcher gespeicherter Wert müsste nur dann neu berechnet werden, wenn sich die Protokollierungskonfiguration während der Laufzeit der Anwendung dynamisch ändert (was nicht allzu häufig vorkommt).
Es gibt weitere Optimierungen, die für spezifische Anwendungen vorgenommen werden können, die eine genauere Kontrolle darüber benötigen, welche Protokollierungsinformationen gesammelt werden. Hier ist eine Liste von Dingen, die Sie tun können, um eine Verarbeitung zu vermeiden, die Sie nicht benötigen
Was Sie nicht sammeln möchten |
Wie Sie die Sammlung vermeiden |
|---|---|
Informationen darüber, wo Aufrufe getätigt wurden. |
Set |
Informationen zu Threads. |
Setzen Sie |
Aktuelle Prozess-ID ( |
Setzen Sie |
Aktueller Prozessname bei Verwendung von |
Setzen Sie |
Aktueller |
Setzen Sie |
Beachten Sie auch, dass das Kern-Logging-Modul nur die grundlegenden Handler enthält. Wenn Sie logging.handlers und logging.config nicht importieren, verbrauchen sie keinen Speicher.
Weitere Ressourcen¶
Siehe auch
- Modul
logging API-Referenz für das Logging-Modul.
- Modul
logging.config Konfigurations-API für das Logging-Modul.
- Modul
logging.handlers Nützliche Handler, die im Logging-Modul enthalten sind.