Configurazione dei logger Log4j a livello di codice


191

Sto provando a usare SLF4J (con log4jassociazione) per la prima volta.

Vorrei configurare 3 Logger con nome diverso che possono essere restituiti da una LoggerFactory che registrerà livelli diversi e invierà i messaggi a diversi appendici:

  • Logger 1 "FileLogger" registra DEBUG e si aggiunge a DailyRollingFileAppender
  • Logger 2 "TracingLogger" registra TRACE + e si aggiunge a JmsAppender
  • Logger 3 "ErrorLogger" registra ERROR + e si aggiunge a un altro JmsAppender

Inoltre li voglio configurati programmaticamente (in Java, al contrario di XML o di un log4j.propertiesfile).

Immagino che, normalmente, li definirei Loggerda qualche parte in un codice di bootstrap, come un init()metodo. Tuttavia, poiché desidero utilizzarlo slf4j-log4j, sono confuso su dove poter definire i logger e renderli disponibili per il percorso di classe.

Non credo che questa sia una violazione dello scopo sottostante di SLF4J (come facciata), perché il mio codice che utilizza l'API SLF4J non saprà mai che esistono questi logger. Il mio codice effettua semplicemente chiamate normali all'API SLF4J, che poi le inoltra ai logger log4j che trova sul percorso di classe.

Ma come faccio a configurare quei logger log4j sul percorso di classe ... in Java ?!



3
Per log4j 1.x usare la risposta accettata sotto per vedere 2.x logging.apache.org/log4j/2.x/manual/customconfig.html
earcam

Risposte:


279

È possibile aggiungere / rimuovere Appender a livello di codice su 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

Ti suggerirei di inserirlo in un init () da qualche parte, dove sei sicuro, che questo verrà eseguito prima di ogni altra cosa. È quindi possibile rimuovere tutte le appendici esistenti sul logger principale con

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

e inizia aggiungendo il tuo. Ovviamente è necessario log4j nel percorso di classe affinché questo funzioni.

Nota:
puoi prendere qualsiasi Logger.getLogger(...)cosa desideri aggiungere appendici. Ho appena preso il logger di root perché è in fondo a tutte le cose e gestirà tutto ciò che viene passato attraverso altri appendici in altre categorie (a meno che non sia configurato diversamente impostando il flag di additività).

Se hai bisogno di sapere come funziona la registrazione e come viene deciso dove vengono scritti i registri, leggi questo manuale per maggiori informazioni a riguardo.
In breve:

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

ti darà un logger per la categoria "com.fizz".
Per l'esempio sopra questo significa che tutto ciò che ha effettuato l'accesso verrà riferito alla console e all'appender di file sul logger principale.
Se si aggiunge un appender a Logger.getLogger ("com.fizz"). AddAppender (newAppender), la registrazione da fizzverrà gestita da tutti gli appendici dal logger principale e da newAppender.
Non si creano logger con la configurazione, si forniscono solo gestori per tutte le possibili categorie nel proprio sistema.


2
Grazie oers! Domanda veloce: ho notato che stai aggiungendo gli appendici al Logger root. C'è una ragione per questo?
IAmYourFaja,

E, soprattutto, dovrò specificare quale Logger recuperare dalla LoggerFactory di SLF4J. È possibile chiedere a SLF4J il logger root di log4j?
IAmYourFaja,

3
@AdamTannon Puoi prendere qualsiasi Logger.getLogger (...) che ti piace. Ho appena preso il logger di root perché è in fondo a tutte le cose e gestirà tutto ciò che viene passato attraverso altri appendici in altre categorie (se non configurato diversamente). Vedi gerarchia dei logger
oers,

@AdamTannon non puoi usare la factory sl4j per ottenere il logger root log4j. SL4j è una facciata di registrazione. Non otterrai nulla di specifico da log4j.
Il

2
oers - apprezzo il tuo meraviglioso feedback, ma non sto collegando tutti i punti qui. Puoi modificare il tuo esempio per mostrare l'aggiunta di un nuovo Logger (non il root logger) che, una volta aggiunto al sistema, sarà disponibile per qualsiasi altra classe che lo richiede? Ad esempio, un Logger a cui normalmente si accede, ad esempio, Logger fizz = LoggerFactory.getLogger("com.fizz");grazie!
IAmYourFaja,

47

Sembra che tu stia provando a utilizzare log4j da "entrambe le estremità" (il lato consumer e il lato configurazione).

Se vuoi programmare contro l'API slf4j ma determinare in anticipo (e programmaticamente) la configurazione dei logger log4j che il percorso di classe restituirà, devi assolutamente avere una sorta di adattamento del log che utilizza la costruzione pigra.

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);
    }

Con questo approccio, non devi preoccuparti di dove / quando vengono configurati i tuoi logger log4j. La prima volta che il percorso di classe li richiede, vengono pigramente costruiti, restituiti e resi disponibili tramite slf4j. Spero che questo abbia aiutato!


2
Azzeccato! Grazie mille per un utile esempio! @Oers - grazie per aver cercato di orientarmi nella giusta direzione - Ti darò il segno di spunta verde per la tua dedizione ma devo dare a Zharvey la generosità perché era esattamente quello che stavo cercando. Grazie ancora a tutti!
IAmYourFaja,

4

Nel caso in cui sia stato definito un appender nelle proprietà log4j e si desidera aggiornarlo a livello di codice, impostare il nome nelle proprietà log4j e ottenerlo per nome.

Ecco una voce di esempio 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

Per aggiornarlo, procedi come segue:

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

1

Se qualcuno viene alla ricerca della configurazione di log4j2 a livello di codice in Java, questo link potrebbe aiutare: ( https://www.studytonight.com/post/log4j2-programmatic-configuration-in-java-class )

Ecco il codice di base per la configurazione di un Appender 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());

Ciò riconfigurerà il rootLogger predefinito e creerà anche un nuovo appender .

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.