587
21.6
Vertiefung: Professionelles Arbeiten mit Logging
Skript:
21.6 Vertiefung: Professionelles Arbeiten mit Logging
In diesem Abschnitt werden weiterführende Funktionen des Moduls logging eingeführt.
21.6.1 Logging-Levels
Logging-Levels sind so etwas wie Dringlichkeitsstufen von Einträgen. Definiert sind fol-
gende Stufen (mit zunehmender Dringlichkeit): DEBUG, INFO, WARNING, ERROR, CRI-
TICAL. Meldungen auf der Stufe DEBUG haben eine sehr niedrige Bedeutsamkeit. Es sind
Routinemeldungen, die man meistens ignorieren kann, wenn man aus irgendwelchen
Gründen die Dokumentation eines Programmlaufs studiert. Meldungen der Stufe CRITI-
CAL sind von hoher Bedeutung und sollten bei einer Überprüfung des Logs auf jeden Fall
beachtet werden. Zu jeder Stufe gibt es eine Funktion gleichen Namens, die kleingeschrie-
ben wird, also
debug(), info() usw. Mit diesen Funktionen können Sie Meldungen unter-
schiedlicher Dringlichkeit in die Log-Datei eintragen lassen.
Das folgende Python-Skript enthält eine Implementierung des Mergesort-Algorithmus zum
Sortieren einer Liste von Zahlen. Abbildung 21.4 visualisiert die Idee: Die eingegebene Liste
# log_gui.py
import logging
from tkinter import Tk, Button, Label, Entry, END
class App(object):
def __init__(self):
self.fenster = Tk()
self.eingabe = Entry(self.fenster)
self.label = Label(self.fenster, text="Bitte Name eingeben!")
self.ok_button = Button(self.fenster, text ="OK",
command=self.verarbeiten)
self.eingabe.pack()
self.label.pack()
self.ok_button.pack()
self.fenster.mainloop()
def verarbeiten(self):
name = self.eingabe.get()
logging.debug("Eingabe erfolgt. Name: " + name)
self.eingabe.delete(0, END)
logging.basicConfig(filename="tmp/logging.txt", level=logging.DEBUG)
logging.debug("Start")
App()
Kapitel 21
Fehler finden und vermeiden
588
wird in zwei Hälften aufgeteilt. Diese Hälften werden durch einen rekursiven Aufruf sor-
tiert und dann »gemischt«. Das heißt, man bearbeitet beide Listen von vorne, entfernt
immer das kleinere Element der beiden Listenköpfe und fügt es der Ergebnisliste an.
Abb. 21.4: Die Idee von Mergesort
Aber bei dem Programm geht es gar nicht um Mergesort selbst, sondern um die Verwen-
dung von Logging-Funktionen. Das Skript enthält zwei rekursive Funktionen. Sie sind zwar
ganz klein und übersichtlich, aber Rekursion ist für uns Menschen nur schwer zu verste-
hen. Schauen Sie sich den Programmtext an. Sind Sie sicher, dass kein logischer Fehler ent-
halten ist?
Das Skript enthält deshalb Aufrufe der Funktionen
logging.debug() und
logging.info(). Sie schreiben Log-Einträge in die Datei /tmp/logging.txt. Für jeden
Funktionsaufruf werden Eingabe und Ausgabe festgehalten. So kann man später mithilfe
der Log-Datei prüfen, ob die Funktionen korrekt arbeiten.
import logging
logging.basicConfig(filename="/tmp/logging.txt",
level=logging.DEBUG,
filemode="w") #1
def merge(s1, s2): #2
logging.debug("Starte merge({}, {}): ".format(
str(s1), str(s2)))
if s1 == []: ergebnis = s2 #3
elif s2 == []: ergebnis = s1
else:
a, b = s1[0], s2[0]
if a <= b: ergebnis = [a] + merge(s1[1:], s2) #4
else: ergebnis = [b] + merge(s1, s2[1:])
589
21.6
Vertiefung: Professionelles Arbeiten mit Logging
Erläuterung:
#1: Das Skript wird im Logging-Level DEBUG ausgeführt. Das heißt, alle Meldungen (auf
den Stufen DEBUG und INFO) werden in die Log-Datei geschrieben. Das Schlüsselwort-
argument
filemode="w" bewirkt, dass bei jedem Programmstart die Log-Datei gelöscht
und neu beschrieben wird.
#2: Die Hilfsfunktion merge() mischt zwei sortierte Listen so, dass eine einzige längere sor-
tierte Liste entsteht.
#3: Das ist der Elementarfall: Eine der beiden Listen ist leer. Dann ist die andere Liste schon
das Ergebnis.
#4: Die Stelle ist schwer verständlich. Hier wird das kleinere erste Element der beiden Listen
ausgewählt und an den Anfang der Ergebnisliste gesetzt. So haben wir schon einmal das
erste Element. Der Rest der Ergebnisliste wird durch einen rekursiven Aufruf von
merge()
berechnet. Eine der beiden Listen, die an merge() übergeben werden, ist ein bisschen klei-
ner. Deshalb können wir sicher sein, dass es keine Endlosrekursion gibt. Oder?
#5: Der Elementarfall: Wenn die Liste leer ist oder nur ein Element besitzt, ist sie bereits sor-
tiert.
#6: Das ist eine ganzzahlige Division. In den folgenden Zeilen wird die Liste s in zwei Hälf-
ten aufgeteilt. Genauer: Es werden zwei Kopien angefertigt, eine Kopie von der ersten Hälfte
und eine von der zweiten.
#7: Rekursiver Aufruf: Die beiden Hälften werden sortiert und die beiden sortierten Teil-
listen zum Gesamtergebnis durch Mischen zusammengefügt.
logging.debug("Ergebnis von merge({}, {}): {}".format(
str(s1), str(s2), str(ergebnis)))
return ergebnis
def msort (s):
logging.info("msort({})".format(str(s)))
if len(s) <= 1:
ergebnis = s #5
else:
n = len(s)//2 #6
s1 = s[:n]
s2 = s[n:]
ergebnis = merge(msort(s1), msort(s2)) #7
logging.info("Ergebnis von msort({}): {}".format(
str(s), str(ergebnis)))
return ergebnis
if __name__ == "__main__":
s = [7, 13, 15, 1, 12, 11, 3, 6, 10, 2, 8, 14, 0, 4, 9, 5]
print(msort(s))

Get Python 3 - Lernen und professionell anwenden now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.