Python Logging

Das schreiben einer Logdatei kann beim Finden von Fehlern enorm helfen. Meine Vorstellung zum Schreiben von Logs war immer das Schreiben einer Logdatei und das Programmieren eben dieser Funktionalität. Mir wurde dann klar, dass es eben diese Funktionalität in einer Bibliothek geben muss und das eben diese Bibliothek viel mehr als nur das klassische Schreiben einer Logdatei kann. Eine Logging-Bibliothek gibt es so gut wie in jeder Programmiersprache und für diesen Blog habe ich mir Python3 mit seinem logging-Modul ausgesucht.

Die einfachste Methode, um eine Lognachricht im Konsolenfenster auszugeben ist wie folgt. Importieren des logging-Modul und anschließend schreiben von Lognachrichten mit logging.warning, logging.error und logging.fatal.

import logging

logging.warning('Lookslikematrix write warning message to stdout.')
logging.error('Lookslikematrix write error message to stdout.')
logging.fatal('Lookslikematrix write fatal message to stdout.')

Lognachrichten werden dabei immer mit einem Loglevel versehen, die eine Hierarchie haben: DEBUG -> INFO -> WARNING -> ERROR -> CRITICAL. Das Loglevel erscheint auch in der Logausgabe im Konsolenfenster. Standardmäßig wird das logging-Modul so konfiguriert, dass nur Lognachrichten größer dem Loglevel INFO angezeigt werden, dass bedeutet, dass DEBUG und INFO Nachrichten garnicht angezeigt werden. Möchtet ihr diese auch anzeigen, dann könnt ihr wie folgt, die Konfiguration anpassen.

import logging
logging.basicConfig(level=logging.INFO)

logging.debug('Lookslikematrix write debug message to stdout.')
logging.info('Lookslikematrix write info message to stdout.')
logging.warning('Lookslikematrix write warning message to stdout.')
logging.error('Lookslikematrix write error message to stdout.')
logging.fatal('Lookslikematrix write fatal message to stdout.')

Am besten ihr modifiziert euer Skript noch so, dass ihr über ein Übergabeparameter das Loglevel einstellen könnt. Damit könnt ihr dann im produktiven Einsatz nur die für den Anwender interessanten Nachrichten anzeigen und im Fehlerfall auch noch die Debug-Informationen anzeigen. Hier ist beschrieben, wie das geht.

Wenn ihr jetzt anstatt in das Konsolenfenster die Ausgabe in eine Textdatei wünscht, dann könnt ihr die Konfiguration anpassen und ihr erhaltet eine Datei.

import logging
logging.basicConfig(filename='lookslikematrix.log')

logging.debug('Lookslikematrix write debug message to file.')
logging.info('Lookslikematrix write info message to file.')
logging.warning('Lookslikematrix write warning message to file.')
logging.error('Lookslikematrix write error message to file.')
logging.fatal('Lookslikematrix write fatal message to file.')

So wird eine Datei lookslikematrix.log in das Verzeichnis geschrieben von dem ihr das Skript ausführt. Diese erhält dann alle Lognachrichten die größer dem Loglevel INFO sind, da dies das Standardverhalten ist. Wollt ihr mehr in die Datei schreiben, könnt ihr die Konfiguration wie folgt ändern.

logging.basicConfig(filename='lookslikematrix.log', level=logging.DEBUG)

Wenn das Logformat nicht euren Anforderung entspricht, dann könnt ihr auch die Formatierung anpassen. Hier sind vordefinierte mögliche Logattribute definiert, womit ihr die Konfiguration beispielsweise wie folgt anpassen könnt, wenn ihr noch einen Zeitstempel haben möchtet.

logging.basicConfig(format='%(asctime)s:%(levelname)s:%(message)s', level=logging.DEBUG)

Der Vorteil bei der Verwendung von Logging-Bibliotheken ist, dass ihr ohne großen Aufwand mehrere Senken/Ziele der Lognachrichten angeben könnt. Ihr könnt so definieren, dass die Lognachrichten im Konsolenfenster ausgegeben werden und in eine Logdatei geschrieben werden. Weiterhin könnt ihr dann auch noch beispielsweise das Loggen an einen Server ermöglichen, um dort Loginformationen mehrere Benutzer zu sammeln. Hier ein Beispiel, wie ihr Nachrichten an ein Konsolenfenster und in eine Datei sendet. Es wird dazu ein logger-Objekt angelegt, dem mehrere Handler hinzugefügt werden. Anschließend werden die Lognachrichten nicht mehr direkt mit dem logging-Modul geschrieben, sondern über das logger-Objekt, womit die Lognachrichten an alle Handler gesendet werden.

import logging

# create logger
logger = logging.getLogger('lookslikematrix')
logger.setLevel(logging.DEBUG)

# create stdout logger and add it as sink
stdout_logger = logging.StreamHandler()
stdout_logger.setLevel(logging.DEBUG)
logger.addHandler(stdout_logger)

# create file logger and add it as sink
file_logger = logging.FileHandler(filename='lookslikematrix.log')
file_logger.setLevel(logging.DEBUG)
logger.addHandler(file_logger)

logger.debug('Lookslikematrix write debug message to file and stdout.')
logger.info('Lookslikematrix write info message to file and stdout.')
logger.warning('Lookslikematrix write warning message to file and stdout.')
logger.error('Lookslikematrix write error message to file and stdout.')
logger.fatal('Lookslikematrix write fatal message to file and stdout.')

Ich hoffe ich konnte euch die Verwendung des logging-Modul in Python etwas näher bringen. Mehr könnt ihr hier https://docs.python.org/3/howto/logging.html nachlesen. Solltet ihr Fragen oder Anregungen haben, dann könnt ihr mich gerne kontaktieren.