Gymterview
middle

Какие есть лучшие практики логирования?

Хорошее логирование — это баланс между достаточностью информации для диагностики и отсутствием шума. Логи должны быть полезны через 3 месяца, когда контекст забыт.

Что логировать

  • Начало и завершение значимых бизнес-операций
  • Ошибки и исключения (с полным стек-трейсом)
  • Входящие запросы (метод, URL, ключевые параметры)
  • Интеграционные вызовы (к другим сервисам, БД, очередям)
  • Изменения состояния (статус заказа, роль пользователя)

Что НЕ логировать

  • Пароли, токены, API-ключи, секреты
  • Персональные данные (PII): номер карты, СНИЛС, паспорт
  • Тела запросов/ответов целиком (могут содержать sensitive данные и быть огромными)

Как логировать правильно

Пример
// ПРАВИЛЬНО — параметризованные сообщения
log.info("Пользователь {} авторизован, роль: {}", userId, role);

// НЕПРАВИЛЬНО — конкатенация (выполняется всегда)
log.debug("Результат: " + expensiveOperation());

// ПРАВИЛЬНО — исключение как последний аргумент (стек-трейс автоматически)
log.error("Ошибка обработки заказа {}", orderId, exception);

// НЕПРАВИЛЬНО — стек-трейс потерян
log.error("Ошибка: " + exception.getMessage());

// ПРАВИЛЬНО — проверка уровня для дорогих операций
if (log.isDebugEnabled()) {
    log.debug("Детали: {}", computeExpensiveDebugInfo());
}

Гайд по выбору уровня

Уровень Когда использовать Пример
ERROR Требуется реакция (алерт) Сервис недоступен, данные повреждены
WARN Потенциальная проблема, система справилась Retry succeeded, deprecated API, fallback
INFO Нормальные бизнес-события Заказ создан, пользователь авторизован
DEBUG Диагностика для разработчика SQL, промежуточные данные, состояние кэша
TRACE Максимальная детализация Вход/выход из метода, значения переменных

Золотые правила

  • Один запрос = одна корреляция: всегда логируйте requestId/traceId для связывания записей
  • Исключение — ВСЕГДА последним аргументом: log.error("msg", arg1, exception)
  • В production: INFO + structured JSON + correlation ID
  • Не логируйте в цикле — 10 000 итераций по одному логу = 10 000 записей; агрегируйте результат
  • Не делайте catch + log + throw — двойное логирование; логируйте на верхнем уровне

Частые ошибки

  • log.error(exception.getMessage()) — теряется стек-трейс; используйте log.error("msg", exception)
  • Логирование в цикле без агрегации — замедляет систему и засоряет логи
  • Catch + log + throw — одно исключение логируется дважды
  • ERROR для всех исключений — NotFoundException при GET /users/999 — это не ERROR, а INFO или WARN

Как используется в 2026

  • Lombok @Slf4j — автоматическая генерация private static final Logger log
  • IDE (IntelliJ) — live templates logi, logd, loge для быстрого логирования
  • Spring Boot Actuator — динамическое изменение уровней через HTTP

На собеседовании: перечислите конкретные антипаттерны: потеря стек-трейса через getMessage(), логирование в цикле, catch-log-throw. Это показывает production-опыт. Частая ошибка — дать абстрактный ответ “логируйте всё важное” без конкретных примеров.