ПУБЛИКАЦИИ

Про правильное observability - часть 1 - correlation id

Решил навалить технического контенту по observability циклом постов от самого простого к сложному. Расскажу для простых работяг, на чём строится хороший мониторинг, как правильно писать логи, как делать дашборды в graphana и для чего это всё нужно.

Correlation ID
Первая базовая база, на которой строится observability — это т.н. correlation id (CID).
CID — это уникальный идентификатор, чаще всего UUID (или любой другой GUID), по которому можно отследить процесс/запрос от входа до выхода. Обычно, с этим ассоциируют всякие распределенные запросы в рамках микросервисной или SOA парадигм, но даже в простом приложении класса «прокладка между пользователем и базой» не построить адекватного мониторинга или отслеживания ошибок без него. Потому что если у тебя больше двух пользователей выполняют запрос к одному API, то попробуй определи, кто что сделал.

Физически мы пишем этот самый cid в каждую строчку лога, а потом по нему ищем или фильтруем. В итоге получаем только наш вызов без лишнего мусора.

Техника
Сам CID получается тремя способами:

  • UI генерит его и шлёт в хедере запроса.
  • Получаем его от сторонней системы
  • Генерим сами на входе запроса в API

Делается это в фильтрах/листенерах на самом раннем этапе обработки запроса, далее cid обычно кладётся в MDC (mapped diagnostic context, имплементирован почти во всех языках) и живёт до конца процесса/запроса. Фишкой MDC как сущности является доступ к ней из логгеров, а это значит, его можно прописать напрямую в паттерне лога.

Классические MDC делаются на базе thread local (грубо говоря — хранилище данных конкретного потока). Это значит, что при асинхронщине или многопоточке нужно будет явно передавать данные из одного потока в поток, а так же не забывать вычищать его при окончании запроса.

Вот пример моего базового паттерна для logback. Обращение к MDC идёт через %X{}
<Pattern>%highlight (%d{ISO8601}) %highlight (%-6level) [%green (%X{app-id}}:%X{correlation-id}:%X{stream-id})] %yellow (%C{20}): %msg%n%throwable</Pattern>
Выдаёт такой лог.

Полезные практики
  •  если запрос с UI — можно добавить в лог id/роль пользователя (если безопасники позволяют)
  •  если запрос от дружественных сервисов — добавить source id (id вызывающей системы)
  •  если процесс запутанный (один метод используется в нескольких бизнес-процессах) — добавить flow id (название бизнес-процесса)
 если произошла ошибка, то возвращать cid в ответе для упрощения диагностики
2025-05-05 13:46