Логирование 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? Иначе у приложения возникают конфликтующие реализации и конфигурации.