DarkRiDDeR16 мин

Trace ID связывает события, но не доказывает причину

АрхитектураНаблюдаемость

Проблема распределённой диагностики выглядит убедительно: в двух журналах найден один trace ID, рядом стоят одинаковые timestamps, а один span заметно длиннее остальных. Из этого легко сделать вывод, что найден виновник. Цена ошибки — неверный rollback или оптимизация не того участка. В распределённом маршруте идентификатор говорит «эти записи относятся к одному контексту», но не говорит «эта запись вызвала задержку». Между двумя утверждениями есть несколько проверок.

Механизм нужно разделить на три слоя. Log содержит сообщение и локальное состояние процесса. Span описывает операцию и её границы во времени. Metric агрегирует множество наблюдений и теряет часть контекста. Смешать эти формы — значит использовать ответ одного инструмента для вопроса другого. Хороший разбор сначала проверяет, что записи относятся к одному trace, затем — что parent/child связи и интервалы совместимы, и только после этого формулирует ограниченный вывод.

Что гарантирует идентификатор

W3C Trace Context стандартизирует HTTP-заголовок traceparent и формат идентификаторов. Это полезный транспортный контракт: сервис может продолжить контекст, а оператор — искать его в нескольких компонентах. Но стандарт не требует, чтобы все внутренние работы были представлены span-ами. Библиотека может не создать span для очереди, фона или локального cache. Отсутствие записи значит «в этом источнике её нет», а не «операции не было».

У trace есть и временная граница. Parent span может завершиться до того, как дочерняя работа закончилась, если связь отражает асинхронную передачу. Два span-а в одном trace могут быть соседями в маршруте, но не причиной друг друга. Поэтому при чтении надо видеть имя операции, service.name, parentSpanId, start и end, а не только цветную линию в интерфейсе.

Матрица различий между логом, span, метрикой и корреляционным ключом: форма записи, полезный вопрос и недопустимый вывод.
Схема отделяет связь событий от причинности. Она показывает, какой дополнительный контекст нужен до технического решения.
Какой инструмент отвечает на какой вопрос
ИсточникСильная сторонаПроверить рядомНе заключать автоматически
Logлокальное сообщение и состояниевремя, источник, schema, request-idчто сообщение объясняет весь маршрут
Spanграница операции и длительностьparent, kind, status, attributesчто самый длинный span вызвал всё
Metricчастота и распределениеокно, population, labelsчто агрегат указывает на один запрос
Trace IDпоиск общего контекстапропагация и samplingчто цепочка полна и причинна

Локальный граф связей

Ниже функция строит минимальное представление родительских связей по массиву span-ов. Она отмечает root, найденного parent и missing parent. Это предметный пример: результат помогает увидеть разрыв контекста в конкретной цепочке. Он не рисует красивый trace и не назначает виновника. Входы — именно те поля, которые должны быть сохранены при экспорте данных.

import { linkTraceRecords } from './upgrade-2027-01.mjs';

const records = [
  { traceId: 't-7', spanId: 's-gateway', service: 'gateway', parentSpanId: '', durationMs: 22 },
  { traceId: 't-7', spanId: 's-api', service: 'api', parentSpanId: 's-gateway', durationMs: 81 },
  { traceId: 't-7', spanId: 's-db', service: 'db', parentSpanId: 's-missing', durationMs: 4 },
];

console.log(linkTraceRecords(records));
// gateway: root; api: present; db: missing

Ожидаемый результат показывает разрыв у db. Это уже полезная находка: прежде чем говорить о задержке, надо понять, откуда взялся span без parent. Возможны потеря span, неправильное поле или независимая работа, ошибочно попавшая в trace. Ни одна из версий не следует из массива сама; функция лишь не даёт скрыть дырку за сплошной линией.

Время, статус и семантика

Длительность span сравнивают внутри одной временной шкалы и одной операции. Если gateway ждёт upstream 800 мс, это не означает, что upstream потратил 800 мс на вычисление: туда может входить соединение, очередь, retry и чтение ответа. В attributes нужны хотя бы тип операции, результат и причина окончания. Для HTTP это могут быть status_code, method и route; для базы — операция и имя зависимости без чувствительных параметров.

Log полезен, когда в нём есть структурированные поля, а не только строка сообщения. RFC 5424 отделяет header, structured data и message, что хорошо совпадает с задачей корреляции. Но формат журнала не гарантирует доставку: transport может отбросить или обрезать запись. Поэтому «в журнале не найдено» — это результат проверки качества источника, а не доказательство отсутствия события.

Действия по порядку

  1. Проверить, что trace-id и span-id имеют ожидаемый формат и не меняются при переходе между сервисами.
  2. Построить parent/child граф и отметить root, missing parent, duplicate span-id и операции без service.name.
  3. Сверить интервалы start/end с локальными timestamps; отдельно учесть async, retry и очередь.
  4. Сопоставить span с application log по span-id или request-id, а metric использовать только как фон для population.
  5. Сформулировать вывод в узкой форме: «этот участок наблюдался дольше» или «связь потеряна», не «он был причиной всего отказа».

Ограничения и следующий шаг

Sampling, tail-based filtering и ошибки clock skew меняют картину. Trace может не включать retry или consumer, а log collector — получить записи в другом порядке. Данные с персональными параметрами нельзя бездумно передавать в общий контур наблюдаемости. Наконец, даже полная trace-цепочка описывает наблюдаемую последовательность, но не контрфактический вопрос: что произошло бы без конкретного вызова.

Следующий шаг — выбрать один критичный маршрут и зафиксировать контракт полей для gateway, application и dependency span. Добавьте проверку на missing parent и отдельную метрику пропущенного контекста. После этого повторите разбор: качество решения растёт не от количества экранов, а от уменьшения числа неразличимых объяснений.

Проверяемые источники

  • Trace Context — W3C Recommendation — версия и дата: Recommendation, 23 November 2021. Применение: Формат traceparent и правила передачи контекста между HTTP-сервисами. Граница: Спецификация не определяет внутреннюю модель span, sampling, очередь и причинность.
  • RFC 5424: The Syslog Protocol — версия и дата: Standards Track, March 2009, DOI 10.17487/RFC5424. Применение: Структурированные поля и границы syslog-сообщения используются как пример дисциплины логирования. Граница: RFC не гарантирует доставку конкретного журнала и не описывает trace-связи приложения.
  • RFC 9110: HTTP Semantics — версия и дата: Internet Standard, June 2022, DOI 10.17487/RFC9110. Применение: Семантика HTTP-операции и статуса отделена от длительности внутренних работ. Граница: HTTP Semantics не описывает конкретный backend, tracer или способ агрегации.