Конфигурирование Log4j Loggers программно - PullRequest
177 голосов
/ 23 января 2012

Я пытаюсь использовать SLF4J (с привязкой log4j) в первый раз.

Я хотел бы настроить 3 разных именованных регистратора, которые могут быть возвращены LoggerFactory, который будет регистрировать разные уровни и отправлять сообщения разным получателям:

  • Logger 1 «FileLogger» регистрирует отладку и добавляет к DailyRollingFileAppender
  • Logger 2 «TracingLogger» регистрирует TRACE + и добавляет к JmsAppender
  • Logger 3 «ErrorLogger» регистрирует ОШИБКУ + и добавляет к другому JmsAppender

Кроме того, я хочу, чтобы они конфигурировались программно (в Java, в отличие от XML или файла log4j.properties).

Я полагаю, что обычно я определяю эти Logger где-нибудь в некотором загрузочном коде, как метод init(). Однако из-за того, что я хочу использовать slf4j-log4j, я не понимаю, где я могу определить регистраторы и сделать их доступными для пути к классам.

Я не считаю, это нарушение основной цели SLF4J (как фасада), потому что мой код, использующий API SLF4J, никогда не узнает о существовании этих регистраторов. Мой код просто выполняет обычные вызовы API SLF4J, который затем перенаправляет их в Log4j Logger, которые он находит на пути к классам.

Но как мне настроить регистраторы log4j на пути к классам ... в Java?!

Ответы [ 3 ]

266 голосов
/ 25 января 2012

Вы можете добавлять / удалять Appender программно в 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

Я бы посоветовал вам поместить его в init () где-нибудь, где вы уверены, что это будет выполнено раньше всего. Затем вы можете удалить все существующие приложения в корневом логгере с помощью

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

и начните с добавления своего. Вам нужно, чтобы log4j находился в пути к классам, чтобы это работало.

Примечание:
Вы можете взять любой Logger.getLogger(...), который хотите добавить в качестве дополнений. Я просто взял root logger, потому что он лежит в основе всех вещей и будет обрабатывать все, что передается через другие appenders в других категориях (если не настроено иначе путем установки флага аддитивности).

Если вам нужно знать, как работает ведение журналов и как определяется, где записываются журналы прочитайте это руководство для получения дополнительной информации об этом.
Короче говоря:

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

выдаст вам регистратор для категории "com.fizz".
Для приведенного выше примера это означает, что все, что было зарегистрировано с ним, будет передано в консоль и файл appender в корневом логгере.
Если вы добавите приложение в Logger.getLogger ( "com.fizz"). AddAppender (newAppender) запись в fizz будет обрабатываться всеми приложениями из корневого регистратора и newAppender.
Вы не создаете регистраторы с этой конфигурацией, вы просто предоставляете обработчики для всех возможных категорий в вашей системе.

43 голосов
/ 28 января 2012

Звучит так, как будто вы пытаетесь использовать log4j с "обоих концов" (конечного пользователя и конечного пункта конфигурации).

Если вы хотите кодировать в API-интерфейсе slf4j, но заранее (и программно) определить конфигурацию Log4j Logger, которую вернет classpath, у вас будет абсолютно , чтобы иметь какую-то адаптацию ведения журнала, которая использует ленивую конструкцию.

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

При таком подходе вам не нужно беспокоиться о том, где и когда будут настроены ваши логгеры log4j. В первый раз, когда classpath запрашивает их, они лениво создаются, передаются обратно и становятся доступными через slf4j. Надеюсь, это помогло!

3 голосов
/ 18 августа 2017

В случае, если вы определили appender в свойствах log4j и хотите обновить его программным способом, задайте имя в свойствах log4j и получите его по имени.

Вот пример записи 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

Чтобы обновить его, выполните следующие действия:

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