Configurazione programmatica con Log4j 2

1. Introduzione

In questo tutorial, daremo un'occhiata a diversi modi per configurare Apache Log4j 2 a livello di programmazione.

2. Configurazione iniziale

Per iniziare a utilizzare Log4j 2, dobbiamo semplicemente includere le dipendenze log4j-core e log4j-slf4j-impl nel nostro pom.xml :

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

3. ConfigurationBuilder

Una volta che abbiamo configurato Maven, dobbiamo creare un ConfigurationBuilder , che è la classe che ci permette di configurare appendici, filtri, layout e logger.

Log4j 2 offre diversi modi per ottenere un ConfigurationBuilder .

Cominciamo con il modo più diretto:

ConfigurationBuilder builder = ConfigurationBuilderFactory.newConfigurationBuilder();

E per iniziare a configurare i componenti, ConfigurationBuilder è dotato di un nuovo metodo corrispondente , come newAppender o newLayout , per ogni componente.

Alcuni componenti hanno sottotipi diversi, come FileAppender o ConsoleAppender, e questi sono indicati nell'API come plug-in .

3.1. Configurazione degli allegati

Diciamo al builder dove inviare ogni riga di registro configurando un appender :

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

Sebbene la maggior parte dei nuovi metodi non lo supporti, newAppender (nome, plugin) ci consente di dare un nome all'appender, che diventerà importante in seguito. Questi appenders, li abbiamo chiamati stdout e log, anche se avremmo potuto chiamarli qualunque.

Abbiamo anche detto al builder quale plug-in per appender (o, più semplicemente, quale tipo di appender) utilizzare. Console e File si riferiscono rispettivamente agli allegati di Log4j 2 per la scrittura su standard out e sul file system.

Sebbene Log4j 2 supporti diversi appenders, configurarli utilizzando Java può essere un po 'complicato poiché AppenderComponentBuilder è una classe generica per tutti i tipi di appender.

Questo fa sì che abbia metodi come addAttribute e addComponent invece di setFileName e 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); 

E, infine, non dimenticare di chiamare builder.add per aggiungerlo alla configurazione principale!

3.2. Configurazione dei filtri

Possiamo aggiungere filtri a ciascuna delle nostre appendici, che decidono su ciascuna riga di registro se deve essere aggiunta o meno.

Usiamo il plug-in MarkerFilter sul nostro appender per console:

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

Si noti che questo nuovo metodo non ci consente di nominare il filtro, ma ci chiede di indicare cosa fare se il filtro supera o non riesce.

In questo caso, abbiamo mantenuto le cose semplici, affermando che se MarkerFilter ha successo , allora ACCETTA la logline. Altrimenti, NEGARLO .

Nota in questo caso che non lo aggiungiamo al builder ma invece agli allegati che vogliamo usare questo filtro.

3.3. Configurazione dei layout

Successivamente, definiamo il layout per ogni riga di registro. In questo caso, useremo il plugin PatternLayout :

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

Di nuovo, li abbiamo aggiunti direttamente agli allegati appropriati anziché direttamente al builder .

3.4. Configurazione del root logger

Ora che sappiamo dove verranno spediti i log, desideriamo configurare quali log andranno a ciascuna destinazione.

Il logger root è il logger più alto, un po 'come Object in Java. Questo logger è ciò che verrà utilizzato per impostazione predefinita a meno che non venga sovrascritto.

Quindi, usiamo un logger root per impostare il livello di registrazione predefinito su ERROR e l'appender predefinito sul nostro appender stdout dall'alto:

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

Per puntare il nostro logger su un appender specifico, non gli diamo un'istanza del builder. Invece, ci riferiamo ad esso con il nome che gli abbiamo dato in precedenza.

3.5. Configurazione di logger aggiuntivi

I logger secondari possono essere utilizzati per indirizzare pacchetti o nomi di logger specifici.

Aggiungiamo un logger per il pacchetto com nella nostra applicazione, impostando il livello di registrazione su DEBUG e facendo in modo che questi vengano inviati al nostro appender di log :

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

Nota che possiamo impostare l' additività con i nostri logger, che indica se questo logger deve ereditare proprietà come il livello di registrazione e i tipi di appender dai suoi antenati.

3.6. Configurazione di altri componenti

Non tutti i componenti hanno un nuovo metodo dedicato su ConfigurationBuilder .

Quindi, in quel caso, chiamiamo newComponent.

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.

Possiamo prendere quel file di configurazione e inviarlo alla nostra implementazione personalizzata di XmlConfiguration dove possiamo posizionare qualsiasi configurazione di override di cui abbiamo bisogno:

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

5. conclusione

In questo articolo, abbiamo esaminato come utilizzare la nuova API ConfigurationBuilder disponibile in Log4j 2.

Abbiamo anche esaminato la personalizzazione di ConfigurationFactory in combinazione con ConfigurationBuilder per casi d'uso più avanzati.

Non dimenticare di controllare i miei esempi completi su GitHub.