Как отслеживать цепочку запросов через несколько сервисов по логам
Что проверяют
Знаете ли вы, как один идентификатор проходит через все сервисы и все потоки и где он теряется. Следом почти всегда спрашивают про асинхронность: что станет с идентификатором в @Async, в CompletableFuture и в консьюмере Kafka.
Как отвечать
Основа это сквозной trace id, который создаётся один раз на входе в систему и дальше только передаётся:
- стандарт передачи: заголовок
traceparentиз W3C Trace Context. СвойX-Correlation-Idдопустим, но тогда отправку и приём придётся писать и поддерживать самим; - инструментирование: в Spring Boot 3 это Micrometer Tracing с мостом в OpenTelemetry (Spring Cloud Sleuth с третьей версией Boot не работает) либо OpenTelemetry Java agent без изменений кода. Оба кладут
traceIdиspanIdв MDC, остаётся вывести их в шаблоне лога через%X{traceId}; - передача дальше: HTTP-клиенты берут из автоконфигурированных
RestClient.BuilderилиWebClient.Builder, а не создают черезnew, иначе заголовок не добавится. Для Kafka включается наблюдение наKafkaTemplateи контейнере слушателей, trace id едет в заголовках сообщения; - формат и сбор: логи в JSON, чтобы
traceIdбыл отдельным полем, а не куском строки. Логи собирают в ELK, OpenSearch или Loki, трейсы в Jaeger или Grafana Tempo, и по trace id из трейса одним фильтром находятся все строки логов.
Отдельно про потоки: MDC живёт в ThreadLocal, и при передаче задачи в пул контекст пропадает. Его переносят через TaskDecorator для экзекуторов Spring или библиотеку Context Propagation, а в Reactor через Hooks.enableAutomaticContextPropagation().
Где спотыкаются
Генерируют новый UUID в каждом сервисе. Тогда связь между сервисами рвётся, и искать по такому идентификатору можно только внутри одного приложения.
Кладут значение в MDC и не очищают его в finally. Поток из пула берёт следующий запрос со старым идентификатором, и логи двух разных клиентов склеиваются.
Путают логи и трассировку. Логи отвечают на вопрос «что произошло», трейс показывает, где ушло время, и сильный ответ объясняет, как их связать, а не выбирает что-то одно.