Configuration par programme avec Log4j 2

Configuration programmatique avec Log4j 2

1. introduction

Dans ce didacticiel, nous allons examiner différentes manières de configurer Apache Log4j 2 par programmation.

2. La configuration initiale

Pour commencer à utiliser Log4j 2, nous devons simplement inclure les dépendanceslog4j-core etlog4j-slf4j-impl dans nospom.xml:


    org.apache.logging.log4j
    log4j-core
    2.11.0


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

3. ConfigurationBuilder

Une fois que nous avons configuré Maven, nous devons créer unConfigurationBuilder, qui est la classe qui nous permet de configurerappenders, filters, layouts, etloggers.

Log4j 2 propose plusieurs méthodes pour obtenir unConfigurationBuilder.

Commençons par la manière la plus directe:

ConfigurationBuilder builder
 = ConfigurationBuilderFactory.newConfigurationBuilder();

Et pour commencer à configurer les composants,ConfigurationBuilder est équipé d'une méthodenew correspondante, commenewAppender ornewLayout, pour chaque composant.

Certains composants ont différents sous-types, commeFileAppender ouConsoleAppender, et ceux-ci sont appelésplugins dans l'API.

3.1. Configurer les appenders

Disons auxbuilder où envoyer chaque ligne de journal en configurant unappender:

AppenderComponentBuilder console
  = builder.newAppender("stdout", "Console");

builder.add(console);

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

builder.add(file);

Bien que la plupart des méthodes denewne le prennent pas en charge,newAppender(name, plugin) nous permet de donner un nom à l'appender, qui s'avérera important plus tard. Ces appenders, nous les avons appelésstdout etlog, , mais nous pourrions les nommer de quelque manière que ce soit.

Nous avons également indiqué auxbuilder quel appenderplugin  (ou, plus simplement, quel type d'appendeur) utiliser. Console etFile font référence aux appenders de Log4j 2 pour l'écriture dans la sortie standard et le système de fichiers, respectivement.

Bien queLog4j 2 supports several appenders,configuring them using Java can be a bit tricky since AppenderComponentBuilder is a generic class for all appender types.

Cela lui donne des méthodes commeaddAttribute etaddComponent au lieu desetFileName etaddTriggeringPolicy:

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

builder.add(rollingFile);

Et, enfin,don’t forget to call builder.add to append it to the main configuration!

3.2. Configuration des filtres

Nous pouvons ajouter des filtres à chacun de nos ajouts, lesquels décident si chaque ligne de journal doit être ajoutée ou non.

Utilisons le pluginMarkerFilter sur notre appender console:

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

console.add(flow);

Notez que cette méthodenew ne nous permet pas de nommer le filtre, mais elle nous demande d'indiquer quoi faire si le filtre réussit ou échoue.

Dans ce cas, nous avons gardé les choses simples, déclarant que si leMarkerFilter réussit, alorsACCEPTest la ligne de connexion. Sinon,DENY it.

Notez dans ce cas que nous n'ajoutons pas ceci auxbuilder mais aux ajouteurs que nous voulons utiliser ce filtre.

3.3. Configuration des dispositions

Ensuite, définissons la disposition de chaque ligne de journal. Dans ce cas, nous utiliserons le pluginPatternLayout:

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

console.add(standard);
file.add(standard);
rolling.add(standard);

Encore une fois, nous les avons ajoutés directement aux appenders appropriés au lieu de lesbuilder directement.

3.4. Configuration de l'enregistreur racine

Maintenant que nous savons où les journaux seront expédiés, nous voulons configurer les journaux qui iront à chaque destination.

L'enregistreur racine est l'enregistreur le plus élevé, un peu commeObject en Java. Cet enregistreur est ce qui sera utilisé par défaut sauf en cas de substitution.

Alors, utilisons un enregistreur racine pour définir le niveau de journalisation par défaut surERROR et l'appender par défaut sur notre appenderstdout ci-dessus:

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

builder.add(rootLogger);

Pour pointer notre enregistreur sur un appender spécifique, nous ne lui donnons pas une instance du constructeur. Au lieu de cela,we refer to it by the name that we gave it earlier.

3.5. Configuration d'enregistreurs supplémentaires

Les enregistreurs enfants peuvent être utilisés pour cibler des packages ou des noms d'enregistreurs spécifiques.

Ajoutons un enregistreur pour le packagecom dans notre application, en définissant le niveau de journalisation surDEBUG et en les envoyant à notre expéditeurlog :

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

builder.add(logger);

Notez que nous pouvons définiradditivity w avec nos enregistreurs, ce qui indique si cet enregistreur doit hériter des propriétés telles que le niveau de journalisation et les types d'appendeurs de ses ancêtres.

3.6. Configuration d'autres composants

Tous les composants n'ont pas de méthodenew dédiée surConfigurationBuilder.

Donc, dans ce cas, nous appelonsnewComponent.

Par exemple, comme il n'y a pas deTriggeringPolicyComponentBuilder, nous devons utilisernewComponent  pour quelque chose comme la spécification de notre politique de déclenchement pour les ajouteurs de fichiers en continu:

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. L'équivalent XML

ConfigurationBuilder comes équipés d'une méthode pratique pour imprimer le XML équivalent:

builder.writeXMLConfiguration(System.out);

L'exécution de la ligne ci-dessus affiche:



   
      
         
         
      
      
         
         
            
            
         
      
      
         
      
   
   
      
         
      
      
         
      
   

Cela est pratique lorsque nous souhaitons vérifier notre configuration ou si nous voulons conserver notre configuration, par exemple, dans le système de fichiers.

3.8. Mettre tous ensemble

Maintenant que nous sommes entièrement configurés, disons à Log4j 2 d'utiliser notre configuration:

Configurator.initialize(builder.build());

Une fois que cela est appelé,future calls to Log4j 2 will use our configuration.

Notez que cela signifie que nous devons invoquerConfigurator.initialize avant de faire des appels àLogManager.getLogger.

4. ConfigurationFactory

Maintenant que nous avons vu un moyen d'obtenir et d'appliquer unConfigurationBuilder, jetons un œil à un autre:

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[] { "*" };
    }
}

Dans ce cas, au lieu d'utiliserConfigurationBuilderFactory, nous avons sous-classéConfigurationFactory, une classe abstraite ciblée pour créer des instances deConfiguration.

Ensuite, au lieu d'appelerConfigurator.initialize comme nous l'avons fait la première fois, nous devons simplement informer Log4j 2 de notre nouvelle usine de configuration.

Il y a trois façons de faire ceci:

  • Initialisation statique

  • Une propriété d'exécution, ou

  • La sannotation@Plugin 

4.1. Utiliser l'initialisation statique

Log4j 2 prend en charge l'appel desetConfigurationFactory  lors de l'initialisation statique:

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

Cette approche a la même limitation que pour la dernière approche que nous avons vue, à savoir que nous devrons l'invoquerbefore any calls to LogManager.getLogger.

4.2. Utiliser une propriété d'exécution

Si nous avons accès à la commande de démarrage Java, alors Log4j 2 prend également en charge la spécification duConfigurationFactory t à utiliser via un paramètre-D:

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

Le principal avantage de cette approche est que nous n'avons pas à nous soucier de l'ordre d'initialisation comme nous le faisons avec les deux premières approches.

4.3. Utilisez l'annotation@Plugin 

Et enfin, dans les circonstances où nous ne voulons pas jouer avec la commande de démarrage Java en ajoutant un-D, nous pouvons simplement annoter nosCustomConfigurationFactory avec l'annotation Log4j 2@Plugin :

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

  // ... rest of implementation
}

Log4j 2 recherchera dans le chemin des classes les classes ayant l'annotation@Plugin et, trouvant cette classe dans la catégorieConfigurationFactory , l'utilisera.

4.4. Combinaison avec la configuration statique

Un autre avantage de l'utilisation d'une extensionConfigurationFactory est que nous pouvons facilement combiner notre configuration personnalisée avec d'autres sources de configuration comme XML:

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

Le paramètresource représente le fichier de configuration XML ou JSON statique que Log4j 2 trouve le cas échéant.

Nous pouvons prendre ce fichier de configuration et l'envoyer à notre implémentation personnalisée deXmlConfiguration où nous pouvons placer toute configuration de remplacement dont nous avons besoin:

public class WithXmlConfiguration extends XmlConfiguration {

    @Override
    protected void doConfigure() {
        super.doConfigure(); // parse xml document

        // ... add our custom configuration
    }
}

5. Conclusion

Dans cet article, nous avons examiné comment utiliser la nouvelle APIConfigurationBuilder disponible dans Log4j 2.

Nous avons également examiné la personnalisation de la combinaisonConfigurationFactory in avecConfigurationBuilder pour des cas d'utilisation plus avancés.

N'oubliez pas de consulter mes exemples completsover on GitHub.