Страховая компания АльфаСтрахование (далее СК), в которой я работаю, продает страховые продукты не только в офисах, но и через сеть страховых агентов. Агенты могут оформлять полисы, используя REST API. Этот API разрабатывает и поддерживает команда, в которой мне посчастливилось трудиться. Статья содержит контекст и технику, поэтому если Вас интересует только техническая часть, можно смело переходить к разделу "Пререквизиты". Статья не содержит описания Zipkin и концепции трейсов. Прочитать про Zipkin можно на официальном сайте. Основными операциями при продаже являются: Расчет страхового продукта; Сохранение данных страхового полиса в core-системах СК; Оплата; Печать документов. Специфика оформления предполагает выполнение вышеуказанных операций с временными задержками. К примеру, рассчитав страховой продукт, мы даем клиенту время на принятие решения. В случае положительного решения, на основании расчета производится сохранение, оплата и т.д. Мы используем микросервисную архитектуру, разделяя операции по сервисам, ответственным за них. Стоит отметить, что каждый такой сервис в свою очередь обращается в десятки других core-сервисов. Основной фреймворк, используемый для написания таких сервисов - Spring Boot. Вышеописанные цепочки вызовов порой возвращают HTTP 500, после чего стартует классический процесс разбора - что же пошло не так. Стандарт нашей компании предполагает наличие логов и трейсов, таким образом добраться до причины ошибки не представляет особого труда. Далее с этим пониманием в системы вносятся исправления (или производятся консультации конечного потребителя). Для трассировки приложений используется Zipkin. Транспортом является Kafka. Такой подход считается общепринятым в рамках организации. Наше светлое будущее в аспекте трейсов выглядит следующим образом: имея трейсы со всех сервисов, мы можем легко отследить цепочки вызовов и с минимальными временными затратами понять, что пошло не так (если все-таки что-то пошло не так). Итак, что мы имеем на входе: Java 17; Сервис, написанный на Spring Boot 3.1.2; Корпоративный Zipkin, принимающий трейсы через транспорт Kafka; Корпоративная Kafka с топиком, в который следует писать трейсы; Потребность в Автоконфигурации (т.к. сервисов много, не хотелось бы писать реализацию в каждом) - будет рассмотрена на втором шаге. В данном разделе (как и в последующих) мы не будем погружаться в детали реализации существующего сервиса. Достаточно будет вышеуказанных вводных, которые сформируют техническое окружение, в котором мы будем находиться. Добавить конфигурации, с помощью которых сервис сможет отправлять трейсы в Zipkin с транспортом Kafka. Предусмотреть возможность собирать трейсы внутри приложения, т.е. не только между сервисами, но и внутри, между компонентами одного сервиса. Для реализации нам потребуются следующие зависимости. Стоит отметить, что при написании сервиса здесь и далее был использован parent org.springframework.boot:spring-boot-starter-parent:3.1.2, из которого все версии подтянулись сами. Ниже они указаны для справки. Потребуются для настройки подключения к топику Kafka, в который будем отправлять трейсы. Вынесем их в отдельную ветку конфигураций. Получим нечто похожее на: Что в конечном счете будет заполняться из фрагмента application.yaml:  Вручную конфигурируем KafkaSender. Потребуется указать действительный способ аутентификации в Kafka. В данном примере используется: security.protocol=SASL_PLAINTEXT; sasl.mechanism=SCRAM-SHA-256. Зная все вводные, собираем конфигурацию: Пример выше показывает, как с помощью KafkaSender.newBuilder() мы заполняем нужные для подключения к Kafka свойства, в т.ч. используя CustomTracingProperties и константы. Константы в примере записаны в виде литералов, чтоб было нагляднее. Примечание. Строка с брокерами разбирается в лист таким образом:  Для того, чтобы иметь возможность смотреть трейсы взаимодействия компонентов внутри одного сервиса, также добавим конфигурацию: Таким образом, аннотируя методы (или классы) с помощью @Observed, получим трейсы конкретного метода (или всех методов класса). Параметр name в аннотации @Observed служит для определения имени наблюдаемого объекта. Тест данной конфигурации рассмотрим позднее, в этой же статье. Подробнее про Observability в Spring Boot 3. В Spring Boot 3 трейсы были вынесены в Micrometer Tracing, про это не следует забывать. Я добавил такие настройки в application.yaml: Реализовав функциональность и убедившись в том, что трейсы сервиса доступны в Zipkin, соберем все в автоконфигурацию. Вероятно, Вам покажется странным что на данном шаге не приведены результаты. Они обязательно будут приведены позже, когда будем тестировать автоконфигурацию. Создать автоконфигурацию, которая может быть подключена к готовому сервису, написанному на Spring Boot, как отдельная библиотека (стартер). Создадим новый Spring Boot проект, добавим класс MyTracingAutoConfiguration.class. Перенесем в проект все конфигурации и зависимости, описанные выше. Сделаем так, чтобы конфигурация включалась при management.tracing.enabled=true. Нижеуказанную зависимость сохраним, но добавим ей <scope>provided</scope>. Данное действие указывает на то, что actuator у нас и так присутствует в classpath сервиса, к которому будем подключать стартер. Хочу обратить Ваше внимание на то, что конфигурацию мы будем производить до ZipkinAutoConfiguration.class во избежание конфликта бинов (restTemplateSender vs. kafkaSender). Сделаем это с помощью аннотации @AutoConfigureBefore. В примере выше мы обозначили следующие условия: @ConditionalOnProperty - говорит о том, что конфигурация будет включаться, если существует property management.tracing.enabled в значении true; @AutoConfigureBefore(ZipkinAutoConfiguration.class) - говорит о том, что обсудили в разделе "Предварительные действия" (см.выше). Далее мы импортируем вышеописанные конфигурации: KafkaSenderConfiguration.class; ObservedAspectConfiguration.class. Чтобы Spring Boot увидел автоконфигурацию, нам нужно добавить файл /src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports с указателем на класс MyTracingAutoConfiguration (указываем каноническое имя класса автоконфигурации). Подробнее про это можно прочитать тут. Ниже приведены тесты, которые, по моему мнению, важно указать в статье, т.к. они наглядно демонстрируют работу приложения. Для тестирования автоконфигурации я добавлю класс TestConfiguration.class, аннотированный @SpringBootConfiguration в тестовый пакет, в котором размещаются тесты автоконфигурации. Подробнее про это можно посмотреть в этом видео. Тест поможет понять, каким образом мы используем аннотацию @Observed и получаем трейсы на уровне взаимодействия компонентов приложения. Шаг 1. Потребуется добавить зависимость: Шаг 2. Создадим аннотацию @EnableTestObservation, которая подготовит контекст для теста. Подготовка тестового контекста заключается в добавлении конфигурационного бина observationRegistry (TestObservationRegistry из зависимости, которую добавили для тестирования). Также импортируем нашу ObservedAspectConfiguration и добавляем аннотацию @AutoConfigureObservability. Мы делаем отдельную аннотацию для того, чтобы переиспользовать ее в нескольких тестах. Шаг 3. Напишем тест и аннотируем его @EnableTestObservation: В тесте мы проверили, что при вызове метода foo() тестового компонента someClass, observation стартовала и завершилась.   Создадим новый проект, в pom.xml добавим следующие зависимости:  Далее добавим application.yaml, укажем необходимые нам properties: Добавим сервис FooService для проверки работоспособности аннотации @Observed: Напишем простейший контроллер: Запустим приложение и отправим запрос Проверим логи. В application.yaml Вы могли увидеть, что уровень логов для org.apache.kafka.clients.NetworkClient: debug. Данная настройка указана для того, чтобы убедиться, что сообщение в Kafka было отправлено. Убедимся, что запрос был: Продолжаем изучать логи. Найдем traceId (650ddd8f171924cbfc5d355d33fb9d9b), по которому будем искать трейс в Zipkin: Найдем трейс в Zipkin: На картинке выше показан трейс, содержащий 2 интервала (span): родительский (parent) и дочерний (тот самый, заданный с помощью @Observed(name = "observation-name")). На самом деле только частично. Да, трейсы и возможность быстрого их подключения у нас есть, но представленная конфигурация добавляет их для конкретного приложения. Она не позволяет собрать их воедино в единую цепочку вызовов (чтобы под одним traceId увидеть span'ы из разных приложений). Иными словами: если поднять 2 приложения, подключив к ним стартер, при этом одно будет вызывать другое, мы сможем увидеть 2 разных traceId: 1го и 2го соответственно. Конфигурация, позволяющая увязать все воедино - наша следующая цель, которую только предстоит реализовать. Уважаемый читатель, если у Вас есть предложения по этому поводу - буду благодарен им в комментариях. Мы рассмотрели вариант добавления трейсов в Spring Boot 3 приложение с возможностью последующего переиспользования этой функциональности. Трейсы передаются в Zipkin через Kafka. Функциональность также позволяет добавлять трейсы межкомпонентного взаимодействия внутри приложения. Исходный код автоконфигурации доступен по ссылке. Надеюсь, эта статья была Вам интересна.  Спасибо за внимание.