Du liest:
Python logging: So gehts richtig! (mit Codebeispielen)

Python logging: So gehts richtig! (mit Codebeispielen)

von Patrick
08.06.2020
Jetzt Python programmieren lernen

Viele Programmierer benutzen zur Fehlersuche die Funktion print. Oft werden die Funktionsaufrufe danach auskommentiert oder gelöscht. Stattdessen würde ich eher empfehlen, mit dem konfigurierbaren Python logging Modul zu arbeiten. Grund dafür ist, dass man dieses auch in produktiven Anwendungen beibehalten kann. Im Folgenden möchte ich dir zeigen, wie du das Modul logging zu diesem Zweck nutzen kannst.

1. grundlegende Nutzung und Konfiguration von dem Python logging Modul

Um logging zu nutzen, kannst du das Modul einfach importieren. Dieses stellt mehrere Funktionen bereit, die du nutzen kannst, um Meldungen auszugeben. Diese unterscheiden sich nach ihrem Level. Standardmäßig gibt es die Level debug, info, warning, error und critical.

import logging

logging.debug('debug')
logging.info('info')
logging.warning('warning')
logging.error('error')
logging.critical('critical')
WARNING:root:warning
ERROR:root:error
CRITICAL:root:critical

Anhand des vorigen Beispiels siehst du, dass nur die Nachrichten von warning, error und critical ausgegeben wurden. Das liegt daran, dass der Level in logging standardmäßig so konfiguriert ist, dass nur diese ausgegeben werden. Mit der Funktion basicConfig kannst du diesen anders konfigurieren:

logging.basicConfig(level=logging.DEBUG)
DEBUG:root:debug
INFO:root:info
WARNING:root:warning
ERROR:root:error
CRITICAL:root:critical

Zusätzlich kannst du an basicConfig noch den Parameter filename übergeben, welcher der Name der Datei ist, in der das Log gespeichert werden soll. Standardmäßig werden die Nachrichten sonst nur in der Textausgabe ausgegeben.

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

Wenn du dies nicht anders festlegst, wird die Logdatei bei jeder Ausführung des Programms erweitert. Dies wird durch den Dateimodus festgelegt, mit dem die Datei geöffnet wird. Diesen kannst du mit dem Parameter filemode beeinflussen. Der Wert w beispielsweise führt dazu, dass der vorige Inhalt überschrieben wird.

logging.basicConfig(
    filename='test.log',
    filemode='w',
    level=logging.DEBUG
)

Wenn du mehr über filemode wissen willst, kannst du gerne unseren Artikel zu Python open lesen. Eine Übersicht über alle für filemode möglichen Werte findest du hier (https://docs.python.org/3/library/functions.html#open).

Weiterhin besteht die Möglichkeit, einen String anzugeben, der beeinflusst, was im Log angezeigt wird. Dafür können wir den Parameter format verwenden.

logging.basicConfig(
    filename='test.log',
    filemode='w',
    format='%(asctime)s %(levelname)s: %(message)s',
    level=logging.DEBUG
)
2020-06-06 11:10:17,596 INFO: Hello world!

Weiterhin unterstützt basicConfig noch den Parameter datefmt. Mit diesem kannst du das Format in der Uhrzeit und Datum angezeigt werden festlegen.

logging.basicConfig(
    filename='test.log',
    filemode='w',
    format='%(asctime)s %(levelname)s: %(message)s',
    datefmt='%d.%m.%y %H:%M:%S',
    level=logging.DEBUG
)
06.06.20 11:11:26 INFO: Hello world!

Für eine Übersicht über alle Optionen für datefmt empfiehlt sich dieser Abschnitt der Dokumentation (https://docs.python.org/3/library/time.html#time.strftime).

2. Python logging in Klassen

Du kannst logging in Klassen genauso verwenden wie im vorigen Abschnitt. Im Folgenden ist eine kleine Testklasse abgebildet, die eine Zahl durch eine andere teilt.

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

class Test:
    def teilen(self, dividend, divisor):
        try:
            logging.info(f'teile {dividend} durch {divisor}')
            quotient = dividend / divisor
            logging.info(f'{dividend} / {divisor} = {quotient}')
            return quotient
        except Exception as e:
            logging.error(f'Fehler beim teilen ({dividend} / {divisor}):', exc_info=True)

test = Test()
e = test.teilen(1024, 128)
e = test.teilen(1024, 0)
INFO:root:teile 1024 durch 128
INFO:root:1024 / 128 = 8.0
INFO:root:teile 1024 durch 0
ERROR:root:Fehler beim teilen (1024 / 0):
Traceback (most recent call last):
  File ".\logging_python.py", line 35, in teilen
    quotient = dividend / divisor
ZeroDivisionError: division by zero

Der Parameter exc_info von error hat im vorigen Beispiel dafür gesorgt, dass die Fehlermeldung auch im Log auftaucht.

3. Logger verwenden mit getLogger

Mit der Funktion getLogger kannst du einen Logger aufrufen oder erstellen. Meist wird für die Erstellung eines neuen Loggers die Variable __name__ verwendet. Diese enthält den Namen des Moduls, in dem sie verwendet wird.

logger = logging.getLogger(__name__)

Auch mit einem logger kannst du den Level bestimmen. Dafür verfügt die Klasse über die Methode setLevel.

logger.setLevel(logging.DEBUG)

Wir können den Logger genauso verwenden, wie logging zuvor. So würde unsere Klasse aus Abschnitt 2 mit dem Logger so aussehen:

class Test:
    def teilen(self, dividend, divisor):
        try:
            logger.info(f'teile {dividend} durch {divisor}')
            quotient = dividend / divisor
            logger.info(f'{dividend} / {divisor} = {quotient}')
            return quotient
        except Exception as e:
            logger.error(f'Fehler beim teilen ({dividend} / {divisor}):', exc_info=True)

Außerdem kannst du noch verschiedene Handler festlegen. Beispielsweise gibt es den sogenannten FileHandler, mit dem du festlegen kannst, in welcher Datei das Log gespeichert werden soll und mit welchem Modus es verwendet werden soll. Diesen Handlern kannst du sogenannte Formatter zuweisen, um das Verhalten von basicConfigs format- und datefmt-Parametern zu simulieren. Der FileHandler muss dann mittels der Methode addHandler zum Logger hinzugefügt werden.

formatter = logging.Formatter(
    '%(asctime)s %(levelname)s %(lineno)s: %(message)s',
    '%d.%m.%y %H:%M:%S'
)
datei_handler = logging.FileHandler('file_handler.log', 'w')
datei_handler.setFormatter(formatter)

logger.addHandler(datei_handler)
INFO: teile 1024 durch 128
INFO: 1024 / 128 = 8.0

Natürlich kannst du deinem Logger mehrere Handler gleichzeitig zuweisen.

4. Fazit

Pythons logging Modul stellt einige praktische Funktionen und Klassen zur Verfügung, um uns zu ermöglichen, Logs zu erstellen. Dies macht uns die Fehlersuche wesentlich einfacher. Wir können verschiedene Handler erstellen, um festzulegen wo das Log gespeichert bzw angezeigt werden soll. Jeder dieser Handler kann seine eigene Formatierung haben und ein Logger kann mehrere Handler gleichzeitig verwenden.

Wenn du noch Fragen, Anmerkungen, Lob oder Kritik hast, lass es mich bitte mit einem Kommentar wissen.



Bislang gibt es keine Kommentare. Markier dein Revier und sei der Erste!

Schreibe einen Kommentar

Das könnte dich auch interessieren