Логирование
Лог (журнал) — записи о том, что делала программа: запустилась, приняла заказ, не смогла подключиться к базе. По логу разбираются, что пошло не так на сервере, где отладчик не запустишь. Можно писать такие записи через System.out.println, но у них нет ни времени, ни важности, их нельзя отключить без правки кода, и они смешиваются с обычным выводом программы. Для этого есть логгеры.
System.Logger
Встроенный в JDK логгер получают методом System.getLogger(имя). Имя обычно совпадает с пакетом или классом и помогает понять, откуда пришла запись. Метод log принимает уровень важности и сообщение:
void main() {
System.Logger log = System.getLogger("shop");
log.log(System.Logger.Level.INFO, "Заказ принят");
}Результат (дата и время у вас будут другими):
окт. 04, 2026 10:30:02 AM Main main
INFO: Заказ принятЛоггер сам добавил время, класс и метод, откуда пришла запись. Пишет он в System.err, а не в System.out, поэтому записи можно перенаправить отдельно от вывода программы.
Формат записи
System.Logger по умолчанию передаёт записи стандартному логгеру JDK — java.util.logging. Его формат задаёт системное свойство java.util.logging.SimpleFormatter.format: в нём %1$s — дата, %3$s — имя логгера, %4$s — уровень, %5$s — сообщение, %6$s — исключение, %n — перевод строки. Свойство передают ключом -D или задают в начале программы:
void main() {
System.setProperty("java.util.logging.SimpleFormatter.format", "[%4$s] %3$s: %5$s%6$s%n");
System.Logger log = System.getLogger("shop");
log.log(System.Logger.Level.INFO, "Заказ принят");
}Результат:
[INFO] shop: Заказ принятУровни
У System.Logger.Level пять основных уровней — от самого подробного к самому важному: TRACE, DEBUG, INFO, WARNING, ERROR. По умолчанию выводятся записи от INFO и выше, а DEBUG и TRACE — подробности для отладки — скрыты. В выводе уровни называются по-своему: ERROR превращается в SEVERE, DEBUG — в FINE:
void main() {
System.setProperty("java.util.logging.SimpleFormatter.format", "[%4$s] %5$s%6$s%n");
System.Logger log = System.getLogger("shop");
log.log(System.Logger.Level.DEBUG, "Корзина: 3 товара");
log.log(System.Logger.Level.INFO, "Заказ принят");
log.log(System.Logger.Level.WARNING, "Осталось мало товара");
log.log(System.Logger.Level.ERROR, "Платёж отклонён");
}Результат:
[INFO] Заказ принят
[WARNING] Осталось мало товара
[SEVERE] Платёж отклонёнПараметры и исключения
Значения в сообщение подставляют через {0}, {1} — строка собирается, только если запись действительно выводится. Исключение передают последним аргументом, и логгер напечатает его вместе со стеком вызовов:
void main() {
System.setProperty("java.util.logging.SimpleFormatter.format", "[%4$s] %5$s%6$s%n");
System.Logger log = System.getLogger("shop");
log.log(System.Logger.Level.INFO, "Заказ {0} от {1}", 42, "Анна");
try {
Integer.parseInt("abc");
} catch (NumberFormatException e) {
log.log(System.Logger.Level.ERROR, "Не удалось прочитать количество", e);
}
}Результат (строки стека из JDK опущены):
[INFO] Заказ 42 от Анна
[SEVERE] Не удалось прочитать количество
java.lang.NumberFormatException: For input string: "abc"
at Main.main(Main.java:7)java.util.logging напрямую
Тот же механизм можно использовать и напрямую. Модуль java.logging не входит в java.base, поэтому нужен import. Методы называются по уровням: severe, warning, info, config, fine, finer, finest:
import java.util.logging.*;
void main() {
System.setProperty("java.util.logging.SimpleFormatter.format", "[%4$s] %3$s: %5$s%6$s%n");
Logger log = Logger.getLogger("shop.orders");
log.info("Заказ принят");
log.fine("Подробности для отладки");
log.warning("Платёж задерживается");
}Результат:
[INFO] shop.orders: Заказ принят
[WARNING] shop.orders: Платёж задерживаетсяВ реальных проектах чаще всего используют библиотеку SLF4J с реализацией Logback (в Spring Boot они подключены по умолчанию): логгер создают через LoggerFactory.getLogger(...), а параметры подставляют через {}. Идеи те же — имя, уровни, параметры, — а настройки хранят в файле logback.xml.
Частая ошибка
Чтобы увидеть отладочные записи, логгеру ставят уровень FINE — но они всё равно не появляются. Дело в том, что фильтров два: у логгера и у обработчика (handler), который печатает записи в консоль. Обработчик по умолчанию пропускает только INFO и выше, поэтому понизить уровень нужно и ему:
import java.util.logging.*;
void main() {
System.setProperty("java.util.logging.SimpleFormatter.format", "[%4$s] %5$s%6$s%n");
Logger log = Logger.getLogger("shop.orders");
log.setLevel(Level.FINE);
log.fine("не видно: обработчик отсекает FINE");
Logger.getLogger("").getHandlers()[0].setLevel(Level.FINE);
log.fine("теперь видно");
}Результат:
[FINE] теперь видноLogger.getLogger("") — корневой логгер, у которого и есть консольный обработчик. В больших программах такие настройки выносят в файл logging.properties и передают его ключом -Djava.util.logging.config.file=logging.properties.