Rheinwerk Computing < openbook >

 
Inhaltsverzeichnis
1 Einleitung
2 Die Programmiersprache Python
Teil I Einstieg in Python
3 Erste Schritte im interaktiven Modus
4 Der Weg zum ersten Programm
5 Kontrollstrukturen
6 Dateien
7 Das Laufzeitmodell
8 Funktionen, Methoden und Attribute
9 Informationsquellen zu Python
Teil II Datentypen
10 Das Nichts – NoneType
11 Operatoren
12 Numerische Datentypen
13 Sequenzielle Datentypen
14 Zuordnungen
15 Mengen
16 Collections
17 Datum und Zeit
18 Aufzählungstypen – Enum
Teil III Fortgeschrittene Programmiertechniken
19 Funktionen
20 Modularisierung
21 Objektorientierung
22 Ausnahmebehandlung
23 Iteratoren
24 Kontextobjekte
25 Manipulation von Funktionen und Methoden
Teil IV Die Standardbibliothek
26 Mathematik
27 Kryptografie
28 Reguläre Ausdrücke
29 Schnittstelle zu Betriebssystem und Laufzeitumgebung
30 Kommandozeilenparameter
31 Dateisystem
32 Parallele Programmierung
33 Datenspeicherung
34 Netzwerkkommunikation
35 Debugging und Qualitätssicherung
36 Dokumentation
Teil V Weiterführende Themen
37 Anbindung an andere Programmiersprachen
38 Distribution von Python-Projekten
39 Grafische Benutzeroberflächen
40 Python als serverseitige Programmiersprache im WWW – ein Einstieg in Django
41 Wissenschaftliches Rechnen
42 Insiderwissen
43 Von Python 2 nach Python 3
A Anhang
Stichwortverzeichnis

Download:
- Beispielprogramme, ca. 464 KB

Jetzt Buch bestellen
Ihre Meinung?

Spacer
<< zurück
Python 3 von Johannes Ernesti, Peter Kaiser
Das umfassende Handbuch
Buch: Python 3

Python 3
Pfeil 35 Debugging und Qualitätssicherung
Pfeil 35.1 Der Debugger
Pfeil 35.2 Formatierte Bildschirmausgabe – pprint
Pfeil 35.3 Logdateien – logging
Pfeil 35.3.1 Das Meldungsformat anpassen
Pfeil 35.3.2 Logging Handler
Pfeil 35.4 Automatisiertes Testen
Pfeil 35.4.1 Testfälle in Docstrings – doctest
Pfeil 35.4.2 Unit Tests – unittest
Pfeil 35.5 Analyse des Laufzeitverhaltens
Pfeil 35.5.1 Laufzeitmessung – timeit
Pfeil 35.5.2 Profiling – cProfile
Pfeil 35.5.3 Tracing – trace
Pfeil 35.6 Optimierung
Pfeil 35.6.1 Die Optimize-Option
Pfeil 35.6.2 Mutabel vs. immutabel
Pfeil 35.6.3 Schleifen
Pfeil 35.6.4 Funktionsaufrufe
Pfeil 35.6.5 C
Pfeil 35.6.6 Lookups
Pfeil 35.6.7 Exceptions
Pfeil 35.6.8 Keyword Arguments
Pfeil 35.6.9 Alternative Interpreter: PyPy
 
Zum Seitenanfang

35.3    Logdateien – logging Zur vorigen ÜberschriftZur nächsten Überschrift

Das Modul logging stellt ein flexibles Interface zum Protokollieren eines Programmablaufs bereit. Protokolliert wird der Programmablauf, indem an verschiedenen Stellen im Programm Meldungen an das logging-Modul abgesetzt werden. Diese Meldungen können unterschiedliche Dringlichkeitsstufen haben. So gibt es beispielsweise Fehlermeldungen, Warnungen oder Debug-Informationen. Das Modul logging kann diese Meldungen auf vielfältige Weise verarbeiten. Üblich ist es, die Meldung mit einem Zeitstempel zu versehen und entweder auf dem Bildschirm auszugeben oder in eine Datei zu schreiben.

In diesem Abschnitt wird die Verwendung des Moduls logging anhand mehrerer Beispiele im interaktiven Modus gezeigt. Um die Beispielprogramme korrekt ausführen zu können, muss zuvor das Modul logging eingebunden sein:

>>> import logging

Bevor Meldungen an den Logger geschickt werden können, muss dieser durch Aufruf der Funktion basicConfig initialisiert werden. Der Funktion basicConfig werden verschiedene Schlüsselwortparameter übergeben. Im folgenden Beispiel wird ein Logger eingerichtet, der alle eingehenden Meldungen in die Logdatei programm.log schreibt:

>>> logging.basicConfig(filename = "programm.log")

Jetzt können mithilfe der im Modul enthaltenen Funktion log Meldungen an den Logger übergeben werden. Die Funktion log bekommt dabei die Dringlichkeitsstufe der Meldung als ersten und die Meldung selbst in Form eines Strings als zweiten Parameter übergeben:

>>> logging.log(logging.ERROR, "Ein Fehler ist aufgetreten")
>>> logging.log(logging.INFO, "Dies ist eine Information")

Durch das Aufrufen der Funktion shutdown wird der Logger korrekt deinitialisiert, und eventuell noch anstehende Schreiboperationen werden durchgeführt:

>>> logging.shutdown()

Natürlich sind nicht nur die Dringlichkeitsstufen ERROR und INFO verfügbar. Tabelle 35.1 listet alle vordefinierten Stufen auf, aus denen Sie wählen können. Die Tabelle ist dabei nach Dringlichkeit geordnet, wobei die dringendste Stufe zuletzt aufgeführt wird.

Level Beschreibung
NOTSET keine Dringlichkeitsstufe
DEBUG eine Meldung, die nur für den Programmierer zur Fehlersuche interessant ist
INFO eine Informationsmeldung über den Programmstatus
WARNING eine Warnmeldung, die auf einen möglichen Fehler hinweist
ERROR eine Fehlermeldung, nach der das Programm weiterarbeiten kann
CRITICAL eine Meldung über einen kritischen Fehler, der das sofortige Beenden des Programms oder der aktuell durchgeführten Operation zur Folge hat

Tabelle 35.1    Vordefinierte Dringlichkeitsstufen

Aus Gründen des Komforts existiert zu jeder Dringlichkeitsstufe eine eigene Funktion. So sind die beiden Funktionsaufrufe von log aus dem letzten Beispiel äquivalent zu:

logging.error("Ein Fehler ist aufgetreten")
logging.info("Dies ist eine Information")

Wenn Sie sich die Logdatei nach dem Aufruf dieser beiden Funktionen ansehen, werden Sie feststellen, dass es lediglich einen einzigen Eintrag gibt:

ERROR:root:Ein Fehler ist aufgetreten

Das liegt daran, dass der Logger in seiner Basiskonfiguration nur Meldungen loggt, deren Dringlichkeit größer oder gleich der einer Warnung ist. Um auch Debug- und Info-Meldungen mitzuloggen, müssen Sie beim Aufruf der Funktion basicConfig im Schlüsselwortparameter level einen geeigneten Wert übergeben:

logging.basicConfig(
filename="programm.log",
level = logging.DEBUG)
logging.error("Ein Fehler ist aufgetreten")
logging.info("Dies ist eine Information")

In diesem Beispiel wurde die Mindestdringlichkeit auf DEBUG gesetzt. Das bedeutet, dass alle Meldungen, die mindestens eine Dringlichkeit von DEBUG haben, geloggt werden. Folglich erscheinen auch beide Meldungen in der Logdatei:

ERROR:root:Ein Fehler ist aufgetreten
INFO:root:Dies ist eine Information

Tabelle 35.2 listet die wichtigsten Schlüsselwortparameter auf, die der Funktion basicConfig übergeben werden können.

Parameter Beschreibung
datefmt Spezifiziert das Datumsformat. Näheres dazu erfahren Sie im folgenden Abschnitt.
filemode Gibt den Modus* an, in dem die Logdatei geöffnet werden soll (Standardwert: "a").
filename Gibt den Dateinamen der Logdatei an.
format Spezifiziert das Meldungsformat. Näheres dazu erfahren Sie im folgenden Abschnitt.
handlers Gibt eine Liste von Handlern an, die registriert werden sollen. Näheres dazu erfahren Sie in Abschnitt 35.3.2, »Logging Handler«.
level Legt die Mindestdringlichkeit für Meldungen fest, damit diese in der Logdatei erscheinen.
stream Gibt einen Stream an, in den die Logmeldungen geschrieben werden sollen. Wenn die Parameter stream und filename gemeinsam angegeben werden, wird stream ignoriert.
style Bestimmt die Formatierungssyntax für die Meldung. Der voreingestellte Wert "%" bedingt die alte %-Syntax aus Python 2, während ein Wert von "{" die neue Syntax zur String-Formatierung** erzwingt.
* Die verschiedenen Modi, in denen Dateien geöffnet werden können, sind in Abschnitt 6.4, »Das Dateiobjekt erzeugen«, aufgeführt.
** Näheres zur String-Formatierung erfahren Sie in Abschnitt 13.4.3.

Tabelle 35.2    Schlüsselwortparameter der Funktion basicConfig

 
Zum Seitenanfang

35.3.1    Das Meldungsformat anpassen Zur vorigen ÜberschriftZur nächsten Überschrift

Wie in den vorangegangenen Beispielen zu sehen war, wird ein Eintrag in einer Logdatei standardmäßig nicht mit einem Zeitstempel versehen. Es gibt eine Möglichkeit, das Format der geloggten Meldung anzupassen. Dazu übergeben Sie beim Funktionsaufruf von basicConfig den Schlüsselwortparameter format:

logging.basicConfig(
filename="programm.log",
level = logging.DEBUG,
style = "{",
format = "{asctime} [{levelname:8}] {message}")
logging.error("Ein Fehler ist aufgetreten")
logging.info("Dies ist eine Information")
logging.error("Und schon wieder ein Fehler")

Sie sehen, dass ein Format-String übergeben wurde, der die Vorlage für eine Meldung enthält, wie sie später in der Logdatei stehen soll. Dabei stehen die Bezeichner asctime für den Timestamp, levelname für die Dringlichkeitsstufe und message für die Meldung. Die von diesem Beispiel generierten Meldungen sehen so aus:

2017-02-05 14:28:55,811 [ERROR   ] Ein Fehler ist aufgetreten
2017-02-05 14:29:00,690 [INFO ] Dies ist eine Information
2017-02-05 14:29:12,686 [ERROR ] Und schon wieder ein Fehler

Tabelle 35.3 listet die wichtigsten Bezeichner auf, die innerhalb des format-Format-Strings verwendet werden dürfen. Je nach Kontext, in dem die Meldung erzeugt wird, haben einige der Bezeichner keine Bedeutung.

Bezeichner Beschreibung
asctime Zeitpunkt der Meldung. Das Datums- und Zeitformat kann beim Funktionsaufruf von basicConfig über den Parameter datefmt angegeben werden. Näheres dazu folgt im Anschluss an diese Tabelle.
filename der Dateiname der Programmdatei, in der die Meldung abgesetzt wurde
funcName der Name der Funktion, in der die Meldung abgesetzt wurde
levelname die Dringlichkeitsstufe der Meldung
lineno die Quellcodezeile, in der die Meldung abgesetzt wurde
message der Text der Meldung
module Der Name des Moduls, in dem die Meldung abgesetzt wurde. Der Modulname entspricht dem Dateinamen ohne Dateiendung.
pathname der Pfad zur Programmdatei, in der die Meldung abgesetzt wurde
process die ID des Prozesses, in dem die Meldung abgesetzt wurde
thread die ID des Threads, in dem die Meldung abgesetzt wurde

Tabelle 35.3    Bezeichner im Format-String

Was an diesen Meldungen noch stört, ist das Format des Zeitstempels. Zum einen wird das amerikanische Datumsformat verwendet, und zum anderen ist eine Auflösung bis auf die Millisekunde für unsere Zwecke etwas zu fein. Das Format des Timestamps kann beim Aufruf von basicConfig über den Schlüsselwortparameter datefmt angegeben werden:

logging.basicConfig(
filename="programm.log",
level = logging.DEBUG,
style = "{",
format = "{asctime} [{levelname:8}] {message}",
datefmt = "%d.%m.%Y %H:%M:%S")
logging.error("Ein Fehler ist aufgetreten")

Die in der Vorlage für das Datumsformat verwendeten Platzhalter wurden in Abschnitt 17.1, »Elementare Zeitfunktionen – time«, eingeführt. Die von diesem Beispiel erzeugte Meldung sieht folgendermaßen aus:

05.02.2017 14:38:49 [ERROR   ] Ein Fehler ist aufgetreten
 
Zum Seitenanfang

35.3.2    Logging Handler Zur vorigen ÜberschriftZur nächsten Überschrift

Bisher haben wir ausschließlich besprochen, wie das Modul logging dazu verwendet werden kann, alle eingehenden Meldungen in eine Datei zu schreiben. Tatsächlich ist das Modul in dieser Beziehung sehr flexibel und erlaubt es, nicht nur in Dateien, sondern beispielsweise auch in Streams zu schreiben oder die Meldungen über eine Netzwerkverbindung zu schicken. Dafür werden sogenannte Logging Handler verwendet. Um genau zu sein, haben wir in den vorangegangenen Abschnitten bereits einen impliziten Handler verwendet, ohne uns darüber im Klaren zu sein.

Um einen speziellen Handler einzurichten, muss eine Instanz der Handler-Klasse erzeugt werden. Diese kann dann vom Logger verwendet werden. Im folgenden Beispiel sollen alle Meldungen auf einen Stream, nämlich sys.stdout, geschrieben werden; dazu wird die Handler-Klasse logging.StreamHandler verwendet:

import logging
import sys
handler = logging.StreamHandler(sys.stdout)
frm = logging.Formatter("{asctime} {levelname}: {message}",
"%d.%m.%Y %H:%M:%S", style="{")
handler.setFormatter(frm)
logger = logging.getLogger()
logger.addHandler(handler)
logger.setLevel(logging.DEBUG)
logger.critical("Ein wirklich kritischer Fehler")
logger.warning("Und eine Warnung hinterher")
logger.info("Dies hingegen ist nur eine Info")

Zunächst wird der Handler, in diesem Fall ein StreamHandler, instanziiert. Im nächsten Schritt wird eine Instanz der Klasse Formatter erzeugt. Diese Klasse kapselt die Formatierungsanweisungen, die wir in den vorangegangenen Beispielen beim Aufruf der Funktion basicConfig übergeben haben. Mithilfe der Methode setFormatter werden dem Handler die Formatierungsanweisungen bekannt gegeben.

Um den Handler beim Logger zu registrieren, benötigen wir Zugriff auf die bisher implizit verwendete Logger-Instanz. Diesen Zugriff erlangen wir über die Funktion getLogger. Danach wird über addHandler der Handler hinzugefügt und über setLevel die gewünschte Dringlichkeitsstufe eingestellt.

Die Meldungen werden im Folgenden nicht über Funktionen des Moduls logging, sondern über die Methoden critical, warning und info der Logger-Instanz logger abgesetzt. Das Beispielprogramm gibt folgenden Text auf dem Bildschirm aus:

05.02.2017 17:21:46 CRITICAL: Ein wirklich kritischer Fehler
05.02.2017 17:21:46 WARNING: Und eine Warnung hinterher
05.02.2017 17:21:46 INFO: Dies hingegen ist nur eine Info

Im Folgenden sollen die wichtigsten zusätzlichen Handler-Klassen beschrieben werden, die im Paket logging bzw. logging.handlers enthalten sind.

logging.FileHandler(filename, [mode, encoding, delay])

Dieser Handler schreibt die Logeinträge in die Datei filename. Dabei wird die Datei im Modus mode geöffnet. Der Handler FileHandler kann auch implizit durch Angabe der Schlüsselwortparameter filename und filemode beim Aufruf der Funktion basicConfig verwendet werden.

Der Parameter encoding kann dazu verwendet werden, das zum Schreiben der Datei verwendete Encoding festzulegen. Wenn Sie für den letzten Parameter True übergeben, wird mit dem Öffnen der Datei so lange gewartet, bis tatsächlich Daten geschrieben werden sollen.

logging.StreamHandler([stream])

Dieser Handler schreibt die Logeinträge in den Stream stream. Beachten Sie, dass der Handler StreamHandler auch implizit durch Angabe des Schlüsselwortparameters stream beim Aufruf der Funktion basicConfig verwendet werden kann.

logging.handlers.SocketHandler(host, port) logging.handlers.DatagramHandler(host, port)

Diese Handler senden die Logeinträge über eine TCP-Schnittstelle (SocketHandler) bzw. über eine UDP-Netzwerkschnittstelle (DatagramHandler) an den Rechner mit dem Hostnamen host unter Verwendung des Ports port.

logging.handlers.SMTPHandler(mailhost, from, to, subject, [credentials])

Dieser Handler sendet die Logeinträge als E-Mail an die Adresse to. Dabei werden subject als Betreff und from als Absenderadresse eingetragen. Über den Parameter mailhost geben Sie den zu verwendenden SMTP-Server an. Sollte dieser Server eine Authentifizierung verlangen, können Sie ein Tupel, das Benutzername und Passwort enthält, für den optionalen letzten Parameter credentials übergeben.

 


Ihre Meinung

Wie hat Ihnen das Openbook gefallen? Wir freuen uns immer über Ihre Rückmeldung. Schreiben Sie uns gerne Ihr Feedback als E-Mail an kommunikation@rheinwerk-verlag.de.

<< zurück
 Zum Rheinwerk-Shop
Zum Rheinwerk-Shop: Python 3 Python 3
Jetzt Buch bestellen

 Buchempfehlungen
Zum Rheinwerk-Shop: Einstieg in Python
Einstieg in Python


Zum Rheinwerk-Shop: Python. Der Grundkurs
Python. Der Grundkurs


Zum Rheinwerk-Shop: Algorithmen mit Python
Algorithmen mit Python


Zum Rheinwerk-Shop: Objektorientierte Programmierung
Objektorientierte Programmierung


Zum Rheinwerk-Shop: Raspberry Pi. Das umfassende Handbuch
Raspberry Pi. Das umfassende Handbuch


Zum Rheinwerk-Shop: Roboter-Autos mit dem Raspberry Pi
Roboter-Autos mit dem Raspberry Pi


Zum Rheinwerk-Shop: Neuronale Netze programmieren mit Python
Neuronale Netze programmieren mit Python


 Lieferung
Versandkostenfrei bestellen in Deutschland, Österreich und der Schweiz
InfoInfo

 
 


Copyright © Rheinwerk Verlag GmbH 2020
Für Ihren privaten Gebrauch dürfen Sie die Online-Version natürlich ausdrucken. Ansonsten unterliegt das Openbook denselben Bestimmungen, wie die gebundene Ausgabe: Das Werk einschließlich aller seiner Teile ist urheberrechtlich geschützt.
Alle Rechte vorbehalten einschließlich der Vervielfältigung, Übersetzung, Mikroverfilmung sowie Einspeicherung und Verarbeitung in elektronischen Systemen.

 
[Rheinwerk Computing]

Rheinwerk Verlag GmbH, Rheinwerkallee 4, 53227 Bonn, Tel.: 0228.42150.0, Fax 0228.42150.77, service@rheinwerk-verlag.de

Cookie-Einstellungen ändern