Этот фреймворк логирования тоже не стоит использовать в реальных проектах (как и System.err), даже не смотря на его присутствие в стандартной поставке Java, но знать о нём полезно. В современных проектах принято использовать Slf4j и Logback.
JUL появился в Java 1.4. Этот пример я пишу в Java 8. Работа с JUL происходит через класс java.util.logging.Logger. Мы получаем экземпляр этого класса через фабричный метод getLogger:
1 2 |
public static final Logger logger = Logger.getLogger( JulExample.class.getName()); |
Для записи сообщений в лог мы будем использовать методы нашего полученного экземпляра. Самый главный метод:
1 |
public void log(LogRecord record) |
Все остальные методы логирования (а их много) вызывают этот метод. Напрямую его мы использовать не будем, так как вызывать другие методы гораздо проще. Например:
1 |
public void log(Level level, String msg) |
Тут уже проще. Мы указываем сообщение и уровень логирования. Уровней логирования у нас всего семь:
- SEVERE (ошибка)
- WARNING (предупреждение)
- INFO (информационное сообщение)
- CONFIG
- FINE (сообщение об успешной операции)
- FINER
- FINEST
Сообщение же может быть любым текстом. Пример записи сообщения в лог с уровнем INFO:
1 |
logger.log(Level.INFO, "Application started and constructed."); |
Также для каждого из уровней логирования есть огромное множество перегруженных методов с различным числом параметров. Например, тот же самый результат можно получить вызвав:
1 |
logger.info("Application started and constructed."); |
Мы также можем писать сообщения об ошибках с уровнем логирования SEVERE, предупреждениях WARNING и т. д.:
1 2 3 |
logger.info("Application started and constructed."); logger.warning("Something to warn"); logger.severe("Something failed."); |
В результате выполнения в консоли мы увидим:
1 2 3 4 5 6 |
Jul 03, 2019 2:49:31 PM JulExample main INFO: Application started and constructed. Jul 03, 2019 2:49:31 PM JulExample main WARNING: Something to warn Jul 03, 2019 2:49:31 PM JulExample main SEVERE: Something failed. |
Если мы хотим передать исключение в лог, то нужно использовать специальный метод, принимающий Throwable:
1 2 3 4 5 |
try { Files.readAllBytes(Paths.get("/file/does/not/exist")); } catch (IOException ioex) { logger.log(Level.SEVERE, "Error message", ioex); } |
В результате выполнения этого кода в консоли будет:
1 2 3 4 5 6 7 8 9 |
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 JulExample.main(JulExample.java:17) |
Каждое сообщение, отправленное в логгер проходит фильтры, которые определяют, должно ли оно попасть в результирующий лог, например, по LogLevel, затем через обработчики. Обработчики (Handlers) направляют результат лога в файл, консоль или куда-нибудь по сети. В самой Java уже есть пять таких обработчиков, но можно добавлять свои. Стандартные обработчики:
- StreamHandler пишет в OutputStream.
- ConsoleHandler пишет в System.err.
- FileHandler пишет в файл.
- SocketHandler отправляет по сети на указанный порт.
- MemoryHandler просто сохраняет в ОЗУ.
Форматировщики используются для записи логов в определённом формате, например в XML или HTML.
Как всё это настраивается? Настраивать можно либо программно, тогда нужно указать -Djava.util.logging.config.class=<имя конфигурационного класса> при старте Java, либо с помощью файла, указываемого в -Djava.util.logging.config.file=<путь к конфигурационному файлу>. Если ничего из этого в аргументах JVM не указано, то используется конфигурация по умолчанию.
Файл с настройками, указываемый в java.util.logging.config.file — это обычный Java Properties файл. Пример его содержимого:
1 2 3 4 5 6 7 |
handlers=java.util.logging.FileHandler,java.util.logging.ConsoleHandler java.util.logging.FileHandler.level=FINEST java.util.logging.FileHandler.formatter=java.util.logging.SimpleFormatter java.util.logging.FileHandler.encoding=UTF-8 java.util.logging.FileHandler.limit=10000000 java.util.logging.FileHandler.pattern=/var/log/julexample/julexample%u.log java.util.logging.ConsoleHandler.level=FINEST |
В свойстве handlers мы указываем список обработчиков (handler-ов), которые нужно добавить к корневому логеру. Затем мы описываем FileHandler и ConsoleHandler.
В свойстве level мы указываем уровень логирования. В нашем случае сообщения с уровнем логирования от SEVERE до FINEST будут попадать в лог.
В свойстве formatter для FileHandler мы указали SimpleFormatter. Можно было указать XMLFormatter или написать какой-нибудь свой. Написание своего форматировщика я как-то расписывал на своём старом сайте (внешняя ссылка, много рекламы, не пугайтесь).
Свойство encoding позволяет задать кодировку для логов.
В limit для FileHandler указывается ограничение на размер файла логов для ротации в байтах.
Свойство pattern позволяет указать путь к файлу лога для FileHandler, где %u будет заменяться на числа (0, 1 …), для разрешения конфликтов имени файла.
Вот и всё. На всякий случай приложу полные коды класса JulExample:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
import java.io.IOException; import java.nio.file.Files; import java.nio.file.Paths; import java.util.logging.Level; import java.util.logging.Logger; public class JulExample { public static final Logger logger = Logger.getLogger( JulExample.class.getName()); public static void main(String[] args) { logger.info("Application started and constructed."); logger.warning("Something to warn"); logger.severe("Something failed."); try { Files.readAllBytes(Paths.get("/file/does/not/exist")); } catch (IOException ioex) { logger.log(Level.SEVERE, "Error message", ioex); } } } |
А полные коды “logging.properties” я уже указывал ранее. Не забывайте при запуске Java указывать параметр JVM-Djava.util.logging.config.file=<путь к файлу logging.properties>.