awesome-everything EN
↑ Обратно к восхождению

Наблюдаемость

traceparent и tracestate: полный формат W3C-заголовка

Суть traceparent — ровно 55 байт: version, trace-id, parent-id, trace-flags. tracestate — escape hatch для vendor-данных. Знание формата на уровне байт позволяет валидировать, отлаживать и безопасно игнорировать невалидный ввод.
Высота — путь к senior
НольJuniorMiddleSenior
Ты на middle-высоте — в небе
◷ 13 min

On-call-инженер видит значение traceparent 99-aaaaaaaa-bbbbbbbb-01 в HTTP-заголовке. Валидно ли оно? Использовать его или сгенерировать свежий трейс? Ответ в спеке, и неправильный выбор тихо ломает trace store backend.

Заголовок traceparent по байтам

Спецификация W3C Trace Context (W3C Recommendation с 2020, Level 2 с 2024) определяет один HTTP-заголовок фиксированной ширины. Значение — ровно 55 байт:

00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01

Четыре поля через дефис:

ПолеШиринаТекущее значениеПравила
Version2 hex (1 байт)00ff зарезервирован и запрещён
Trace-id32 строчных hex (16 байт)128-битный randomAll-zeros недопустим
Parent-id16 строчных hex (8 байт)64-битный span-id вызывающегоAll-zeros недопустим
Trace-flags2 hex (1 байт)01 = sampledОпределён только бит 0 (sampled)

Ширина намеренно фиксирована, чтобы router или sidecar мог парсить заголовок без regex-движка — просто разбей по дефисам и проверь длины байт. Компактная форма означает ~0.04 KB на HTTP-запрос — измеримо, но ничтожно относительно типичных payload’ов.

Позиция в строкеПолеПримерСмысл
0–1version00Версия спеки; ff запрещён
3–34trace-id4bf92f3577b34da6a3ce929d0e0e4736128-битный random; all-zeros недопустим
36–51parent-id00f067aa0ba902b7span-id вызывающего; all-zeros недопустим
53–54trace-flags01Бит 0 = sampled; остальные зарезервированы

Trace-id обязан быть равномерно случайным

Спека категорична: trace-id должен генерироваться криптостойким случайным 128-битным значением. Он не должен кодировать timestamp, IP или user-id потому что:

  • Downstream-инструменты полагаются на равномерное распределение для решений по sampling (consistent hashing опирается на это).
  • Встроенная информация утекает операционные данные.

OTel SDK используют secure random платформы: crypto.getRandomValues в браузерах, /dev/urandom на Linux, java.security.SecureRandom на JVM. Генерация одного 128-битного id — sub-microsecond, никогда не измеримая стоимость. При 128-битной случайности вероятность коллизии среди триллиона трейсов порядка 10⁻¹⁵ — практически ноль.

Уникальность trace-id — фундамент: tracing-backend ключит все span’ы по trace-id, склеивает при запросе, и если два независимых запроса делят id — backend тихо смешает их в один бессмысленный трейс.

Валидация и fallback «нет заголовка»

Когда сервис получает запрос без traceparent или с невалидным (неверная version, all-zero trace-id, malformed hex), receiver обязан сгенерировать совершенно новый trace-id и стартовать свежий трейс. Спека явно определяет этот fallback, чтобы один сбойный caller не каскадно ломал трейсы.

Сбои валидации должны логироваться как атрибут span’а (invalid_traceparent_received=true), чтобы трейс появлялся в backend с маркером, позволяя операторам найти плохого upstream-caller. Production-команды трактуют ненулевую частоту invalid_traceparent span’ов как propagation-регресс.

Пример 99-aaaaaaaa-bbbbbbbb-01: версия 99 неизвестна (текущий max — 00); trace-id и span-id неправильной длины (8 и 8 hex-символов, не 32 и 16). Заголовок невалиден — принимающий сервис стартует свежий трейс.

Компаньон tracestate

Где traceparent — универсальный идентификатор, tracestate несёт vendor-специфичный контекст: какой sampler принял решение, какая canary-версия эмитнула, какие дополнительные id backend хочет.

Формат: comma-separated key=value, до 32 членов, ключ и значение до 256 символов каждый. Спека обязывает vendor’ов пропагировать не менее 512 символов кумулятивного tracestate, даже если они не понимают ключи — это сохраняет end-to-end tracing через разнородные vendor-инструменты.

Правила мутации:

  • Vendor может добавить новый ключ (prepend в начало списка).
  • Vendor может обновить свой ключ (передвинуть в начало).
  • Vendor не должен удалять ключи других vendor’ов.

Заголовок — escape hatch для того, что не вмещается в жёсткий traceparent.

Интерфейс propagator

OpenTelemetry обобщает логику заголовков двумя операциями над объектом Context:

  • inject(context, carrier) — пишет нужные заголовки в исходящий запрос.
  • extract(carrier) -> context — читает их из входящего запроса.

Carrier’ы pluggable (HTTP-заголовки, gRPC metadata, AMQP properties, обычный dict), propagator’ы pluggable (W3C TraceContext, W3C Baggage, B3 single, B3 multi, Jaeger). Дефолтный OTel composite — TraceContext + Baggage. B3 поддерживается для interop с Zipkin-эрой.

Библиотека делает bit-кодирование, валидацию и логику «если входящего нет — сгенерируй», поэтому прикладной код никогда не трогает сырой hex.

Ключевые числа traceparent
Размер заголовка traceparent
55 байт (фиксировано)
Ширина trace-id
128 бит / 32 hex-символа
Ширина span-id (parent-id)
64 бита / 16 hex-символов
Определённых бит trace-flags
1 (sampled-флаг, бит 0)
Макс. членов tracestate
32
Мин. пропагируемых символов tracestate на vendor
512
Вероятность коллизии trace-id при триллионе трейсов
~10⁻¹⁵
Стоимость на запрос
~0.04 KB overhead заголовка
Викторина

Значение traceparent `00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01`. Что значит финальный `01`?

Викторина

HTTP-запрос пришёл в твой сервис с `traceparent: 99-aaaaaaaa-bbbbbbbb-01`. Что сервис делает по W3C-спеке?

Викторина

Vendor читает заголовок tracestate с ключами двух других vendor'ов. Какая мутация запрещена спекой?

Вспомните перед уходом
  1. 01
    Перечисли четыре поля traceparent по порядку и их назначение.
  2. 02
    Почему trace-id обязан быть равномерно случайным и почему он никогда не должен кодировать timestamp или IP?
  3. 03
    Что такое интерфейс propagator inject/extract и какую проблему он решает?
Итог

W3C-заголовок traceparent несёт четыре поля фиксированной ширины — version, 128-битный trace-id, 64-битный parent-id и trace-flags — в ровно 55 байтах. Фиксированная ширина — намеренный выбор дизайна: любой router или sidecar парсит без regex-движка. Trace-id обязан быть равномерно случайным, никогда не кодировать timestamp’ы или IP, потому что consistent sampler’ы и приватность оба зависят от этого. Невалидный заголовок (неизвестная version, неверная длина поля, all-zero trace-id или parent-id) должен быть отброшен и стартован свежий трейс, залогированный как invalid_traceparent_received для отслеживания регрессий. Компаньон tracestate несёт vendor-специфику — до 32 пар key=value; vendor’ы обязаны пропагировать чужие ключи, не понимая их. OTel propagator interface (inject/extract) оборачивает всё это, чтобы прикладной код никогда не трогал сырой hex.

Связанные уроки
встречается в40
Продолжить восхождение ↑Baggage и async-границы: перенос контекста через очереди и callback''''и
хоткеи развернуть
поиск
K
пред. пьеса
k
след. пьеса
j
тиры
t
это меню
?
sources3
expand
  1. 01
  2. 02
  3. 03

Trademarks belong to their respective owners. Editorial reference only.