18. Oktober 2005 Hinweise zur Verwendung der Logging API im JDK 1.4 18. Oktober 2005 [email protected] [email protected] Inhalt 1 Logging........................................................................................................................................ 2 1.1 Übersicht.............................................................................................................................. 2 1.1.1 Logger...........................................................................................................................3 1.1.2 Handler......................................................................................................................... 3 1.1.3 Logging Properties-File................................................................................................ 4 1.2 Logging Levels.....................................................................................................................4 1.2.1 SEVERE....................................................................................................................... 5 1.2.2 WARNING...................................................................................................................5 1.2.3 INFO.............................................................................................................................6 1.2.4 CONFIG....................................................................................................................... 6 1.2.5 FINE............................................................................................................................. 6 1.2.6 FINER...........................................................................................................................6 1.2.7 FINEST.........................................................................................................................6 1.3 Beispiele............................................................................................................................... 7 1.4 Programmierrichtlinien........................................................................................................ 9 1.4.1 Initialisierung................................................................................................................9 1.4.2 Logging Meldungen......................................................................................................9 1.4.3 Debugging.................................................................................................................... 9 1.4.4 root-Handler und root-Logger.................................................................................... 10 1.5 Kurzanleitung..................................................................................................................... 11 1.5.1 Konfigurationsfile.......................................................................................................11 1.5.2 Start der Anwendung.................................................................................................. 11 1.5.3 Meldungen..................................................................................................................11 1/11 18. Oktober 2005 1 Logging Die Logging API wurde von Sun in der Java Version 1.4 in das JDK integriert. Vor JDK1.4 wurden Logging APIs in verschieden Open-Source Projekten entwickelt, diese APIs werden teilweise noch weiter verwendet (Jakarta Commons-Logging, Log4j). Im Folgenden wird die Logging API in JDK1.4 kurz dokumentiert und Überlegungen und Implementierungsvorschläge für die Verwendung zusammengefasst. Einen vollständigen Überblick findet man bei [http://java.sun.com/j2se/1.4.2/docs/guide/util/logging/] 1.1 Übersicht Die zentrale Komponente der Logging API ist die Klasse java.util.logging.LogManager. Der LogManager hat die Aufgabe verschiedene Logger-Objekte in einem hierachischem Namensraum zu organisieren, sowie zugehörige Logging-Handler zu verwalten. Der LogManager ist auch für das Einlesen des Logging Konfigurationsfiles beim Start einer Anwendung zuständig. Das folgende Schaubild zeigt stark vereinfacht den Ablauf bei der Verwendung der Logging API: LoggingManager Anwendung Logging Meldung Logger log(level,msg) LogRecord Handler Ausgabe Die Anwendung verwendet einen Logger um ein Ereignis an die Logging API zu melden, der Logger leitet diese Meldung in Form eines LogRecord an einen Handler weiter, der diese als Meldung ausgibt. Alle Handler sind Unterklassen der abstrakten Klasse java.util.logging.Handler. Häufig verwendete Handler sind ConsoleHandler, der die Meldungen auf die Konsole ausgibt und FileHandler, der die Meldungen in eine Datei schreibt. Wird kein Handler explizit definiert, so installiert der LogManager einen ConsoleHandler als Default. Um einen Logger in einer Anwendung zu verwenden muss dieser zunächst mit der static Methode Logger.getLogger(“<name>“) erzeugt werden. Meldungen können dann mit der Methode log(...) an diesen übergeben werden. Bei der Übergabe einer Meldung durch die Anwendung an den Logger wird explizit oder implizit ein Logging-Level für diese Meldung vorgegeben. Dieser Logging-Level gibt die Priorität der Meldung an. Logger und Handler können so konfiguriert werden, dass lediglich Meldungen ab einer bestimmten Priorität weitergeleitet werden. Hierfür wird die Methode setLevel() im Handler bzw. im Logger Objekt verwendet. Die Initialisierung des LogManager und damit die Konfiguration der verwendeten Logger und Handler kann beim Start einer Java Anwendung über ein properties-File vorgenommen werden. Dabei wird über den Parameter -Djava.util.logging.config.file=<filename> das zu verwendende Properties File angegeben. Für eine einfache Anwendung ist es hinreichend lediglich mit Logger Objekten zu arbeiten. Normalerweise werden die Handler lediglich in einem Konfigurationsfile definiert und nicht von der Anwendung selbst initialisiert. In einer aufwändigeren Konfiguration können sie verwendet werden um z.B. Log Records in einem Ringpuffer zu speichern und lediglich bei Bedarf auszugeben. Auch der LogManager selbst wird von einer einfachen Anwendung in der Regeln nicht direkt verwendet. Er kann bei Bedarf jedoch benutzt werden, um z.B. ein geändertes Konfigurationsfile in einer laufenden Anwendung neu zu laden. In den folgenden Abschnitten wird genauer auf die Konfiguration der einzelnen Komponenten der Logging API für eine “einfache“ Anwendung eingegangen. 2/11 18. Oktober 2005 1.1.1 Logger Alle Logger Objekte werden in einem Namensraum hierachisch verwaltet. Bei der Initialisierung eines Loggers mit der Methode Logger.getLogger(“<name>“) wird der Name des Loggers angegeben. Normalerweise werden Logger nach dem Package- oder Klassennamen benannt in dem sie verwendet werden. Ein besonderer Logger ist der root-Logger, der den Namen ““ (leerer String) hat. Außer dem root-Logger besitzt jeder Logger eine Referenz auf den im Namensraum übergeordneten Logger, dieser Logger wird auch als parent-Logger bezeichnet. Ein Handler kann mit der Methode addHandler() bei einem Logger angemeldet werden. Alle Logging Meldungen werden sowohl an die im Logger registrierten Handler als auch an seinen parent-Logger weitergeleitet. Aus diesem Grund genügt das Registrieren eines einzigen Handlers beim root-Logger, um die Meldungen aller in einer Anwendung verwendeten Logger entgegenzunehmen. Jeder Logger besitzt einen Level, der den minimalen Level der Meldungen darstellt, die von ihm angenommen werden. Wenn die Meldung z.B. über die Methode log(Level, String) von der Anwendung übermittelt wird nimmt der Logger diese Meldung an, wenn der als Parameter übergebene Logging-Level der Meldung größer ist als der vorgegebene minimale Logging-Level. Die Meldung wird dann an alle angehängten Handler und an den parent-Logger weitergegeben. Der parent-Logger führt die Überprüfung des Logging-Level nicht mehr durch da die Meldung bereits von einem anderen Logger angenommen wurde. Daraus folgt, dass eine Meldung, die durch einen Logger angenommen wurde, alle parent-Logger dieses Loggers erreicht, und damit auch den Handler des root-Loggers und zwar unabhängig vom Logging-Level der parent-Logger. Der Logging-Level eines Loggers kann entweder über die Methode setLevel() in einer Anwendung direkt konfiguriert werden, oder wird in einem properties-File definiert. Wird vom Anwender kein Level vorgegeben, so wird der Level des parent-Logger verwendet. 1.1.2 Handler Logging Handler haben die Aufgabe die Logging Meldungen von den Loggern entgegenzunehmen und auszugeben oder ggf. zwischenzuspeichern. Der Logging-Level kann über die Methode setLevel() konfiguriert werden und definiert welche Meldungen bearbeitet werden. Die folgende Auflistung beschreibt einen Teil der im JDK implementierten Handler: • ConsoleHandler Dieser Handler schreibt die Meldungen nach System.err, als default-Level wird INFO verwendet. • FileHandler Dieser Handler schreibt die Meldungen in eine Datei oder in eine Menge von rotierenden Logfiles welche im Konstruktor angegeben werden können, als default-Level wird ALL verwendet. • MemoryHandler Bei diesem Handler werden die Meldungen in einem Ringpuffer gespeichert und können bei Bedarf an einen zweiten Handler weitergegeben werden. Für einen Handler können Formatter-Objekte gesetzt werden, die definieren in welchen Format die Meldungen ausgegeben werden. Im JDK sind die beiden folgenden Formatter implementiert: • SimpleFormatter Konvertiert eine Logging Meldung in einen einfachen String, der aus ein oder zwei Zeilen besteht. Dieser Formatter wird als Default verwendet. • XMLFormatter Konvertiert eine Logging Meldung in eine XML Struktur. 3/11 18. Oktober 2005 1.1.3 Logging Properties-File Beim Start einer Java Anwendung kann mit dem Kommandozeilenparameter “-Djava.util. logging.config.file=<filename>“ ein Properties-File angegeben werden, n dem für den LogManager die Konfiguration der Logger und Handler festgelegt werden kann. Wird kein solcher Kommandozeilenparameter angegeben so liest der LogManager die Konfiguration aus einer Datei an der Stelle lib/logging.properties im Verzeichnis der verwendeten JRE. Die Properties-Files können unter anderem die folgenden Angaben enthalten: • Property “handlers“ definiert eine durch Whitespace oder Komma getrennte Liste von Klassennamen, die dem rootLogger als Handler zugewiesen werden. • Propety “<logger>.handlers“ definiert eine durch Whitespace oder Komma getrennte Liste, die dem Logger mit dem Namen “<logger>“ als Handler zugewiesen werden. • Property “.level“ definiert einen Logging Level für den root-Logger. • Property “<logger>.level“ definiert einen Logging-Level für einen Logger mit dem Namen „<logger>“. Das oben genannte Properties-File innerhalb der JRE enthält u.a. die folgenden Parameter: handlers = java.util.logging.ConsoleHandler java.util.logging.ConsoleHandler.level = INFO .level = INFO Dadurch wird eine ConsoleHandler für den root-Logger installiert, sowie der Level INFO als Default-Level für alle in einer Anwendung verwendeten Logger initialisiert. Diese Einstellungen können sowohl in der Anwendung durch explizite Methodenaufrufe als auch durch die Verwendung eines eigenen Properties-File verändert werden. Um z.B. einen ConsoleHandler für den root-Logger zu installieren, der alle Logging Meldung ausgibt, müssen die folgenden Parameter im properties-File gesetzt werden: handlers = java.util.logging.ConsoleHandler java.util.logging.ConsoleHandler.level = ALL Um beispielsweise die Logger in einem Package net.mypackage so zu konfigurieren, dass sie alle Meldungen an den Handler weitergeben, muss der folgenden Parameter im properties-File gesetzt werden: net.mypackage.level = ALL An Stelle des Namens eines Packages kann auch eine einzelne Klasse angegeben werden. Dies ist jedoch nur sinnvoll, wenn für die Logger in der Klasse auch der Name der Klasse verwendet wurde. Für den root-Logger setzt man den Level zur Ausgabe aller Meldungen mit dem Parameter .level = ALL 1.2 Logging Levels Für die Logger entscheidet der eingestellte Logging Level über die Annahme einer Meldung wenn diese z.B. über die log(Level, String) Methode durch die Anwendung übergeben wird. Wurde eine Meldung jedoch einmal von einem Logger angenommen, so wird diese an den parentLogger weitergegeben und von diesem unabhängig vom Logging-Level angenommen. Für die Handler entscheidet der Logging-Level über die Ausgabe einer Meldung z.B. auf die Konsole oder in eine Datei. 4/11 18. Oktober 2005 Zusammengefasst bedeutet dies: Entscheidend, ob eine Meldung angenommen wird, ist der Level des Loggers, entscheidend, ob eine Meldung ausgegeben wird, ist der Level des Handlers. Die Logging Levels des JDK 1.4 sind in der Reihenfolge ihrer Priorität: • SEVERE (höchste Priorität) • WARNING • INFO (default Level für Logger und Handler) • CONFIG • FINE • FINER • FINEST (niedrigste Priorität) Darüber hinaus gibt es noch die Level OFF und ALL, diese können verwendet werden, um in den Loggern oder Handlern sämtliche Logging Meldungen ein- oder auszuschalten. Die Logging Level werden als public static Felder des Objekts java.util.logging.Level implementiert. Es ist möglich java.util.logging.Level zu erweitern und eigene Logging Level zu implementieren. In der default-Konfiguration ,d.h. wenn die verwendeten Logger oder Handler nicht durch das Setzen der Logging Levels in der Anwendung konfiguriert werden, werden alle Meldungen mit der Priorität INFO oder höher ausgegeben. Die folgenden Abschnitte schlagen Richtlinien zur Verwendung der einzelnen Level vor. 1.2.1 SEVERE Dieser Level sollte verwendet werden wenn aufgrund von auftretenden Fehlern eine Anwendungnicht länger ausgeführt werden kann, d.h. wenn ein weiteres Ausführen der Anwendung zu inkonsistenten Daten oder zum unmittelbaren Absturz der Anwendung führen würde. Dieser Level sollte auch verwendet werden, wenn Ereignisse im Programm auf einen Fehler in der Implementierung der Anwendung hindeuten (Programmierfehler), die Anwendung jedoch mit sinnvollen Werten weiterrechnen kann. Beispiele: • Ein Operative konnte sich nach mehreren Versuchen nicht beim Dispatcher anmelden, der Operative bricht mit mit einer SEVERE Message ab. • Bei der Überprüfung mit instanceof hat ein Objekt nicht die notwendige Klasse. • Der Kontrollfluss in einem switch-Block landet in einem „unmöglichen“ case/default-Zweig. • Fehler in Architeuthis 1.2.2 WARNING Dieser Level sollte verwendet werden wenn Fehler in einer Anwendung auftreten, die Anwendung jedoch selbständig versucht den Fehler zu beheben, oder die Anwendung zunächst weiterarbeiten kann, der Fehler also keine unmittelbaren Auswirkungen hat. Beispiele: • Temporäre Fehler z.B. durch Netzwerkprobleme. • Der Verbindungsaufbau zu einem Operative ist fehlgeschlagen, es wird jedoch weiter versucht die Verbindung herzustellen. • Fehler in den durch den Anwender programmierten Teilproblemen, RemoteStores etc. (Fehler im Benutzercode) 5/11 18. Oktober 2005 1.2.3 INFO Sonstige Meldungen, die für den Anwender von Interesse sein könnten. Da Meldungen mit diesem Level in der default-Konfiguration ausgegeben werden sollten lediglich selten auftretende wichtige Ereignisse in einer Anwendung dokumentiert werden, die für den Anwender von Interesse sind. • Angeforderte Dateien im Classfileserver • Start/Ende der Berechnung 1.2.4 CONFIG Dieser Level sollte verwendet werden, um den “normalen“ Kontrollfluss in einer Anwendung zu dokumentieren. Beispiel: • Verbindungsaufbau oder Verbindungsabbau zu einem Operative • Meldungen wenn default-Werte für optionale Parameter beim Programmstart verwendet werden. • Kommandozeilenargumente nach dem Parsen im Operative • Anmeldung des Operative 1.2.5 FINE Dieser Level sollte verwendet werden, um ein oberflächliches Debugging einer Anwendung zu erlauben. Dabei werden vor allen Konfigurationsparameter einer Anwendung ausgegeben. Damit können häufiger auftretende Ereignisse im normalen Kontrollfluss einer Anwendung dokumentiert werden Beispiele: • Ausgabe der Filenamen von Ein- und Ausgabedateien, Port- und IP-Nummern im laufenden Betrieb. • Ein neues Problem wird zum Dispatcher übermittelt und berechnet. • Aufrufe der wichtigen Methoden registerRemoteStore() und fetchPartialProblem(). • Zurückliefern eine Lösung im Operative 1.2.6 FINER Dieser Level sollte verwendet werden um einzelne Methodenaufrufe zu dokumentieren. Dabei können zusätzlich auch die Parameter der Methodenaufrufe ausgegeben werden. Dieser Level wird von den Methoden entering(), exiting() und throwing() eines Logging Objekts verwendet. Diese Methoden definieren also implizit einen Logging Level und können verwendet werden, um bequem die entsprechenden Ereignisse in einer Anwendung an einen Logger zu melden. Beim Aufruf müssen als Parameter mindestens der Name der Methode sowie der Name der Klasse übergeben werden: entering(String sourceClass, String sourceMethod); Beispiele: • sämtliche “interessantern“ Methodenein- oder -austritte. 1.2.7 FINEST Dieser Level sollte verwendet werden, um gegebenenfalls den Kontrollfluss innerhalb einer Methode zu dokumentieren. Beispiele: 6/11 18. Oktober 2005 • Ausgabe von Schleifendurchläufen • “interessante“ Ereignisse innerhalb einer Methode 1.3 Beispiele In diesem Abschnitt soll anhand einiger Beispiele die Funktionsweise der Logging API veranschaulicht werden. Es soll insbesondere die Verarbeitung der Logging Meldungen innerhalb der hierachischen Struktur der Logger verdeutlicht werden. Zunächst wird der Aufbau einer solchen Struktur aus Loggern und Handler sowohl mit Hilfe der Parameter eines Properties-Files als auch mit Hilfe von Java-Methoden beschrieben. Die folgende Abbildung verdeutlicht die verwendete Struktur, die Pfeile veranschaulichen den “Weg“ zweier Logging-Meldungen, die im Folgenden besprochen werden. default root-Logger (““) default Logger (“A“) default handler1 "hello A.B.A!" "hello A.B.C!" default Logger (“A.A“) default Logger (“A.B“) default handler2 "hello A.B.A!“ "hello A.B.C!" default Logger (“A.B.B“) default Logger (“A.B.C“) default Logger (“A.B.A“) log(Level.INFO, "hello A.B.A!"); log(Level.INFO, "hello A.B.C!"); Symbole: Logging-Level level object Objekt (Logger/Handler) default handler3 "hello A.B.C!" Logging-Meldungen: weiter geleitet/ angenommen nicht angenommen Das folgende Codefragment erzeugt diese Struktur: Logger logger = Logger.getLogger(""); Logger logger_A = Logger.getLogger("A"); Logger logger_A_A = Logger.getLogger("A.A"); Logger logger_A_B = Logger.getLogger("A.B"); Logger logger_A_B_A = Logger.getLogger("A.B.A"); Logger logger_A_B_B = Logger.getLogger("A.B.B"); Logger logger_A_B_C = Logger.getLogger("A.B.C"); Handler handler1 = new ConsoleHandler(); logger_A.addHandler(handler1); Handler handler2 = new ConsoleHandler(); logger_A_B.addHandler(handler2); Handler handler3 = new ConsoleHandler(); logger_A_B_C.addHandler(handler3); alternativ kann diese Struktur auch mit einem properties-File mit dem folgenden Inhalt erzeugt werden: A.handlers = java.util.logging.ConsoleHandler 7/11 18. Oktober 2005 A.B.handlers = java.util.logging.ConsoleHandler A.B.C.handlers = java.util.logging.ConsoleHandler Durch dieses properties-File werden lediglich die verwendeten Handler den entsprechenden Loggern zugeordnet. Die gewünschte hierachische Struktur wird automatisch durch die Namen der verwendeten Logger erzeugt sobald diese in der Anwendung initialisiert werden. Die Initialisierung erfolgt in der Anwendung durch die statische Methode Logger.getLogger(“...“). • Mit dem folgenden Befehl wird durch jeden der 3 verwendeten Handler die Meldung “hello A.B.C!“ ausgegeben: logger_A_B_C.log(Level.INFO, "hello A.B.C!"); • Der folgende Befehl gibt lediglich über handler1 und handler2 die Meldung “hello A.B.A!“ aus: logger_A_B_A.log(Level.INFO, “hello A.B.A!“); Nun werden zusätzlich die Logging-Level der einzelnen Handler und Logger gesetzt, so dass die folgende Struktur entsteht: default root-Logger (““) default Logger (“A“) default handler1 "hello A.B.C!" default Logger (“A.A“) WARN. Logger (“A.B“) default handler2 "hello A.B.C!" Level vom parent default Logger (“A.B.B“) default Logger (“A.B.A“) log(Level.INFO, "hello A.B.A!"); INFO Logger (“A.B.C“) WARN. handler3 log(Level.INFO, "hello A.B.C!"); Logging-Meldungen: weiter geleitet/ object level Logging-Level angenommen nicht angenommen Logging-Level wird vom vom parent-Logger übernommen Symbole: Objekt (Logger/Handler) Das Setzen der Level erfolgt mit den folgenden zusätzlichen Methodenaufrufen: logger_A_B_C.setLevel(Level.INFO); logger_A_B.setLevel(Level.WARNING); handler3.setLevel(Level.WARNING); • Der folgende Befehl gibt keine Meldung aus: logger_A_B_A.log(Level.INFO, "hello A.B.A!"); Für logger_A_B_A wurde kein Logging-Level explizit gesetzt, der Logger übernimmt also den Logging-Level WARNING seines parent-Loggers wie in Abschnitt 1.1.1 beschrieben. Die Meldung mit dem Level INFO wird also nicht angenommen. • Der folgende Befehlt gibt über die handler1 und handler2 die Meldung “hello A.B.C“ aus: logger_A_B_C.log(Level.INFO, "hello A.B.C!"); Der Logger logger_A_B_C wird auf den level INFO gesetzt, die Meldung mit dem Level INFO wird also angenommen und an den registrierten Handler sowie den parent-Logger 8/11 18. Oktober 2005 weitergegeben. Der parent-Logger von logger_A_B_C hat zwar den Level WARNING, er leitet die Meldung jedoch ebenfalls an die registrierten Handler und an seinen parentLogger weiter, da die Meldung nicht über die Methode log(“...“) von der Anwendung abgesetzt wurde, sondern von einem anderen Logger an ihn weitergeleitet wurde. 1.4 Programmierrichtlinien In diesem Abschnitt werden verschiedenen Vorschläge für die Verwendung der Logging API zusammengefasst. 1.4.1 Initialisierung Für jede Klasse einer Anwendung kann wie folgt ein Logger initialisiert werden: private static final Logger LOGGER = Logger.getLogger(<Klassenname>.class.getName()); Diese Methode bietet die folgenden Vorteile • Der Logger ist static und wird daher von allen Instanzen dieser Klasse verwendet. • In einer Anwendung bilden die mit dieser Methode initialisierten Logger die Klassen- und Packagestruktur der Anwendung nach. • Beim Umbenennen einer Klasse durch ein Refactoring-Tool wird auch der Name des Loggers umbenannt 1.4.2 Logging Meldungen Jedem Logging Level ist in der Klasse Logger eine Methode zugeordnet, mit der Meldungen der entsprechenden Priorität an den Logger übermittelt werden können. Beispielsweise wird beim Aufruf der Methode info(“Meldung“) die Meldung mit der Priorität INFO weitergeleitet. Diese Methode können verwendet werden, um bequem ein Ereignis mit dem entsprechenden Level zu melden. Häufig werden beim Aufruf der Logging Methoden die Meldungen aus mehreren Strings zusammengesetzt. Beispiel: LOGGER.log(Level.INFO, “Verbindungsabau über Port “ + Portnumber + “ mit “ + IPnumber + “ war erfolgreich“); Da das Zusammenfügen von Strings mit dem “+“ Operator in Java aufwändig ist, ist es in solchen Fällen sinnvoll zunächst zu prüfen, ob der Logging Level vom Logger überhaupt bearbeitet wird: if (LOGGER.isEnabled(Level.INFO)) { LOGGER.log(Level.INFO, “Verbindungsabau über Port “ + Portnumber + “ mit “ + IPnumber + “ war erfolgreich“); } 1.4.3 Debugging Für das Debugging einer Anwendung wird häufig ein Komandozeilenparameter verwendet. Dieser wird beim Start abgefragt und als ein boolean Flag innerhalb der Anwendung implementiert. Vor der Ausgabe von Debugging Informationen wird jeweils überprüft, ob dieses Flag gesetzt ist. Durch das folgenden Schema kann dieses Flag ersetzt werden: • Der Komandozeilenparameter wird abgefragt. Falls gewünscht wird der Log-Level für die Logger der Anwendung auf einen definierten Wert gesetzt. Dies kann geschehen, indem man z.B. den Logging-Level für den root-Logger (““) auf eine entsprechend niedrigere Priorität setzt. Damit 9/11 18. Oktober 2005 werden in der gesamte Anwendung alle Meldungen mit der gleichen oder höheren Priorität ausgegeben. Der Zugriff auf dem root-Logger wird in Abschnitt 1.4.4 erläutert. Falls nur die Meldungen eines Teilpakets ausgegeben werden sollen kann natürlich auch nur der Logger dieses Teilpakets durch das Setzen der Priorität entsprechen konfiguriert werden. • Bei der Ausgabe von Debugging Meldungen werden die Meldungen mit einer definierten Priorität an den Logger geschickt. Diese Priorität muss höher sein, als die zuvor für die Konfiguration der Logger verwendetet Priorität, damit die Meldungen angenommen und durch den Handler später ausgegeben werden. Durch Abfrage eines Kommandozeilenparameters und entsprechendes Setzen der Log-Level kann also die Ausgabe ein- oder ausgeschaltet werden. Vorteile: • Das Verwalten des debug-Flags und ggf. die Weitergabe des Flags an Komponenten einer Anwendung entfällt. • Es können bequem mehrere debug-Levels implementiert werden. Nachteile: • Es muss darauf geachtet werden, dass der Logging Level im Handler nicht auf einem zu hohen Wert eingestellt werden, so dass die gewünschten Debug Meldungen im Handler versehentlich ausgefiltert werden. 1.4.4 root-Handler und root-Logger In einer einfachen Anwendung genügt es den root-Handler für die Ausgabe von LoggingMeldungen zu verwenden. Damit können alle Meldungen direkt auf die Konsole ausgegeben werden. Standardmäßig werden alle Meldungen mit dem Level INFO oder höher ausgegeben. Möchte man in der Anwendung auch Meldungen mit niedrigerem Level ausgeben, so muss der Level des root-Loggers und des root-Handlers verändert werden. Dies kann mit dem folgenden Codefragment implementiert werden: // der DefaultHandler hängt am root-Logger Logger rootLogger = Logger.getLogger(""); Handler[] handlers = rootLogger.getHandlers(); // einen ConsoleHandler finden: ConsoleHandler consoleHandler = null; for (int i=0; i < handlers.length; i++) { if (handlers[i] instanceof ConsoleHandler) { consoleHandler = (ConsoleHandler) handlers[i]; } } // kein ConsoleHandler am root-Logger ?! // wir hängen selbst einen an: if (consoleHandler == null) { consoleHandler = new java.util.logging.ConsoleHandler(); Logger.getLogger("").addHandler(consoleHandler); } consoleHandler.setLevel(Level.FINE); rootLogger.setLevel(Level.FINE); Damit werden alle Logging-Meldungen der Anwendung mit dem Level FINE oder höher ausgegeben. 10/11 18. Oktober 2005 1.5 Kurzanleitung In diesem Abschnitt werden noch einmal die wichtigsten Schritte zur Verwendung der Logging-API beschrieben. 1.5.1 Konfigurationsfile Ein minimales Konfigurationsfile, mit dem alle Meldungen auf die Konsole ausgegeben werden und der root-Logger alle Meldungen annimmt, kann wie folgt aussehen: handlers = java.util.logging.ConsoleHandler java.util.logging.ConsoleHandler.level = ALL .level = ALL Dieses File kann unter dem Dateinamen logging.properties gespeichert werden. Möchte man nur für einen Teil der Anwendung alle Meldungen ausgeben, für alle anderen Teile der Anwendung lediglich Meldung mit dem Level WARNING oder höher: handlers = java.util.logging.ConsoleHandler java.util.logging.ConsoleHandler.level = ALL .level = WARNING teil.package.level = ALL 1.5.2 Start der Anwendung Um dem LoggingManager das oben beschriebene Konfigurationsfile zu übergeben, muss die JavaAnwendung mit dem zusätzlichen Parameter -Djava.util.logging.config.file=logging.properties gestartet werden. 1.5.3 Meldungen In der Anwendung selbst wird zunächst der Logger innerhalb einer Klasse mit dem folgenden Befehl erzeugt: private static final Logger LOGGER = Logger.getLogger(MeineKlasse.class.getName()); Eine Meldung mit dem Level INFO wird mit folgendem Kommando abgesetzt: LOGGER.log(Level.INFO,“eine info-Meldung“); Um einen Methodeneintritt zu melden kann folgender Code verwendet werden: LOGGER.entering(“Klassennamen“, “Methodennamen“); Die Meldung wird dann mit dem Level FINER ausgegeben. Falls gewünscht können zusätzlich noch die Parameter der Methode ausgegeben werden: LOGGER.entering( “Klassennamen“, “Methodennamen“, new Object[] {"param1", "param2"}); 11/11