Это довольно старый логер, появление которого, как и огромного количества других связано с тем, что в Java в своё время не было стандартного механизма логирования, что привело к настоящему хаосу. Библиотека логирования log4j 1.2 больше не поддерживается (начиная с 5 августа 2015), так что новые проекты его точно не используют, но старые ещё могли остаться. В современном мире правильным считается подход с использованием Slf4j и Logback.
Для начала давайте проведёт общим вводный курс в работу Log4j 1.2 (дальше в статье я не буду упоминать версию для краткости, но подразумевается именно версия 1.2). Работа с log4j заключается с работой с:
- Logger — это куда мы в своём приложении отправляем сообщения.
- Appender — различные обработчики сообщений лога. Каждый Appender обрабатывает какое-то определённое место назначения для сообщений лога (файл, память, TCP порт, JMS и т. д.), то есть это то же самое, что и Handler для java.util.logging.
- Layout — форматирует сообщения логов, например в XML или HTML. Это аналог форматировщиков (formatters) в java.util.logging.
Для дальнейшего изучения создайте новый проект Maven. Добавьте туда зависимость:
1 2 3 4 5 |
<dependency> <groupId>log4j</groupId> <artifactId>log4j</artifactId> <version>1.2.17</version> </dependency> |
Это самая последняя версия log4j 1.2. Новых версий больше не будет. Полную документацию (на английском) можно прочесть на официальном сайте. Возможности
Получим экземпляр логера для нашего класса:
1 2 |
private static final Logger logger = Logger.getLogger( Log4j12ExampleApp.class); |
Теперь нам нужно создавть файл конфигурации “log4j.properties” в “src/main/resources”:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
# Set root logger level to DEBUG and two appenders log4j.rootLogger=DEBUG, MyConsAppender, MyFileAppender # A1 is set to be a ConsoleAppender. log4j.appender.MyConsAppender=org.apache.log4j.ConsoleAppender # A1 uses PatternLayout. log4j.appender.MyConsAppender.layout=org.apache.log4j.PatternLayout log4j.appender.MyConsAppender.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} [%t] %-5p %c - %m%n log4j.appender.MyFileAppender=org.apache.log4j.DailyRollingFileAppender log4j.appender.MyFileAppender.File=log4j12example.log log4j.appender.MyFileAppender.datePattern=yyyy-MM-dd log4j.appender.MyFileAppender.layout=org.apache.log4j.PatternLayout log4j.appender.MyFileAppender.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} [%t] %-5p %c - %m%n |
В этом файле мы указываем, что корневой логер будет обрабатывать сообщения вплоть до уровня DEBUG, а также присоединяем к нему два appender-а: MyConsAppender и MyFileAppender. Первый будет писать логи в консоль, а второй будет писать логи в файл “log4j12example.log”, а также каждый новый день переименовывать старый файл в “log4j12example.log<дата>”, формат даты указан в datePattern.
Разберём строку, указанную в ConversionPattern:
%d{yyyy-MM-dd HH:mm:ss} — указываем формат вывода даты и времени для сообщений лога.
%t — название потока
%-5p — уровень сообщения лога (DEBUG, TRACE, ERROR…)
%c — категория лога (у нас будет выводиться имя класса)
%m — само сообщение
%n — перевод строки
Теперь нужно написать какое-нибудь тестовое приложение. Но для начала нужно разобраться с уровнями логирования. В log4j 1.2 существует шесть уровней логирования:
- TRACE (для ещё большего количества ещё более детальных отладочных сообщений),
- DEBUG (для отладочных сообщений),
- INFO (для информационных сообщений),
- WARN (для предупреждений),
- ERROR (для логирования ошибок),
- FATAL (для критических ошибок).
С этими знаниями мы уже можем написать простое приложение с логированием:
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 |
package ru.urvanov.javaexamples.log4j12; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Paths; import org.apache.log4j.Logger; public class Log4j12ExampleApp { private static final Logger logger = Logger.getLogger( Log4j12ExampleApp.class); private static final String FILENAME = "/file/does/not/exist"; public static void main( String[] args ) { logger.info("Just a log message."); logger.debug("Message for debug level."); try { Files.readAllBytes(Paths.get(FILENAME)); } catch (IOException ioex) { logger.error( String.format("Failed to read file '%s'.", FILENAME), ioex); } } } |
Если мы запустим этот класс на выполнение, то увидим в консоли и в файле лога следующее:
1 2 3 4 5 6 7 8 9 10 11 12 |
2019-07-04 10:57:00 [main] INFO ru.urvanov.javaexamples.log4j12.Log4j12ExampleApp - Just a log message. 2019-07-04 10:57:00 [main] DEBUG ru.urvanov.javaexamples.log4j12.Log4j12ExampleApp - Message for debug level. 2019-07-04 10:57:00 [main] ERROR ru.urvanov.javaexamples.log4j12.Log4j12ExampleApp - Failed to read file '/file/does/not/exist'. java.nio.file.NoSuchFileException: \file\does\not\exist at sun.nio.fs.WindowsException.translateToIOException(WindowsException.java:79) at sun.nio.fs.WindowsException.rethrowAsIOException(WindowsException.java:97) at sun.nio.fs.WindowsException.rethrowAsIOException(WindowsException.java:102) at sun.nio.fs.WindowsFileSystemProvider.newByteChannel(WindowsFileSystemProvider.java:230) at java.nio.file.Files.newByteChannel(Files.java:361) at java.nio.file.Files.newByteChannel(Files.java:407) at java.nio.file.Files.readAllBytes(Files.java:3152) at ru.urvanov.javaexamples.log4j12.Log4j12ExampleApp.main(Log4j12ExampleApp.java:21) |
В log4j существует иерархия логеров. В нашем файле “log4j.properties” мы задавали настройки для корневого логера, а используем логер с именем класса (мы его получаем как Logger.getLogger(Log4j12ExampleApp.class)). При большом желании мы могли бы указать для этого логера отдельные настройки, appender-ы, уровень логирования и т. д. Например, следующая строчка в файле конфигурации укажет уровень логирования для пакета ru.urvanov:
1 |
log4j.logger.ru.urvanov=WARN |