Logger.info: примеры (JAVA)

Обзор применения Logger.info() и практики ведения логов
Раздел: Логирование
Logger.info(String msg): void

Общее описание метода Logger.info()

Метод Logger.info() используется для записи сообщений журнала на уровне информационных сообщений (INFO). В Java этот метод встречается у разных реализаций логирования: у стандартного java.util.logging.Logger, у SLF4J (org.slf4j.Logger), у Log4j и у обёрток над ними. Назначение одно: фиксировать сообщения, важные для понимания нормального состояния приложения, но не являющиеся ошибками.

Основные свойства и поведение зависят от реализации, но общая модель следующая:

  • уровень: INFO;
  • возвращаемое значение: метод обычно возвращает void;
  • основной аргумент: строка сообщения (String); многие реализации поддерживают шаблонизацию и дополнительный параметр Throwable для стек-трейса;
  • в некоторых API есть перегрузки с varargs для подстановки значений в шаблон, а также варианты с объектом-меткой (Marker) или ленивой генерацией сообщения через Supplier или лямбду.

Перечень типичных перегрузок (на примере популярных API):

  • java.util.logging: info(String msg). Для ленивой генерации используется log(Level.INFO, Supplier<String>);
  • SLF4J / Logback / Log4j2:
    • info(String msg)
    • info(String format, Object arg)
    • info(String format, Object arg1, Object arg2)
    • info(String format, Object... arguments)
    • info(String msg, Throwable t)
    • варианты с Marker и контекстом MDC

Замечания по аргументам:

  • шаблоны SLF4J используют плейсхолдеры {} для замены аргументов;
  • последний аргумент varargs может интерпретироваться как Throwable, если он является исключением и количество плейсхолдеров меньше числа аргументов;
  • в java.util.logging рекомендуется избегать дорогих вычислений сообщения без ленивой генерации, иначе накладные расходы выполнятся даже если уровень INFO отключён;
  • возвращаемого значения нет, информация выводится в конфигурируемые аппендеры/хендлеры.

Примеры конфигурации и поведение форматирования зависят от конкретной библиотеки и настроек аппендера/файла/консоли.

Короткие примеры использования

Ниже показаны минимальные примеры для стандартного логгера JDK и для SLF4J. В каждом примере код и ожидаемый результат.

java.util.logging.Logger - простое сообщение

import java.util.logging.Logger;

public class ExampleJUL {
    private static final Logger logger = Logger.getLogger(ExampleJUL.class.getName());

    public static void main(String[] args) {
        logger.info("Приложение запущено");
    }
}
Jul 21, 2024 10:00:00 AM ExampleJUL main
INFO: Приложение запущено

SLF4J - параметризованное сообщение

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class ExampleSlf4j {
    private static final Logger logger = LoggerFactory.getLogger(ExampleSlf4j.class);

    public static void main(String[] args) {
        String user = "ivan";
        logger.info("Пользователь {} вошёл в систему", user);
    }
}
INFO  com.example.ExampleSlf4j - Пользователь ivan вошёл в систему

SLF4J - сообщение с исключением

try {
    throw new IllegalStateException("Непредвиденное состояние");
} catch (Exception e) {
    logger.info("Обнаружено исключение при обработке", e);
}
INFO  com.example.ExampleSlf4j - Обнаружено исключение при обработке
java.lang.IllegalStateException: Непредвиденное состояние
    at ...

Похожие методы в Java и их особенности

  • Logger.log(Level.INFO, ...) - более гибкий метод в java.util.logging, позволяет задать уровень и дополнительные параметры, в том числе ленивые поставщики сообщений.
  • Logger.fine / config / warning / severe - методы для других уровней логирования в JDK; выбирать по важности записи.
  • org.slf4j.Logger.debug / warn / error - аналоги в SLF4J для соответствующих уровней. Для подробной отладки используется debug, для ошибок - error.
  • System.out.println - не является методом логирования; подходит для простых выводов, но не поддерживает уровни, фильтрацию и форматирование.

Выбор зависит от потребностей: для гибкой маршрутизации и фильтрации предпочтение у лог-фреймворков (SLF4J + реализация). Для простых случаев можно временно использовать консоль, но это ухудшает последующий анализ.

Аналоги в других языках и отличия

  • PHP: error_log() или фреймворки типа Monolog.
    error_log("INFO: Пользователь вошёл");
    (запись в лог или syslog в зависимости от конфигурации)
    Отличие: чаще используется централизованный компонент Monolog для уровней и обработчиков.
  • JavaScript (Node.js): console.info() или библиотеки Winston, Bunyan.
    console.info('Пользователь %s вошёл', 'ivan');
    Пользователь ivan вошёл
    Отличие: JSON-логирование и асинхронные передатчики у популярных библиотек.
  • Python: модуль logging, метод logging.info().
    import logging
    logging.info('Пользователь %s вошёл', 'ivan')
    INFO:root:Пользователь ivan вошёл
    Отличие: форматирование выполняется лениво, если используется параметризация через запятые.
  • SQL: в SQL-скриптах не предусмотрено стандартного логирования как в приложениях. В T-SQL используется PRINT или запись в таблицу для логов.
  • C# (.NET): интерфейс Microsoft.Extensions.Logging.ILogger, метод LogInformation().
    logger.LogInformation("Пользователь {User} вошёл", "ivan");
    info: MyApp[0]
          Пользователь ivan вошёл
    Отличие: встроенная поддержка структурированного логирования и провайдеров.
  • Go: пакет log с Println или сторонние библиотеки (zap, logrus) с уровнями.
    log.Println("INFO: Пользователь", user)
    2009/11/10 23:00:00 INFO: Пользователь ivan
  • Kotlin: использует Java-логгеры; часто применяет SLF4J с теми же методами info(). Отличие: синтаксический сахар и расширения для удобства.
  • Lua: простая функция print или библиотеки log4lua.
    print('INFO: Пользователь вошёл')
    INFO: Пользователь вошёл

В большинстве языков наблюдается одна общая задача: структурированное логирование и контроль уровней. Java предоставляет широкую экосистему совместимых библиотек (SLF4J + реализация), что обеспечивает переносимость кода и единую модель использования.

Типичные ошибки при использовании Logger.info()

  • Дорогая конкатенация строк без проверки уровня. Пример:
    logger.info("Результат: " + computeHeavy());
    (computeHeavy() выполнится даже если INFO отключён, что приведёт к потерям производительности)
    Решение: использовать параметризованное логирование или ленивую генерацию.
  • Неверное число плейсхолдеров в SLF4J. Пример:
    logger.info("Пользователь {} выполнил {} операций", user);
    INFO ... - Пользователь ivan выполнил {} операций
    Здесь второй плейсхолдер останется не заполненным.
  • Передача исключения как первый аргумент вместо последнего. Пример:
    logger.info(e, "Ошибка при обработке: {}", id);
    (некорректный порядок аргументов, вызовет компиляционную ошибку или некорректный вывод в зависимости от API)
    Следует передавать throwable последним: logger.info("...", id, e) или logger.info("...", e) согласно сигнатуре.
  • Использование нулевого экземпляра логгера. Пример:
    Logger logger = null; logger.info("test");
    java.lang.NullPointerException
    Проверка инициализации обязательна.
  • Ожидание возвращаемого значения. Все распространённые реализации возвращают void; попытка использовать значение приведёт к ошибке компиляции.

Изменения в поведении и новых возможностях

В развитии экосистемы логирования отмечаются следующие тенденции:

  • в стандартной библиотеке Java добавлены возможности ленивой генерации сообщений через Supplier в методах log(Level, Supplier<String>), что снижает накладные расходы при отброшенных уровнях;
  • SLF4J и реализаций активно вводят поддержку параметризации и структурированного логирования; в новых версиях увеличено внимание к эффективной обработке varargs и безопасному логированию исключений;
  • в современных реализациях растёт поддержка асинхронной записи (асинхронные аппендеры) и форматов JSON для централизованного сбора логов.
  • Конкретные изменения зависят от версии библиотеки: рекомендуется проверять заметки релиза используемой реализации (Logback, Log4j2, SLF4J).

Расширенные примеры использования

Дальше несколько продвинутых сценариев с пояснениями и примерным выводом.

Ленивая генерация сообщения в java.util.logging через Supplier

Пример java
import java.util.logging.*;

public class LazyExample {
    private static final Logger logger = Logger.getLogger(LazyExample.class.getName());

    public static void main(String[] args) {
        logger.log(Level.INFO, () -> "Дорогой расчёт: " + expensive());
    }

    private static String expensive() {
        // эмуляция тяжёлой операции
        try { Thread.sleep(100); } catch (InterruptedException ignored) {}
        return "результат";
    }
}
(если уровень INFO включён) INFO: Дорогой расчёт: результат
(если уровень INFO отключён) (ничего не вычисляется)

Пояснение: Supplier вызывается только при необходимости, что экономит ресурсы.

Использование MDC с SLF4J для контекста запроса

Пример java
import org.slf4j.MDC;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class MdcExample {
    private static final Logger logger = LoggerFactory.getLogger(MdcExample.class);

    public static void main(String[] args) {
        MDC.put("requestId", "req-123");
        try {
            logger.info("Обработка запроса");
        } finally {
            MDC.clear();
        }
    }
}
INFO  com.example.MdcExample [requestId=req-123] - Обработка запроса

Пояснение: MDC добавляет контекст, автоматически включаемый в шаблон формата логов.

Структурированное логирование с параметрами и JSON-выводом

Пример java
// Конфигурация Logback/Log4j2 для JSON + пример использования
logger.info("{\"event\":\"login\", \"user\":\"{}\"}", "ivan");
{"timestamp":"2024-07-21T10:00:00","level":"INFO","logger":"com.example.App","event":"login","user":"ivan"}

Пояснение: структурированное сообщение упрощает парсинг и последующий анализ в системах типа ELK или Splunk. Часто применяется форматтер на стороне аппендера.

Асинхронная запись логов для высокой нагрузки (пример архитектуры)

Конфигурация асинхронного аппендера (Log4j2 AsyncAppender или Logback AsyncAppender) позволяет писать логи в отдельном потоке, снижая влияние на latency основного потока. Код вызова остаётся прежним: logger.info(...), конфигурация отвечает за асинхронность.

Логирование больших объектов с безопасной сериализацией

Пример java
// Лучше сериализовать выборочно, чтобы избежать утечки данных
logger.info("Профиль пользователя: id={}, имя={}", user.getId(), mask(user.getName()));
INFO ... - Профиль пользователя: id=42, имя=iv***

Пояснение: при логировании объектов следует избегать вывода чувствительных данных и больших бинарных полей; применять маскирование и ограничение размера.

джава Logger.info function comments

En
Logger.info Запись информационного сообщения