С выходом 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 “из коробки”. Чтобы добавить ваш собственный формат, необходимо проделать следующие действия:

  1. Создать собственную реализацию интерфейса StructuredLogFormatter 

  2. Сослаться на вашу реализацию из 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 и всего, что с ним связано.

Ждем всех, присоединяйтесь

Комментарии (2)


  1. olku
    11.09.2024 09:26

    Есть ли такое для OpenTelemetry?


    1. spring_aio Автор
      11.09.2024 09:26
      +1

      Судя по всему, речь про структурное логирование спанов? Если да, то оно в OpenTelemetry именно такое