🐝
Что логировать
Вид сообщений, записываемых в лог, зависит от уровня логирования. В современных Java-приложениях стандартом де-факто для логирования является библиотека SLF4J, поэтому приведены уровни логирования предоставляемые его API:
TRACE
- Сверх подробное описание работы программы. Используется очень редкоDEBUG
- Подробное описание работы программы. Используется для отладкиINFO
- Верхнеуровневое описание основных шагов выполнения программы / запроса.WARN
- Оповещение о некритических сбоях и о необычном поведении системы (отсутствие в БД запрашиваемых данных, временная недоступность внешнего сервиса и др.)ERROR
- Алерт о критическом сбое, свидетельствующий о наличии серьезного бага в приложении
Что может пойти не так
Излишнее логирование
Иногда требуется узнать время выполнения какого либо действия. В таком случае производится логирование Если это действие выполняется в цикле, то время, затрачиваемое на логирование, может превысить время выполнения действия, что серьезно ударит по производительности:
return entities.stream()
.map(it -> {
long startTime = System.currentTimeMillis();
MappedEntity mappedEntity = map(it);
long finishTime = System.currentTimeMillis();
log.debug(
"Mapping of enitity with id '{}' done in {} millis",
it.getId(),
finishTime - startTime);
return mappedEntity;
})
.collect(toList());
В таких случаях стоит отказаться от логирования, либо зарефакторить его:
long startTime = System.currentTimeMillis();
List<MappedEntity> mappedEntities = entities.stream()
.map(it -> map(it))
.collect(toList());
long delay = System.currentTimeMillis() - startTime;
log.debug(
"Mapping of {} enitities done in {} millis. Average time = {}",
entities.size()
delay,
(double) delay / entities.size());
return mappedEntities;
Исполнение методов при записи в лог
Иногда при отладке требуется вывести в лог результат выполнения какого-либо действия.
log.debug("Interesting details: {}", getSmth());
В таких случаях метод getSmth()
будет вызван, даже если в приложении установлен уровень логирования выше, чем DEBUG
.
Для того чтобы такое не происходило, можно использовать ленивую поставку логируемых данных с помощью лямбда-выражений:
log.debug("Interesting details: {}", () -> getSmth());
К сожалению, такой функционал не доступен в актуальной версии SLF4J. Но более современная библиотека log4j2 уже поддерживает лямбда-выражения и в ней уже можно использовать такие трюки.
При использовании лямбда-выражений в логировании следует иметь в виду, что поведение приложения может начать различаться в зависимости от выставленного уровня логирования. Например, при выполнении лямбда-выражения может быть выброшено исключение, которое при другом уровне логирования никогда бы не появилось.
Чем логировать
Как отмечалось ранее, на данный момент стандартом де-факто является фасад SLF4J, при этом под его капотом могут использоваться различные библиотеки:
- Logback - на сегодня самая популярный логгер. При этом он разработан создателями SLF4J, не имеет дополнительных оберток и адаптеров, а потому работает с SLF4J быстрее, чем другие библиотеки
- Log4j - предтеча всех библиотек для логирования
- JUL - стандартная Java реализация
- Log4j2 - набирающая популярность библиотека, поддерживающая lazy evaluation с помощью лямбда-выражений.
На сегодня репозиторий SLF4J кажется заброшенным. Последний коммит в репозитории был сделан в феврале 2020 г. Релиз 2.0.0, в котором тоже должна появиться поддержка лямбда-выражений, был анонсирован в середине 2019 г. и до сих пор находится в альфе.
Тем временем log4j2 активно развивается и кажется идеальным выбором для новых проектов.
Трассировщики
В веб-приложениях, зачастую требуется отслеживать последовательность выполнения запроса. Для того чтобы вычленить логи, относящиеся к конкретному запросу, следует в каждый лог добавлять какой-то уникальный идентификатор запроса. Чтобы не делать это вручную, и не прокидывать этот идентификатор через все методы, по которым проходит запрос, используются трассировщики.
В SLF4J таким трассировщиком является MDC - Mapped Diagnostic Context.
Существуют решения, упрощающие работу с MDC. Одним из таких решений является Spring Cloud Sleuth.
Куда логировать
По стандартам двенадцатифакторных приложений все логи должны записываться только в консоль. Для хранения логов может использоваться Logstash или Graylog.
Задача по переливке логов из консоли запущенного приложение в хранилище логов относится скорее к области ответственности администраторов системы.