Configuration de Log4j Loggers par programme

J’essaie d’utiliser SLF4J (avec la liaison log4j ) pour la première fois.

Je voudrais configurer 3 Loggers nommés différents qui peuvent être retournés par un LoggerFactory qui enregistrera différents niveaux et transmettra les messages à différents appenders:

  • Logger 1 “FileLogger” enregistre DEBUG et ajoute à DailyRollingFileAppender
  • Logger 2 “TracingLogger” enregistre TRACE + et ajoute un JmsAppender
  • Logger 3 “ErrorLogger” enregistre ERROR + et ajoute un JmsAppender différent

De plus, je souhaite qu’ils soient configurés par programmation (en Java, par opposition à XML ou à un fichier log4j.properties ).

J’imagine que, normalement, je définirais ces Logger quelque part dans un code d’amorçage, comme une méthode init() . Cependant, parce que je veux utiliser slf4j-log4j , je ne slf4j-log4j pas où je pourrais définir des enregistreurs et les rendre disponibles au slf4j-log4j .

Je ne crois pas que cela constitue une violation de l’objective sous-jacent de SLF4J (en tant que façade), car mon code utilisant l’API SLF4J ne saura jamais que ces enregistreurs existent. Mon code effectue simplement des appels normaux à l’API SLF4J, qui les transmet ensuite aux log4j Loggers qu’il trouve sur le chemin de classe.

Mais comment puis-je configurer ces log4j Loggers sur le classpath … en Java ?!

Vous pouvez append / supprimer Appender par programme à Log4j:

  ConsoleAppender console = new ConsoleAppender(); //create appender //configure the appender Ssortingng PATTERN = "%d [%p|%c|%C{1}] %m%n"; console.setLayout(new PatternLayout(PATTERN)); console.setThreshold(Level.FATAL); console.activateOptions(); //add appender to any Logger (here is root) Logger.getRootLogger().addAppender(console); FileAppender fa = new FileAppender(); fa.setName("FileLogger"); fa.setFile("mylog.log"); fa.setLayout(new PatternLayout("%d %-5p [%c{1}] %m%n")); fa.setThreshold(Level.DEBUG); fa.setAppend(true); fa.activateOptions(); //add appender to any Logger (here is root) Logger.getRootLogger().addAppender(fa); //repeat with all other desired appenders 

Je vous suggère de le placer dans un init () quelque part, où vous êtes sûr, que cela sera exécuté avant toute autre chose. Vous pouvez ensuite supprimer tous les appenders existants sur l’enregistreur racine avec

  Logger.getRootLogger().getLoggerRepository().resetConfiguration(); 

et commencez par append les vôtres. Vous devez bien sûr avoir log4j dans le classpath pour que cela fonctionne.

Remarque:
Vous pouvez utiliser n’importe quel Logger.getLogger(...) pour append des appenders. Je viens de prendre l’enregistreur racine car il est au bas de toutes les choses et gérera tout ce qui passe par d’autres appenders dans les autres catégories (sauf si configuré autrement en définissant l’indicateur d’additivité).

Si vous avez besoin de savoir comment fonctionne la journalisation et comment vous décidez où les journaux sont écrits, lisez ce manuel pour plus d’informations à ce sujet.
En bref:

  Logger fizz = LoggerFactory.getLogger("com.fizz") 

vous donnera un enregistreur pour la catégorie “com.fizz”.
Pour l’exemple ci-dessus, cela signifie que tout ce qui est connecté sera renvoyé à la console et à l’appender de fichier dans le journal racine.
Si vous ajoutez un appender à Logger.getLogger (“com.fizz”). AddAppender (newAppender), la journalisation de fizz sera gérée par alle les appenders du logger racine et du newAppender .
Vous ne créez pas de Loggers avec la configuration, vous fournissez simplement des gestionnaires pour toutes les catégories possibles de votre système.

Il semble que vous essayiez d’utiliser log4j à partir des “deux extrémités” (l’extrémité consommateur et la fin de la configuration).

Si vous voulez coder avec l’api slf4j mais déterminez à l’avance (et par programmation) la configuration des log4j Loggers que le classpath renverra, vous devez absolument avoir une sorte d’adaptation de journalisation qui utilise une construction paresseuse.

 public class YourLoggingWrapper { private static boolean loggingIsInitialized = false; public YourLoggingWrapper() { // ...blah } public static void debug(Ssortingng debugMsg) { log(LogLevel.Debug, debugMsg); } // Same for all other log levels your want to handle. // You mentioned TRACE and ERROR. private static void log(LogLevel level, Ssortingng logMsg) { if(!loggingIsInitialized) initLogging(); org.slf4j.Logger slf4jLogger = org.slf4j.LoggerFactory.getLogger("DebugLogger"); switch(level) { case: Debug: logger.debug(logMsg); break; default: // whatever } } // log4j logging is lazily constructed; it gets initialized // the first time the invoking app calls a log method private static void initLogging() { loggingIsInitialized = true; org.apache.log4j.Logger debugLogger = org.apache.log4j.LoggerFactory.getLogger("DebugLogger"); // Now all the same configuration code that @oers suggested applies... // configure the logger, configure and add its appenders, etc. debugLogger.addAppender(someConfiguredFileAppender); } 

Avec cette approche, vous n’avez pas à vous soucier de la configuration de vos loggers log4j. La première fois que le classpath les demande, ils sont construits paresseusement, renvoyés et rendus disponibles via slf4j. J’espère que cela a aidé!

Dans le cas où vous avez défini un appender dans les propriétés log4j et souhaitez le mettre à jour par programmation, définissez le nom dans les propriétés log4j et obtenez-le par nom.

Voici un exemple d’entrée log4j.properties:

 log4j.appender.stdout.Name=console log4j.appender.stdout=org.apache.log4j.ConsoleAppender log4j.appender.stdout.Target=System.out log4j.appender.stdout.Threshold=INFO 

Pour le mettre à jour, procédez comme suit:

 ((ConsoleAppender) Logger.getRootLogger().getAppender("console")).setThreshold(Level.DEBUG);