Перейти к содержанию

Введение в логирование Java

Логирование является мощным средством для понимания и отладки поведения программы во время выполнения. Логи собирают и сохраняют важные данные и делают их доступными для анализа в любой момент времени.

В этой статье обсуждаются самые популярные фреймворки логирования Java, Log4j 2 и Logback, а также их предшественник Log4j. Кроме того, кратко затрагивается SLF4J, который предоставляет общий интерфейс для различных фреймворков логирования.

Включение логирования

Все фреймворки логирования, обсуждаемые в статье, разделяют понятия loggers, appenders и layouts. Включение логирования внутри проекта выполняется в три общих шага:

  1. Добавление необходимых библиотек.
  2. Конфигурация.
  3. Размещение логов.

В следующих разделах обсуждаются шаги для каждой платформы в отдельности.

Log4j 2

Log4j 2 – это новая и улучшенная версия платформы ведения журналов Log4j. Наиболее убедительным улучшением является возможность асинхронного ведения журнала. Для Log4j 2 требуются следующие библиотеки:

<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-api</artifactId>
    <version>2.6.1</version>
</dependency>
<dependency>
    <groupId>org.apache.logging.log4j</groupId>
    <artifactId>log4j-core</artifactId>
    <version>2.6.1</version>
</dependency>

Последнюю версию log4j-api можно найти здесь, а log4j-coreздесь.

Конфигурация

Настройка Log4j 2 основана на файле конфигурации log4j2.xml. Первое, что нужно настроить, это аппендеры (appenders). Они определяют, куда будет направляться сообщение журнала. Местом назначения может быть консоль, файл, сокет и т. д.

Log4j 2 имеет множество приложений для разных целей, найти дополнительную информацию можно на официальном сайте Log4j 2.

Посмотрим на простой пример конфигурации:

<Configuration status="debug" name="javamaster" packages="">
    <Appenders>
        <Console name="stdout" target="SYSTEM_OUT">
            <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss} %p %m%n"/>
        </Console>
    </Appenders>
</Configuration>

Можно установить name для каждого приложения, например, использовать console вместо stdout.

Обратите внимание на элемент PatternLayout – он определяет, как должно выглядеть сообщение. В нашем примере шаблон задается на основе параметра шаблона, где %d определяет шаблон даты, %p – вывод уровня логирования, %m – вывод сообщения лога, %n – добавляет символ новой строки. Более подробную информацию о шаблоне можете найти на официальной странице Log4j 2.

Наконец, чтобы включить appender (или несколько), нужно добавить его в раздел <Root>:

<Root level="error">
    <AppenderRef ref="STDOUT"/>
</Root>

Запись логов в файл

Иногда требуется логирование в файл, поэтому добавим в конфигурацию логера fout:

<Appenders>
    <File name="fout" fileName="javamaster.log" append="true">
        <PatternLayout>
            <Pattern>%d{yyyy-MM-dd HH:mm:ss} %-5p %m%nw</Pattern>
        </PatternLayout>
    </File>
</Appenders>

File аппендера имеет несколько параметров, которые можно настроить:

  • file – определяет имя лог-файла;
  • append – значение по умолчанию для этого параметра равно true, что означает, что по умолчанию File аппендера будет добавляться к существующему файлу, а не обрезать его;
  • PatternLayout, описанный в предыдущем примере.

Чтобы включить File аппендера, нужно добавить его в раздел <Root>:

<Root level="INFO">
    <AppenderRef ref="stdout" />
    <AppenderRef ref="fout"/>
</Root>

Асинхронное логирование

Если хотите сделать свой Log4j 2 асинхронным, нужно добавить библиотеку LMAX disruptor в pom.xml. LMAX disruptor – это неблокирующая библиотека межпотокового взаимодействия.

Добавим disruptor в pom.xml:

<dependency>
    <groupId>com.lmax</groupId>
    <artifactId>disruptor</artifactId>
    <version>3.3.4</version>
</dependency>

Последнюю версию disruptor можно найти здесь. Если хотите использовать LMAX disruptor, нужно использовать <asyncRoot> вместо <Root> в конфигурации.

<AsyncRoot level="DEBUG">
    <AppenderRef ref="stdout" />
    <AppenderRef ref="fout"/>
</AsyncRoot>

Или можно включить асинхронное логирование, задав для системного свойства Log4jContextSelector значение org.apache.logging.log4j.core.async.AsyncLoggerContextSelector.

Можно прочитать больше о настройке асинхронного логера Log4j2 и посмотреть некоторые диаграммы производительности на официальной странице Log4j2.

Применение

Ниже приведен простой пример, демонстрирующий использование Log4j для логирования:

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

public class Log4jExample {

    private static Logger logger = LogManager.getLogger(Log4jExample.class);

    public static void main(String[] args) {
        logger.debug("Debug log message");
        logger.info("Info log message");
        logger.error("Error log message");
    }
}

После запуска приложение будет регистрировать следующие сообщения как в консоли, так и в файле с именем javamaster.log:

2021-06-16 17:02:13 INFO  Info log message
2021-06-16 17:02:13 ERROR Error log message

Если повысите уровень корневого журнала до ERROR:

<level value="ERROR" />

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

2021-06-16 17:02:13 ERROR Error log message

Как видите, изменение параметра уровня логирования вверх приводит к тому, что сообщения с более низким уровнем логирования не будут печататься в приложениях.

Метод logger.error также можно использовать для регистрации произошедшего исключения:

try {
    // Here some exception can be thrown
} catch (Exception e) {
    logger.error("Error log message", throwable);
}

Конфигурация уровня пакета

Допустим, нужно показать сообщения с уровнем логирования TRACE – например, из определенного пакета, такого как ru.javamaster.log4j2:

logger.trace("Trace log message");

Для всех других пакетов вы хотите продолжать регистрировать только сообщения INFO. Имейте в виду, что TRACE ниже уровня корневого журнала INFO, который указали в конфигурации.

Чтобы включить логирование только для одного из пакетов, нужно добавить следующий раздел перед <Root> в log4j2.xml:

<Logger name="ru.javamaster.log4j2" level="debug">
    <AppenderRef ref="stdout"/>
</Logger>

Это позволит вести журнал для пакета ru.javamaster.log4j, и вывод будет выглядеть так:

2021-06-16 17:02:13 TRACE Trace log message
2021-06-16 17:02:13 DEBUG Debug log message
2021-06-16 17:02:13 INFO  Info log message
2021-06-16 17:02:13 ERROR Error log message

Logback

Logback задуман как улучшенная версия Log4j, разработанная тем же разработчиком, который создал Log4j.

Logback также имеет гораздо больше функций по сравнению с Log4j, и многие из них представлены в Log4j 2. Вот краткий обзор всех преимуществ Logback на официальном сайте.

Начнем с добавления следующей зависимости в pom.xml:

<dependency>
    <groupId>ch.qos.logback</groupId>
    <artifactId>logback-classic</artifactId>
    <version>1.2.6</version>
</dependency>

Эта зависимость транзитивно подтянет еще две зависимости: logback-core и slf4j-api. Обратите внимание, что последнюю версию Logback можно найти здесь.

Конфигурация

Посмотрим на пример конфигурации Logback:

<configuration>
  # Console appender
  <appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
    <layout class="ch.qos.logback.classic.PatternLayout">
      # Pattern of log message for console appender
      <Pattern>%d{yyyy-MM-dd HH:mm:ss} %-5p %m%n</Pattern>
    </layout>
  </appender>

  # File appender
  <appender name="fout" class="ch.qos.logback.core.FileAppender">
    <file>javamaster.log</file>
    <append>false</append>
    <encoder>
      # Pattern of log message for file appender
      <pattern>%d{yyyy-MM-dd HH:mm:ss} %-5p %m%n</pattern>
    </encoder>
  </appender>

  # Override log level for specified package
  <logger name="ru.javamaster.log4j" level="TRACE"/>

  <root level="INFO">
    <appender-ref ref="stdout" />
    <appender-ref ref="fout" />
  </root>
</configuration>

Logback использует SLF4J в качестве интерфейса, поэтому необходимо импортировать Logger и LoggerFactory SLF4J.

SLF4J

SLF4J предоставляет общий интерфейс и абстракцию для большинства фреймворков логирования Java. Он действует как фасад и предоставляет стандартизированный API для доступа к базовым функциям среды логирования.

Logback использует SLF4J в качестве собственного API для своей функциональности. Ниже приведен пример использования логирования Logback:

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Log4jExample {

    private static Logger logger = LoggerFactory.getLogger(Log4jExample.class);

    public static void main(String[] args) {
        logger.debug("Debug log message");
        logger.info("Info log message");
        logger.error("Error log message");
    }
}

Вывод останется таким же, как и в предыдущих примерах.

Log4j

Наконец, взглянем на почтенный фреймворк логирования Log4j.

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

Многие детали конфигурации соответствуют описанным в разделе Log4j 2.

Конфигурация

Прежде всего нужно добавить библиотеку Log4j в проекты pom.xml:

<dependency>
    <groupId>log4j</groupId>
    <artifactId>log4j</artifactId>
    <version>1.2.17</version>
</dependency>

Здесь можно найти последнюю версию Log4j.

Посмотрим на полный пример простой конфигурации Log4j только с одним консольным appender:

<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd" >
<log4j:configuration debug="false">

    <!--Console appender-->
    <appender name="stdout" class="org.apache.log4j.ConsoleAppender">
        <layout class="org.apache.log4j.PatternLayout">
            <param name="ConversionPattern" 
              value="%d{yyyy-MM-dd HH:mm:ss} %p %m%n" />
        </layout>
    </appender>

    <root>
        <level value="INFO" />
        <appender-ref ref="stdout" />
    </root>

</log4j:configuration>

<log4j:configuration debug=”false”> – это открытый тег всей конфигурации, который имеет одно свойство – debug. Он определяет, хотите ли вы добавлять отладочную информацию Log4j в логи.

Применение

После того, как добавили библиотеку и конфигурацию Log4j, можно использовать логер в своем коде. Рассмотрим простой пример:

import org.apache.log4j.Logger;

public class Log4jExample {
    private static Logger logger = Logger.getLogger(Log4jExample.class);

    public static void main(String[] args) {
        logger.debug("Debug log message");
        logger.info("Info log message");
        logger.error("Error log message");
    }
}

Заключение

В этой статье показаны очень простые примеры использования различных фреймворков логирования, таких как Log4j, Log4j2 и Logback. Она охватывает простые примеры конфигурации для всех упомянутых фреймворков.

Примеры, сопровождающие статью, можно найти на GitHub.

Оригинал