Конфигурирование Log4j Loggers Programmatically

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

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

  • Logger 1 "FileLogger" регистрирует DEBUG и добавляет к DailyRollingFileAppender
  • Logger 2 "TracingLogger" регистрирует TRACE + и добавляет к JmsAppender
  • Logger 3 "ErrorLogger" регистрирует ERROR + и добавляет к другому JmsAppender

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

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

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

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

Ответ 1

Вы можете добавить/удалить 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(...), который вам нравится добавлять. Я просто взял корневой журнал, потому что он находится в нижней части всех вещей и будет обрабатывать все, что передается через другие приложения в других категориях (если не настроено иначе, установив флаг аддитивности).

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

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

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

Ответ 2

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

Если вы хотите скопировать код с slf4j api, но заранее определите (и программно) конфигурацию log4j Loggers, возвращаемую классом pathpath, у вас абсолютно есть какая-то адаптация ведения журнала который использует ленивую конструкцию.

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

В том случае, если вы определили приложение в свойствах 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);