Programmatische Konfiguration mit Log4j 2

1. Einleitung

In diesem Tutorial werden verschiedene Möglichkeiten zur programmgesteuerten Konfiguration von Apache Log4j 2 vorgestellt.

2. Ersteinrichtung

Um Log4j 2 verwenden zu können, müssen wir lediglich die Abhängigkeiten log4j-core und log4j-slf4j-impl in unsere pom.xml aufnehmen :

 org.apache.logging.log4j log4j-core 2.11.0   org.apache.logging.log4j log4j-slf4j-impl 2.11.0 

3. ConfigurationBuilder

Sobald wir Maven konfiguriert haben, müssen wir einen ConfigurationBuilder erstellen . Mit dieser Klasse können wir Appender, Filter, Layouts und Logger konfigurieren .

Log4j 2 bietet verschiedene Möglichkeiten, um einen ConfigurationBuilder abzurufen .

Beginnen wir mit dem direktesten Weg:

ConfigurationBuilder builder = ConfigurationBuilderFactory.newConfigurationBuilder();

Um mit der Konfiguration von Komponenten zu beginnen, verfügt ConfigurationBuilder für jede Komponente über eine entsprechende neue Methode wie newAppender oder newLayout .

Einige Komponenten haben unterschiedliche Untertypen, wie FileAppender oder ConsoleAppender, und diese werden in der API als Plugins bezeichnet .

3.1. Appender konfigurieren

Lassen Sie uns dem Builder mitteilen, wohin jede Protokollzeile gesendet werden soll, indem ein Appender konfiguriert wird :

AppenderComponentBuilder console = builder.newAppender("stdout", "Console"); builder.add(console); AppenderComponentBuilder file = builder.newAppender("log", "File"); file.addAttribute("fileName", "target/logging.log"); builder.add(file);

Während die meisten neuen Methoden dies nicht unterstützen, können wir mit newAppender (Name, Plugin) dem Appender einen Namen geben, der sich später als wichtig herausstellen wird. Diese Appender haben wir stdout und log genannt, obwohl wir sie alles benennen könnten.

Wir haben dem Builder auch mitgeteilt, welches Appender- Plugin (oder einfacher gesagt, welche Art von Appender) verwendet werden soll. Konsole und Datei beziehen sich auf die Appender von Log4j 2 zum Schreiben in den Standardausgang bzw. in das Dateisystem.

Obwohl Log4j 2 mehrere Appender unterstützt, kann die Konfiguration mit Java etwas schwierig sein, da AppenderComponentBuilder eine generische Klasse für alle Appendertypen ist.

Dadurch verfügt es über Methoden wie addAttribute und addComponent anstelle von setFileName und addTriggeringPolicy :

AppenderComponentBuilder rollingFile = builder.newAppender("rolling", "RollingFile"); rollingFile.addAttribute("fileName", "rolling.log"); rollingFile.addAttribute("filePattern", "rolling-%d{MM-dd-yy}.log.gz"); builder.add(rollingFile); 

Und vergessen Sie nicht, builder.add aufzurufen , um es an die Hauptkonfiguration anzuhängen!

3.2. Filter konfigurieren

Wir können jedem unserer Appender Filter hinzufügen, die in jeder Protokollzeile entscheiden, ob sie angehängt werden soll oder nicht.

Verwenden wir das MarkerFilter- Plugin in unserem Konsolen-Appender:

FilterComponentBuilder flow = builder.newFilter( "MarkerFilter", Filter.Result.ACCEPT, Filter.Result.DENY); flow.addAttribute("marker", "FLOW"); console.add(flow);

Beachten Sie, dass wir mit dieser neuen Methode den Filter nicht benennen können, sondern angeben müssen, was zu tun ist, wenn der Filter erfolgreich ist oder fehlschlägt.

In diesem Fall haben wir es einfach gehalten, die besagt , dass , wenn die MarkerFilter passiert, dann akzeptieren die logline. Andernfalls verweigern Sie es.

Beachten Sie in diesem Fall, dass wir dies nicht an den Builder anhängen, sondern an die Appender, die diesen Filter verwenden möchten.

3.3. Layouts konfigurieren

Als nächstes definieren wir das Layout für jede Protokollzeile. In diesem Fall verwenden wir das PatternLayout- Plugin:

LayoutComponentBuilder standard = builder.newLayout("PatternLayout"); standard.addAttribute("pattern", "%d [%t] %-5level: %msg%n%throwable"); console.add(standard); file.add(standard); rolling.add(standard);

Auch hier haben wir diese direkt zu den entsprechenden Appendern anstatt direkt zum Builder hinzugefügt .

3.4. Root Logger konfigurieren

Nachdem wir nun wissen, wohin die Protokolle gesendet werden, möchten wir konfigurieren, welche Protokolle an die einzelnen Ziele gesendet werden.

Der Root-Logger ist der höchste Logger, ähnlich wie Object in Java. Dieser Logger wird standardmäßig verwendet, sofern er nicht überschrieben wird.

Also, lassen Sie sich einen Root - Logger verwenden , um die Standard - Protokollebene einstellen ERROR und den Standard appender in unserem stdout appender von oben:

RootLoggerComponentBuilder rootLogger = builder.newRootLogger(Level.ERROR); rootLogger.add(builder.newAppenderRef("stdout")); builder.add(rootLogger);

Um unseren Logger auf einen bestimmten Appender zu richten, geben wir ihm keine Instanz des Builders. Stattdessen bezeichnen wir es mit dem Namen , den wir ihm zuvor gegeben haben.

3.5. Zusätzliche Logger konfigurieren

Untergeordnete Logger können verwendet werden, um auf bestimmte Pakete oder Loggernamen abzuzielen.

Fügen wir in unserer Anwendung einen Logger für das com- Paket hinzu, setzen die Protokollierungsstufe auf DEBUG und lassen diese an unseren Log- Appender gehen:

LoggerComponentBuilder logger = builder.newLogger("com", Level.DEBUG); logger.add(builder.newAppenderRef("log")); logger.addAttribute("additivity", false); builder.add(logger);

Beachten Sie, dass wir mit unseren Protokollierern die Additivität festlegen können. Dies gibt an, ob dieser Protokollierer Eigenschaften wie Protokollierungsstufe und Appender-Typen von seinen Vorfahren erben soll.

3.6. Andere Komponenten konfigurieren

Nicht alle Komponenten verfügen über eine dedizierte neue Methode in ConfigurationBuilder .

In diesem Fall rufen wir also newComponent auf.

For example, because there isn't a TriggeringPolicyComponentBuilder, we need to use newComponent for something like specifying our triggering policy for rolling file appenders:

ComponentBuilder triggeringPolicies = builder.newComponent("Policies") .addComponent(builder.newComponent("CronTriggeringPolicy") .addAttribute("schedule", "0 0 0 * * ?")) .addComponent(builder.newComponent("SizeBasedTriggeringPolicy") .addAttribute("size", "100M")); rolling.addComponent(triggeringPolicies);

3.7. The XML Equivalent

ConfigurationBuilder comes equipped with a handy method to print out the equivalent XML:

builder.writeXmlConfiguration(System.out);

Running the above line prints out:

This comes in handy when we want to double-check our configuration or if we want to persist our configuration, say, to the file system.

3.8. Putting It All Together

Now that we are fully configured, let's tell Log4j 2 to use our configuration:

Configurator.initialize(builder.build());

After this is invoked, future calls to Log4j 2 will use our configuration.

Note that this means that we need to invoke Configurator.initialize before we make any calls to LogManager.getLogger.

4. ConfigurationFactory

Now that we've seen one way to get and apply a ConfigurationBuilder, let's take a look at one more:

public class CustomConfigFactory extends ConfigurationFactory { public Configuration createConfiguration( LoggerContext context, ConfigurationSource src) { ConfigurationBuilder builder = super .newConfigurationBuilder(); // ... configure appenders, filters, etc. return builder.build(); } public String[] getSupportedTypes() { return new String[] { "*" }; } }

In this case, instead of using ConfigurationBuilderFactory, we subclassed ConfigurationFactory, an abstract class targetted for creating instances of Configuration.

Then, instead of calling Configurator.initialize like we did the first time, we simply need to let Log4j 2 know about our new configuration factory.

There are three ways to do this:

  • Static initialization
  • A runtime property, or
  • The @Plugin annotation

4.1. Use Static Initialization

Log4j 2 supports calling setConfigurationFactory during static initialization:

static { ConfigurationFactory custom = new CustomConfigFactory(); ConfigurationFactory.setConfigurationFactory(custom); }

This approach has the same limitation as for the last approach we saw, which is that we'll need to invoke it before any calls to LogManager.getLogger.

4.2. Use a Runtime Property

If we have access to the Java startup command, then Log4j 2 also supports specifying the ConfigurationFactory to use via a -D parameter:

-Dlog4j2.configurationFactory=com.baeldung.log4j2.CustomConfigFactory

The main benefit of this approach is that we don't have to worry about initialization order as we do with the first two approaches.

4.3. Use the @Plugin Annotation

And finally, in circumstances where we don't want to fiddle with the Java startup command by adding a -D, we can simply annotate our CustomConfigurationFactory with the Log4j 2 @Plugin annotation:

@Plugin( name = "CustomConfigurationFactory", category = ConfigurationFactory.CATEGORY) @Order(50) public class CustomConfigFactory extends ConfigurationFactory { // ... rest of implementation }

Log4j 2 will scan the classpath for classes having the @Plugin annotation, and, finding this class in the ConfigurationFactory category, will use it.

4.4. Combining With Static Configuration

Another benefit to using a ConfigurationFactory extension is that we can easily combine our custom configuration with other configuration sources like XML:

public Configuration createConfiguration( LoggerContext context, ConfigurationSource src) { return new WithXmlConfiguration(context, src); } 

The source parameter represents the static XML or JSON configuration file that Log4j 2 finds if any.

Wir können diese Konfigurationsdatei nehmen und an unsere benutzerdefinierte Implementierung von XmlConfiguration senden, wo wir die erforderliche überschreibende Konfiguration platzieren können:

public class WithXmlConfiguration extends XmlConfiguration { @Override protected void doConfigure() { super.doConfigure(); // parse xml document // ... add our custom configuration } }

5. Schlussfolgerung

In diesem Artikel haben wir uns mit der Verwendung der neuen ConfigurationBuilder- API befasst, die in Log4j 2 verfügbar ist.

Wir haben uns auch mit dem Anpassen von ConfigurationFactory in Kombination mit ConfigurationBuilder für erweiterte Anwendungsfälle befasst.

Vergiss nicht, dir meine vollständigen Beispiele auf GitHub anzusehen.