Логирование Java

Log — наблюдаемое событие, а не текстовый дамп состояния. Он должен отвечать: что произошло, с какой операцией, чем закончилось и как связать это с metrics/trace.

Слои

  • API/façade: SLF4J или конкретный logging API.
  • Backend: Log4j 2, Logback или java.util.logging.
  • Encoder/layout: plain text либо structured JSON.
  • Destination: stdout, file, collector.

В application выбираю один backend. Libraries обычно зависят от façade и не навязывают backend потребителю.

Что записывать

timestamp=...
level=INFO
service=demo
event=order_processed
orderId=42
traceId=...
durationMs=83
result=success

Не дублирую один exception на каждом слое. Нижний слой либо добавляет контекст и пробрасывает exception, либо верхняя boundary логирует итоговую неуспешную операцию.

Levels по действию

  • DEBUG можно временно включить для диагностики.
  • INFO не должен расти на каждую строку batch без необходимости.
  • WARN означает необычную, но обработанную ситуацию.
  • ERROR означает провал операции, а не любую перехваченную ошибку.

Audit log и application log — разные контракты. Audit требует полноты, защищённости и retention; обычный debug log не заменяет его.

Correlation

В синхронной цепочке передаю trace/request id через разрешённый header. В Kafka — через record headers. Не использую business id как единственный trace id: одна сущность участвует во многих операциях.

Стоимость

Логирование потребляет CPU, allocation, I/O и место. Большой payload увеличивает latency и риск утечки. Sampling допустим для шумных диагностических events, но не для обязательного audit.

Типичные сбои

  • Пароль или Authorization header попал в log.
  • Сообщение без идентификатора невозможно связать с запросом.
  • Exception залогирован без stack trace.
  • Одна ошибка размножилась в пяти сервисах без correlation id.
  • Health endpoint генерирует INFO на каждый probe.
  • Logs используются как единственная метрика количества операций.

Вопросы для собеседования

Чем log отличается от metric? Log хранит дискретное событие с контекстом; metric — агрегируемое числовое измерение.

Где логировать exception? На boundary, где известен результат операции, либо один раз с добавленным контекстом.

Зачем structured logs? Поля можно надёжно фильтровать и агрегировать без разбора произвольной строки.

Можно ли логировать весь request? Только после оценки секретов/персональных данных, размера и необходимости; обычно лучше выбранные поля.

Почему library не должна навязывать backend? Иначе у приложения возникают конфликтующие реализации и конфигурации.

См. Log4j, Микросервисная архитектура.