Zum Inhalt springen

cat posts/logging-statt-print.md

Logging statt print

print hilft beim schnellen Nachsehen, logging begleitet laufende Programme: Levels, Logger pro Modul, Formatierung, Dateien und Tracebacks.

print(...) ist großartig, wenn Du schnell etwas im Terminal sehen möchtest.

print("Bin hier")
print(spieler.hp)
print("Speichern fertig")

Für kleine Experimente ist das völlig in Ordnung. Sobald ein Programm aber länger läuft oder von anderen benutzt wird, stößt print(...) schnell an seine Grenzen.

Ein Cronjob, ein Webdienst, ein Bot oder ein größeres Tool soll nicht einfach irgendwelche Ausgaben ins Terminal werfen. Es soll nachvollziehbar melden:

  • was passiert ist,
  • wann es passiert ist,
  • wo im Programm es passiert ist,
  • wie wichtig die Meldung ist,
  • ob ein Fehler mit Traceback aufgetreten ist.

Dafür gibt es in Python das Standardmodul logging.

In Teil 8 der Python-Serie ging es um Exceptions und Fehlerbehandlung. Logging beantwortet die nächste wichtige Frage:

Was ist vor dem Fehler passiert?

Warum print(...) nicht reicht

Mit print(...) kannst Du schnell einen Wert anzeigen:

print(f"Spieler: {spieler.name}")

Das ist direkt, einfach und für Lerncode nützlich.

In einem dauerhaft laufenden Programm fehlen aber wichtige Eigenschaften.

Keine Wichtigkeit

Diese Ausgaben sehen gleich wichtig aus:

print("Spiel gestartet")
print("Spielstand gespeichert")
print("Spielstand konnte nicht geladen werden")
print("Datenbank nicht erreichbar")

Als Mensch erkennst Du vielleicht aus dem Text, was ernst ist. Ein Programm, ein Monitoring oder ein Log-Viewer erkennt es nicht automatisch.

Logging kennt dafür Levels.

Keine zentrale Steuerung

Mit print(...) musst Du jede einzelne Ausgabe anfassen, wenn Du sie entfernen, umleiten oder anders darstellen möchtest.

Bei Logging kannst Du zentral festlegen:

  • ab welchem Level Meldungen erscheinen,
  • ob sie auf der Konsole ausgegeben werden,
  • ob sie in eine Datei geschrieben werden,
  • wie jede Logzeile formatiert wird.

Der Code, der loggt, muss dafür nicht geändert werden.

Kein automatischer Kontext

Mit print(...) müsstest Du Zeitstempel, Modulnamen oder Levels von Hand ergänzen:

print("[INFO] dungeon.save: Spielstand gespeichert")

Das ist fehleranfällig und wird schnell uneinheitlich.

Logging kann diesen Kontext automatisch liefern.

Ein erstes Logging-Beispiel

Das Modul heißt logging:

import logging

Die einfachste Verwendung sieht so aus:

import logging

logging.warning("Etwas ist seltsam.")
logging.error("Eine Operation ist fehlgeschlagen.")

Die Ausgabe sieht ungefähr so aus:

WARNING:root:Etwas ist seltsam.
ERROR:root:Eine Operation ist fehlgeschlagen.

Ohne weitere Konfiguration zeigt Python standardmäßig nur Meldungen ab WARNING an.

Diese Meldung erscheint deshalb zunächst nicht:

logging.info("Spiel gestartet.")

Damit INFO-Meldungen sichtbar werden, konfigurieren wir Logging.

Logging konfigurieren mit basicConfig(...)

Für ein Skript reicht zu Beginn häufig logging.basicConfig(...):

import logging

logging.basicConfig(
    level=logging.INFO,
    format="%(asctime)s %(levelname)s %(name)s: %(message)s",
)

logging.info("Spiel gestartet.")

Eine mögliche Ausgabe:

2026-07-29 14:30:00,123 INFO root: Spiel gestartet.

Die wichtigsten Bestandteile:

Einstellung Bedeutung
level niedrigstes Level, das ausgegeben wird
format Aufbau jeder Logzeile
%(asctime)s Zeitstempel
%(levelname)s Levelname
%(name)s Logger-Name
%(message)s eigentliche Nachricht

basicConfig(...) sollte möglichst einmal zentral beim Programmstart aufgerufen werden.

In einem größeren Projekt passiert das typischerweise in der Anwendung, nicht in einzelnen Modulen.

Die wichtigsten Logging-Levels

Logging kennt mehrere Stufen.

Level Verwendung
DEBUG sehr detaillierte Informationen für die Fehlersuche
INFO normale Ereignisse im Programmablauf
WARNING etwas Unerwartetes, aber das Programm kann weiterlaufen
ERROR eine Operation ist fehlgeschlagen
CRITICAL schwerer Fehler, Programm oder Dienst kann möglicherweise nicht weiterarbeiten

Beispiel:

import logging

logging.debug("Raumdaten geladen: %s", raum_id)
logging.info("Spiel gestartet")
logging.warning("Spielstand fehlt, neues Spiel wird begonnen")
logging.error("Spielstand konnte nicht gespeichert werden")
logging.critical("Konfiguration fehlt, Programm wird beendet")

Setzt Du das Level auf INFO, erscheinen INFO, WARNING, ERROR und CRITICAL.

logging.basicConfig(level=logging.INFO)

DEBUG wird dann ausgefiltert.

Setzt Du das Level auf WARNING, erscheinen nur noch WARNING, ERROR und CRITICAL.

logging.basicConfig(level=logging.WARNING)

Das ist der große Vorteil gegenüber print(...): Die Logzeilen bleiben im Code, aber Du steuerst zentral, welche davon tatsächlich ausgegeben werden.

Ein Logger pro Modul

Für kurze Skripte funktionieren die direkten Funktionen:

logging.info("Spiel gestartet")

Sie verwenden den sogenannten Root-Logger.

In Modulen und größeren Programmen ist diese Schreibweise üblicher:

import logging

logger = logging.getLogger(__name__)

Danach verwendest Du den Logger:

logger.info("Spiel gestartet")
logger.warning("Kein Spielstand gefunden")

__name__ enthält den Namen des aktuellen Moduls.

In einer Datei speichern.py wäre der Logger-Name beispielsweise:

speichern

In einem Package könnte er so aussehen:

dungeon.speichern

Dadurch erkennst Du später im Log, aus welchem Modul eine Meldung stammt.

Logger-Hierarchie

Logger-Namen bilden eine Hierarchie.

Ein Logger namens

dungeon.speichern

liegt unterhalb von:

dungeon

Und dieser wiederum unterhalb des Root-Loggers.

Das ist praktisch, weil Du später gezielt steuern kannst:

logging.getLogger("dungeon.speichern").setLevel(logging.DEBUG)
logging.getLogger("dungeon").setLevel(logging.INFO)

So könntest Du für ein bestimmtes Modul mehr Details einschalten, ohne das gesamte Programm auf DEBUG zu setzen.

Für den Einstieg reicht die Konvention:

logger = logging.getLogger(__name__)

Nachrichten richtig formatieren

Bei print(...) würdest Du oft f-Strings verwenden:

print(f"Spielstand für {spieler.name} gespeichert")

Beim Logging ist diese Schreibweise besser:

logger.info("Spielstand für %s gespeichert", spieler.name)

Das sieht zunächst ungewohnt aus, hat aber einen Vorteil: Logging kann die Nachricht verzögert zusammensetzen.

Wenn das Level ausgefiltert wird, muss die vollständige Nachricht nicht unbedingt gebaut werden.

Schlecht:

logger.debug(f"Raumdaten: {raeume}")

Besser:

logger.debug("Raumdaten: %s", raeume)

Gerade bei DEBUG-Logs, die im normalen Betrieb häufig deaktiviert sind, ist das sinnvoll.

Für einfache Werte ist der Unterschied meist klein. Die Logging-Schreibweise mit %s ist trotzdem die übliche Form.

Logging mit Kontext

Mehrere Werte werden als zusätzliche Argumente übergeben:

logger.info(
    "Spielstand gespeichert: spieler=%s ort=%s",
    spieler.name,
    ort,
)

Ausgabe:

2026-07-29 14:30:00,123 INFO __main__: Spielstand gespeichert: spieler=Karl ort=halle

Du kannst auch strukturiert loggen:

logger.debug(
    "Befehl verarbeitet: verb=%s argument=%s ort=%s",
    verb,
    argument,
    ort,
)

Das ist oft besser als eine sehr freie Textmeldung, weil wichtige Werte konsistent auftauchen.

Exceptions loggen

In einem except-Block möchtest Du häufig nicht nur eine freundliche Meldung ausgeben, sondern den vollständigen Traceback festhalten.

Dafür gibt es logger.exception(...):

try:
    lade_spielstand()
except SpielstandError:
    logger.exception("Spielstand konnte nicht geladen werden")
    print("Der Spielstand konnte nicht geladen werden.")

logger.exception(...) loggt mit Level ERROR und hängt automatisch die Exception-Informationen inklusive Traceback an.

Wichtig: Verwende logger.exception(...) innerhalb eines except-Blocks. Nur dort gibt es eine aktuelle Exception, deren Traceback sinnvoll angehängt werden kann.

Außerhalb eines except-Blocks verwendest Du normalerweise:

logger.error("Spielstand konnte nicht geladen werden")

Oder ausdrücklich:

logger.error("Spielstand konnte nicht geladen werden", exc_info=True)

logger.exception(...) ist praktisch eine Kurzform für logger.error(..., exc_info=True) innerhalb eines Exception-Handlers.

Erwartete Fehler nicht immer als Traceback loggen

Nicht jeder abgefangene Fehler ist automatisch ein technischer Fehler.

Wenn ein Spieler nimm drachenei eingibt und im Raum kein Drachenei liegt, ist das eine erwartbare Benutzereingabe.

Dafür reicht vielleicht:

logger.info("Unmögliche Aktion: %s", fehler)
print(fehler)

Ein vollständiger Traceback wäre hier eher Lärm.

Anders ist es bei unerwarteten Fehlern beim Speichern:

try:
    speichere_spielstand(...)
except SpielstandError:
    logger.exception("Speichern fehlgeschlagen")
    print("Der Spielstand konnte nicht gespeichert werden.")

Als Faustregel:

  • Erwartbare Benutzerfehler: eher INFO oder WARNING, meist ohne Traceback.
  • Unerwartete technische Fehler: ERROR oder CRITICAL, oft mit Traceback.

In Dateien loggen

basicConfig(...) kann Logs direkt in eine Datei schreiben:

import logging

logging.basicConfig(
    filename="dungeon.log",
    encoding="utf-8",
    level=logging.INFO,
    format="%(asctime)s %(levelname)s %(name)s: %(message)s",
)

Nun landen die Logmeldungen in dungeon.log.

Standardmäßig wird an die Datei angehängt. Möchtest Du die Datei bei jedem Start neu schreiben, setzt Du:

filemode="w"

Beispiel:

logging.basicConfig(
    filename="dungeon.log",
    filemode="w",
    encoding="utf-8",
    level=logging.INFO,
    format="%(asctime)s %(levelname)s %(name)s: %(message)s",
)

Für einfache Skripte ist das ausreichend.

Gleichzeitig auf Konsole und in Datei loggen

Manchmal möchtest Du Logs sowohl im Terminal sehen als auch in eine Datei schreiben.

Das geht mit mehreren Handlern:

import logging

logging.basicConfig(
    level=logging.INFO,
    format="%(asctime)s %(levelname)s %(name)s: %(message)s",
    handlers=[
        logging.StreamHandler(),
        logging.FileHandler(
            "dungeon.log",
            encoding="utf-8",
        ),
    ],
)

Ein Handler entscheidet, wohin Log-Records geschrieben werden.

Typische Handler sind:

Handler Ziel
StreamHandler Konsole beziehungsweise Stream
FileHandler Datei
RotatingFileHandler Datei mit Größenrotation
TimedRotatingFileHandler Datei mit Zeitrotation

Für ein kleines Projekt reichen StreamHandler und FileHandler.

Rotierende Logdateien

Eine dauerhaft laufende Anwendung sollte nicht endlos in dieselbe Datei schreiben. Sonst kann die Logdatei sehr groß werden.

Dafür gibt es rotierende File Handler:

import logging
from logging.handlers import RotatingFileHandler

handler = RotatingFileHandler(
    "dungeon.log",
    maxBytes=1_000_000,
    backupCount=3,
    encoding="utf-8",
)

logging.basicConfig(
    level=logging.INFO,
    format="%(asctime)s %(levelname)s %(name)s: %(message)s",
    handlers=[handler],
)

Wenn dungeon.log ungefähr 1_000_000 Bytes erreicht, wird rotiert. backupCount=3 sorgt dafür, dass einige ältere Dateien erhalten bleiben.

Für unseren Lern-Dungeon ist das nicht notwendig. Für Dienste, Bots und Cronjobs ist es aber ein wichtiges Muster.

Datum und Uhrzeit formatieren

Das Feld %(asctime)s erzeugt einen Zeitstempel.

Mit datefmt kannst Du seine Darstellung anpassen:

logging.basicConfig(
    level=logging.INFO,
    format="%(asctime)s %(levelname)s %(name)s: %(message)s",
    datefmt="%Y-%m-%d %H:%M:%S",
)

Eine mögliche Ausgabe:

2026-07-29 14:30:00 INFO __main__: Spiel gestartet

Ohne datefmt verwendet Logging eine eigene Standarddarstellung mit Millisekunden.

basicConfig(...) wirkt nur einmal

logging.basicConfig(...) richtet den Root-Logger ein, wenn noch keine Handler vorhanden sind.

Das bedeutet: Der erste wirksame Aufruf gewinnt.

Diese Situation kann verwirren:

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

logging.debug("Diese Meldung erscheint nicht.")

Der zweite Aufruf ändert normalerweise nichts mehr.

Seit Python 3.8 gibt es die Option force=True:

logging.basicConfig(
    level=logging.DEBUG,
    force=True,
)

Damit werden vorhandene Handler entfernt und die Konfiguration neu gesetzt.

force=True ist nützlich in kleinen Skripten, Tests oder interaktiven Sessions. In größeren Anwendungen solltest Du Logging trotzdem gezielt und zentral konfigurieren.

In Bibliotheken nicht konfigurieren

Eine wichtige Regel:

Bibliotheken konfigurieren Logging nicht.

Eine Bibliothek sollte nur einen Logger holen und Nachrichten schreiben:

import logging

logger = logging.getLogger(__name__)


def speichern(name):
    logger.info("Speichere Spielstand für %s", name)

Sie sollte aber nicht selbst basicConfig(...) aufrufen.

Warum?

Die Anwendung, die die Bibliothek benutzt, entscheidet:

  • ob überhaupt geloggt wird,
  • ab welchem Level geloggt wird,
  • ob Logs in die Konsole, Datei oder ein anderes System gehen,
  • welches Format verwendet wird.

Wenn eine Bibliothek ungefragt Logging konfiguriert, überschreibt oder stört sie die Entscheidung der Anwendung.

Für eigene Skripte und Anwendungen ist basicConfig(...) in Ordnung. Für wiederverwendbare Module und Bibliotheken nicht.

Logging im Dungeon

Wir ergänzen unseren Dungeon um Logging.

Am Anfang der Datei:

import logging
from pathlib import Path

LOGDATEI = Path("dungeon.log")
logger = logging.getLogger(__name__)

Dann eine zentrale Konfigurationsfunktion:

def konfiguriere_logging():
    logging.basicConfig(
        level=logging.INFO,
        format="%(asctime)s %(levelname)s %(name)s: %(message)s",
        handlers=[
            logging.StreamHandler(),
            logging.FileHandler(
                LOGDATEI,
                encoding="utf-8",
            ),
        ],
    )

Diese Funktion rufen wir einmal in main() auf:

def main():
    konfiguriere_logging()

    logger.info("Dungeon gestartet")

    ...

Beim Beenden:

if verb == "ende":
    logger.info("Dungeon beendet: spieler=%s ort=%s", spieler.name, ort)
    print("Du verlässt das Verlies. Bis zum nächsten Mal.")
    break

Beim Speichern:

if verb == "speichern":
    speichere_spielstand(
        spieler=spieler,
        ort=ort,
        raeume=raeume,
        besuchte_raeume=besuchte_raeume,
    )
    logger.info(
        "Spielstand gespeichert: spieler=%s ort=%s",
        spieler.name,
        ort,
    )
    print("Spielstand gespeichert.")
    continue

Beim Laden:

if verb == "laden":
    ort, besuchte_raeume = lade_spielstand(
        spieler=spieler,
        raeume=raeume,
    )
    raum_anzeigen = True

    logger.info(
        "Spielstand geladen: spieler=%s ort=%s",
        spieler.name,
        ort,
    )
    print("Spielstand geladen.")
    continue

Und im Fehlerfall:

try:
    ...
except DungeonError as fehler:
    logger.warning("Benutzerfehler: %s", fehler)
    print(fehler)

Damit landet eine erwartbare falsche Eingabe im Log, ohne den Benutzer mit einem Traceback zu belasten.

Für unerwartete Fehler wäre ein vollständiger Traceback sinnvoller. In unserem Game-Loop fangen wir aber bewusst nur DungeonError. Echte Bugs bleiben sichtbar und brechen weiterhin mit Traceback ab.

Logging in der Speicherfunktion

Auch in der Speicherlogik können Logs hilfreich sein.

def speichere_spielstand(spieler, ort, raeume, besuchte_raeume):
    logger.debug(
        "Erstelle Spielstand: spieler=%s ort=%s inventar=%s",
        spieler.name,
        ort,
        len(spieler.inventar),
    )

    daten = erstelle_spielstand(
        spieler=spieler,
        ort=ort,
        raeume=raeume,
        besuchte_raeume=besuchte_raeume,
    )

    try:
        with SPEICHERDATEI.open("w", encoding="utf-8") as datei:
            json.dump(daten, datei, ensure_ascii=False, indent=2)
            datei.write("\n")
    except OSError as fehler:
        logger.exception("Schreiben des Spielstands fehlgeschlagen")
        raise SpielstandError(
            f"Der Spielstand konnte nicht gespeichert werden: {fehler}"
        ) from fehler

Bei normalem INFO-Level erscheint die DEBUG-Meldung nicht.

Stellst Du auf DEBUG, bekommst Du zusätzliche Details.

logging.basicConfig(level=logging.DEBUG)

Das ist besonders nützlich, wenn ein Fehler nur in bestimmten Situationen auftritt.

Logging ersetzt keine Benutzeroberfläche

Ein wichtiger Unterschied:

print("Spielstand gespeichert.")

ist eine Meldung an den Benutzer.

logger.info("Spielstand gespeichert: spieler=%s ort=%s", spieler.name, ort)

ist eine Meldung an Entwickler, Betreiber oder das spätere Debugging.

Beides kann im selben Programm vorkommen.

Ein Benutzer soll nicht jede technische Logzeile sehen. Umgekehrt reicht eine freundliche Konsolenausgabe nicht aus, um später einen Fehler zu untersuchen.

Deshalb gilt:

  • print(...) oder UI-Ausgabe für direkte Benutzerkommunikation.
  • logging für Diagnose, Betrieb und Nachvollziehbarkeit.

stack_info und stacklevel

Neben Exception-Tracebacks kann Logging auch Informationen über den aktuellen Aufrufpfad ausgeben.

Mit stack_info=True erhältst Du Stack-Informationen, auch wenn keine Exception aufgetreten ist:

logger.debug("Aktueller Pfad durch das Programm", stack_info=True)

Das brauchst Du selten, kann aber bei schwer nachvollziehbaren Aufrufen helfen.

stacklevel ist nützlich, wenn Du eigene Logging-Hilfsfunktionen schreibst:

def logge_warnung(nachricht):
    logger.warning(nachricht, stacklevel=2)

Dadurch zeigt die Logmeldung auf den Aufrufer der Hilfsfunktion statt auf die Hilfsfunktion selbst.

Für den Einstieg sind beide Optionen nicht notwendig. Gut zu kennen sind sie trotzdem, weil sie in größeren Projekten auftauchen können.

Logging-Konfiguration über Datei

Für größere Anwendungen wird Logging häufig nicht direkt mit basicConfig(...) konfiguriert, sondern über eine Konfigurationsdatei oder ein Dictionary.

Das Standardmodul bietet dafür unter anderem:

logging.config.dictConfig(...)

Damit lassen sich mehrere Logger, Handler und Formatter zentral beschreiben.

Für unseren Lernstand ist basicConfig(...) übersichtlicher. Sobald ein Projekt mehrere unterschiedliche Logdateien, JSON-Logs oder externe Logsysteme benötigt, lohnt sich ein Blick auf logging.config.

Welche Meldung gehört auf welches Level?

Die Level-Wahl ist nicht immer eindeutig. Diese grobe Orientierung hilft:

DEBUG

Sehr detaillierte Informationen für die Fehlersuche:

logger.debug("Geladene Rohdaten: %r", daten)
logger.debug("Befehl zerlegt: verb=%s argument=%s", verb, argument)

Im normalen Betrieb meist deaktiviert.

INFO

Normale wichtige Ereignisse:

logger.info("Dungeon gestartet")
logger.info("Spielstand gespeichert")
logger.info("Spielstand geladen")

Gut für die Frage: Was hat das Programm regulär getan?

WARNING

Unerwartete, aber verkraftbare Situationen:

logger.warning("Kein Spielstand gefunden, neues Spiel wird gestartet")
logger.warning("Unbekannter Befehl: %s", verb)

Das Programm kann weiterlaufen, aber die Situation ist auffällig.

ERROR

Eine Operation ist fehlgeschlagen:

logger.error("Spielstand konnte nicht gespeichert werden")

Das Programm läuft vielleicht weiter, aber die konkrete Aktion ist gescheitert.

Mit Traceback im except-Block:

logger.exception("Spielstand konnte nicht gespeichert werden")

CRITICAL

Ein schwerer Fehler, bei dem das Programm wahrscheinlich nicht sinnvoll weiterarbeiten kann:

logger.critical("Konfiguration fehlt, Programm wird beendet")

Dieses Level sollte selten sein.

Stolperfallen

  • Logging nur als besseres print(...) verwenden: Logging ist nicht nur Ausgabe, sondern strukturierte Diagnose mit Levels, Loggern, Handlern und Formatierung.

  • In jedem Modul basicConfig(...) aufrufen: Konfiguriere Logging einmal zentral in der Anwendung.

  • In Bibliotheken Logging konfigurieren: Bibliotheken holen sich nur einen Logger und schreiben Logs. Die Anwendung entscheidet über Ausgabe und Format.

  • Den Root-Logger als Dauerlösung verwenden: Für mehr als kleine Skripte ist logger = logging.getLogger(__name__) die bessere Gewohnheit.

  • f-Strings für Logmeldungen verwenden: logger.debug(f"{wert}") baut den String sofort. Verwende besser logger.debug("%s", wert).

  • logger.exception(...) außerhalb eines except-Blocks verwenden: Die Methode ist für den aktuellen Exception-Kontext gedacht.

  • Erwartete Benutzerfehler immer mit Traceback loggen: Das erzeugt unnötigen Lärm. Nicht jeder ungültige Befehl ist ein technischer Fehler.

  • Zu viele Meldungen auf ERROR setzen: Wenn alles ein Fehler ist, ist am Ende nichts mehr priorisiert.

  • logging.warn(...) verwenden: Die alte Methode ist veraltet. Verwende logging.warning(...) beziehungsweise logger.warning(...).

  • Geheimnisse loggen: Passwörter, Tokens, Session-Cookies, personenbezogene Daten oder private Inhalte gehören nicht unbedacht ins Log.

  • Unbegrenzte Logdateien erzeugen: Für dauerhaft laufende Programme solltest Du Rotation oder ein externes Logsystem verwenden.

  • Logs mit Benutzerkommunikation verwechseln: Eine Logmeldung ersetzt keine verständliche Ausgabe für den Benutzer.

  • basicConfig(...) mehrfach erwarten: Ohne force=True wirkt ein späterer Aufruf oft nicht mehr, wenn bereits Handler eingerichtet sind.

Übungen

1. Logging einrichten

Richte Logging so ein, dass INFO und höher mit Zeitstempel, Level und Logger- Name ausgegeben werden.

Lösung
import logging

logging.basicConfig(
    level=logging.INFO,
    format="%(asctime)s %(levelname)s %(name)s: %(message)s",
)

logger = logging.getLogger(__name__)

logger.info("Programm gestartet")

2. Einen Modul-Logger verwenden

Schreibe eine Funktion speichern(name), die eine Logmeldung ausgibt, ohne print(...) zu verwenden.

Lösung
import logging

logger = logging.getLogger(__name__)


def speichern(name):
    logger.info("Speichere Spielstand für %s", name)
Die Logging-Konfiguration gehört nicht in diese Funktion, sondern an den Programmstart.

3. Eine Exception mit Traceback loggen

Fange einen ValueError ab und logge den vollständigen Traceback.

Lösung
import logging

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

try:
    zahl = int("viel")
except ValueError:
    logger.exception("Umwandlung in int fehlgeschlagen")
`logger.exception(...)` hängt automatisch die Exception-Informationen an.

4. In eine Datei loggen

Konfiguriere Logging so, dass Meldungen ab INFO in die Datei app.log geschrieben werden.

Lösung
import logging

logging.basicConfig(
    filename="app.log",
    encoding="utf-8",
    level=logging.INFO,
    format="%(asctime)s %(levelname)s %(name)s: %(message)s",
)

logger = logging.getLogger(__name__)
logger.info("Datei-Logging aktiv")

Vertiefung

Wenn Logs zeigen, dass etwas schiefgeht, Du aber den laufenden Code genauer untersuchen möchtest:

Debuggen mit pdbgeplant

Wenn Du die Fehlerbehandlung aus der Python-Serie noch einmal nachlesen möchtest:

Python lernen, Teil 8: Wenn's schiefgeht

Weiterlesen

0 Kommentare

Noch keine Kommentare. Sei der/die Erste!