С выходом Spring Boot 3.4 логирование станет ещё удобнее: логи можно будет записывать в более унифицированном формате, что упростит их анализ и обработку.
В новом переводе от команды Spring АйО мы разберем основные шаги для настройки и использования этой технологии в проекте.
Логирование — это часть отладки приложения, без которой уже давно невозможно представить себе этот процесс, а также один из трех столпов observability, помимо метрик и инструментов отслеживания. Никому не нравится работать с продакшен средой вслепую, и, когда случаются инциденты, разработчики всегда рады тому, что у них есть файлы логов. Логи часто записываются в формате, удобном для чтения человеком.
Структурное логирование — это техника, при которой вывод логов записывается в четко определенном формате, часто пригодном для машинной обработки. Этот формат может быть передан в системы управления логами и дает возможность использовать мощные возможности для поиска и анализа. Один из наиболее часто используемых форматов для структурного логирования — это JSON.
Spring Boot 3.4 поддерживает структурное логирование “из коробки”. Он поддерживает форматы Elastic Common Schema (ECS) и Logstash, однако вы можете также расширить этот список вашими собственными форматами.
Давайте сразу перейдем к делу и посмотрим, как это работает!
Hello World структурного логирования
Создайте новый проект в start.spring.io. Вам не потребуется добавлять никаких зависимостей, но следует убедиться в том, что выбрали как минимум Spring Boot 3.4.0-M2.
Чтобы включить структурное логирование в консоли, добавьте следующую строку к файлу application.properties:
logging.structured.format.console=ecs
Это свойство сообщит Spring Boot, что необходимо писать логи в формате Elastic Common Schema (ECS).
Теперь запустите приложение, и вы увидите, что логи будут форматированы в JSON:
{"@timestamp":"2024-07-30T08:41:10.561295200Z","log.level":"INFO","process.pid":67455,"process.thread.name":"main","service.name":"structured-logging-demo","log.logger":"com.example.structured_logging_demo.StructuredLoggingDemoApplication","message":"Started StructuredLoggingDemoApplication in 0.329 seconds (process running for 0.486)","ecs.version":"8.11"}
Довольно круто, не так ли? Теперь давайте погрузимся в более сложные темы.
Структурное логирование в файл
Вы можете также включить структурное логирование в файл. Эту опцию можно использовать, например, для вывода человеко-читаемых логов на консоли и сохранения структурных логов в файле для передачи в машинную обработку.
Чтобы включить эту опцию, добавьте к файлу application.properties приведенный ниже код и не забудьте удалить настройку logging.structured.format.console=ecs:
logging.structured.format.file=ecs
logging.file.name=log.json
Теперь запустите приложение и вы увидите, что на консоли появляется человеко-читаемый лог, а файл log.json содержит понятный машине JSON-контент.
Как добавить больше полей
Одна из мощных функций структурного логирования состоит в том, что разработчики могут добавлять информацию к событию логирования структурным образом. Вы можете, например, добавить идентификатор пользователя в каждый лог-событие, а затем фильтровать по этому идентификатору, чтобы увидеть, что именно делал этот пользователь.
Как Elastic Common Schema, так и Logstash включают содержимое Mapped Diagnostic Context в JSON. Чтобы посмотреть на это в действии, давайте создадим наше собственное сообщение лога:
@Component
class MyLogger implements CommandLineRunner {
private static final Logger LOGGER = LoggerFactory.getLogger(MyLogger.class);
@Override
public void run(String... args) {
MDC.put("userId", "1");
LOGGER.info("Hello structured logging!");
MDC.remove("userId");
}
}
Прежде чем логировать это сообщение, этот код также устанавливает user id в MDC. Spring Boot автоматически включает user id в JSON:
{ ... ,"message":"Hello structured logging!","userId":"1" ... }
Вы также можете использовать fluent logging API, чтобы добавить дополнительные поля, не полагаясь при этом на MDC:
@Component
class MyLogger implements CommandLineRunner {
private static final Logger LOGGER = LoggerFactory.getLogger(MyLogger.class);
@Override
public void run(String... args) {
LOGGER.atInfo().setMessage("Hello structured logging!").addKeyValue("userId", "1").log();
}
}
Elastic Common Schema задает множество имен полей, а Spring Boot включает в себя встроенную поддержку имени сервиса, версии сервиса, окружения сервиса и имени ноды. Чтобы установить значения для этих полей, вы можете использовать следующий вид файла application.properties:
logging.structured.ecs.service.name=MyService
logging.structured.ecs.service.version=1
logging.structured.ecs.service.environment=Production
logging.structured.ecs.service.node-name=Primary
Если теперь посмотреть на информацию, выведенную в JSON, там присутствуют поля для service.name, service.version, service.environment и service.node.name. Теперь вы можете выполнять фильтрацию в вашей системе логирования по имени ноды, версии сервиса и т.д.
Кастомизированные форматы логов
Как уже было сказано ранее, Spring Boot поддерживает форматы Elastic Common Schema и Logstash formats “из коробки”. Чтобы добавить ваш собственный формат, необходимо проделать следующие действия:
Создать собственную реализацию интерфейса StructuredLogFormatter
Сослаться на вашу реализацию из application.properties
Прежде всего, давайте создадим кастомную реализацию:
class MyStructuredLoggingFormatter implements StructuredLogFormatter<ILoggingEvent> {
@Override
public String format(ILoggingEvent event) {
return "time=" + event.getTimeStamp() + " level=" + event.getLevel() + " message=" + event.getMessage() + "\n";
}
}
Как видите, поддержка структурного логирования не ограничивается, вы можете вернуть любую строку String, какую захотите. В этом примере мы выбираем использование пар ключ=значение.
Теперь мы должны сообщить Spring Boot о нашей кастомизированной реализации. Чтобы это сделать, добавьте следующую строку к файлу application.properties:
logging.structured.format.console=com.example.structured_logging_demo.MyStructuredLoggingFormatter
Настало время запустить приложение и полюбоваться готовым логом!
time=1722330118045 level=INFO message=Hello structured logging!
Ух ты, вы только посмотрите! Какая красота!
Если вы хотите писать логи в формате JSON, Spring Boot 3.4 содержит удобный новый класс JsonWriter, который вы можете использовать:
class MyStructuredLoggingFormatter implements StructuredLogFormatter<ILoggingEvent> {
private final JsonWriter<ILoggingEvent> writer = JsonWriter.<ILoggingEvent>of((members) -> {
members.add("time", (event) -> event.getInstant());
members.add("level", (event) -> event.getLevel());
members.add("thread", (event) -> event.getThreadName());
members.add("message", (event) -> event.getFormattedMessage());
members.add("application").usingMembers((application) -> {
application.add("name", "StructuredLoggingDemo");
application.add("version", "1.0.0-SNAPSHOT");
});
members.add("node").usingMembers((node) -> {
node.add("hostname", "node-1");
node.add("ip", "10.0.0.7");
});
}).withNewLineAtEnd();
@Override
public String format(ILoggingEvent event) {
return this.writer.writeToString(event);
}
}
Конечно, вы также можете использовать любую другую библиотеку для работы с JSON (например, Jackson) для создания JSON. Нет необходимости использовать именно JsonWriter.
Получившееся сообщение в логе выглядит примерно так:
{"time":"2024-07-30T09:14:49.377308361Z","level":"INFO","thread":"main","message":"Hello structured logging!","application":{"name":"StructuredLoggingDemo","version":"1.0.0-SNAPSHOT"},"node":{"hostname":"node-1","ip":"10.0.0.7"}}
Заключение
Мы надеемся, что вам понравилась новая функциональность Spring Boot 3.4! Мы также обновили документацию, включив в нее информацию о структурном логировании.
Пожалуйста сообщите нам, если обнаружите какие-то проблемы, наш issue tracker всегда открыт!
Присоединяйтесь к русскоязычному сообществу разработчиков на Spring Boot в телеграм - Spring АйО, чтобы быть в курсе последних новостей из мира разработки на Spring Boot и всего, что с ним связано.
Ждем всех, присоединяйтесь
olku
Есть ли такое для OpenTelemetry?
spring_aio Автор
Судя по всему, речь про структурное логирование спанов? Если да, то оно в OpenTelemetry именно такое