JUL (Java util Logging) - фреймворк для логирования входящий в состав Java SE. Находится в пакете java.util.logging. Если говорить о Java 9+, то он представляет собой модуль java.logging.
JUL, несмотря на его присутствие в стандартной поставке Java, как и System.out.println() или System.err.println(), не стоит его использовать в реальных проектах, т.к. он появился в Java значительно позже, по сравнению со специализированными решениями (библиотеками) для логирования и значительно уступает им по функциональности и производительности. В современных проектах чаще всего используют связки:
-
Slf4j + Log4j2
-
Slf4j + Logback
JUL появился в Java 1.4. Работа с JUL происходит через класс java.util.logging.Logger. Получить экземпляр этого класса можно через фабричный метод getLogger():
import java.util.logging.Logger;
public class JavaUtilLoggingExample {
public static final Logger logger = Logger.getLogger(JavaUtilLoggingExample.class.getName());
}
Для записи сообщений в лог используются методы полученного экземпляра класса Logger. Самый главный метод у которого public void log(LogRecord record). Все остальные методы логирования вызывают этот метод. Напрямую его использовать не стоит, так как вызывать другие методы гораздо проще, например public void log(Level level, String msg). Этому методу достаточно указать уровень логирования и сообщение.
Уровней логирования всего семь:
-
SEVERE (ошибка)
-
WARNING (предупреждение)
-
INFO (информационное сообщение)
-
CONFIG
-
FINE (сообщение об успешной операции)
-
FINER
-
FINEST
Сообщение же может быть любым текстом.
import java.util.logging.Level;
import java.util.logging.Logger;
public class JavaUtilLoggingExample {
public static final Logger logger = Logger.getLogger(JavaUtilLoggingExample.class.getName());
public void printLogWithInfo() {
logger.log(Level.INFO, "Print log with info level");
}
}
Также для каждого из уровней логирования есть огромное множество перегруженных методов с различным числом параметров. Например, тот же самый результат можно получить вызвав метод info()
import java.util.logging.Logger;
public class JavaUtilLoggingExample {
public static final Logger logger = Logger.getLogger(JavaUtilLoggingExample.class.getName());
public void printInfoLog() {
logger.info("Print info log");
}
}
Также можно писать сообщения об ошибках с другими уровнями логирования.
import java.util.logging.Logger;
public class JavaUtilLoggingExample {
public static final Logger logger = Logger.getLogger(JavaUtilLoggingExample.class.getName());
public void printLogWithAnotherLevel() {
logger.severe("Ошибка");
logger.warning("Предупреждение");
logger.info("Информация");
logger.fine("Отладка");
logger.finer("Отладка с деталями");
logger.finest("Отладка с огромным количеством деталей");
}
}
В результате вызова этого метода в консоль будет выведено:
Oct 10, 2022 6:59:22 AM com.rakovets.course.java.core.example.jul.JavaUtilLoggingExample printLogWithAnotherLevel SEVERE: Ошибка Oct 10, 2022 6:59:22 AM com.rakovets.course.java.core.example.jul.JavaUtilLoggingExample printLogWithAnotherLevel WARNING: Предупреждение Oct 10, 2022 6:59:22 AM com.rakovets.course.java.core.example.jul.JavaUtilLoggingExample printLogWithAnotherLevel INFO: Информация
Если необходимо передать исключение в лог, то нужно использовать специальный метод, принимающий Throwable:
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 JavaUtilLoggingExample {
public static final Logger logger = Logger.getLogger(JavaUtilLoggingExample.class.getName());
public void catchExceptionAndPrintLog() {
try {
Files.readAllBytes(Paths.get("/file/does/not/exist"));
} catch (IOException ex) {
logger.log(Level.SEVERE, "Error message", ex);
}
}
}
Oct 10, 2022 7:02:21 AM com.rakovets.course.java.core.example.jul.JavaUtilLoggingExample catchExceptionAndPrintLog SEVERE: Error message java.nio.file.NoSuchFileException: /file/does/not/exist at java.base/sun.nio.fs.UnixException.translateToIOException(UnixException.java:92) at java.base/sun.nio.fs.UnixException.rethrowAsIOException(UnixException.java:111) at java.base/sun.nio.fs.UnixException.rethrowAsIOException(UnixException.java:116) at java.base/sun.nio.fs.UnixFileSystemProvider.newByteChannel(UnixFileSystemProvider.java:219) at java.base/java.nio.file.Files.newByteChannel(Files.java:371) at java.base/java.nio.file.Files.newByteChannel(Files.java:422) at java.base/java.nio.file.Files.readAllBytes(Files.java:3206) at com.rakovets.course.java.core.example.jul.JavaUtilLoggingExample.catchExceptionAndPrintLog(JavaUtilLoggingExample.java:39) at com.rakovets.course.java.core.example.jul.JavaUtilLoggingExample.main(JavaUtilLoggingExample.java:17)
1. Handler

Каждое сообщение, отправленное в логгер проходит фильтры, которые определяют, должно ли оно попасть в результирующий лог, например, по LogLevel, затем через обработчики. Обработчики (Handlers) направляют результат лога в файл, консоль или куда-нибудь по сети.
В самой Java уже есть пять таких обработчиков, но можно добавлять свои. Стандартные обработчики:
-
StreamHandlerпишет вOutputStream. -
ConsoleHandlerпишет вSystem.err. -
FileHandlerпишет в файл. -
SocketHandlerотправляет по сети на указанный порт. -
MemoryHandlerпросто сохраняет в ОЗУ.

2. Formatter
Formatter используются для записи логов в определённом формате, например в XML или HTML.
3. Configuration
Настраивать JUL можно двумя способами:
-
Конфигурационный класс
Нужно указать аргумент-Djava.util.logging.config.class=<имя конфигурационного класса>при запуске Java программы. -
Конфигурационный файл
Нужно указать аргумент-Djava.util.logging.config.file=<путь к конфигурационному файлу>при запуске Java программы.
Второй способ более предпочтительный, так как не требует повторной сборки приложения. Если ничего из этого в аргументах JVM не указано, то используется конфигурация по умолчанию.
Файл с конфигурацией, указываемый в -Djava.util.logging.config.file — это обычный properties-файл. Например:
logging.propertieshandlers=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-ов), которые нужно добавить к корневому logger. -
Можно более детально описать работу handlers, в частности
FileHandlerиConsoleHandler. -
В свойстве
levelуказывается уровень логирования. В данном случае сообщения с уровнем логирования от SEVERE до FINEST будут попадать в лог. -
В свойстве
formatterдляFileHandlerуказаноSimpleFormatter. Можно указатьXMLFormatterили реализовать свой formatter. -
Свойство
encodingпозволяет задать кодировку для логов. -
В
limitдляFileHandlerуказывается ограничение на размер файла логов для ротации в байтах. -
Свойство
patternпозволяет указать путь к файлу лога дляFileHandler, где%uбудет заменяться на числа (0,1, …), для разрешения конфликтов имени файла.