Не пугайтесь, я помню, что писал уже про log4j, но я писал про версию 1.2, которая уже устарела. Сейчас уже существует вторая версия, которая добавляет новые возможности. Полную документацию на английском можно найти на официальном сайте. Здесь же я коротко расскажу о настройке и создании простого приложения с помощью этого логера. Имейте в виду, что подход, описанный в этой статье тоже неудачный. Сейчас обычно используют подход с Slf4j и Logback.
В Log4j 2 отдельно выделен интерфейс API и сама реализация, в результате чего мы можем использовать API Log4j 2, но реализацию другого логера. Я, правда, ни разу не видел в реальных проектах, чтобы кто-то так делал.
Итак, давайте создадим простое приложение с Log4j 2 в качестве библиотеки логирования. Для начала создадим новый Maven проект и в зависимости добавим Log4j 2:
1 2 3 4 5 6 7 8 9 10 |
<dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-api</artifactId> <version>2.12.0</version> </dependency> <dependency> <groupId>org.apache.logging.log4j</groupId> <artifactId>log4j-core</artifactId> <version>2.12.0</version> </dependency> |
Мы подключили API (log4j-api), содержащий интерфейсы и реализацию этих интерфейсов от Log4j2 (log4j-core)
Нам нужно создать файл конфигурации. Log4j два поддерживает файлы Java Properties, XML, JSON, YAML и программную настройку. Мы будем использовать файл XML. Создайте файл “log4j2.xml” (обратите внимание на цифру 2 после log4j, она обязательна) в “src/main/resources” со следующим содержимым:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="debug" strict="true" name="XMLConfigTest" packages="org.apache.logging.log4j.test"> <Filter type="ThresholdFilter" level="trace" /> <Appenders> <Console name="STDOUT"> <Layout type="PatternLayout" pattern="%m %n" /> </Console> <RollingFile name="rollingFile" fileName="logs/log4j2.log" filePattern="logs/$${date:yyyy-MM}/app-%d{MM-dd-yyyy}-%i.log.gz"> <PatternLayout> <Pattern>%d %p %c{1.} [%t] %m%n</Pattern> </PatternLayout> <Policies> <TimeBasedTriggeringPolicy interval = "1" /> <SizeBasedTriggeringPolicy size="250 MB" /> </Policies> </RollingFile> </Appenders> <Loggers> <Root level="INFO"> <AppenderRef ref="STDOUT" /> <AppenderRef ref="rollingFile" /> </Root> </Loggers> </Configuration> |
Здесь мы указываем, что к корневому логеру подключены два Appender-а: STDOUT и rollingFile. Первый пишет в консоль, а второй пишет в файл “logs/log4j2.log”, при этом каждый день создаёт новый файл ( TimeBasedTriggeringPolicy interval = "1"), а также ограничивает размер файла 250 мегабайтами.
В PatternLayout мы указываем формат сообщения:
%d — дата и время
%p — уровень сообщения (DEBUG, WARN, INFO…)
%c{1.} — категория, причём имена пакетов будут сокращаться до первой буквы
%t — название потока
%m — сообщение для лога
%n — перевод строки
Сам код программы будет выглядеть так:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
package ru.urvanov.javaexamples.log4j2; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Paths; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; public class Log4j2ExampleApp { private static final Logger logger = LogManager.getLogger(); public static void main(String[] args) { logger.info("Log4j2ExampleApp started."); logger.warn("Something to warn"); logger.error("Something failed."); try { Files.readAllBytes(Paths.get("/file/does/not/exist")); } catch (IOException ioex) { logger.error("Error message", ioex); } } } |
Если мы запусим этот код на исполнение, то в каталог “log” появится файл “log4j2.log” со следующим содержимым:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
2019-07-04 16:12:21,327 INFO r.u.j.l.Log4j2ExampleApp [main] Log4j2ExampleApp started. 2019-07-04 16:12:21,343 WARN r.u.j.l.Log4j2ExampleApp [main] Something to warn 2019-07-04 16:12:21,343 ERROR r.u.j.l.Log4j2ExampleApp [main] Something failed. 2019-07-04 16:12:21,343 ERROR r.u.j.l.Log4j2ExampleApp [main] Error message java.nio.file.NoSuchFileException: \file\does\not\exist at sun.nio.fs.WindowsException.translateToIOException(WindowsException.java:79) ~[?:1.8.0_192] at sun.nio.fs.WindowsException.rethrowAsIOException(WindowsException.java:97) ~[?:1.8.0_192] at sun.nio.fs.WindowsException.rethrowAsIOException(WindowsException.java:102) ~[?:1.8.0_192] at sun.nio.fs.WindowsFileSystemProvider.newByteChannel(WindowsFileSystemProvider.java:230) ~[?:1.8.0_192] at java.nio.file.Files.newByteChannel(Files.java:361) ~[?:1.8.0_192] at java.nio.file.Files.newByteChannel(Files.java:407) ~[?:1.8.0_192] at java.nio.file.Files.readAllBytes(Files.java:3152) ~[?:1.8.0_192] at ru.urvanov.javaexamples.log4j2.Log4j2ExampleApp.main(Log4j2ExampleApp.java:19) [classes/:?] |
В тестах мы тоже пишем сообщения в лог, но нам уже не нужно создавать файл лога, достаточно консоли, поэтому мы создаём файл “log2j2-test.xml” в каталоге “src/test/resources”, в котором указываем только Appender, пишущий в консоль:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
<?xml version="1.0" encoding="UTF-8"?> <Configuration status="debug" strict="true" name="XMLConfigTest" packages="org.apache.logging.log4j.test"> <Filter type="ThresholdFilter" level="trace" /> <Appenders> <Console name="STDOUT"> <Layout type="PatternLayout" pattern="%m %n" /> </Console> </Appenders> <Loggers> <Root level="DEBUG"> <AppenderRef ref="STDOUT" /> </Root> </Loggers> </Configuration> |
Сам класс с тестом будет выглядеть, например, так:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
package ru.urvanov.javaexamples.log4j2; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.junit.Test; public class AppTest { private static final Logger logger = LogManager.getLogger(); @Test public void test1() { logger.info("App test log message."); } } |