0Pricing
Java Academy · Урок

Параметризованная регистрация

Эффективно форматируйте сообщения

«Параметризованная регистрация» — бесплатный урок 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 — локальная установка не требуется.

Все уроки этого курса

  1. Зачем нужна структурированная регистрация
  2. Фасад SLF4J и регистраторы
  3. Параметризованная регистрация
  4. Настройка Logback
← Назад к Java Academy