Programowa konfiguracja rejestratorów Log4j

191

Próbuję użyć SLF4J (z log4jwiązaniem) po raz pierwszy.

Chciałbym skonfigurować 3 różne nazwane Loggery, które mogą zostać zwrócone przez LoggerFactory, który będzie rejestrował różne poziomy i przekazywał wiadomości do różnych programów dołączających:

  • Logger 1 „FileLogger” rejestruje DEBUG i dołącza do DailyRollingFileAppender
  • Logger 2 „TracingLogger” rejestruje TRACE + i dołącza do JmsAppender
  • Logger 3 „ErrorLogger” rejestruje BŁĄD + i dołącza do innego JmsAppender

Ponadto chcę je skonfigurować programowo (w Javie, w przeciwieństwie do XML lub log4j.propertiespliku).

Wyobrażam sobie, że normalnie zdefiniowałbym je Loggergdzieś w kodzie ładującym, jak init()metoda. Ponieważ jednak chcę korzystać slf4j-log4j, nie jestem pewien, gdzie mogę zdefiniować programy rejestrujące i udostępnić je ścieżce klasy.

Nie wierzę, że jest to naruszenie podstawowego celu SLF4J (jako fasady), ponieważ mój kod korzystający z interfejsu API SLF4J nigdy nie będzie wiedział, że te programy rejestrujące istnieją. Mój kod wykonuje zwykłe wywołania do interfejsu API SLF4J, który następnie przekazuje je do rejestratorów log4j, które znajdzie na ścieżce klasy.

Ale jak skonfigurować te log4j Loggery na ścieżce klas ... w Javie ?!

IAmYourFaja
źródło
3
Dla log4j 1.x używać Zaakceptowanych odpowiedź poniżej 2.x zobaczyć logging.apache.org/log4j/2.x/manual/customconfig.html
earcam

Odpowiedzi:

279

Możesz dodać / usunąć Appender programowo do 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

Sugeruję umieszczenie go w init () gdzieś, gdzie masz pewność, że zostanie to wykonane zanim cokolwiek innego. Następnie możesz usunąć wszystkie istniejące programy dołączające z głównego programu rejestrującego za pomocą

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

i zacznij od dodania własnego. Aby to zadziałało, potrzebujesz log4j w ścieżce klas.

Uwaga:
Możesz wziąć dowolne Logger.getLogger(...), aby dodać programy dołączające. Właśnie wziąłem główny rejestrator, ponieważ jest on na dole wszystkich rzeczy i będzie obsługiwał wszystko, co przechodzi przez inne programy dołączające w innych kategoriach (chyba że skonfigurowano inaczej przez ustawienie flagi addytywności).

Jeśli chcesz wiedzieć, jak działa rejestrowanie i jak zdecydować, gdzie są zapisywane logi, przeczytaj ten podręcznik, aby uzyskać więcej informacji na ten temat.
W skrócie:

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

da ci logger dla kategorii „com.fizz”.
W powyższym przykładzie oznacza to, że wszystko, co się z nim zaloguje, będzie odsyłane do konsoli i programu dołączającego pliki w głównym programie rejestrującym.
Jeśli dodasz program dołączający do Logger.getLogger („com.fizz”). AddAppender (newAppender), wówczas logowanie z fizzbędzie obsługiwane przez wszystkie programy dołączające z głównego loggera i newAppender.
Nie tworzysz rejestratorów z konfiguracją, po prostu udostępniasz moduły obsługi wszystkich możliwych kategorii w twoim systemie.

oers
źródło
2
Dzięki, proszę! Szybkie pytanie - zauważyłem, że dodajesz programy dołączające do głównego programu rejestrującego. Czy jest tego powód?
IAmYourFaja,
I, co ważniejsze, będę musiał określić, który Logger ma pobrać z LoggerFactory SLF4J. Czy można zapytać SLF4J o główny program rejestrujący log4j?
IAmYourFaja,
3
@AdamTannon Możesz wziąć dowolny Logger.getLogger (...), który ci się podoba. Właśnie wziąłem główny rejestrator, ponieważ jest on na dole wszystkich rzeczy i będzie obsługiwał wszystko, co jest przekazywane przez inne programy dołączające w innych kategoriach (chyba że skonfigurowano inaczej). Zobacz rejestratora hierarchię
Oers
@AdamTannon nie można użyć fabryki sl4j do uzyskania głównego loggera log4j. SL4j to fasada zrębowa. Nie dostaniesz z tego niczego specyficznego dla log4j.
dniu
2
oers - Doceniam twoją wspaniałą opinię, ale po prostu nie łączę tutaj wszystkich kropek. Czy możesz zmodyfikować swój przykład, aby pokazać dodanie nowego Loggera (nie root loggera), który po dodaniu do systemu będzie dostępny dla każdej innej klasy, która o to poprosi? Na przykład Logger, do którego normalnie można uzyskać dostęp, powiedzmy: Logger fizz = LoggerFactory.getLogger("com.fizz");Dzięki!
IAmYourFaja,
47

Wygląda na to, że próbujesz użyć log4j z „obu końców” (od strony konsumenta i od konfiguracji).

Jeśli chcesz napisać kodowanie do interfejsu API slf4j, ale z góry określisz (i programowo) konfigurację rejestratorów log4j, że ścieżka klasy zwróci, absolutnie musisz mieć jakąś adaptację rejestrowania, która wykorzystuje leniwą konstrukcję.

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

Dzięki takiemu podejściu nie musisz się martwić o to, gdzie / kiedy zostaną skonfigurowane rejestratory log4j. Za pierwszym razem, gdy prosi o nie classpath, leniwie je konstruują, wracają i udostępniają przez slf4j. Mam nadzieję, że to pomogło!

IAmYourFaja
źródło
2
Przybiłam to! Dziękuję bardzo za pomocny przykład! @Oers - dziękuję za próbę skierowania mnie we właściwym kierunku - dam ci zielony czek za twoje poświęcenie, ale muszę dać zharvey nagrodę, ponieważ to było dokładnie to, czego szukałem. Jeszcze raz dziękuję wszystkim!
IAmYourFaja
4

W przypadku, gdy zdefiniowałeś moduł dołączający we właściwościach log4j i chciałbyś go zaktualizować programowo, ustaw nazwę we właściwościach log4j i uzyskaj ją według nazwy.

Oto przykładowy wpis 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

Aby go zaktualizować, wykonaj następujące czynności:

((ConsoleAppender) Logger.getRootLogger().getAppender("console")).setThreshold(Level.DEBUG);
Kyle Shrader
źródło
1

Jeśli ktoś szuka programowej konfiguracji log4j2 w Javie, ten link może pomóc: ( https://www.studytonight.com/post/log4j2-programmatic-configuration-in-java-class )

Oto podstawowy kod do konfigurowania programu dołączającego do konsoli:

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

Spowoduje to zmianę konfiguracji domyślnego rootLoggera, a także utworzenie nowego programu dołączającego .

iamabhishek
źródło