Параметризованная регистрация
Эффективно форматируйте сообщения
«Параметризованная регистрация» — бесплатный урок Java Academy на CoddyKit. Это урок 3 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения Java Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс Java Academy содержит 4 уроков всего.
Проблема конкатенации строк
При конкатенации сообщения журнала полная строка создаётся до вызова, даже если уровень отключён.
log.debug("id=" + id + " name=" + name) расходует ресурсы CPU, когда DEBUG отключён, поскольку строка создаётся в любом случае.
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Main {
private static final Logger log = LoggerFactory.getLogger(Main.class);
public static void main(String[] args) {
String name = "Ada"; int id = 7;
// Bad: string is built even if DEBUG is disabled
log.debug("id=" + id + " name=" + name);
}
}Заполнители с помощью {}
SLF4J использует {} как заполнитель. Передавайте значения в качестве дополнительных аргументов.
Сообщение собирается только при включённом уровне, поэтому отключённые записи почти ничего не стоят.
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Main {
private static final Logger log = LoggerFactory.getLogger(Main.class);
public static void main(String[] args) {
String name = "Ada"; int id = 7;
// Good: no string built unless DEBUG is on
log.debug("id={} name={}", id, name);
}
}Несколько заполнителей
Заполнители подставляются по порядку. В первый {} подставляется первый аргумент, во второй — второй и так далее.
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Main {
private static final Logger log = LoggerFactory.getLogger(Main.class);
public static void main(String[] args) {
log.info("order {} for user {} totaling {} cents", "A-1", 42, 1599);
}
}Почему это эффективно
Сначала библиотека проверяет уровень. Если он отключён, она сразу возвращается, не вызывая toString() ни для одного аргумента.
Затратная часть — форматирование — выполняется отложенно и только тогда, когда сообщение действительно будет выведено.
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Main {
private static final Logger log = LoggerFactory.getLogger(Main.class);
static String describe(Object o) { System.out.println("toString called"); return o.toString(); }
public static void main(String[] args) {
// Note: passing describe(...) still evaluates eagerly; pass the raw object instead
log.trace("value={}", new int[]{1, 2, 3});
}
}Передавайте исходные объекты, а не отформатированные строки
Чтобы получить преимущество отложенного выполнения, передавайте исходный объект, а не вызов метода, который его форматирует.
Если написать log.debug("{}", buildReport()), buildReport() всё равно выполнится немедленно. Передавайте аргументы, которые регистратор сможет отформатировать самостоятельно.
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Main {
private static final Logger log = LoggerFactory.getLogger(Main.class);
public static void main(String[] args) {
Object user = new Object();
// Logger calls user.toString() only if DEBUG is enabled
log.debug("current user: {}", user);
}
}Отложенные поставщики для тяжёлых операций
Если форматирование действительно требует много ресурсов, используйте плавный API SLF4J 2.x с Supplier, чтобы отложить выполнение.
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Main {
private static final Logger log = LoggerFactory.getLogger(Main.class);
static String heavyReport() { return "...expensive..."; }
public static void main(String[] args) {
log.atDebug()
.setMessage("report: {}")
.addArgument(() -> heavyReport())
.log();
}
}Экранирование фигурной скобки
Если в сообщении нужна литеральная пара {}, экранируйте её обратной косой чертой: \\{}.
Это требуется редко, но полезно при журналировании текста, похожего на JSON.
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Main {
private static final Logger log = LoggerFactory.getLogger(Main.class);
public static void main(String[] args) {
// Logs a literal {} then the value
log.info("empty object is \\{} and id is {}", 7);
}
}Исключение и заполнители
Заполнители можно сочетать с исключением в конце. SLF4J распознаёт, что последний аргумент — это Throwable, и выводит его трассировку стека.
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Main {
private static final Logger log = LoggerFactory.getLogger(Main.class);
public static void main(String[] args) {
int id = 99;
try {
throw new RuntimeException("db down");
} catch (Exception e) {
log.error("failed processing record {}", id, e);
}
}
}Не используйте слишком много аргументов
Если количество заполнителей не совпадает с количеством аргументов, SLF4J старается обработать ситуацию, но вывод может выглядеть неправильно.
Следите за их соответствием. Для более чем пары значений рассмотрите структурированный контекст (MDC).
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Main {
private static final Logger log = LoggerFactory.getLogger(Main.class);
public static void main(String[] args) {
// Two placeholders, two arguments: correct
log.info("user {} did {}", "ada", "login");
}
}Добавление контекста с помощью MDC
Для значений, общих для многих строк (например, идентификатора запроса), используйте MDC, а не добавляйте их в каждое сообщение.
После этого шаблон форматирования сможет автоматически выводить значение MDC в каждой строке.
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;
public class Main {
private static final Logger log = LoggerFactory.getLogger(Main.class);
public static void main(String[] args) {
MDC.put("requestId", "req-1234");
try {
log.info("handling request");
log.info("request done");
} finally {
MDC.clear();
}
}
}Итоги рекомендаций
Правила эффективного журналирования:
- Всегда используйте заполнители
{}, никогда не используйте конкатенацию с помощью+. - Передавайте исходные объекты, а не заранее созданные строки.
- Используйте поставщики или
isXEnabled()для действительно тяжёлых операций. - Используйте MDC для сквозного контекста.
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Main {
private static final Logger log = LoggerFactory.getLogger(Main.class);
public static void main(String[] args) {
log.info("processed {} items in {} ms", 1000, 42);
}
}Быстрая проверка
Проверьте свои знания о параметризованном журналировании.
Итоги
Вы изучили параметризованное журналирование:
- Используйте заполнители
{}с дополнительными аргументами. - Сообщения создаются отложенно, только при включённом уровне.
- Передавайте исходные объекты, а для тяжёлых операций используйте поставщиков.
- Используйте MDC для общих значений контекста.
Далее — настройка реализации Logback.
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class Main {
private static final Logger log = LoggerFactory.getLogger(Main.class);
public static void main(String[] args) {
log.info("Parameterized logging recap: {}", "done");
}
}Часто задаваемые вопросы
Урок «Параметризованная регистрация» бесплатный?
Да — полный текст урока «Параметризованная регистрация» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс Java Academy, подпишись на CoddyKit PRO. Курс Java Academy содержит 4 уроков всего.
Чему я научусь в уроке «Параметризованная регистрация»?
Эффективно форматируйте сообщения Ты практикуешь Java Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.
Нужен ли мне опыт, чтобы начать Java Academy?
Предыдущий опыт не требуется. Java Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 3 из 4.
Сколько времени занимает урок «Параметризованная регистрация»?
Большинство уроков CoddyKit занимают около 5–10 минут. Каждый из них компактный и интерактивный, поэтому ты постоянно делаешь прогресс и продолжаешь с того же места в веб-версии и приложении.
Можно ли писать и запускать код в этом уроке Java Academy?
Да. Каждый урок Java Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.
Все уроки этого курса
- Зачем нужна структурированная регистрация
- Фасад SLF4J и регистраторы
- Параметризованная регистрация
- Настройка Logback