Logging mit Log4j

+ andere TechDocs
+ Apache Log4j
+


Log4j ist ein Framework zur Unterstützung zentral konfiguriertem Loggings.

Zur Laufzeit und ohne Neucompilierung kann der Logging-Level umgeschaltet werden, um zusätzliche Meldungen zur Fehlersuche einzuschalten.

'Logger' definieren den Logging-Priority-Level und über welche 'Appender' die Logging-Meldungen ausgegeben werden.

'Appender' definieren den Ausgabekanal, zum Beispiel Console, Datei, DailyRollingFile, E-Mail, Socket, Telnet, JDBC und JMS.

'Layout' definiert die Ausgabeformatierung, zum Beispiel 'SimpleLayout', 'PatternLayout', 'HTMLLayout' und 'XMLLayout'.

Die Log4j-Konfiguration erfolgt wahlweise entweder programmatisch im Java-Sourcecode, über eine Property-Datei oder eine XML-Datei.



Inhalt

  1. Simple Logging
  2. Logging mit PatternLayout und DailyRollingFileAppender
  3. Logging mit Properties-Konfigurationsdatei
  4. Logging mit XML-Konfigurationsdatei
  5. Logging mit MDC-Variablen und eigener Logger-Klasse
  6. Logging mit zweitem Logger und eigener Appender-Klasse
  7. "log4j.additivity...=false"
  8. Asynchrones Logging
  9. Weitere Tipps
  10. Log4j 2.x


Simple Logging

  1. Installieren Sie ein aktuelles Java SE JDK, zum Beispiel wie beschrieben unter java-install.htm
  2. Erzeugen Sie folgende Verzeichnisstruktur ('\MeinWorkspace' kann bei Ihnen anders lauten) (Sie können stattdessen auch 'Log4j-Test' in Eclipse als Java-Projekt anlegen) (kontrollieren Sie die Struktur mit "tree /F"):

    [\MeinWorkspace]
      '- [Log4j-Test]
           |- [bin]
           |- [lib]
           |- [logs]
           '- [src]
                '- [meinpackage1]
    
  3. Downloaden Sie die Log4j-Installationsdatei (z.B. 'apache-log4j-1.2.16.zip') von http://logging.apache.org/log4j/docs/download.html. Extrahieren Sie aus dem Archiv die Log4j-.jar-Bibliothek (z.B. 'log4j-1.2.16.jar'). Kopieren Sie diese in das 'lib'-Unterverzeichnis.
  4. Sie können entweder die Sourcen downloaden oder, wie im Folgenden beschrieben wird, selbst erzeugen.
  5. Speichern Sie in 'src\meinpackage1' die folgende Datei 'Main.java':

    package meinpackage1;
    
    import org.apache.log4j.*;
    
    public class Main
    {
      private static Logger logger = Logger.getRootLogger();
    
      public static void main( String[] args )
      {
        try {
          SimpleLayout layout = new SimpleLayout();
          ConsoleAppender consoleAppender = new ConsoleAppender( layout );
          logger.addAppender( consoleAppender );
          FileAppender fileAppender = new FileAppender( layout, "logs/MeineLogDatei.log", false );
          logger.addAppender( fileAppender );
          // ALL | DEBUG | INFO | WARN | ERROR | FATAL | OFF:
          logger.setLevel( Level.WARN );
        } catch( Exception ex ) {
          System.out.println( ex );
        }
        logger.debug( "Meine Debug-Meldung" );
        logger.info(  "Meine Info-Meldung"  );
        logger.warn(  "Meine Warn-Meldung"  );
        logger.error( "Meine Error-Meldung" );
        logger.fatal( "Meine Fatal-Meldung" );
      }
    }
    
  6. Öffnen Sie ein Kommandozeilenfenster ('Windows-Taste' + 'R', 'cmd') und geben Sie folgende Befehle ein (unter Windows können Sie den Kommandotext im Webbrowser mit gedrückter Maustaste markieren, mit 'Strg+C' zwischenspeichern und irgendwo im Kommandozeilenfenster mit rechter Maustaste, 'Einfügen' und 'Return' ausführen):

    cd \MeinWorkspace\Log4j-Test

    tree /F

    set CLASSPATH=bin;lib/*

    javac -d bin src/meinpackage1/Main.java

    java meinpackage1.Main

    type logs\MeineLogDatei.log

    Passen Sie den Pfad '\MeinWorkspace\Log4j-Test' an Ihr '<projektverzeichnis>' an.

  7. In diesem Beispiel wird der Logger programmatisch konfiguriert, um möglichst einfach einige Grundprinzipien zu zeigen. Diese programmatische Konfiguration kann bei Kombinationen verschieder Module problematisch sein, wenn die verschieden Module sich gegenseitig die Konfiguration überschreiben. Deshalb sollte normalerweise die in anderen Beispielen weiter unten gezeigte Konfiguration per Properties- oder XML-Konfigurationsdatei bevorzugt werden.
  8. Es kann entweder der Root-Logger verwendet werden (über 'Logger.getRootLogger()', wie hier im Beispiel) oder ein eigener Logger definiert werden (wird später gezeigt).
  9. Normalerweise wird nur ein Appender verwendet. Hier in diesem Beispiel werden zwei Appender eingesetzt, zum einen um zu verdeutlichen, dass mehrere Appender gleichzeitig verwendet werden können und zum anderen um zwei verschiedene Appender zu demonstrieren. Sie erhalten die Logging-Meldungen deshalb sowohl über den 'ConsoleAppender' im Kommandozeilenfenster als auch über den 'FileAppender' in der Logdatei 'MeineLogDatei.log'.
  10. Ändern Sie im 'setLevel()'-Aufruf den Logging-Level auf verschiedene der angegebenen sieben Möglichkeiten ('ALL, DEBUG, INFO, WARN, ERROR, FATAL, OFF') und führen Sie jedesmal die genannten 'javac'- und 'java'-Kommandozeilenbefehle aus. Je nach gesetztem Logging-Level erhalten Sie verschieden viele Ausgabezeilen.
  11. Ändern Sie im 'new FileAppender()'-Aufruf den letzten Parameter auf 'true', kompilieren Sie mit dem genannten 'javac'-Kommando, und führen Sie die Anwendung mehrmals mit dem genannten 'java'-Kommando aus. Während vor der Änderung 'MeineLogDatei.log' bei jedem Start der Anwendung geleert wurde, bleiben jetzt alle vorherigen Logmeldungen erhalten.
  12. Testen Sie weitere Appender:

    AsyncAppender

    ConsoleAppender

    DailyRollingFileAppender

    ExternallyRolledFileAppender

    FileAppender

    JDBCAppender

    JMSAppender

    LF5Appender

    NTEventLogAppender

    RollingFileAppender

    SMTPAppender

    SocketAppender

    SocketHubAppender

    SyslogAppender

    TelnetAppender

    WriterAppender

  13. Testen Sie weitere Layout-Typen:

    SimpleLayout

    PatternLayout

    HTMLLayout

    XMLLayout



Logging mit PatternLayout und DailyRollingFileAppender

  1. Erweitern Sie die oben gezeigte Verzeichnisstruktur im src-Verzeichnis um das Package 'meinpackage2'.
  2. Speichern Sie in 'src\meinpackage2' die folgende Datei 'Main.java':

    package meinpackage2;
    
    import org.apache.log4j.*;
    
    public class Main
    {
      private static Logger logger = Logger.getRootLogger();
    
      public static void main( String[] args )
      {
        try {
          PatternLayout layout = new PatternLayout( "%d{ISO8601} %-5p [%t] %c: %m%n" );
          DailyRollingFileAppender fileAppender =
            new DailyRollingFileAppender( layout, "logs/MeineLogDatei.log", "'.'yyyy-MM-dd_HH-mm" );
          logger.addAppender( fileAppender );
          logger.setLevel( Level.ALL );
        } catch( Exception ex ) {
          System.out.println( ex );
        }
        new MeineKlasse2();
      }
    }
    

    Und die folgende Datei 'MeineKlasse2.java':

    package meinpackage2;
    
    import org.apache.log4j.Logger;
    
    public class MeineKlasse2
    {
      private static Logger logger = Logger.getLogger( MeineKlasse2.class );
    
      MeineKlasse2()
      {
        logger.info(  "Meine Info-Meldung aus MeineKlasse2."  );
        logger.error( "Meine Error-Meldung aus MeineKlasse2." );
      }
    }
    
  3. Öffnen Sie ein Kommandozeilenfenster und geben Sie folgende Befehle ein:

    cd \MeinWorkspace\Log4j-Test

    del logs\*.log*

    set CLASSPATH=bin;lib/*

    javac -d bin src/meinpackage2/*.java

    java meinpackage2.Main

    type logs\MeineLogDatei.log*

    Passen Sie den Pfad '\MeinWorkspace\Log4j-Test' an Ihr '<projektverzeichnis>' an.

  4. Zu Beginn der Anwendung (hier in der 'main()'-Methode) wird Log4j konfiguriert.
    Danach können auch in anderen Klassen einfach über 'Logger.getLogger()' Logger instanziiert werden, die diese Konfiguration übernehmen.
  5. Hier im Beispiel ist ein etwas aufwändigerer Appender gezeigt. Der 'DailyRollingFileAppender' speichert in vorgegebenen Zeitintervallen die Logdatei unter einem Dateinamen mit Zeitstempel (z.B. 'MeineLogDatei.log.2005-05-22_22-40') und leert die aktuelle Logdatei (z.B. 'MeineLogDatei.log'), damit sie nicht zu groß wird. Das Zeitintervall wird durch das dem Konstruktor übergebene 'datePattern' definiert, zum Beispiel so:

    '.'yyyy-MM-dd_HH-mm startet minütlich eine neue Logdatei (die Uhrzeit darf nicht mit ':' definiert werden)
    '.'yyyy-MM-dd startet täglich eine neue Logdatei

    Um den Effekt beobachten zu können, müssen Sie die letzten beiden der oben genannten Kommandos nach einer Minute noch mal ausführen.

  6. Es wird nicht das 'SimpleLayout', sondern stattdessen das 'PatternLayout' verwendet. Es generiert einen Meldetext, dessen Format durch das dem Konstruktor übergebene 'ConversionPattern' definiert wird:

    %d{ISO8601} Zeitstempel im internationalen ISO-8601-Format 'yyyy-MM-dd HH:mm:ss,SSS'
    %-5pPrioritäts-Level (z.B. 'INFO'), das '-' bedeutet linksbündig, die '5' bedeutet verlängert auf 5 Zeichen (damit z.B. 'INFO'- und 'DEBUG'-Ausgaben bündig untereinander stehen)
    %tThread-Name
    %cKategoriename
    %mÜbergebener Meldetext
    %nZeilenwechsel
    %X{...}MDC-Variable (Message Diagnostic Context) (gesetzt mit 'MDC.put()', siehe unten)
  7. Fügen Sie weitere 'Conversion Characters' beim 'ConversionPattern' des 'PatternLayout' hinzu. Erklärungen finden Sie in der API-Javadoc zur 'PatternLayout'-Klasse.


Logging mit Properties-Konfigurationsdatei

  1. Erweitern Sie die oben gezeigte Verzeichnisstruktur im src-Verzeichnis um das Package 'meinpackage3'.
  2. Speichern Sie in 'src\meinpackage3' die folgende Datei 'Main.java':

    package meinpackage3;
    
    import org.apache.log4j.PropertyConfigurator;
    
    public class Main
    {
      public static void main( String[] args )
      {
        PropertyConfigurator.configureAndWatch( "log4j-3.properties", 60*1000 );
        new MeineKlasse3();
      }
    }
    

    Und die folgende Datei 'MeineKlasse3.java':

    package meinpackage3;
    
    import org.apache.log4j.Logger;
    
    public class MeineKlasse3
    {
      private static Logger logger = Logger.getLogger( MeineKlasse3.class );
    
      MeineKlasse3()
      {
        logger.info(  "Meine Info-Meldung aus MeineKlasse3."  );
        logger.error( "Meine Error-Meldung aus MeineKlasse3." );
      }
    }
    
  3. Speichern Sie im '<projektverzeichnis>' die folgende Datei 'log4j-3.properties':

    log4j.rootLogger=DEBUG, MeinConsoleAppender, MeinDaRoFiAppender
    
    log4j.appender.MeinConsoleAppender=org.apache.log4j.ConsoleAppender
    log4j.appender.MeinConsoleAppender.layout=org.apache.log4j.PatternLayout
    log4j.appender.MeinConsoleAppender.layout.ConversionPattern=%d{ISO8601} %-5p [%t] %c: %m%n
    
    log4j.appender.MeinDaRoFiAppender=org.apache.log4j.DailyRollingFileAppender
    log4j.appender.MeinDaRoFiAppender.datePattern='.'yyyy-MM-dd_HH-mm
    log4j.appender.MeinDaRoFiAppender.file=logs/MeineLogDatei.log
    log4j.appender.MeinDaRoFiAppender.layout=org.apache.log4j.PatternLayout
    log4j.appender.MeinDaRoFiAppender.layout.ConversionPattern=%d{ISO8601} %-5p [%t] %c: %m%n
    
  4. Öffnen Sie ein Kommandozeilenfenster und geben Sie folgende Befehle ein:

    cd \MeinWorkspace\Log4j-Test

    del logs\*.log*

    set CLASSPATH=bin;lib/*

    javac -d bin src/meinpackage3/*.java

    java meinpackage3.Main

    type logs\MeineLogDatei.log

    Passen Sie den Pfad '\MeinWorkspace\Log4j-Test' an Ihr '<projektverzeichnis>' an.

  5. Zu Beginn der Anwendung (hier in der 'main()'-Methode) wird über 'PropertyConfigurator.configureAndWatch()' der Dateiname 'log4j-3.properties' einmalig bekannt gegeben und die Log4j-Konfiguration geladen.
    Danach können auch in anderen Klassen einfach über 'Logger.getLogger()' Logger instanziiert werden, die ihre Konfiguration aus der Konfigurationsdatei beziehen.
    Die configureAndWatch()-Methode ermöglicht zweierlei: Sie können vorgeben, dass die Konfigurationsdatei regelmäßig auf Änderungen überprüft wird, so dass Änderungen zur Laufzeit übernommen werden. Außerdem nützen wir bei den Beispielen auch noch aus, dass wir (für die unterschiedlichen Beispiele) nicht den Defaultnamen log4j.properties, sondern andere Namen für die Konfigurationsdatei verwenden können. Wenn Sie beides nicht benötigen, können Sie den Defaultnamen verwenden, und brauchen configureAndWatch() nicht zu verwenden.
  6. In der Konfigurationsdatei 'log4j-3.properties' wird entweder der Root-Logger 'rootLogger' verwendet (wie hier im Beispiel) oder ein eigener Logger definiert (wird später gezeigt). Der Logger referenziert seine Appender (hier 'MeinConsoleAppender' und 'MeinDaRoFiAppender').
  7. Das Beispiel verwendet wieder den 'DailyRollingFileAppender' und das 'PatternLayout' (siehe oben).
  8. Sie können für bestimmte Packages oder Klassen spezielle Logging-Level einstellen. Tragen Sie dazu in die 'log4j-3.properties'-Datei Zeilen ein wie zum Beispiel:

    log4j.logger.meinpackage3=DEBUG



Logging mit XML-Konfigurationsdatei

  1. Erweitern Sie die oben gezeigte Verzeichnisstruktur im src-Verzeichnis um das Package 'meinpackage4'.
  2. Speichern Sie in 'src\meinpackage4' die folgende Datei 'Main.java':

    package meinpackage4;
    
    import org.apache.log4j.xml.DOMConfigurator;
    
    public class Main
    {
      public static void main( String[] args )
      {
        DOMConfigurator.configureAndWatch( "log4j-4.xml", 60*1000 );
        new MeineKlasse4();
      }
    }
    

    Und die folgende Datei 'MeineKlasse4.java':

    package meinpackage4;
    
    import org.apache.log4j.Logger;
    
    public class MeineKlasse4
    {
      private static Logger logger = Logger.getLogger( MeineKlasse4.class );
    
      MeineKlasse4()
      {
        logger.info(  "Meine Info-Meldung aus MeineKlasse4."  );
        logger.error( "Meine Error-Meldung aus MeineKlasse4." );
      }
    }
    
  3. Speichern Sie im Verzeichnis '<projektverzeichnis>' die folgende Datei 'log4j-4.xml':

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
    
    <log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
    
      <appender name="MeinAppender" class="org.apache.log4j.DailyRollingFileAppender">
        <param name="datePattern" value="'.'yyyy-MM-dd_HH-mm" />
        <param name="file" value="logs/MeineLogDatei.log" />
        <param name="Append" value="true" />
        <layout class="org.apache.log4j.PatternLayout">
          <param name="ConversionPattern" value="%d{ISO8601} %-5p [%t] %c: %m%n" />
        </layout>
      </appender>
    
      <root>
        <priority value="INFO" />
        <appender-ref ref="MeinAppender" />
      </root>
    
    </log4j:configuration>
    
  4. Öffnen Sie ein Kommandozeilenfenster und geben Sie folgende Befehle ein:

    cd \MeinWorkspace\Log4j-Test

    del logs\*.log*

    set CLASSPATH=bin;lib/*

    javac -d bin src/meinpackage4/*.java

    java meinpackage4.Main

    type logs\MeineLogDatei.log

    Passen Sie den Pfad '\MeinWorkspace\Log4j-Test' an Ihr '<projektverzeichnis>' an.

  5. Zu Beginn der Anwendung (hier in der 'main()'-Methode) wird über 'DOMConfigurator.configureAndWatch()' der Dateiname 'log4j-4.xml' einmalig bekannt gegeben und die Log4j-Konfiguration geladen.
    Danach können auch in anderen Klassen einfach über 'Logger.getLogger()' Logger instanziiert werden, die ihre Konfiguration aus der Konfigurationsdatei beziehen.
    Auch hier gilt wieder: Falls Sie Änderungen nicht zur Laufzeit übernehmen wollen und keinen anderen als den Defaultnamen log4j.xml verwenden wollen, bräuchten Sie configureAndWatch() nicht zu verwenden.
  6. In der Konfigurationsdatei 'log4j-4.xml' wird entweder der Root-Logger '<root>' verwendet (wie hier im Beispiel) oder ein eigener Logger definiert (wird später gezeigt). Der Logger referenziert seinen Appender (hier 'MeinAppender').
  7. Das Beispiel verwendet wieder den 'DailyRollingFileAppender' und das 'PatternLayout' (siehe oben).


Logging mit MDC-Variablen und eigener Logger-Klasse

  1. Erweitern Sie die oben gezeigte Verzeichnisstruktur um ein 'res'-Verzeichnis und im src-Verzeichnis um das Package 'meinpackage5'.
  2. Speichern Sie in 'src\meinpackage5' die folgende Datei 'Main.java':

    package meinpackage5;
    
    public class Main
    {
      public static void main( String[] args )
      {
        new MeineKlasse5();
      }
    }
    

    Und die folgende Datei 'MeineKlasse5.java':

    package meinpackage5;
    
    import org.apache.log4j.Level;
    
    public class MeineKlasse5
    {
      private static MeinLogger logger = MeinLogger.getInstance();
    
      MeineKlasse5()
      {
        logger.log( Level.ERROR, this, "E002", new String[] { "abc", "xyz" } );
      }
    }
    

    Und die folgende Datei 'MeinLogger.java':

    package meinpackage5;
    
    import java.text.MessageFormat;
    import java.util.MissingResourceException;
    import java.util.ResourceBundle;
    import org.apache.log4j.*;
    import org.apache.log4j.xml.DOMConfigurator;
    
    public class MeinLogger
    {
      private static final String LOG4J_CONFIG_FILE  = "log4j-5.xml";
      private static final String MEIN_LOGGER_NAME   = "MeinLogger";
      private static final String MESSAGES_RESBUNDLE = "messages";
      private static ResourceBundle messagesResBundle;
      private static MeinLogger meinLogger;
      private static Logger log4jLogger;
    
      // private damit Singleton
      private MeinLogger()
      {
        init();
      }
    
      private synchronized void init()
      {
        try {
          DOMConfigurator.configureAndWatch( LOG4J_CONFIG_FILE, 60*1000 );
          log4jLogger = Logger.getLogger( MEIN_LOGGER_NAME );
          messagesResBundle = ResourceBundle.getBundle( MESSAGES_RESBUNDLE );
          log4jLogger.setResourceBundle( messagesResBundle );
        } catch( MissingResourceException ex ) {
          System.err.println( "Fehler: '" + MESSAGES_RESBUNDLE + "'-.properties-Datei fehlt!" );
        } catch( Exception ex ) {
          System.err.println( "Fehler bei Logger-Initialisierung!" );
        }
      }
    
      // Singleton-Instanz
      public static synchronized MeinLogger getInstance()
      {
        if( meinLogger == null ) meinLogger = new MeinLogger();
        return meinLogger;
      }
    
      public synchronized void log( Level level, Object caller, String id, Object[] parms )
      {
        MDC.put( "clss", caller.getClass().getName() );
        MDC.put( "id", id );
    
        String message = id;
        if( null != messagesResBundle ) {
          try {
            message = messagesResBundle.getString( id );
          } catch( MissingResourceException ex ) {/**/}
        }
        if( null != parms )
          message = MessageFormat.format( message, parms );
    
        switch( level.toInt() ) {
          case Priority.ALL_INT:
          case Priority.DEBUG_INT: log4jLogger.debug( message ); break;
          case Priority.INFO_INT:  log4jLogger.info(  message ); break;
          case Priority.WARN_INT:  log4jLogger.warn(  message ); break;
          case Priority.ERROR_INT: log4jLogger.error( message ); break;
          case Priority.FATAL_INT: log4jLogger.fatal( message ); break;
        }
      }
    
      public boolean isEnabledFor( Level level )
      {
         return log4jLogger.isEnabledFor( level );
      }
    }
    
  3. Speichern Sie im Verzeichnis '<projektverzeichnis>' die folgende Datei 'log4j-5.xml':

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
    
    <log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
    
      <appender name="MeinStandardAppender" class="org.apache.log4j.DailyRollingFileAppender">
        <param name="datePattern" value="'.'yyyy-MM-dd" />
        <param name="file" value="logs/MeineLogDatei.log" />
        <param name="Append" value="true" />
        <layout class="org.apache.log4j.PatternLayout">
          <param name="ConversionPattern" value="%d{ISO8601} %-5p %X{id} [%t] %X{clss}: %m%n" />
        </layout>
      </appender>
    
      <root>
        <priority value="INFO" />
        <appender-ref ref="MeinStandardAppender" />
      </root>
    
    </log4j:configuration>
    
  4. Speichern Sie im Verzeichnis 'res' die folgende Datei 'messages.properties':

    E002=My Message with the two Parameters {0} and {1}.
    

    Und die folgende Datei 'messages_de.properties':

    E002=Meine Meldung mit den zwei Parametern {0} und {1}.
    
  5. Ihre Verzeichnisstruktur enthält jetzt folgende Verzeichnisse und Dateien (kontrollieren Sie es mit "tree /F"):

    [\MeinWorkspace]
      '- [Log4j-Test]
           |- [bin]
           |- [lib]
           |    '- log4j-1.2.16.jar
           |- [logs]
           |- [res]
           |    |- messages.properties
           |    '- messages_de.propertie
           |- [src]
           |    '- [meinpackage5]
           |         |- Main.java
           |         |- MeineKlasse5.java
           |         '- MeinLogger.java
           '- log4j-5.xml
    
  6. Falls Sie das Beispiel in Eclipse ausführen wollen, müssen Sie das res-Verzeichnis zum Build-Path hinzufügen: Klicken Sie im Eclipse-Package-Explorer mit der rechten Maustaste auf den Projektnamen Log4j-Test und wählen Sie: 'Build Path' | 'Configure Build Path...' | Tabulatorreiter 'Source' | 'Add Folder...' | Aktivierung von 'res' | 'OK' | 'OK'. Dann können Sie im Eclipse-Package-Explorer mit der rechten Maustaste auf die Main.java im Package src/meinpackage5 klicken und 'Run As' | 'Java Application' wählen.
  7. Öffnen Sie ein Kommandozeilenfenster und geben Sie folgende Befehle ein:

    cd \MeinWorkspace\Log4j-Test

    del logs\*.log*

    tree /F

    set CLASSPATH=bin;res;lib/*

    javac -d bin src/meinpackage5/*.java

    java meinpackage5.Main

    type logs\MeineLogDatei.log

    Passen Sie den Pfad '\MeinWorkspace\Log4j-Test' an Ihr '<projektverzeichnis>' an.

  8. Als Ergebnis erhalten Sie in etwa:

    2005-05-23 22:04:47,019 ERROR E002 [main] meinpackage5.MeineKlasse5: Meine Meldung mit den zwei Parametern abc und xyz.

  9. Die 'main()'-Methode braucht nicht mehr 'DOMConfigurator.configureAndWatch()' aufzurufen, da dies in 'MeinLogger.init()' geschieht.

    Um den Logger zu benutzen, wird in 'MeineKlasse5' nicht der Log4j-'Logger', sondern der eigene Logger 'MeinLogger' instanziiert.

    Um verschiedene Sprachen realisieren zu können, wird nicht direkt der Meldetext, sondern nur die Message-ID (im Beispiel 'E002') dem Logger übergeben. Für jede implementierte Sprache müssen die Meldetexte in 'messages_XX.properties'-Dateien vorgehalten werden, wobei 'XX' durch das Sprachkürzel ersetzt werden muss (z.B. 'de'). Zusätzlich können in den Meldetext einzusetzende Parameter ('{0}', '{1}', ...) als 'String[]' übergeben werden.

  10. 'MeinLogger' erzeugt nicht nur den Meldetext aus der Message-ID, sondern erzeugt zusätzlich zwei MDC-Strings die dem 'Message Diagnostic Context' des Log4j hinzugefügt werden. Mit 'MDC.put()' werden unter den angegebenen Namen 'clss' und 'id' zwei Text-Strings abgelegt, die über die Ausdrücke '%X{clss}' und '%X{id}' im 'ConversionPattern' des 'PatternLayout' in der 'log4j-5.xml'-Datei im Log-Text eingefügt werden.

  11. Die Methode 'isEnabledFor()' kann verwendet werden, um dem Logger für einen bestimmten Priority-Level (z.B. 'DEBUG') zu übergebende aber zeitaufwändig zu berechnende Ausdrücke nur dann berechnen zu müssen, wenn wirklich der entsprechende Level eingeschaltet ist (allerdings muss bereits der Logger-Level entsprechend gesetzt sein, nur beim Appender genügt nicht).



Logging mit zweitem Logger und eigener Appender-Klasse

  1. Erweitern Sie die oben gezeigte Verzeichnisstruktur im src-Verzeichnis um das Package 'meinpackage6'.
  2. Speichern Sie in 'src\meinpackage6' die folgende Datei 'Main.java':

    package meinpackage6;
    
    import org.apache.log4j.xml.DOMConfigurator;
    
    public class Main
    {
      public static void main( String[] args )
      {
        DOMConfigurator.configureAndWatch( "log4j-6.xml", 60*1000 );
        new MeineKlasse6();
      }
    }
    

    Und die folgende Datei 'MeineKlasse6.java':

    package meinpackage6;
    
    import org.apache.log4j.Logger;
    
    public class MeineKlasse6
    {
      private static Logger stdLogger = Logger.getLogger( MeineKlasse6.class );
      private static Logger hbtLogger = Logger.getLogger( "MeinHeartbeatLogger" );
    
      MeineKlasse6()
      {
        stdLogger.info(  "Meine Info-Meldung aus MeineKlasse6." );
        stdLogger.error( "Meine Error-Meldung aus MeineKlasse6." );
        hbtLogger.info(  "Meine HeartbeatLogger-Meldung." );
      }
    }
    

    Und die folgende Datei 'HeartbeatFileAppender.java':

    package meinpackage6;
    
    import java.io.*;
    import org.apache.log4j.FileAppender;
    import org.apache.log4j.helpers.LogLog;
    import org.apache.log4j.spi.LoggingEvent;
    
    public class HeartbeatFileAppender extends FileAppender
    {
      private RandomAccessFile raFile;
    
      /** @see org.apache.log4j.FileAppender#activateOptions() */
      @Override
      public void activateOptions()
      {
        super.activateOptions();
        if( null == raFile ) {
          if( null != fileName ) {
            try {
              raFile = new RandomAccessFile( fileName, "rw" );
            } catch( FileNotFoundException ex ) { //
            }
          }
          if( null == raFile ) {
            LogLog.error( "Heartbeat-Logdatei '" + fileName
                          + "' kann nicht angelegt werden fuer '"
                          + name + "'." );
          }
        }
      }
    
      /** @see org.apache.log4j.WriterAppender#subAppend(LoggingEvent) */
      @Override
      protected void subAppend( LoggingEvent event )
      {
        // Nicht 'super.subAppend(event)' aufrufen!
        if( null != raFile ) {
          try {
            raFile.seek( 0 );
            raFile.setLength( 0 );
            raFile.writeBytes( getLayout().format( event ) );
          } catch( IOException ex ) {
            LogLog.error( "Probleme beim Schreiben in Heartbeat-Logdatei '"
                          + fileName + "' fuer '" + name + "'." );
          }
        }
      }
    }
    
  3. Speichern Sie im Verzeichnis '<projektverzeichnis>' die folgende Datei 'log4j-6.xml':

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
    
    <log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/">
    
      <appender name="MeinStandardAppender" class="org.apache.log4j.DailyRollingFileAppender">
        <param name="datePattern" value="'.'yyyy-MM-dd" />
        <param name="file" value="logs/MeineLogDatei.log" />
        <param name="Append" value="true" />
        <layout class="org.apache.log4j.PatternLayout">
          <param name="ConversionPattern"
                 value="%d{ISO8601} %-5p [%t] %c: %m%n" />
        </layout>
      </appender>
    
      <appender name="MeinHeartbeatAppender" class="meinpackage6.HeartbeatFileAppender">
        <param name="file" value="logs/MeineHeartbeatLogDatei.log" />
        <param name="Append" value="false" />
        <layout class="org.apache.log4j.PatternLayout">
          <param name="ConversionPattern"
                 value="%d{ISO8601} %-5p [%t] %c: %m%n" />
        </layout>
      </appender>
    
      <logger name="MeinHeartbeatLogger" additivity="false">
        <level value="INFO" />
        <appender-ref ref="MeinHeartbeatAppender" />
      </logger>
    
      <root>
        <priority value="INFO" />
        <appender-ref ref="MeinStandardAppender" />
      </root>
    
    </log4j:configuration>
    
  4. Öffnen Sie ein Kommandozeilenfenster und geben Sie folgende Befehle ein:

    cd \MeinWorkspace\Log4j-Test

    del logs\*.log*

    set CLASSPATH=bin;lib/*

    javac -d bin src/meinpackage6/*.java

    java meinpackage6.Main

    java meinpackage6.Main

    java meinpackage6.Main

    type logs\MeineLogDatei.log

    type logs\MeineHeartbeatLogDatei.log

    Passen Sie den Pfad '\MeinWorkspace\Log4j-Test' an Ihr '<projektverzeichnis>' an.

  5. Der 'HeartbeatFileAppender' ist ein spezieller 'FileAppender', der in eine Logdatei schreibt und dabei jedesmal den alten Inhalt löscht, so dass in der Logdatei immer nur die eine letzte Meldung enthalten ist.
    Wenn Sie 'java meinpackage6.Main' mehrmals aufrufen, enthält 'MeineLogDatei.log' mehrere Einträge, während 'MeineHeartbeatLogDatei.log' immer nur einen Eintrag enthält.


"log4j.additivity...=false"

  1. Die Konsequenzen der "log4j.additivity...=false"-Anweisung in log4j.properties-Dateien (bzw. "<logger name="..." additivity="false">"-Anweisung in log4j.xml-Dateien) sind nicht immer leicht zu durchschauen. Deshalb folgt hierzu ein etwas ausführlicheres Beispiel.
    Sehen Sie sich hierzu auch die Erläuterungen unter manual.html#additivity an.
  2. Sie können entweder die Sourcen downloaden oder, wie im Folgenden beschrieben wird, selbst erzeugen.
  3. Erweitern Sie die oben gezeigte Verzeichnisstruktur um folgende Packages:
    [\MeinWorkspace]
      '- [Log4j-Test]
           |- [bin]
           |- [lib]
           |    '- log4j-1.2.16.jar
           |- [logs]
           |- [res]
           '- [src]
                '- [meinpackage7]
                     |- [pkg1]
                     |- [pkg2]
                     |    '- [pkg22]
                     '- [pkg3]
                          '- [pkg33]
    
  4. Speichern Sie folgende Klassen:

    'src\meinpackage7\Main.java':

    package meinpackage7;
    
    import meinpackage7.pkg1.Klasse1;
    import meinpackage7.pkg2.Klasse2;
    import meinpackage7.pkg2.pkg22.Klasse22;
    import meinpackage7.pkg3.Klasse3;
    import meinpackage7.pkg3.pkg33.Klasse33;
    import org.apache.log4j.Logger;
    
    public class Main
    {
       static final Logger CLASS_LOGGER = Logger.getLogger( Main.class );
       static final Logger ADD_T_LOGGER = Logger.getLogger( "AdditivityTrueLogger" );
       static final Logger ADD_F_LOGGER = Logger.getLogger( "AdditivityFalseLogger" );
    
       public static void main( String[] args )
       {
          CLASS_LOGGER.info(  "Mein Text" );
          CLASS_LOGGER.error( "Mein Text" );
          ADD_T_LOGGER.info(  "Mein Text" );
          ADD_T_LOGGER.error( "Mein Text" );
          ADD_F_LOGGER.info(  "Mein Text" );
          ADD_F_LOGGER.error( "Mein Text" );
    
          Klasse1.log();
          Klasse2.log();
          Klasse3.log();
          Klasse22.log();
          Klasse33.log();
    
          System.out.println( "Ergebnisse siehe Logdateien im logs-Verzeichnis." );
       }
    }
    

    'src\meinpackage7\pkg1\Klasse1.java':

    package meinpackage7.pkg1;
    
    import org.apache.log4j.Logger;
    
    public class Klasse1
    {
       static final Logger CLASS_LOGGER = Logger.getLogger( Klasse1.class );
       static final Logger ADD_T_LOGGER = Logger.getLogger( "AdditivityTrueLogger" );
       static final Logger ADD_F_LOGGER = Logger.getLogger( "AdditivityFalseLogger" );
    
       public static void log()
       {
          CLASS_LOGGER.info(  "Mein Text" );
          CLASS_LOGGER.error( "Mein Text" );
          ADD_T_LOGGER.info(  "Mein Text" );
          ADD_T_LOGGER.error( "Mein Text" );
          ADD_F_LOGGER.info(  "Mein Text" );
          ADD_F_LOGGER.error( "Mein Text" );
       }
    }
    

    'src\meinpackage7\pkg2\Klasse2.java':

    package meinpackage7.pkg2;
    
    import org.apache.log4j.Logger;
    
    public class Klasse2
    {
       static final Logger CLASS_LOGGER = Logger.getLogger( Klasse2.class );
    
       public static void log()
       {
          CLASS_LOGGER.info(  "Mein Text" );
          CLASS_LOGGER.error( "Mein Text" );
       }
    }
    

    'src\meinpackage7\pkg2\pkg22\Klasse22.java':

    package meinpackage7.pkg2.pkg22;
    
    import org.apache.log4j.Logger;
    
    public class Klasse22
    {
       static final Logger CLASS_LOGGER = Logger.getLogger( Klasse22.class );
    
       public static void log()
       {
          CLASS_LOGGER.info(  "Mein Text" );
          CLASS_LOGGER.error( "Mein Text" );
       }
    }
    

    'src\meinpackage7\pkg3\Klasse3.java':

    package meinpackage7.pkg3;
    
    import org.apache.log4j.Logger;
    
    public class Klasse3
    {
       static final Logger CLASS_LOGGER = Logger.getLogger( Klasse3.class );
    
       public static void log()
       {
          CLASS_LOGGER.info(  "Mein Text" );
          CLASS_LOGGER.error( "Mein Text" );
       }
    }
    

    'src\meinpackage7\pkg3\pkg33\Klasse33.java':

    package meinpackage7.pkg3.pkg33;
    
    import org.apache.log4j.Logger;
    
    public class Klasse33
    {
       static final Logger CLASS_LOGGER = Logger.getLogger( Klasse33.class );
    
       public static void log()
       {
          CLASS_LOGGER.info(  "Mein Text" );
          CLASS_LOGGER.error( "Mein Text" );
       }
    }
    
  5. Speichern Sie folgende 'res\log4j.properties'-Datei:

    log4j.rootLogger=error, RootAppender, RootErrorAppender
    
    log4j.logger.AdditivityTrueLogger=info, AdditivityTrueAppender
    log4j.additivity.AdditivityTrueLogger=true
    
    log4j.logger.AdditivityFalseLogger=info, AdditivityFalseAppender
    log4j.additivity.AdditivityFalseLogger=false
    
    log4j.logger.meinpackage7.pkg2=info, pkg2Appender
    log4j.additivity.meinpackage7.pkg2=true
    
    log4j.logger.meinpackage7.pkg3=info, pkg3Appender
    log4j.additivity.meinpackage7.pkg3=false
    
    log4j.appender.AdditivityFalseAppender=org.apache.log4j.RollingFileAppender
    log4j.appender.AdditivityFalseAppender.file=logs/AdditivityFalse.log
    log4j.appender.AdditivityFalseAppender.MaxFileSize=100KB
    log4j.appender.AdditivityFalseAppender.MaxBackupIndex=10
    log4j.appender.AdditivityFalseAppender.layout=org.apache.log4j.PatternLayout
    log4j.appender.AdditivityFalseAppender.layout.ConversionPattern=<%d{yyyy-MM-dd HH:mm:ss}> %-5p : %C{1} %c{2} : %m%n
    
    log4j.appender.AdditivityTrueAppender=org.apache.log4j.RollingFileAppender
    log4j.appender.AdditivityTrueAppender.file=logs/AdditivityTrue.log
    log4j.appender.AdditivityTrueAppender.MaxFileSize=100KB
    log4j.appender.AdditivityTrueAppender.MaxBackupIndex=10
    log4j.appender.AdditivityTrueAppender.layout=org.apache.log4j.PatternLayout
    log4j.appender.AdditivityTrueAppender.layout.ConversionPattern=<%d{yyyy-MM-dd HH:mm:ss}> %-5p : %C{1} %c{2} : %m%n
    
    log4j.appender.pkg2Appender=org.apache.log4j.RollingFileAppender
    log4j.appender.pkg2Appender.file=logs/pkg2.log
    log4j.appender.pkg2Appender.MaxFileSize=100KB
    log4j.appender.pkg2Appender.MaxBackupIndex=10
    log4j.appender.pkg2Appender.layout=org.apache.log4j.PatternLayout
    log4j.appender.pkg2Appender.layout.ConversionPattern=<%d{yyyy-MM-dd HH:mm:ss}> %-5p : %C{1} %c{2} : %m%n
    
    log4j.appender.pkg3Appender=org.apache.log4j.RollingFileAppender
    log4j.appender.pkg3Appender.file=logs/pkg3.log
    log4j.appender.pkg3Appender.MaxFileSize=100KB
    log4j.appender.pkg3Appender.MaxBackupIndex=10
    log4j.appender.pkg3Appender.layout=org.apache.log4j.PatternLayout
    log4j.appender.pkg3Appender.layout.ConversionPattern=<%d{yyyy-MM-dd HH:mm:ss}> %-5p : %C{1} %c{2} : %m%n
    
    log4j.appender.RootAppender=org.apache.log4j.RollingFileAppender
    log4j.appender.RootAppender.file=logs/Root.log
    log4j.appender.RootAppender.MaxFileSize=100KB
    log4j.appender.RootAppender.MaxBackupIndex=10
    log4j.appender.RootAppender.layout=org.apache.log4j.PatternLayout
    log4j.appender.RootAppender.layout.ConversionPattern=<%d{yyyy-MM-dd HH:mm:ss}> %-5p : %C{1} %c{2} : %m%n
    
    log4j.appender.RootErrorAppender=org.apache.log4j.RollingFileAppender
    log4j.appender.RootErrorAppender.file=logs/RootError.log
    log4j.appender.RootErrorAppender.MaxFileSize=100KB
    log4j.appender.RootErrorAppender.MaxBackupIndex=10
    log4j.appender.RootErrorAppender.layout=org.apache.log4j.PatternLayout
    log4j.appender.RootErrorAppender.layout.ConversionPattern=<%d{yyyy-MM-dd HH:mm:ss}> %-5p : %C{1} %c{2} : %m%n
    log4j.appender.RootErrorAppender.threshold=error
    

    Im Beispiel wird in der log4j.properties-Datei "%C{1} %c{2}" verwendet: Erläuterungen zur Syntax finden Sie unter http://logging.apache.org/log4j/1.2/apidocs/org/apache/log4j/PatternLayout.html. Bitte beachten Sie: Während "%c" (mit kleinem "c") bedenkenlos verwendet werden kann, sollte "%C" (mit großem "C") nur in besonderen Test-/Debug-Situationen verwendet werden, da es die Performance beeinträchtigt.

  6. Ihre Verzeichnisstruktur enthält jetzt folgende Verzeichnisse und Dateien (kontrollieren Sie es mit "tree /F"):

    [\MeinWorkspace]
      '- [Log4j-Test]
           |- [bin]
           |- [lib]
           |    '- log4j-1.2.16.jar
           |- [logs]
           |- [res]
           |    '- log4j.properties
           '- [src]
                '- [meinpackage7]
                     |- Main.java
                     |- [pkg1]
                     |    '- Klasse1.java
                     |- [pkg2]
                     |    |- Klasse2.java
                     |    '- [pkg22]
                     |         '- Klasse22.java
                     '- [pkg3]
                          |- Klasse3.java
                          '- [pkg33]
                               '- Klasse33.java
    
  7. Falls Sie das Beispiel in Eclipse ausführen wollen, müssen Sie das res-Verzeichnis zum Build-Path hinzufügen (falls noch nicht geschehen): Klicken Sie im Eclipse-Package-Explorer mit der rechten Maustaste auf den Projektnamen Log4j-Test und wählen Sie: 'Build Path' | 'Configure Build Path...' | Tabulatorreiter 'Source' | 'Add Folder...' | Aktivierung von 'res' | 'OK' | 'OK'. Dann können Sie im Eclipse-Package-Explorer mit der rechten Maustaste auf die Main.java im Package src/meinpackage7 klicken und 'Run As' | 'Java Application' wählen.
  8. Öffnen Sie ein Kommandozeilenfenster und geben Sie folgende Befehle ein:

    cd \MeinWorkspace\Log4j-Test

    del logs\*.log*

    tree /F

    set CLASSPATH=bin;src;res;lib/*

    javac -d bin src/meinpackage7/*.java

    java meinpackage7.Main

    type logs\*.log

  9. Sie erhalten folgende Logdateien im logs-Verzeichnis:

    'AdditivityFalse.log':

    <2009-05-21 13:12:14> INFO  : Main AdditivityFalseLogger : Mein Text
    <2009-05-21 13:12:14> ERROR : Main AdditivityFalseLogger : Mein Text
    <2009-05-21 13:12:14> INFO  : Klasse1 AdditivityFalseLogger : Mein Text
    <2009-05-21 13:12:14> ERROR : Klasse1 AdditivityFalseLogger : Mein Text
    

    'AdditivityTrue.log':

    <2009-05-21 13:12:14> INFO  : Main AdditivityTrueLogger : Mein Text
    <2009-05-21 13:12:14> ERROR : Main AdditivityTrueLogger : Mein Text
    <2009-05-21 13:12:14> INFO  : Klasse1 AdditivityTrueLogger : Mein Text
    <2009-05-21 13:12:14> ERROR : Klasse1 AdditivityTrueLogger : Mein Text
    

    'pkg2.log':

    <2009-05-21 13:12:14> INFO  : Klasse2 pkg2.Klasse2 : Mein Text
    <2009-05-21 13:12:14> ERROR : Klasse2 pkg2.Klasse2 : Mein Text
    <2009-05-21 13:12:14> INFO  : Klasse22 pkg22.Klasse22 : Mein Text
    <2009-05-21 13:12:14> ERROR : Klasse22 pkg22.Klasse22 : Mein Text
    

    'pkg3.log':

    <2009-05-21 13:12:14> INFO  : Klasse3 pkg3.Klasse3 : Mein Text
    <2009-05-21 13:12:14> ERROR : Klasse3 pkg3.Klasse3 : Mein Text
    <2009-05-21 13:12:14> INFO  : Klasse33 pkg33.Klasse33 : Mein Text
    <2009-05-21 13:12:14> ERROR : Klasse33 pkg33.Klasse33 : Mein Text
    

    'Root.log':

    <2009-05-21 13:12:14> ERROR : Main meinpackage7.Main : Mein Text
    <2009-05-21 13:12:14> INFO  : Main AdditivityTrueLogger : Mein Text
    <2009-05-21 13:12:14> ERROR : Main AdditivityTrueLogger : Mein Text
    <2009-05-21 13:12:14> ERROR : Klasse1 pkg1.Klasse1 : Mein Text
    <2009-05-21 13:12:14> INFO  : Klasse1 AdditivityTrueLogger : Mein Text
    <2009-05-21 13:12:14> ERROR : Klasse1 AdditivityTrueLogger : Mein Text
    <2009-05-21 13:12:14> INFO  : Klasse2 pkg2.Klasse2 : Mein Text
    <2009-05-21 13:12:14> ERROR : Klasse2 pkg2.Klasse2 : Mein Text
    <2009-05-21 13:12:14> INFO  : Klasse22 pkg22.Klasse22 : Mein Text
    <2009-05-21 13:12:14> ERROR : Klasse22 pkg22.Klasse22 : Mein Text
    

    'RootError.log':

    <2009-05-21 13:12:14> ERROR : Main meinpackage7.Main : Mein Text
    <2009-05-21 13:12:14> ERROR : Main AdditivityTrueLogger : Mein Text
    <2009-05-21 13:12:14> ERROR : Klasse1 pkg1.Klasse1 : Mein Text
    <2009-05-21 13:12:14> ERROR : Klasse1 AdditivityTrueLogger : Mein Text
    <2009-05-21 13:12:14> ERROR : Klasse2 pkg2.Klasse2 : Mein Text
    <2009-05-21 13:12:14> ERROR : Klasse22 pkg22.Klasse22 : Mein Text
    
  10. Die ersten beiden Logdateien (Additivity...log) zeigen nichts Besonderes.

    Auch die nächsten beiden Logdateien (pkg...log) sind wie erwartet. Erwähnenswert ist höchstens, dass die log4j.logger.meinpackage...-Anweisung sich nicht nur auf das in der Anweisung genannte Package bezieht, sondern auch auf alle Unter-Packages (im Beispiel die Klassen Klasse22 und Klasse33 in den Unter-Packages pkg22 und pkg33).

    Interessant ist die Root.log:

    "INFO : Main meinpackage7.Main" und "INFO : Klasse1 pkg1.Klasse1":
    Diese INFO-Meldungen fehlen, weil wegen "log4j.rootLogger=error, ..." nur ERROR- und keine INFO-Meldungen geloggt werden.

    "INFO : ... AdditivityTrueLogger":
    Obwohl für den rootLogger definiert wurde, dass nur ERROR- und keine INFO-Meldungen geloggt werden, werden diese INFO-Meldungen geloggt, wegen "log4j.logger.AdditivityTrueLogger=info, AdditivityTrueAppender". Obwohl hier ein anderer Appender genannt ist, bezieht sich die Logging-Level-Umdefinition auch zusätzlich auf den rootLogger/RootAppender.

    "INFO : Klasse2 pkg2.Klasse2" und "INFO : Klasse22 pkg22.Klasse22":
    Obwohl für den rootLogger definiert wurde, dass nur ERROR- und keine INFO-Meldungen geloggt werden, werden diese INFO-Meldungen geloggt, wegen "log4j.logger.meinpackage7.pkg2=info, pkg2Appender". Obwohl auch hier ein anderer Appender genannt ist, bezieht sich die Logging-Level-Umdefinition auch wieder zusätzlich auf den rootLogger/RootAppender.

    "... Main AdditivityFalseLogger":
    Fehlt, weil durch "log4j.additivity.AdditivityFalseLogger=false" die Verbindung zum rootLogger unterbrochen wurde (auch ERROR-Meldungen fehlen).

    "... Klasse3 pkg3.Klasse3" und "... Klasse33 pkg33.Klasse33":
    Fehlen, weil durch "log4j.additivity.meinpackage7.pkg3=false" die Verbindung zum rootLogger unterbrochen wurde. Hierbei wird zweierlei leicht übersehen:
    a) Dies gilt nicht nur für INFO-Meldungen, sondern auch für ERROR-Meldungen.
    b) Dies gilt nicht nur für das Package pkg3, sondern auch für alle Unter-Packages, wie pkg33.

    Zur RootError.log:

    Der RootErrorAppender zeigt, dass nicht nur im Logger auf einen Logging-Level begrenzt werden kann, sondern auch im Appender, nämlich per "log4j.appender.RootErrorAppender.threshold=error".



Asynchrones Logging

Das folgende Beispiel demonstriert, wie das Logging asynchron erfolgen kann. Falls Ihre Applikation viel loggt, kann dies eine merkliche Performanceverbesserung bringen.

Anders als bei den bisherigen Beispielen wird hier Maven verwendet.

  1. JDK und Maven müssen installiert sein.

  2. Wechseln Sie in Ihr Workspace-Verzeichnis (z.B. \MeinWorkspace) und führen Sie folgende Kommandos aus:

    cd \MeinWorkspace

    md Log4j-Async

    cd Log4j-Async

    md src\main\resources

    md src\main\java\log4jdemo

    tree /F

  3. Erstellen Sie im Log4j-Async-Projektverzeichnis die Maven-Projektkonfigurationsdatei: pom.xml

    <?xml version="1.0"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
       <modelVersion>4.0.0</modelVersion>
       <groupId>log4jdemo</groupId>
       <artifactId>Log4j-Async</artifactId>
       <version>1.0-SNAPSHOT</version>
       <packaging>jar</packaging>
       <build>
          <plugins>
             <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-assembly-plugin</artifactId>
                <version>3.1.0</version>
                <configuration>
                   <descriptorRefs>
                      <descriptorRef>jar-with-dependencies</descriptorRef>
                   </descriptorRefs>
                   <archive>
                      <manifest>
                         <mainClass>log4jdemo.Log4jZeitmessung</mainClass>
                      </manifest>
                   </archive>
                </configuration>
                <executions>
                   <execution>
                      <id>make-assembly</id>
                      <phase>package</phase>
                      <goals>
                         <goal>single</goal>
                      </goals>
                   </execution>
                </executions>
             </plugin>
          </plugins>
       </build>
       <dependencies>
          <dependency>
             <groupId>log4j</groupId>
             <artifactId>log4j</artifactId>
             <version>1.2.17</version>
          </dependency>
       </dependencies>
    </project>
    
  4. Erzeugen Sie im src/main/resources-Verzeichnis die Log4j1-Konfiguration: log4j.xml

    <?xml version="1.0" encoding="UTF-8" ?>
    <!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
    <log4j:configuration>
       <appender name="MeinFileAppender" class="org.apache.log4j.FileAppender">
          <param name="file" value="logs/MeineLogDatei.log" />
          <param name="Append" value="true" />
          <layout class="org.apache.log4j.PatternLayout">
             <param name="ConversionPattern" value="%d{ISO8601} %-5p [%t] %c: %m%n" />
          </layout>
       </appender>
       <appender name="MeinAsyncAppender" class="org.apache.log4j.AsyncAppender">
          <param name="BufferSize" value="500" />
          <appender-ref ref="MeinFileAppender" />
       </appender>
       <root>
          <priority value="info" />
          <appender-ref ref="MeinAsyncAppender" />
       </root>
    </log4j:configuration>
    
  5. Erzeugen Sie im src/main/java/log4jdemo-Verzeichnis die Main-Klasse: Log4jZeitmessung.java

    package log4jdemo;
    
    import org.apache.log4j.Logger;
    
    /** Logging-Zeitmessung: Asynchrones Logging mit AsyncAppender ist etwa 20 % schneller */
    public class Log4jZeitmessung
    {
       private static Logger logger = Logger.getLogger( Log4jZeitmessung.class );
    
       public static void main( String[] args )
       {
          long startZeitMs = System.nanoTime() / 1000000L;
          long dauerMs = 0;
          for( int i = 0; i < 10000; i++ ) {
             dauerMs = System.nanoTime() / 1000000L - startZeitMs;
             logger.info( "i: " + i + ", Aktuelle Dauer: " + dauerMs + " ms" );
          }
          logger.info( "Gesamtauer: " + dauerMs );
          System.out.println( "Gesamtauer: " + dauerMs + " ms" );
          // Etwas Nachlaufzeit fuer asynchrones Logging:
          try { Thread.sleep( 1000 ); } catch( InterruptedException e ) {}
       }
    }
    
  6. Die Projektstruktur sieht jetzt so aus (überprüfen Sie es mit tree /F):

    [\MeinWorkspace\Log4j-Async]
     |- [src]
     |   '- [main]
     |       |- [java]
     |       |   '- [log4jdemo]
     |       |       '- Log4jZeitmessung.java
     |       '- [resources]
     |           '- log4j.xml
     '- pom.xml
    
  7. Da die log4j.xml-Konfigurationsdatei im Classpath liegt, wird kein zusätzlicher Aufrufparameter benötigt. Mit Hilfe des maven-assembly-plugin wird eine ausführbare Jar-Datei erzeugt, die alle benötigten Abhängigkeiten enthält und einfach gestartet werden kann. Führen Sie im Kommandozeilenfenster aus:

    cd \MeinWorkspace\Log4j-Async

    mvn clean package

    java -jar target\Log4j-Async-1.0-SNAPSHOT-jar-with-dependencies.jar

    dir logs

  8. Bei der oben gezeigten Konfiguration in der log4j.xml ist im root-Element der asynchrone Appender konfiguriert:

       <root>
          <priority value="info" />
          <appender-ref ref="MeinAsyncAppender" />
       </root>
    

    Um auf synchrones Logging umzuschalten, ersetzen Sie in diesem Block einfach die Referenz zum Appender:

       <root>
          <priority value="info" />
          <appender-ref ref="MeinFileAppender" />
       </root>
    
  9. Je nach PC beträgt bei diesem simplen Beispiel der Performancevorteil durch asynchrones Logging circa 20 %.



Weitere Tipps



Log4j 2.x

Das folgende Beispiel demonstriert:

Infos zu Log4j 2.x

Apache Log4j 2, Migrating from Log4j 1.x, Log4j2 Configuration, Log4j2 Appenders

Erstellen Sie zum Vergleich zuerst ein einfaches Log4j1-Projekt:

  1. JDK und Maven müssen installiert sein.

  2. Wechseln Sie in Ihr Workspace-Verzeichnis (z.B. \MeinWorkspace) und führen Sie folgende Kommandos aus:

    cd \MeinWorkspace

    md Log4j1-RollingFileAppender

    cd Log4j1-RollingFileAppender

    md src\main\resources

    md src\main\java\log4j1demo

    tree /F

  3. Erstellen Sie im Log4j1-RollingFileAppender-Projektverzeichnis die Maven-Projektkonfigurationsdatei: pom.xml

    <?xml version="1.0"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
       <modelVersion>4.0.0</modelVersion>
       <groupId>log4j1demo</groupId>
       <artifactId>Log4j1-RollingFileAppender</artifactId>
       <version>1.0-SNAPSHOT</version>
       <packaging>jar</packaging>
       <build>
          <plugins>
             <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-assembly-plugin</artifactId>
                <version>3.1.0</version>
                <configuration>
                   <descriptorRefs>
                      <descriptorRef>jar-with-dependencies</descriptorRef>
                   </descriptorRefs>
                   <archive>
                      <manifest>
                         <mainClass>log4j1demo.Log4j1Demo</mainClass>
                      </manifest>
                   </archive>
                </configuration>
                <executions>
                   <execution>
                      <id>make-assembly</id>
                      <phase>package</phase>
                      <goals>
                         <goal>single</goal>
                      </goals>
                   </execution>
                </executions>
             </plugin>
          </plugins>
       </build>
       <dependencies>
          <dependency>
             <groupId>log4j</groupId>
             <artifactId>log4j</artifactId>
             <version>1.2.17</version>
          </dependency>
       </dependencies>
    </project>
    
  4. Erzeugen Sie im src/main/resources-Verzeichnis die Log4j1-Konfiguration: log4j.properties

    log4j.rootLogger=INFO, RoFiAppender
    log4j.appender.RoFiAppender=org.apache.log4j.RollingFileAppender
    log4j.appender.RoFiAppender.file=logs/Log4j1-RollingFileAppender.log
    log4j.appender.RoFiAppender.MaxFileSize=10KB
    log4j.appender.RoFiAppender.MaxBackupIndex=3
    log4j.appender.RoFiAppender.layout=org.apache.log4j.PatternLayout
    log4j.appender.RoFiAppender.layout.ConversionPattern=%d{ISO8601} %-5p [%t] %c: %m%n
    

    Als Logging-Level ist INFO konfiguriert. RollingFileAppender starten nach konfigurierbaren Kriterien neue Logdateien. In diesem Beispiel wird eine neue Logdatei gestartet, wenn die Dateigröße MaxFileSize von 10 KByte überschreitet. MaxBackupIndex 3 definiert, dass maximal drei vorherige Logdateien beibehalten werden. Ältere Logdateien werden gelöscht.

  5. Erzeugen Sie im src/main/java/log4j1demo-Verzeichnis die Main-Klasse: Log4j1Demo.java

    package log4j1demo;
    
    import org.apache.log4j.Logger;
    
    public class Log4j1Demo
    {
       private static Logger logger = Logger.getLogger( Log4j1Demo.class );
    
       public static void main( String[] args )
       {
          logger.debug( "Meine Debug-Meldung" );
          logger.info(  "Meine Info-Meldung"  );
          logger.warn(  "Meine Warn-Meldung"  );
          logger.error( "Meine Error-Meldung" );
          logger.fatal( "Meine Fatal-Meldung" );
       }
    }
    

    Sehen Sie sich die Javadoc an zu: Logger.

  6. Die Projektstruktur sieht jetzt so aus (überprüfen Sie es mit tree /F):

    [\MeinWorkspace\Log4j1-RollingFileAppender]
     |- [src]
     |   '- [main]
     |       |- [java]
     |       |   '- [log4j1demo]
     |       |       '- Log4j1Demo.java
     |       '- [resources]
     |           '- log4j.properties
     '- pom.xml
    
  7. Da die log4j.properties-Konfigurationsdatei im Classpath liegt, wird kein zusätzlicher Aufrufparameter benötigt. Mit Hilfe des maven-assembly-plugin wird eine ausführbare Jar-Datei erzeugt, die alle benötigten Abhängigkeiten enthält und einfach gestartet werden kann. Führen Sie im Kommandozeilenfenster aus:

    cd \MeinWorkspace\Log4j1-RollingFileAppender

    mvn clean package

    java -jar target\Log4j1-RollingFileAppender-1.0-SNAPSHOT-jar-with-dependencies.jar

    dir logs

    type logs\Log4j1-RollingFileAppender.log

  8. Sie erhalten:

    2017-01-01 01:01:01,000 INFO  [main] log4j1demo.Log4j1Demo: Meine Info-Meldung
    2017-01-01 01:01:01,000 WARN  [main] log4j1demo.Log4j1Demo: Meine Warn-Meldung
    2017-01-01 01:01:01,000 ERROR [main] log4j1demo.Log4j1Demo: Meine Error-Meldung
    2017-01-01 01:01:01,000 FATAL [main] log4j1demo.Log4j1Demo: Meine Fatal-Meldung
    

    Die Debug-Meldung wird nicht geloggt, weil in der log4j.properties beim log4j.rootLogger der Logging-Level "INFO" konfiguriert ist.

Erstellen Sie jetzt das neue Log4j2-Projekt:

  1. Wechseln Sie in Ihr Workspace-Verzeichnis (z.B. \MeinWorkspace) und führen Sie folgende Kommandos aus:

    cd \MeinWorkspace

    md Log4j2-RollingFileAppender

    cd Log4j2-RollingFileAppender

    md src\main\java\log4j2demo

    tree /F

  2. Erstellen Sie im Log4j2-RollingFileAppender-Projektverzeichnis die Maven-Projektkonfigurationsdatei: pom.xml

    <?xml version="1.0"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
       <modelVersion>4.0.0</modelVersion>
       <groupId>log4j2demo</groupId>
       <artifactId>Log4j2-RollingFileAppender</artifactId>
       <version>2.0-SNAPSHOT</version>
       <packaging>jar</packaging>
       <build>
          <plugins>
             <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-assembly-plugin</artifactId>
                <version>3.1.0</version>
                <configuration>
                   <descriptorRefs>
                      <descriptorRef>jar-with-dependencies</descriptorRef>
                   </descriptorRefs>
                   <archive>
                      <manifest>
                         <mainClass>log4j2demo.Log4j2Demo</mainClass>
                      </manifest>
                   </archive>
                </configuration>
                <executions>
                   <execution>
                      <id>make-assembly</id>
                      <phase>package</phase>
                      <goals>
                         <goal>single</goal>
                      </goals>
                   </execution>
                </executions>
             </plugin>
          </plugins>
       </build>
       <dependencies>
          <dependency>
             <groupId>org.apache.logging.log4j</groupId>
             <artifactId>log4j-core</artifactId>
             <version>2.9.1</version>
          </dependency>
       </dependencies>
    </project>
    
  3. Erzeugen Sie im Log4j2-RollingFileAppender-Projektverzeichnis die Log4j2-Konfiguration: log4j2.properties

    status = error
    name = PropertiesConfig
    
    filters = threshold
    filter.threshold.type = ThresholdFilter
    filter.threshold.level = debug
    
    appenders = rofi
    appender.rofi.type = RollingFile
    appender.rofi.name = RollingFile
    appender.rofi.fileName = logs/${sys:log4j.logfilename}.log
    appender.rofi.filePattern = logs/${sys:log4j.logfilename}-%i.log.gz
    appender.rofi.layout.type = PatternLayout
    appender.rofi.layout.pattern = %d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n
    appender.rofi.policies.type = Policies
    appender.rofi.policies.size.type = SizeBasedTriggeringPolicy
    appender.rofi.policies.size.size = 10 KB
    appender.rofi.strategy.type = DefaultRolloverStrategy
    appender.rofi.strategy.max = 3
    
    loggers = rofi
    logger.rofi.name = log4j2demo
    logger.rofi.level = info
    logger.rofi.additivity = false
    logger.rofi.appenderRef.rofi.ref = RollingFile
    

    Beachten Sie das im Vergleich zu Log4j1 geänderte Format der Log4j-Konfigurationsdatei. Wie schon bei Log4j1 werden auch bei Log4j2 mit RollingFile nach konfigurierbaren Kriterien neue Logdateien gestartet. In diesem Beispiel wird eine neue Logdatei gestartet, wenn die Dateigröße ...policies.size.size von 10 KByte überschreitet. ...strategy.max 3 definiert, dass maximal drei vorherige Logdateien beibehalten werden. Ältere Logdateien werden gelöscht. Der Dateiname der Logdateien soll bei diesem Beispiel per Kommandozeilenparameter vorgegeben werden können. Deshalb finden Sie bei ...fileName und bei ...filePattern die Platzhalterausdrücke {sys:log4j.logfilename}. Die Dateiendung .gz bei ...filePattern gibt an, dass die alten Logdateien gezippt werden sollen. Für das Package log4j2demo ist als Logging-Level info konfiguriert.

  4. Erzeugen Sie im src/main/java/log4j2demo-Verzeichnis die Main-Klasse: Log4j2Demo.java

    package log4j2demo;
    
    import org.apache.logging.log4j.Logger;
    import org.apache.logging.log4j.LogManager;
    
    public class Log4j2Demo
    {
       private static Logger logger = LogManager.getLogger( Log4j2Demo.class );
    
       public static void main( String[] args )
       {
          logger.debug( "Meine Debug-Meldung" );
          logger.info(  "Meine Info-Meldung"  );
          logger.warn(  "Meine Warn-Meldung"  );
          logger.error( "Meine Error-Meldung" );
          logger.fatal( "Meine Fatal-Meldung" );
       }
    }
    

    Beachten Sie die im Vergleich zu Log4j1 geänderten import-Anweisungen und den neuen LogManager.getLogger()-Aufruf. Sehen Sie sich die Javadoc an zu: Logger und LogManager.

  5. Die Projektstruktur sieht etwas anders aus als beim vorherigen Beispiel, weil die log4j2.properties-Konfigurationsdatei diesmal nicht im Classpath liegen soll:

    [\MeinWorkspace\Log4j2-RollingFileAppender]
     |- [src]
     |   '- [main]
     |       '- [java]
     |           '- [log4j2demo]
     |               '- Log4j2Demo.java
     |- log4j2.properties
     '- pom.xml
    
  6. Da die log4j2.properties-Konfigurationsdatei diesmal nicht im Classpath liegt, wird der zusätzliche Aufrufparameter -Dlog4j.configurationFile=log4j2.properties benötigt, der den Pfad zur Log4j2-Konfigurationsdatei angibt. Außerdem muss über den zweiten Aufrufparameter -Dlog4j.logfilename=Log4j2-RollingFileAppender der gewünschte Dateiname der Logdatei angegeben werden, da in der Log4j2-Konfigurationsdatei hierfür der Platzhalter ${sys:log4j.logfilename} eingetragen ist. Mit Hilfe des maven-assembly-plugin wird wieder eine ausführbare Jar-Datei erzeugt, die alle benötigten Abhängigkeiten enthält. Führen Sie im Kommandozeilenfenster aus:

    cd \MeinWorkspace\Log4j2-RollingFileAppender

    mvn clean package

    java -jar -Dlog4j.logfilename=Log4j2-RollingFileAppender -Dlog4j.configurationFile=log4j2.properties target\Log4j2-RollingFileAppender-2.0-SNAPSHOT-jar-with-dependencies.jar

    dir logs

    type logs\Log4j2-RollingFileAppender.log

  7. Sie erhalten:

    2017-01-01 01:01:01 INFO  Log4j2Demo:13 - Meine Info-Meldung
    2017-01-01 01:01:01 WARN  Log4j2Demo:14 - Meine Warn-Meldung
    2017-01-01 01:01:01 ERROR Log4j2Demo:15 - Meine Error-Meldung
    2017-01-01 01:01:01 FATAL Log4j2Demo:16 - Meine Fatal-Meldung
    

    Die Debug-Meldung wird nicht geloggt, weil in der log4j2.properties beim logger.rofi.level als Logging-Level "info" konfiguriert ist.





Weitere Themen: andere TechDocs | Apache Log4j
© 1998-2009 Torsten Horn, Aachen