Про правильное 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{}