Important
🎯 TL;DR
Im Paket java.util.logging findet sich eine einfache Logging-API.
Über die Methode getLogger() der Klasse Logger
(Factory-Method-Pattern) kann ein (neuer) Logger erzeugt werden,
dabei wird über den String-Parameter eine Logger-Hierarchie aufgebaut
analog zu den Java-Package-Strukturen. Der oberste Logger (der
"Basis-Logger" bzw. "Root-Logger") hat den leeren Namen.
Jeder Logger kann mit einem Log-Level (Klasse Level) eingestellt
werden; Log-Meldungen unterhalb des eingestellten Levels werden
verworfen.
Vom Logger nicht verworfene Log-Meldungen werden an den bzw. die Handler des Loggers und (per Default) an den Eltern-Logger weiter gereicht. Die Handler haben ebenfalls ein einstellbares Log-Level und verwerfen alle Nachrichten unterhalb der eingestellten Schwelle. Zur tatsächlichen Ausgabe gibt man einem Handler noch einen Formatter mit. Defaultmäßig hat nur der Root-Logger einen Handler.
Der Root-Logger (leerer String als Name) hat als Default-Level (wie
auch sein Console-Handler) "Info" eingestellt.
Nachrichten, die durch Weiterleitung nach oben empfangen wurden, werden nicht am Log-Level des empfangenden Loggers gemessen, sondern akzeptiert und an die Handler des Loggers und (sofern nicht deaktiviert) an den Eltern-Logger weitergereicht.
Tip
- Debugging
- Beeinflusst Code nicht
- Kann schnell komplex und umständlich werden
- Sitzung transient - nicht reproduzierbar/speicherbar
- "Poor-man's-debugging" (Ausgaben mit
IO.println)- Müssen irgendwann vor Release/Produktivbetrieb entfernt werden
- Ausgabe nur auf einem Kanal (Konsole)
- Keine Filterung nach Problemgrad - keine Unterscheidung zwischen Warnungen, einfachen Informationen, ...
- Logging
- Verschiedene (Java-) Frameworks:
java.util.logging(JDK), log4j (Apache), SLF4J, Logback, ...
- Verschiedene (Java-) Frameworks:
Paket java.util.logging

Eine Applikation kann verschiedene Logger instanziieren. Die Logger bauen per Namenskonvention hierarchisch aufeinander auf. Jeder Logger kann selbst mehrere Handler haben, die eine Log-Nachricht letztlich auf eine bestimmte Art und Weise an die Außenwelt weitergeben.
Log-Meldungen werden einem Level zugeordnet. Jeder Logger und Handler hat ein Mindest-Level eingestellt, d.h. Nachrichten mit einem kleineren Level werden verworfen.
Zusätzlich gibt es noch Filter, mit denen man Nachrichten (zusätzlich zum Log-Level) nach weiteren Kriterien filtern kann.
import java.util.logging.Logger;
Logger l = Logger.getLogger(MyClass.class.getName());-
Factory-Methode der Klasse
java.util.logging.Loggerpublic static Logger getLogger(String name);
=> Methode liefert bereits vorhandenen Logger mit diesem Namen (sonst neuen Logger)
-
Best Practice: Nutzung des vollqualifizierten Klassennamen:
MyClass.class.getName()- Leicht zu implementieren
- Leicht zu erklären
- Spiegelt modulares Design
- Ausgaben enthalten automatisch Hinweis auf Herkunft (Lokalität) der Meldung
- Alternativen: Funktionale Namen wie "XML", "DB", "Security"
public void log(Level level, String msg);-
Diverse Convenience-Methoden (Auswahl):
public void warning(String msg) public void info(String msg) public void entering(String srcClass, String srcMethod) public void exiting(String srcClass, String srcMethod)
-
Beispiel
import java.util.logging.Logger; Logger l = Logger.getLogger(MyClass.class.getName()); l.info("Hello World :-)");
java.util.logging.Leveldefiniert 7 Stufen:SEVERE,WARNING,INFO,CONFIG,FINE,FINER,FINEST(von höchster zu niedrigster Prio)- Zusätzlich
ALLundOFF
- Nutzung der Log-Level:
- Logger hat Log-Level: Meldungen mit kleinerem Level werden verworfen
- Prüfung mit
public boolean isLoggable(Level) - Setzen mit
public void setLevel(Level)
=> Warum wird im Beispiel nach log.setLevel(Level.ALL); trotzdem nur
ab INFO geloggt? Wer erzeugt eigentlich die Ausgaben?!
- Pro Logger mehrere Handler möglich
- Logger übergibt nicht verworfene Nachrichten an Handler
- Handler haben selbst ein Log-Level (analog zum Logger)
- Handler verarbeiten die Nachrichten, wenn Level ausreichend
- Standard-Handler:
StreamHandler,ConsoleHandler,FileHandler
- Handler nutzen zur Formatierung der Ausgabe einen
Formatter - Standard-Formatter:
SimpleFormatterundXMLFormatter
Konsole: logging.LoggingHandler
=> Warum wird im Beispiel nach dem Auskommentieren von
log.setUseParentHandlers(false); immer noch eine zusätzliche Ausgabe
angezeigt (ab INFO aufwärts)?!
- Logger bilden Hierarchie über Namen
- Trenner für Namenshierarchie: "
." (analog zu Packages) => mit jedem "." wird eine weitere Ebene der Hierarchie aufgemacht ... - Jeder Logger kennt seinen Eltern-Logger:
Logger#getParent() - Basis-Logger: leerer Name (
"")- Voreingestelltes Level des Basis-Loggers:
Level.INFO(!)
- Voreingestelltes Level des Basis-Loggers:
- Trenner für Namenshierarchie: "
- Weiterleiten von Nachrichten
- Nicht verworfene Log-Aufrufe werden an Eltern-Logger
weitergeleitet (Default)
- Abschalten mit
Logger#setUseParentHandlers(false);
- Abschalten mit
- Diese leiten an ihre Handler sowie an ihren Eltern-Logger weiter (unabhängig von Log-Level!)
- Nicht verworfene Log-Aufrufe werden an Eltern-Logger
weitergeleitet (Default)
Konsole: logging.LoggingParent; Tafel: Skizze Logger-Baum
Bei genauerem Hinschauen auf die API von java.util.logging erkennt
man, dass es die log-Funktion in zwei Varianten gibt: Einmal mit einem
String (der Message) als Parameter, und einmal mit einem Supplier
(funktionales Interface aus dem JDK):
public void log(Level level, String msg);
public void log(Level level, Supplier<String> msgSupplier);Das gilt auch für die meisten Convenience-Log-Funktionen:
public void warning(String msg)
public void warning(Supplier<String> msgSupplier)
public void info(String msg)
public void info(Supplier<String> msgSupplier)Damit kann man den Aufruf auch mit einem Lambda-Ausdruck gestalten:
import java.util.logging.Logger;
Logger l = Logger.getLogger(MyClass.class.getName());
l.info("Hello World"); // String
l.info(() -> "Hello World"); // SupplierDas Logging mit java.util.logging ist an sich bereits sehr effizient:
Wenn bei einem Aufruf einer Log-Funktion die eingestellten Level beim
Logger, den Handlern und den Elternloggern nicht erreicht werden, wird
nichts ausgegeben. Um noch effizienter zu werden, kann man auch das
Bauen der Message selbst davon abhängig machen, ob man sie wirklich
braucht: Während bei der ersten Aufruf-Variante mit dem String-Parameter
die Message bereits vor dem Aufruf der Log-Methode berechnet werden
muss, wird sie in der zweiten Variante erst dann wirklich berechnet,
wenn sie gebraucht wird. Wenn die Log-Methode tatsächlich loggen kann
(die verschiedenen Level werden erreicht), dann und nur dann wertet sie
den übergebenen Lambda-Ausdruck aus und erzeugt dabei die auszugebende
Message. (Anmerkung: Im obigen Beispiel ist das egal, da der String
ohnehin fest ist und stets bekannt/berechnet ist. Aber stellen Sie sich
statt "Hello World" einen Funktionsaufruf vor, der mehr oder weniger
aufwändig einen String produziert ...)
- Pro Klasse ein
private static final Logger LOG = Logger.getLogger(MyClass.class.getName()); - Keine Log-Ausgaben in Bibliotheken mit
System.out/System.err, sondern immer ein Logging-Framework verwenden - Log-Meldungen:
- Klar, kurz, technisch brauchbar ("Was ist passiert? Wo? Welche Daten/IDs?")
- Keine sensiblen Daten (Passwörter, Tokens, personenbezogene Daten)
- Log-Level-Richtlinien:
SEVERE: Fehler, nach denen fachlich nicht sinnvoll weitergearbeitet werden kannWARNING: Unerwartete Situationen, aber das System läuft weiterINFO: Wichtige StatusmeldungenCONFIG: KonfigurationsdetailsFINE,FINER,FINEST: eher für detaillierte Diagnose/Entwicklung
Wir haben in den Beispielen den Logger immer mit setLevel(...) und
setUseParentHandlers(false) etc. im Code konfiguriert. Es gibt aber -
analog zu größeren Frameworks wie SLF4J - auch bei java.util.logging
die Möglichkeit, die Konfiguration von außen über eine Properties-Datei
vorzunehmen (logging.properties).
Tip
Hinweis: In vielen professionellen Projekten werden heute (für flexible Konfiguration und bessere Integrationen) Logging-Frameworks wie SLF4J mit Logback genutzt. Die hier vorgestellte Logik (Logger, Level, Handler/Appender, Formatter/Layouts, Hierarchie) überträgt sich jedoch nahezu 1:1 darauf.
- Java Logging API im Paket
java.util.logging
- Neuer Logger über Factory-Methode der Klasse
Logger- Einstellbares Log-Level (Klasse
Level) - Handler kümmern sich um die Ausgabe, nutzen dazu Formatter
- Mehrere Handler je Logger registrierbar
- Log-Level auch für Handler einstellbar (!)
- Logger (und Handler) "interessieren" sich nur für Meldungen ab bestimmter Wichtigkeit
- Logger reichen nicht verworfene Meldungen defaultmäßig an Eltern-Logger weiter (rekursiv)
- Einstellbares Log-Level (Klasse
Tip
📖 Zum Nachlesen
Lesen Sie in der Dokumentation von Oracle zu den JDK Core Libraries nach: Java Logging Overview.
Note
✅ Lernziele
- k3: Ich kann die Java Logging API im Paket
java.util.loggingaktiv einsetzen - k3: Ich kann eigene Handler und Formatter schreiben
Important
🏅 Challenges
Logger-Konfiguration
Betrachten Sie den folgenden Java-Code:
import java.util.logging.*;
public class Logging {
public static void main(String... args) {
Logger l = Logger.getLogger("Logging");
l.setLevel(Level.FINE);
ConsoleHandler myHandler = new ConsoleHandler();
myHandler.setFormatter(new SimpleFormatter() {
public String format(LogRecord record) {
return "WUPPIE\n";
}
});
l.addHandler(myHandler);
l.info("A");
l.fine("B");
l.finer("C");
l.finest("D");
l.severe("E");
}
}Welche Ausgaben entstehen durch den obigen Code? Erklären Sie, welche der Logger-Aufrufe zu einer Ausgabe führen und wieso und wie diese Ausgaben zustande kommen bzw. es keine Ausgabe bei einem Logger-Aufruf gibt. Gehen Sie dabei auf jeden der fünf Aufrufe ein.
Analyse eines Live-Beispiels aus dem Dungeon
Analysieren Sie die Konfiguration des Loggings im Dungeon-Projekt: Dungeon-CampusMinden/Dungeon: core.utils.logging.DungeonLoggerConfig.
Unless otherwise noted, this work is licensed under CC BY-SA 4.0.
Last modified: 9c71914 2026-06-19 logging: fix challenge
