Log4j2: журналы не отправляются на консоль, где как журналы в файл работает нормально - PullRequest
0 голосов
/ 02 мая 2019

Я новичок в log4j.Моя конфигурация log4j не записывает журналы в консоль, где, как журналы в файл, работает нормально.Я не могу решить эту проблему, несмотря на ссылки на более ранние сообщения.У меня есть два приложения - один для консоли, а другой для файла.Я намерен записать ОШИБКИ и ФАТАЛЬНЫЕ в файл, следовательно, используя уровень = ОШИБКА.Я намерен записать все журналы на консоль, следовательно, используя level = TRACE для консоли.Мой код содержит только один пакет с именем «параллельный», имеет один класс с именем ClassA и один метод, который регистрирует все типы журналов.

Если я укажу как консольные, так и файловые приложения в теге Root, мои ожидания оправдаются.Если я переместлю File appender за пределы Root и упомяну его в теге Logger, тогда только File appender работает там, где Console appender не работает.Обязательно ли помещать все добавочные элементы в корневой тег?

package parallel;
public class ClassA {
private final   Logger log = LogManager.getLogger(ClassA.class);
@Test 
public void testLogs() {
    log.info("info");
    log.debug("debug");
    log.warn("warn");
    log.error("error");
    log.fatal("fatal");
    log.trace("trace");
}

}

<Configuration status="INFO">
<Properties>
   <Property name="basePath" value="./logs" />
</Properties>
<Appenders>
  <Console name="console" target="SYSTEM_OUT">
    <PatternLayout>
     <Pattern>
     [%-5level] %d{yyyy-MM-dd HH:mm:ss.SSS} [%t] %c{1} - %msg%n
     </Pattern>
    </PatternLayout>
  </Console>
  <File name="fileLogger" fileName="${basePath}/error.log">
    <PatternLayout>
    <Pattern>
     [%-5level] %d{yyyy-MM-dd HH:mm:ss} [%t] %c{1} - %msg%n
    </Pattern>
    </PatternLayout>
  </File>
</Appenders>
<Loggers>
   <Root name="parallel">
     <AppenderRef ref="console" level="trace" />
   </Root>
   <Logger name="parallel" level="warn" additivity="false">
      <AppenderRef ref="fileLogger" />
   </Logger>
</Loggers>

Ответы [ 2 ]

1 голос
/ 05 мая 2019

Насколько я понимаю, ваша цель состоит в том, чтобы выполнить следующие пункты:

Я намереваюсь записать ОШИБКИ и ФАТАЛЬНЫЕ в файл, следовательно, используя level = ERROR.Я намереваюсь записать все журналы в консоль, следовательно, используя level = TRACE for Console.

Пожалуйста, прочитайте весь ответ, прежде чем сделать окончательный выбор относительно того, что вы будете внедрять в свой код.

Вы можете сделать это, настроив свои регистраторы следующим образом:

<Loggers>
    <Root>
        <AppenderRef ref="console"/>
    </Root>
    <Logger name="parallel" level="ALL" additivity="true">
        <AppenderRef ref="fileLogger" level="ERROR"/>
    </Logger>
</Loggers>

События журнала будут приниматься каждым регистратором на основе имени регистратора и уровня события.Например, если вы звоните log.error(...), генерируется событие уровня ERROR.Если log было получено через LogManager.getLogger(ClassA.class), то log4j будет искать в своей конфигурации регистратор с именем «parallel.ClassA».Если он не найдет такой регистратор, он перейдет вверх по иерархии к менее специфичному регистратору - «параллельному».Если этот регистратор не существует, он перейдет к корневому регистратору.

Как только регистратор идентифицирован, log4j должен определить, является ли событие принятым этим регистратором.Это основано на настройке уровня для регистратора.Поскольку «параллельный» логгер установлен на уровне ALL, он будет принимать события любого уровня.

После того, как регистратор принимает событие, его добавщики также должны принять событие.Уровень, связанный с файловым аппендером «параллельного» регистратора, равен ERROR, поэтому этот аппендер будет принимать только события уровня ERROR и FATAL.

Поскольку аддитивность составляет true для «параллельного» регистратора всякий раз, когда он принимает событие, он передает это событие аппендерам всех своих родительских регистраторов (если только один из них не сломается)цепочку, указав аддитивность false - подробности см. на странице архитектуры log4j2 ).Таким образом, любые события, принятые «параллелью», будут передаваться приложению консоли, связанному с корневым регистратором.

Существует проблема с этим подходом в том, что если событие журнала достигло корневого регистратора суровень ERROR или FATAL не будет записан в ваш файл журнала.Логи будут «просачиваться» в консоль.Это может произойти, если вы случайно написали какой-то плохой код или случайно забыли обновить файл конфигурации после добавления нового кода.

Вот пример кода, иллюстрирующий проблему:

package parallel;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

public class ClassA {
    private static final Logger log = LogManager.getLogger(ClassA.class);

    public static void main(String[] args) {
        log.info("info");
        log.debug("debug");
        log.warn("warn");
        log.error("error");
        log.fatal("fatal");
        log.trace("trace");

        // See the mistake here? 
        // The wrong logger name was used in the code, 
        // now the error event goes to the root logger!
        final Logger log2 = LogManager.getLogger("foo");
        log2.error("Woops an error!");
    }
}

консольный вывод для вышеприведенного с использованием конфигурации с начала ответа:

[INFO ] 2019-05-05 12:48:31.410 [main] ClassA - info
[DEBUG] 2019-05-05 12:48:31.411 [main] ClassA - debug
[WARN ] 2019-05-05 12:48:31.411 [main] ClassA - warn
[ERROR] 2019-05-05 12:48:31.411 [main] ClassA - error
[FATAL] 2019-05-05 12:48:31.412 [main] ClassA - fatal
[TRACE] 2019-05-05 12:48:31.412 [main] ClassA - trace
[ERROR] 2019-05-05 12:48:31.413 [main] foo - Woops an error!

Файл журнала ошибок показывает только:

[ERROR] 2019-05-05 12:48:31 [main] ClassA - error
[FATAL] 2019-05-05 12:48:31 [main] ClassA - fatal

Самое простое решение - просто переместить все ваши приложения в корневой логгер, как показано ниже:

<Loggers>
    <Root level="ALL">
        <AppenderRef ref="console"/>
        <AppenderRef ref="fileLogger" level="ERROR"/>
    </Root>
</Loggers>

Теперь все события принимаются корневым регистратором и консольным приложением, но только события ERROR и FATALпринимается заявителем файла.Теперь даже при неверном коде журнал событий будет идти в нужное место.

Выход консоли:

[INFO ] 2019-05-05 12:59:32.419 [main] ClassA - info
[DEBUG] 2019-05-05 12:59:32.421 [main] ClassA - debug
[WARN ] 2019-05-05 12:59:32.421 [main] ClassA - warn
[ERROR] 2019-05-05 12:59:32.421 [main] ClassA - error
[FATAL] 2019-05-05 12:59:32.421 [main] ClassA - fatal
[TRACE] 2019-05-05 12:59:32.421 [main] ClassA - trace
[ERROR] 2019-05-05 12:59:32.422 [main] foo - Woops an error!

Файл журнала ошибок:

[ERROR] 2019-05-05 12:59:32 [main] ClassA - error
[FATAL] 2019-05-05 12:59:32 [main] ClassA - fatal
[ERROR] 2019-05-05 12:59:32 [main] foo - Woops an error!

Другие возможные полезные ссылки:

https://stackoverflow.com/a/51567436/3284624

Надеюсь, это поможет вам!

0 голосов
/ 03 мая 2019

Частично решено ..... Я добавил Additivity = "true" в теге Logger, и это сделало печать журналов как в консоли, так и в файле.Однако уровень журнала ERROR применялся как к консоли, так и к файлу.Мое действительное требование - чтобы консоль имела TRACE, а File - уровень ERROR.Я не могу понять концепцию аддитивности из официального документа log4j2.Любой, кто мог бы объяснить эту концепцию, очень помог бы.

...