Короткий ответ
OpenTelemetry SDK инструментирует код (автоматически через auto-instrumentation для популярных фреймворков или вручную через API), создаёт спаны и передаёт контекст трейса (trace_id, span_id) между сервисами через стандартный HTTP-заголовок traceparent (W3C Trace Context); собранные спаны экспортируются в OpenTelemetry Collector, который пересылает их в backend (Jaeger, Tempo, Zipkin).
Как это работает подробнее
при входящем запросе SDK либо создаёт новый trace_id (если заголовка traceparent нет), либо продолжает существующий трейс (если заголовок есть), создавая для текущей операции span с родителем из заголовка. При исходящем HTTP/gRPC-вызове SDK автоматически прокидывает тот же traceparent в заголовки следующего запроса, обеспечивая сквозную связность без ручной передачи ID разработчиком.
Пример кода
# Псевдокод с OpenTelemetry Python SDK
from opentelemetry import trace
tracer = trace.get_tracer("checkout-service")
with tracer.start_as_current_span("apply_discount"):
result = discount_service.apply(order)
# --- text ---
# HTTP-заголовок, передающий контекст трейса между сервисами
traceparent: 00-4bf92f3577b34da6a3ce929d0e0e4736-00f067aa0ba902b7-01Что использовать на практике
- Практика. для большинства популярных веб-фреймворков (Express, Spring, Django, Gin) существуют готовые auto-instrumentation библиотеки OpenTelemetry, которые оборачивают HTTP-клиент и сервер без изменения бизнес-кода; ручная инструментация нужна для внутренней логики, которую хочется видеть отдельным span (например, конкретный дорогой вызов к БД или внешнему API). OpenTelemetry Collector в середине цепочки позволяет централизованно настраивать sampling, batching и маршрутизацию без изменения кода приложений.
- Практика. После внедрения в Jaeger должен появиться span с именем
apply_discountвнутри общего трейса запроса; отсутствие span-а при наличии кода инструментации обычно означает, что экспортёр не настроен или Collector недоступен — это проверяется логами SDK на уровне debug.
Подводные камни
- Частые ошибки. не прокидывать контекст через асинхронные границы (очереди сообщений, фоновые задачи, cron) — трейс "рвётся" ровно в этом месте, если явно не передать
trace_idв заголовках сообщения и не продолжить span на стороне обработчика; инструментировать только HTTP-слой и не видеть внутренние дорогие операции (SQL-запросы, вызовы кэша), из-за чего трейс показывает только "сервис был медленным", но не почему.