Baggage — «рюкзак» пользовательских данных, путешествующих вместе с контекстом. А корреляция трейсов с логами превращает Jaeger и ELK в единую систему. Обе темы — про то, что видит инженер при расследовании.
Baggage: контекст вне трейса
Span context — служебные ID. Baggage — ваши произвольные key-value, которые распространяются по всей цепочке и доступны каждому сервису:
# Python: кладём значение у входа в систему
from opentelemetry.baggage import set_baggage, get_baggage
from opentelemetry.context import attach, get_current
ctx = set_baggage("tenant.id", "acme")
token = attach(ctx)
# дальше по цепочке любой сервис:
tenant = get_baggage("tenant.id") # "acme"
Заголовок baggage: tenant.id=acme,user.tier=premium — и значение видно в каждом
сервисе, включая те, что не принимают участие в «бизнес-запросе» (логирование, лимиты).
Для чего годится и не годится
- ✔ tenant/team-маркеры для мультитенанта, tier пользователя, версия фичи, request-«путь» для маршрутизации;
- ✘ большие данные (в каждый заголовок каждого запроса!), секреты, персональные данные;
- ✘ данные, которые не должны покидать сервис: baggage — часть публичного контракта заголовков.
⚠️ Баггаж распространяется только через инструментированные границы.
Как и traceparent, он может быть вырезан прокси и теряется в неинструментированных переходах.
И ещё: baggage не попадает в спаны автоматически — если нужно видеть его в Jaeger,
добавляйте в атрибуты (processor attributes на Collector или в коде).
Корреляция с логами: trace_id в логе
Канонический цикл расследования: метрика → трейс → лог. Чтобы он сработал, в каждый лог-порядок попадают идентификаторы текущего спана:
- Python: LoggingHandler из OTel либо вручную
trace.get_current_span().get_span_context()→ trace_id/span_id в поля лога; - Java: MDC —
traceId/spanId(logback pattern%X{trace_id}; OTel-агент умеет заполнять MDC автоматически через opentelemetry-logback-1.0 интеграции); - Node: pino-модули или ручной запрос контекста из AsyncLocalStorage.
# Java logback pattern
%d{HH:mm:ss} %-5level [tid=%X{trace_id} sid=%X{span_id}] %logger - %msg%n
Двунаправленные переходы
- Из лога в трейс: скопируйте trace_id из лога → Jaeger UI → вставьте в поле поиска (поиск по Trace ID) → весь запрос;
- Из трейса в логи: в Kibana/клике поиска по полю
trace_id— все логи этого запроса во всех сервисах; - Ссылка в UI: Jaeger умеет deep-link из спана во внешний UI (span links в process tags — настраивается в query-сервисе), но и просто копирование ID уже работает.
Паттерн «один запрос — вся история»
- Метрика: p99 endpoint'а вырос →
- Трейс: медленный сегмент в сервисе B, атрибут order.id=42 →
- Логи: запросы Kibana по
trace_idпоказывают retry-цикл и предупреждения → - Код: локализована причина.
Без trace_id в логах шаг 3 распадается: вы не можете найти «логи именно этого запроса».
Практика
- Добавьте в оба сервиса практикума логгер с trace_id/span_id в каждом сообщении; убедитесь, что идентификаторы совпадают с трейсом в UI.
- Передайте baggage
tenant.idиз A в B и залогируйте его в B (проверьте: дошёл ли баггаж, если вызов идёт через неинструментированный клиент?). - Положите baggage ключ с 2 КБ текста и посмотрите на размер заголовков каждого исходящего запроса — почувствуйте, почему большие значения запрещены.
Мини-квиз
1. Чем baggage отличается от атрибутов спана? — Баггаж — распространяемый контекст между сервисами; атрибуты — данные конкретного спана.
2. Что нужно, чтобы цикл «метрика→трейс→лог» работал? — trace_id/span_id в каждом лог-порядке + поиск по ним в log-системе.
3. Почему в baggage нельзя секреты? — Он летит в открытых заголовках через все сервисы и прокси.