Skip to content

Fehlerbehandlung und Logging

Robuste Python-Skripte entwickeln, Fehler behandeln und wichtige Ereignisse protokollieren.

In produktiven Umgebungen treten Fehler regelmäßig auf. Dateien können fehlen, Netzwerkverbindungen abbrechen, APIs nicht erreichbar sein oder Benutzereingaben ungültige Werte enthalten.

Professionelle Automatisierungsskripte müssen mit solchen Situationen umgehen können. Statt bei jedem Problem sofort abzustürzen, sollten sie Fehler erkennen, sinnvoll reagieren und nachvollziehbare Informationen protokollieren.

Python stellt hierfür ein leistungsfähiges Exception-System sowie umfangreiche Logging-Funktionen bereit. Beide gehören zu den wichtigsten Werkzeugen für den produktiven Einsatz von Automatisierungsskripten.

In diesem Kapitel lernen Sie, wie Fehler behandelt, Ausnahmen gezielt abgefangen und aussagekräftige Logdateien erzeugt werden.

Exceptions verstehen

Warum Exceptions in Python wichtig sind

In der Systemadministration und Automatisierung treten häufig unerwartete Situationen auf: Dateien fehlen, Netzwerkverbindungen brechen ab oder APIs liefern Fehler. Python nutzt Exceptions (Ausnahmen), um solche Fehler klar und kontrolliert zu behandeln – anstatt das Programm abrupt zu beenden.

Grundlagen: try, except, else und finally

Der Kern der Fehlerbehandlung in Python ist der try-Block, in dem potenziell fehlerhafte Anweisungen stehen. Tritt ein Fehler auf, wird die Ausführung sofort zum passenden except-Block weitergeleitet.

try:
    with open('/var/log/syslog') as f:
        lines = f.readlines()
except FileNotFoundError:
    print('Logdatei nicht gefunden.')
else:
    print(f'Datei erfolgreich gelesen, {len(lines)} Zeilen.')
finally:
    print('Versuch, die Logdatei zu lesen, ist abgeschlossen.')
  • except fängt spezifische Fehler (hier FileNotFoundError) ab.
  • else wird nur ausgeführt, wenn kein Fehler auftrat.
  • finally läuft immer, z.B. um Ressourcen freizugeben.

Typische Fehlerarten in Administrationsskripten

  • Dateifehler: Datei nicht gefunden (FileNotFoundError), Zugriffsrechte (PermissionError)
  • Netzwerkfehler: Verbindungsabbrüche, Zeitüberschreitungen (ConnectionError, TimeoutError)
  • Datenfehler: Ungültige JSON- oder CSV-Daten (json.JSONDecodeError, csv.Error)

Beispiel: API-Abfrage mit Fehlerbehandlung

import requests

try:
    response = requests.get('https://api.example.com/status', timeout=5)
    response.raise_for_status()  # HTTP-Fehler auslösen
    data = response.json()
except requests.exceptions.Timeout:
    print('API-Anfrage hat zu lange gedauert.')
except requests.exceptions.HTTPError as err:
    print(f'HTTP-Fehler: {err}')
except requests.exceptions.RequestException as err:
    print(f'Netzwerkfehler: {err}')
else:
    print('API-Daten erfolgreich empfangen:', data)

Best Practices für Fehlerbehandlung

  • Fange nur die Fehler, die du erwartest und sinnvoll behandeln kannst.
  • Vermeide zu breite except:-Blöcke, um unerwartete Fehler nicht zu verschleiern.
  • Nutze else für Code, der nur bei Erfolg ausgeführt werden soll.
  • Verwende finally, um wichtige Aufräumarbeiten sicherzustellen, z.B. das Schließen von Dateien oder Verbindungen.

Hinweis: Unterschied zu Shell-Skripten

In Shell-Skripten prüft man meist den Rückgabewert ($?), was schnell unübersichtlich wird, wenn viele Befehle nacheinander ausgeführt werden. Python erlaubt durch Exceptions eine klare Trennung von Fehler- und Erfolgslogik, was besonders bei komplexeren Automatisierungen die Wartbarkeit erhöht.

Zusammenfassung

Exceptions sind in Python das Mittel der Wahl, um Fehler kontrolliert zu behandeln. Sie helfen dabei, Automatisierungsskripte stabil zu halten und auf typische Fehler im Administrationsalltag gezielt zu reagieren. Das Verständnis von try, except, else und finally ist dabei die Basis für robuste Python-Skripte.

Logging in der Praxis

Warum Logging in Automatisierungsskripten wichtig ist

In der täglichen Administration und Automatisierung ist es entscheidend, nicht nur Fehler zu erkennen, sondern auch nachvollziehen zu können, was ein Skript wann getan hat. Anders als bei interaktiven Programmen laufen Automatisierungsskripte oft unbeaufsichtigt, etwa als Cron-Job oder in CI/CD-Pipelines. Logging liefert eine dauerhafte Aufzeichnung dieser Abläufe und erleichtert Fehlersuche, Monitoring und Dokumentation.

Das Python-Logging-Modul: Grundfunktionen

Python bringt mit dem Modul logging ein mächtiges und flexibles Werkzeug mit, das weit über einfache Ausgaben mit print() hinausgeht. Es erlaubt:

  • Verschiedene Schweregrade (DEBUG, INFO, WARNING, ERROR, CRITICAL)
  • Ausgabe in Dateien, Konsolen oder externe Systeme
  • Zeitstempel und Kontextinformationen automatisch

Ein einfaches Beispiel:

import logging

logging.basicConfig(
    filename='admin_script.log',
    level=logging.INFO,
    format='%(asctime)s %(levelname)s: %(message)s'
)

logging.info('Skript gestartet')

try:
    with open('/var/log/syslog', 'r') as f:
        lines = f.readlines()
    logging.info(f'Logdatei erfolgreich gelesen, {len(lines)} Zeilen')
except FileNotFoundError:
    logging.error('Logdatei nicht gefunden')

Schweregrade sinnvoll nutzen

  • DEBUG: Detaillierte Informationen, meist nur beim Entwickeln oder für tiefe Analysen
  • INFO: Wichtige Ereignisse, die den normalen Ablauf dokumentieren
  • WARNING: Unerwartete Situationen, die aber noch keine Fehler sind
  • ERROR: Fehler, die eine Funktionalität beeinträchtigen
  • CRITICAL: Schwere Fehler, die das Skript möglicherweise abbrechen

Für produktive Skripte empfiehlt sich mindestens das Niveau INFO, um wichtige Schritte zu protokollieren.

Logging in der Praxis: Beispiel API-Abfrage

import logging
import requests

logging.basicConfig(
    filename='api_check.log',
    level=logging.INFO,
    format='%(asctime)s %(levelname)s: %(message)s'
)

url = 'https://api.example.com/status'

try:
    response = requests.get(url, timeout=5)
    response.raise_for_status()
    data = response.json()
    logging.info(f'API erfolgreich abgefragt: Status {data.get("status")}')
except requests.exceptions.Timeout:
    logging.error('API-Anfrage zeitüberschritten')
except requests.exceptions.RequestException as e:
    logging.error(f'API-Anfrage fehlgeschlagen: {e}')

Tipps für den Administrationsalltag

  • Logrotation einplanen: Logdateien wachsen schnell. Nutzen Sie Tools wie logrotate oder Python-Handler wie RotatingFileHandler.
  • Klar verständliche Meldungen: Schreiben Sie Logs so, dass auch Kollegen oder Sie selbst in Wochen noch verstehen, was passiert ist.
  • Kontext mitgeben: Wo sinnvoll, ergänzen Sie Logs um Variablenwerte oder Statusinformationen.
  • Keine sensiblen Daten loggen: Achten Sie auf Datenschutz und Sicherheit.

Vergleich zu Shell-Skripten

In Shell-Skripten wird oft per echo oder Umleitung in Dateien geloggt. Python-Logging bietet hier klare Vorteile:

  • Einheitliches Format mit Zeitstempel
  • Unterschiedliche Schweregrade
  • Einfaches Umschalten der Ausgabemedien
  • Bessere Wartbarkeit und Erweiterbarkeit

Zusammenfassung

Logging ist ein unverzichtbares Werkzeug, um Automatisierungsskripte transparent und wartbar zu machen. Python liefert mit dem logging-Modul eine einfache, aber mächtige Lösung, die Sie schon mit wenigen Zeilen Code effektiv einsetzen können. So behalten Sie auch bei komplexen Abläufen den Überblick und können Probleme schnell erkennen und beheben.

Robuste Automatisierungsskripte entwickeln

Fehlerbehandlung gezielt einsetzen

Ein typisches Beispiel ist das Einlesen einer Konfigurationsdatei, die eventuell fehlt oder beschädigt ist:

try:
    with open('/etc/mein_tool/config.json', 'r') as f:
        config = f.read()
except FileNotFoundError:
    print('Konfigurationsdatei nicht gefunden. Bitte prüfen.')
except PermissionError:
    print('Keine Leseberechtigung für die Konfigurationsdatei.')
else:
    print('Konfiguration erfolgreich geladen.')

Hier werden zwei häufige Fehler explizit behandelt. Das else-Statement wird nur ausgeführt, wenn kein Fehler auftritt – das ist nützlich, um den normalen Ablauf sauber abzuschließen.

Logging statt nur print()

Für produktive Skripte reicht print() oft nicht aus, weil Ausgaben nicht systematisch erfasst werden. Python bietet mit dem logging-Modul eine flexible Lösung, um Ereignisse mit verschiedenen Schweregraden (DEBUG, INFO, WARNING, ERROR, CRITICAL) zu protokollieren.

Ein einfaches Logging-Setup für ein Automatisierungsskript könnte so aussehen:

import logging

logging.basicConfig(
    filename='/var/log/mein_tool.log',
    level=logging.INFO,
    format='%(asctime)s %(levelname)s: %(message)s'
)

logging.info('Skript gestartet')

try:
    # Beispiel: Datei öffnen
    with open('/tmp/data.csv') as f:
        data = f.read()
except Exception as e:
    logging.error(f'Fehler beim Lesen der Datei: {e}')
else:
    logging.info('Datei erfolgreich eingelesen')

Die Logdatei kann später für Monitoring oder Fehlersuche ausgewertet werden. Im Gegensatz zu Shell-Skripten ist das Logging in Python sehr flexibel konfigurierbar und unterstützt auch Rotationen oder unterschiedliche Ausgabekanäle.

Rückfallstrategien planen

Automatisierungsskripte laufen oft unbeaufsichtigt. Deshalb sollten sie bei Fehlern nicht einfach abbrechen, sondern wenn möglich alternative Wege gehen oder zumindest den Fehler sauber dokumentieren.

Beispiel: Beim Download einer Datei von einer API kann ein Ausfall durch einen zweiten Mirror abgefangen werden:

import requests
import logging

urls = [
    'https://primary.example.com/data.json',
    'https://backup.example.com/data.json'
]

for url in urls:
    try:
        response = requests.get(url, timeout=5)
        response.raise_for_status()
    except requests.RequestException as e:
        logging.warning(f'Download von {url} fehlgeschlagen: {e}')
    else:
        with open('/tmp/data.json', 'wb') as f:
            f.write(response.content)
        logging.info(f'Download von {url} erfolgreich')
        break
else:
    logging.error('Alle Downloadversuche sind fehlgeschlagen')

Hier wird mit einer for-Schleife über mehrere URLs iteriert. Bei einem Fehler wird die nächste URL versucht. Nur wenn alle Versuche scheitern, wird ein Fehler geloggt. Dieses Muster erhöht die Zuverlässigkeit deutlich.

Zusammenfassung

  • Nutze try/except gezielt, um erwartete Fehlerarten sauber zu behandeln.
  • Verwende logging statt print() für dauerhafte und strukturierte Protokollierung.
  • Plane Rückfallstrategien, um Skripte robust gegen Ausfälle zu machen.
  • Dokumentiere Fehler und Erfolge im Log, um spätere Analysen zu erleichtern.

Mit diesen Techniken werden Python-Skripte zu verlässlichen Helfern im Administrationsalltag, die auch bei Fehlern kontrolliert reagieren und wertvolle Informationen liefern.