Суть
Трассировка внутри одного процесса — задача несложная. Проблема начинается на границах: пользовательский запрос идёт через UI, HTTP-слой, оркестратор агента, ретривер, иногда наружу к чужому сервису. Каждый участок пишет свои логи, и без общего ключа они не склеиваются.
W3C Trace Context решает это одним HTTP-заголовком traceparent, который каждый участник цепочки обязан принять, использовать и передать дальше. Это стандарт консорциума W3C — он не привязан ни к вендору наблюдаемости, ни к языку.
Как работает
Заголовок состоит из четырёх полей через дефис:
00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01
│ │ │ │
│ Trace ID — един для всей цепочки │ Trace Flags
Версия parent-id (сэмплирование)
- Trace ID не меняется от первого до последнего узла — по нему собирается вся история.
- parent-id (так поле названо в спецификации; в инструментах его обычно показывают как Parent Span ID) указывает на вызывающий узел, из этого строится дерево.
- Trace Flags говорят, сэмплировать этот трейс или пропустить. Флаг
sampled— рекомендация вызывающей стороны, а не приказ: принимающая может решить иначе.
Рядом со стандартом живёт заголовок tracestate — для вендор-специфичных данных, которые не помещаются в жёсткий формат traceparent.
Принимающая сторона извлекает контекст из заголовка и восстанавливает его для всех дочерних задач, включая асинхронные:
carrier = {"traceparent": request.headers.get("traceparent", "")}
context = TraceContextTextMapPropagator().extract(carrier=carrier)
После восстановления контекста каждый порождённый спан автоматически привязывается к общему дереву — даже если исполняется в другом потоке или корутине.
Зачем это агенту
У агента шаги не выстроены в линию: один запрос порождает ветвление на планирование, вызовы инструментов, обращения к ретриверу, иногда — делегирование чужому агенту. Сквозной Trace ID даёт три вещи, которых иначе нет:
- Поиск по инциденту. Пользователь жалуется на ответ — по одному идентификатору поднимается вся траектория, а не разрозненные записи.
- Атрибуция стоимости. Токены и латентность каждого узла суммируются по трейсу, и цену конкретного взаимодействия наконец можно посчитать.
- Локализация сбоя. Видно не «система вернула ошибку», а на каком именно узле ветка ушла не туда.
В событийно-ориентированных архитектурах именно это становится главной болью: протащить Trace ID через шину сообщений сложнее, чем через синхронный HTTP-вызов, и без дисциплины контекст теряется (см. Event Driven Agents).
Асинхронные переходы и доля сэмплирования
Через очередь контекст передаётся заголовками сообщения, а не телом. И Kafka, и RabbitMQ дают место под метаданные — заголовки записи и headers в свойствах сообщения соответственно; traceparent кладётся туда, а потребитель восстанавливает контекст из них перед началом обработки. Класть идентификатор в полезную нагрузку не стоит: схема сообщения — контракт предметной области, и телеметрия в ней со временем разъедется с реальностью.
Практическая тонкость, из-за которой трасса рвётся чаще всего: потребитель должен восстановить контекст до создания своего спана, иначе спан заведётся под новым корнем и станет отдельным деревом. И отдельно — асинхронный переход правильнее оформлять связью, а не вложением: издатель и потребитель разнесены во времени, и вложенный спан покажет длительность, включающую ожидание в очереди, что маскирует настоящую длительность обработки.
Доля сэмплирования решается не одним числом, а разделением потока. Равномерная выборка экономит объём, но ровно она и теряет редкие сбои — редкое событие с вероятностью попадания в выборку 1% почти наверняка не попадёт. Поэтому в проде обычно комбинируют: низкая базовая доля для успешных трасс плюс безусловное сохранение всех трасс с ошибкой, превышением латентности или срабатыванием guardrail. Отбор при этом делается по завершении трассы, когда исход уже известен, — решение на входе не может знать, что дальше произойдёт сбой.
Связано с
- OpenInference — что именно писать внутрь спанов, когда контекст уже проброшен
- Agent Observability — трейсинг шагов как основа наблюдаемости агента
- AgentOps — стандарт как обязательный пункт продакшен-чеклиста
- Agent Failure Modes — без сквозного трейса часть режимов отказа неотличима друг от друга
- Event Driven Agents — где проброс контекста ломается чаще всего