Configuration des enregistreurs Log4j par programme

191

J'essaye d'utiliser SLF4J (avec log4jliaison) pour la première fois.

Je voudrais configurer 3 enregistreurs nommés différents qui peuvent être retournés par un LoggerFactory qui enregistrera différents niveaux et enverra 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 autre JmsAppender

De plus, je veux qu'ils soient configurés par programme (en Java, par opposition à XML ou à un log4j.propertiesfichier).

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

Je ne pense pas que ce soit une violation de l'objectif 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 fait juste des appels normaux à l'API SLF4J, qui les transmet ensuite aux enregistreurs log4j qu'il trouve sur le chemin de classe.

Mais comment configurer ces Log4j Loggers sur le chemin de classe ... en Java?!

IAmYourFaja
la source
3
Pour log4j 1.x, utilisez la réponse acceptée ci-dessous pour 2.x voir logging.apache.org/log4j/2.x/manual/customconfig.html
earcam

Réponses:

279

Vous pouvez ajouter / supprimer Appender par programme à Log4j:

  ConsoleAppender console = new ConsoleAppender(); //create appender
  //configure the appender
  String 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 mettre 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 ajouter le vôtre. Vous avez besoin de log4j dans le classpath bien sûr pour que cela fonctionne.

Remarque:
vous pouvez prendre tout Logger.getLogger(...)ce que vous voulez pour ajouter des appenders. Je viens de prendre l'enregistreur racine car il est au bas de toutes les choses et gérera tout ce qui est passé par d'autres appenders dans d'autres catégories (sauf configuration contraire en définissant l'indicateur d'additivité).

Si vous avez besoin de savoir comment fonctionne la journalisation et comment est décidé 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 y est consigné sera référencé vers la console et l'appender de fichier sur l'enregistreur racine.
Si vous ajoutez un appender à Logger.getLogger ("com.fizz"). AddAppender (newAppender), la journalisation à partir de fizzsera gérée par tous les appenders du root logger 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.

oers
la source
2
Merci oers! Question rapide - J'ai remarqué que vous ajoutez les appenders au root Logger. Y a-t-il une raison à cela?
IAmYourFaja
Et, plus important encore, je devrai spécifier quel Logger récupérer à partir de LoggerFactory de SLF4J. Est-il possible de demander à SLF4J le logger racine de log4j?
IAmYourFaja
3
@AdamTannon Vous pouvez prendre n'importe quel Logger.getLogger (...) que vous aimez. Je viens de prendre le root logger car il est au bas de toutes choses et gérera tout ce qui est passé par d'autres appenders dans d'autres catégories (sauf configuration contraire). Voir la hiérarchie des enregistreurs
oers
@AdamTannon vous ne pouvez pas utiliser l'usine sl4j pour obtenir le logger root log4j. SL4j est une façade d'exploitation forestière. Vous n'obtiendrez rien de spécifique à log4j.
oers le
2
oers - J'apprécie vos merveilleux commentaires, mais je ne relie tout simplement pas tous les points ici. Pouvez-vous modifier votre exemple pour montrer l'ajout d'un nouvel enregistreur (pas l'enregistreur racine) qui, une fois ajouté au système, sera disponible pour toute autre classe qui le demande? Par exemple, un enregistreur auquel on accède normalement, disons, Logger fizz = LoggerFactory.getLogger("com.fizz");Merci!
IAmYourFaja
47

On dirait que vous essayez d'utiliser log4j des «deux extrémités» (la fin du consommateur et la fin de la configuration).

Si vous voulez coder contre l'api slf4j mais déterminez à l'avance (et par programme) la configuration des log4j Loggers que le chemin de classe retournera, 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(String 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, String 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 l'endroit / du moment où vos enregistreurs log4j sont configurés. 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é!

IAmYourFaja
la source
2
J'y suis arrivé! Merci beaucoup pour cet exemple utile! @Oers - merci d'avoir essayé de me diriger dans la bonne direction - je vais vous donner le chèque vert pour votre dévouement, mais je dois donner la prime à zharvey parce que c'était exactement ce que je cherchais. Merci encore à tous!
IAmYourFaja
4

Dans le cas où vous avez défini un appender dans les propriétés log4j et souhaitez le mettre à jour par programme, définissez le nom dans les propriétés log4j et obtenez-le par son 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);
Kyle Shrader
la source
1

Si quelqu'un cherche à configurer log4j2 par programmation en Java, ce lien pourrait aider: ( https://www.studytonight.com/post/log4j2-programmatic-configuration-in-java-class )

Voici le code de base pour configurer un Appender de console:

ConfigurationBuilder<BuiltConfiguration> builder = ConfigurationBuilderFactory.newConfigurationBuilder();

builder.setStatusLevel(Level.DEBUG);
// naming the logger configuration
builder.setConfigurationName("DefaultLogger");

// create a console appender
AppenderComponentBuilder appenderBuilder = builder.newAppender("Console", "CONSOLE")
                .addAttribute("target", ConsoleAppender.Target.SYSTEM_OUT);
// add a layout like pattern, json etc
appenderBuilder.add(builder.newLayout("PatternLayout")
                .addAttribute("pattern", "%d %p %c [%t] %m%n"));
RootLoggerComponentBuilder rootLogger = builder.newRootLogger(Level.DEBUG);
rootLogger.add(builder.newAppenderRef("Console"));

builder.add(appenderBuilder);
builder.add(rootLogger);
Configurator.reconfigure(builder.build());

Cela reconfigurera le rootLogger par défaut et créera également un nouvel appender .

iamabhishek
la source