OpenTelemetry
Один открытый стандарт для трейсов, метрик и логов, чтобы проследить запрос через все сервисы.
За 30 секунд
OpenTelemetry (OTel) — open-source-стандарт сбора телеметрии, не привязанный к вендору: трейсы (путь одного запроса через систему), метрики (числа во времени) и логи. Вы один раз инструментируете код с помощью OTel SDK, отправляете данные в формате OTLP в Collector, а оттуда экспортируете в любой бэкенд: Grafana, Jaeger, Datadog, Honeycomb, New Relic, Elastic или облачного провайдера. Это проект CNCF, который поддерживают почти все observability-вендоры.
Не в моём ежедневном стеке — я понимаю принципы и изучу детали, когда это понадобится проекту.
Почему это важно
- В системе из нескольких сервисов, очередей и баз одни логи не скажут, почему конкретный запрос был медленным; распределённый трейс показывает каждый переход и его время.
- Он избавляет от vendor lock-in: инструментация пишется один раз под открытый API, а смена бэкенда — это изменение конфигурации Collector, а не переписывание кода.
- Автоинструментация HTTP, баз данных, очередей и фреймворков даёт полезные трейсы за минуты, ещё до того, как вы напишете хоть один свой span.
- Команды приходят к нему, когда перерастают простые проверки доступности и error tracking и им нужно ответить на вопрос «куда уходит время?» в масштабе нескольких сервисов.
Как это работает
01Три сигнала и как они связаны
Телеметрия бывает трёх основных видов (сигналов). Трейс — это история одного запроса: дерево спанов, где каждый span — одна единица работы (HTTP-обработчик, SQL-запрос, вызов платёжного API) со временем начала, длительностью, статусом и атрибутами вроде http.route или db.system. Метрики — числовые измерения, агрегированные во времени: частота запросов, доля ошибок, гистограммы задержек, глубина очереди, память. Их дёшево хранить, и они отлично подходят для дашбордов и алертов. Логи — записи о событиях с временными метками. Сила OpenTelemetry — в корреляции: логи, записанные внутри спана, несут его trace ID и span ID, а метрики могут нести exemplars со ссылками на примерные трейсы. Так алерт по p95-задержке приводит вас к медленному трейсу, а трейс — к точным строкам логов. Трейсы, метрики и логи в спецификации стабильны; профилирование добавляется как четвёртый сигнал.
- Трейс = дерево спанов для одного запроса.
- Метрики = дешёвые агрегаты для алертов и дашбордов.
- Логи = события, связанные через trace ID и span ID.
02Архитектура: API, SDK, экспортёры и Collector
OTel чётко разделяет обязанности. API — это то, что вызывают библиотеки и ваш код, чтобы создавать спаны и записывать метрики; сам по себе он ничего не делает, поэтому библиотеки могут безопасно от него зависеть. SDK — реализация, которую вы настраиваете в приложении: он решает, что сэмплировать, собирает данные в батчи и передаёт экспортёрам. Экспортёры отправляют данные наружу, обычно по OTLP (OpenTelemetry Protocol), на порт 4317 для gRPC или 4318 для HTTP. Библиотеки инструментации патчат популярные фреймворки и клиенты (Express, Fastify, Next.js, Laravel, pg, mysql, Redis, HTTP-клиенты), чтобы создавать спаны автоматически. Collector — отдельный сервис, который принимает телеметрию, обрабатывает её (батчинг, фильтрация, удаление чувствительных атрибутов, сэмплирование) и экспортирует в один или несколько бэкендов. Его можно запускать как агент рядом с каждым приложением, как центральный шлюз или и так и так. Ресурсы описывают, кто отправил данные: service.name, service.version, deployment.environment.name.
03Инструментация сервиса на Node.js
Быстрее всего начать в Node.js с SDK и набора автоинструментаций. Установите @opentelemetry/sdk-node, @opentelemetry/auto-instrumentations-node и OTLP-экспортёр, затем подгрузите небольшой файл настройки до кода приложения — для ES-модулей через node --import. Настраивайте через стандартные переменные окружения, а не захардкоженные значения, чтобы один и тот же образ работал во всех окружениях: OTEL_SERVICE_NAME, OTEL_EXPORTER_OTLP_ENDPOINT, OTEL_RESOURCE_ATTRIBUTES и OTEL_TRACES_SAMPLER. В Next.js есть встроенный хук instrumentation.ts и хелпер @vercel/otel. Laravel и PHP используют расширение OpenTelemetry для PHP плюс пакеты автоинструментации. Начните с автоинструментации, посмотрите на реальные трейсы, а затем добавляйте свои спаны только вокруг важных бизнес-шагов.
// instrumentation.mjs: run with node --import ./instrumentation.mjs server.mjs
import { NodeSDK } from "@opentelemetry/sdk-node";
import { getNodeAutoInstrumentations } from "@opentelemetry/auto-instrumentations-node";
import { OTLPTraceExporter } from "@opentelemetry/exporter-trace-otlp-http";
import { OTLPMetricExporter } from "@opentelemetry/exporter-metrics-otlp-http";
import { PeriodicExportingMetricReader } from "@opentelemetry/sdk-metrics";
// Endpoint and service name come from OTEL_EXPORTER_OTLP_ENDPOINT / OTEL_SERVICE_NAME
const sdk = new NodeSDK({
traceExporter: new OTLPTraceExporter(),
metricReader: new PeriodicExportingMetricReader({ exporter: new OTLPMetricExporter() }),
instrumentations: [getNodeAutoInstrumentations({ "@opentelemetry/instrumentation-fs": { enabled: false } })],
});
sdk.start();
process.on("SIGTERM", () => sdk.shutdown().finally(() => process.exit(0)));
04Свои спаны и атрибуты
Автоинструментация показывает HTTP-вызовы и обращения к базе, но не вашу бизнес-логику. Добавьте span вокруг значимых шагов вроде «расчёт цены», «резервирование товара» или «генерация PDF-счёта» и прикрепите атрибуты, которые помогут потом искать: order.items_count, tenant.tier, cache.hit. Для распространённых имён следуйте semantic conventions (http.request.method, db.system.name, messaging.system), чтобы бэкенды их понимали. Помните о кардинальности атрибутов: ID заказа на спане — нормально, ведь span — это одно событие, но никогда не кладите ID пользователей или URL с ID в атрибуты метрик, потому что каждое уникальное значение создаёт новый временной ряд. Записывайте исключения в span и выставляйте статус ошибки, чтобы неудачные запросы легко находились. Никогда не кладите в атрибуты пароли, токены или полные номера карт.
import { trace, SpanStatusCode } from "@opentelemetry/api";
const tracer = trace.getTracer("checkout");
export async function placeOrder(cart: { items: unknown[] }) {
return tracer.startActiveSpan("checkout.place_order", async (span) => {
span.setAttribute("order.items_count", cart.items.length);
try {
const order = await saveOrder(cart); // pg / HTTP calls become child spans
span.setAttribute("order.id", order.id);
return order;
} catch (err) {
span.recordException(err as Error);
span.setStatus({ code: SpanStatusCode.ERROR });
throw err;
} finally {
span.end();
}
});
}
05Запуск Collector
Отправлять телеметрию из приложений прямо вендору можно, но Collector посередине даёт контроль. Приложения быстро отправляют OTLP в локальный Collector и возвращаются к работе; Collector собирает батчи, повторяет отправку и буферизует, если бэкенд тормозит, так что приложение не страдает. Это правильное место, чтобы добавить атрибуты окружения, отбросить шумные спаны вроде health checks, удалить чувствительные данные и применить tail sampling. Он также умеет собирать метрики Prometheus и читать файлы логов, становясь вашим единым конвейером телеметрии. Используйте contrib-дистрибутив (otelcol-contrib) для полного набора процессоров и экспортёров или соберите минимальный с помощью OpenTelemetry Collector Builder. В каждом пайплайне всегда ставьте процессор memory_limiter первым, а batch — последним, и следите за собственными метриками Collector на предмет потерянных данных.
# otel-collector.yaml
receivers:
otlp:
protocols:
grpc: { endpoint: 0.0.0.0:4317 }
http: { endpoint: 0.0.0.0:4318 }
processors:
memory_limiter: { check_interval: 1s, limit_percentage: 80, spike_limit_percentage: 20 }
attributes/scrub:
actions: [{ key: http.request.header.authorization, action: delete }]
batch: {}
exporters:
otlphttp: { endpoint: https://otlp.example.com }
service:
pipelines:
traces: { receivers: [otlp], processors: [memory_limiter, attributes/scrub, batch], exporters: [otlphttp] }
metrics: { receivers: [otlp], processors: [memory_limiter, batch], exporters: [otlphttp] }
Когда применять
- У вас несколько сервисов, очередей или фоновых воркеров, и нужно проследить запрос через них.
- Вы хотите избежать привязки к одному observability-вендору или планируете позже сменить бэкенд.
- Для отладки задержек и ошибок в продакшене нужны связанные между собой трейсы, метрики и логи.
- Ваша платформа или фреймворк уже нативно поддерживает OTel (Next.js, Kubernetes, облачные балансировщики, многие базы данных).
Когда не стоит
- Один небольшой монолит, где error tracking, проверки доступности и хорошие логи уже отвечают на все вопросы.
- У команды нет времени поддерживать tracing-бэкенд или платить за него; телеметрия, на которую никто не смотрит, — это только расходы.
- Когда встроенный агент hosted-инструмента уже покрывает ваши потребности, а переносимость вам не важна.
Альтернативы
- Агенты вендоров (Datadog, New Relic)
Более быстрая настройка «всё в одном» с отполированным UI, но проприетарная инструментация и счета по использованию. Большинство теперь тоже принимает OTLP.
- Sentry
В первую очередь error tracking, плюс трассировка; его JavaScript SDK внутри построен на OpenTelemetry.
- Только Prometheus + логи
Метрики и логи без трейсов: проще и дешевле, но проследить один запрос через сервисы нельзя.
- Облачные инструменты
AWS X-Ray, Google Cloud Trace, Azure Monitor; все они теперь принимают данные OpenTelemetry.
Лучшие практики
- Задавайте service.name, service.version и deployment.environment.name для каждого сервиса.
- Настраивайте через переменные окружения OTEL_*, чтобы код был одинаковым во всех окружениях.
- Начните с автоинструментации, затем добавьте несколько своих спанов вокруг критичных для бизнеса шагов.
- Отправляйте данные через Collector с процессорами memory_limiter и batch.
- Сэмплируйте трейсы осознанно: head sampling — для объёма, tail sampling — чтобы сохранить ошибки и медленные запросы.
- Встраивайте trace ID в логи, чтобы переходить от строки лога к её трейсу.
- Держите кардинальность атрибутов метрик низкой и никогда не записывайте в атрибуты секреты или персональные данные.
Частые ошибки
- Подгружать инструментацию после того, как приложение уже импортировало свои библиотеки, — тогда ничего не патчится.
- Забыть service.name, из-за чего каждый сервис отображается как unknown_service.
- Класть ID пользователей или полные URL в метки метрик и взрывать число временных рядов.
- Ломать распространение контекста через очереди или самописные HTTP-клиенты, получая разорванные трейсы.
- Хранить 100% трейсов в продакшене и получать огромный счёт за хранилище.
Глубже
06Tail sampling в масштабе
Tail sampling сохраняет трейсы целиком в зависимости от того, что в них произошло, но спаны одного трейса приходят из многих сервисов в разное время. Collector держит спаны в памяти в течение периода ожидания решения (часто 10–30 секунд), а затем применяет политики: status_code ERROR, задержка выше порога, конкретные атрибуты или вероятностная доля для остальных. При нескольких репликах Collector все спаны одного трейса должны попасть в один инстанс, поэтому запускают два уровня: агенты или первый шлюзовой слой с load-balancing-экспортёром по ключу trace ID, а за ними — слой сэмплирования. Рассчитывайте память как трафик × время ожидания и следите за метриками процессора по отброшенным трейсам. Помните, что отброшенные при сэмплировании трейсы влияют и на метрики, построенные из спанов; генерируйте RED-метрики (rate, errors, duration) коннектором spanmetrics до сэмплирования, чтобы дашборды оставались точными.
processors:
tail_sampling:
decision_wait: 15s
num_traces: 100000
policies:
- { name: errors, type: status_code, status_code: { status_codes: [ERROR] } }
- { name: slow, type: latency, latency: { threshold_ms: 1000 } }
- { name: baseline, type: probabilistic, probabilistic: { sampling_percentage: 5 } }
07Распространение контекста через очереди и асинхронную работу
Автоматическое распространение покрывает синхронные HTTP и gRPC. С асинхронной работой нужна аккуратность. Когда вы публикуете задачу в Redis, RabbitMQ или Kafka, встраивайте активный контекст в заголовки сообщения; когда воркер её забирает, извлекайте контекст и начинайте consumer-span. Semantic conventions моделируют это через виды спанов producer и consumer. Сильно отложенная задача ставит вопрос дизайна: должны ли её спаны быть дочерними к запросу, который её создал? Для коротких конвейеров — да, но задача, выполняемая через час, даёт странный, очень длинный трейс. Альтернатива — новый трейс со span link на исходный контекст: связь сохраняется, а трейс не растягивается. Пакетные потребители должны использовать ссылки на множество контекстов producer-ов. Baggage может переносить между сервисами значения вроде tenant ID, но он отправляется с каждым запросом, поэтому держите его маленьким и никогда не кладите туда секреты.
import { context, propagation, trace } from "@opentelemetry/api";
// Producer: carry the trace context inside the job payload
export function withTraceHeaders<T extends object>(payload: T) {
const headers: Record<string, string> = {};
propagation.inject(context.active(), headers);
return { ...payload, otel: headers };
}
// Consumer: continue the trace when the job runs
export function runJob(job: { otel?: Record<string, string> }, work: () => Promise<void>) {
const parent = propagation.extract(context.active(), job.otel ?? {});
return context.with(parent, () =>
trace.getTracer("worker").startActiveSpan("job.process", (span) => work().finally(() => span.end())),
);
}
08Дизайн метрик: инструменты, temporality и кардинальность
Метрики OTel используют инструменты: Counter для того, что только растёт (запросы, отправленные байты), UpDownCounter для значений, которые растут и падают (размер очереди, активные соединения), Histogram для распределений (задержка, размер payload) и Gauge для снимков текущих значений. Именно гистограммы дают p95 и p99; экспоненциальные гистограммы обеспечивают хорошую точность при меньшем числе бакетов. Temporality важна при экспорте: бэкенды в стиле Prometheus ожидают кумулятивные значения, а некоторые вендоры предпочитают delta, и экспортёр можно настроить в любую сторону. Кардинальность — главный драйвер стоимости: каждая уникальная комбинация значений атрибутов — отдельный временной ряд. http.route=/orders/:id — нормально; «сырой» URL /orders/123 — катастрофа. Используйте views, чтобы отбрасывать или переименовывать атрибуты и менять бакеты гистограмм, не трогая код инструментации.
09Накладные расходы, безопасность и поэтапное внедрение
Инструментация не бесплатна, но обычно её цена мала: несколько процентов CPU, в основном на создание и экспорт спанов. Держите её низкой с помощью batch span processor (никогда не simple processor в продакшене), сэмплирования и отключения шумных инструментаций вроде спанов файловой системы или DNS. Экспорт никогда не должен блокировать запросы: если бэкенд недоступен, SDK отбрасывает данные после заполнения очереди, а не замедляет приложение. Очищайте чувствительные данные на двух уровнях: не собирайте их в коде и удаляйте заголовки, query-строки и SQL-параметры в Collector. Внедряйте посервисно, начиная с edge и самого критичного пути, и сравнивайте задержку до и после. Относитесь к Collector как к продакшен-инфраструктуре: health checks, лимиты ресурсов, горизонтальное масштабирование и алерты на потерянные спаны.
Реальные ситуации
Трейсы обрываются на очереди
Проблема
Трейсы показывают API-запрос, который ставит задачу в очередь, но спаны воркера появляются как отдельные трейсы, и никто не видит полного пути заказа.
Как решить
Контекст не передаётся через очередь. Проверьте, есть ли инструментация для вашей библиотеки очередей; включите её и в producer, и в consumer. Если нет — вручную встройте контекст в payload задачи через propagation.inject при постановке в очередь, а в воркере извлеките его и запустите обработчик внутри context.with. Выберите между parent-child и ссылками: для задач, выполняемых за секунды, parent-child даёт один читаемый трейс; для отложенных или пакетных задач начинайте новый трейс со span link. Добавьте атрибуты messaging.system и messaging.destination.name. Проверьте в бэкенде, что producer-span и consumer-span теперь имеют общий trace ID или связь.
Счёт за трассировку растёт быстрее трафика
Проблема
После инструментации всех сервисов с настройками по умолчанию счёт observability-вендора удвоился. Большинство сохранённых трейсов — health checks и быстрые успешные запросы.
Как решить
Добавьте шлюзовой Collector, если его нет. Отбрасывайте спаны health check и readiness probe filter-процессором. Добавьте tail sampling: сохраняйте 100% ошибок и запросов медленнее порога вашего SLO и 2–10% всего остального. Генерируйте RED-метрики коннектором spanmetrics до сэмплирования, чтобы дашборды и алерты оставались точными. Отключите в SDK малоценные инструментации (fs, dns, net). Проверьте атрибуты на большие значения вроде текста SQL или payload и обрежьте или удалите их. Наконец, задайте бюджет на сервис и посмотрите число спанов по сервисам, чтобы найти самые шумные.
Миграция с агента вендора на OpenTelemetry
Проблема
Компания использует проприетарный APM-агент и хочет оценить другой бэкенд, не теряя видимости во время переезда.
Как решить
Разверните Collector с OTLP-ресиверами. Инструментируйте один сервис через OTel SDK и автоинструментации, сохранив прежние имена сервисов. Настройте Collector на экспорт и текущему вендору (большинство принимает OTLP), и новому бэкенду, чтобы сравнивать их на одинаковых данных. Переносите сервисы по одному и удаляйте старый агент, только когда OTel-версия показывает такое же покрытие; никогда не запускайте два агента, патчащих одни и те же библиотеки в одном процессе. Воссоздайте ключевые дашборды и алерты на именах из semantic conventions. После оценки сменить вендора или остаться — это изменение конфигурации Collector, без изменений в коде.
Шпаргалка
- Установить Node SDK и автоинструментацию
npm i @opentelemetry/sdk-node @opentelemetry/auto-instrumentations-node @opentelemetry/exporter-trace-otlp-http- Старт без кода для Node.js
node --require @opentelemetry/auto-instrumentations-node/register app.js- Задать имя сервиса
OTEL_SERVICE_NAME=checkout-api- Направить в Collector
OTEL_EXPORTER_OTLP_ENDPOINT=http://otel-collector:4318- Добавить атрибуты ресурса
OTEL_RESOURCE_ATTRIBUTES=service.version=1.4.2,deployment.environment.name=production- Сохранять 10% новых трейсов
OTEL_TRACES_SAMPLER=parentbased_traceidratio OTEL_TRACES_SAMPLER_ARG=0.1- Отладка: выводить спаны в консоль
OTEL_TRACES_EXPORTER=console- Запустить локальный Collector
docker run -p 4317:4317 -p 4318:4318 -v ./otel-collector.yaml:/etc/otelcol-contrib/config.yaml otel/opentelemetry-collector-contrib- Локальный UI для трейсов
docker run -p 16686:16686 -p 4318:4318 jaegertracing/jaeger- Формат заголовка W3C trace
traceparent: 00-<32-hex trace-id>-<16-hex span-id>-01
Вопросы и ответы
Q1Чем трейс отличается от спана?
Span — одна операция с замеренным временем: входящий HTTP-запрос, запрос к базе, вызов другого сервиса или фрагмент бизнес-логики. У него есть имя, время начала и конца, статус, атрибуты и родитель. Трейс — всё дерево спанов с общим trace ID, отражающее путь одного запроса через систему. Корневой span — обычно первая точка входа, например запрос на API-шлюзе, а дочерние спаны показывают работу, которую он вызвал. Глядя на водопад трейса, видно, куда ушло время и где произошла ошибка, — отдельные логи этого показать не могут.
Q2Что такое распространение контекста (context propagation)?
Context propagation — это то, как трейс продолжается через границы процессов. Когда сервис A вызывает сервис B, SDK сервиса A встраивает текущие trace ID и span ID в исходящий запрос — по умолчанию в виде заголовка W3C traceparent, плюс tracestate и опционально baggage. Инструментация сервиса B извлекает их и создаёт свои спаны дочерними к спану A, так что оба оказываются в одном трейсе. Для HTTP и gRPC это происходит автоматически. Для очередей сообщений нужно передавать контекст в заголовках или атрибутах сообщения и извлекать его в потребителе — многие инструментации для messaging так и делают. Если распространение ломается, вы получаете отдельные, не связанные трейсы.
Q3Зачем Collector, если можно экспортировать прямо из приложения?
Collector отвязывает приложение от бэкенда. Приложение отправляет данные на ближайший эндпоинт и идёт дальше, а Collector занимается батчингом, повторами, сжатием и буферизацией, когда бэкенд медленный. Он централизует обработку: добавление атрибутов, фильтрацию health checks, удаление чувствительных данных и tail sampling, которому нужно видеть трейсы целиком и который невозможно сделать внутри одного сервиса. Он также позволяет менять или добавлять бэкенды без передеплоя приложений и во время миграции отправлять одни и те же данные двум вендорам. Прямой экспорт подходит для быстрого старта или одного небольшого сервиса, но в продакшен-системах обычно есть Collector.
Q4Что такое сэмплирование и какое бы вы использовали?
Сэмплирование решает, какие трейсы сохранять, потому что хранить каждый трейс при высоком трафике дорого. Head sampling решает в начале трейса, например сохраняет 10% с parent-based-сэмплером TraceIdRatio. Это дёшево и согласованно между сервисами, но может отбросить ту самую редкую ошибку, которая вам важна. Tail sampling решает после завершения трейса, в Collector, поэтому может сохранить все ошибки, все медленные запросы и небольшой процент остального. Для этого все спаны трейса должны попасть в один и тот же инстанс Collector, и он расходует память. Распространённая комбинация — лёгкий head sampling в SDK плюс политики tail sampling в шлюзовом Collector.
Q5Чего OpenTelemetry не делает?
OpenTelemetry собирает и передаёт телеметрию; он её не хранит, не визуализирует и не алертит. Вам всё равно нужен бэкенд: Grafana с Tempo, Prometheus или Mimir и Loki, Jaeger для трейсов или коммерческий сервис вроде Honeycomb, Datadog или New Relic. Он также не решает, что важно: имена сервисов, атрибуты, сэмплирование и то, какие бизнес-операции заслуживают спанов, выбираете вы. И он не заменяет error tracking с группировкой, отслеживанием релизов и пользовательским контекстом — поэтому многие команды используют его вместе с Sentry. Думайте о нём как о стандартной «сантехнике», которая делает остальной observability-стек взаимозаменяемым.
Вопросы уровня senior
S1Как внедрить OpenTelemetry в 40 сервисов, которыми владеют разные команды?
Относитесь к этому как к платформенному продукту. Дайте для каждого языка тонкий внутренний пакет или базовый образ, который настраивает SDK, атрибуты ресурса, propagators и экспортёры из переменных OTEL_*, чтобы командам нужно было добавить одну зависимость, а не проектировать настройку. Запускайте Collector как агенты (DaemonSet или sidecar) плюс шлюзовой слой, которым владеет платформенная команда, — для сэмплирования, очистки и маршрутизации. Опубликуйте соглашения: именование сервисов, обязательные атрибуты вроде tenant tier, какие бизнес-операции получают спаны и правила кардинальности для метрик. Начните с пути запроса от edge до базы, чтобы трейсы сразу были полезны, затем расширяйте. Измеряйте внедрение покрытием спанами по сервисам. Компромисс — централизованный контроль против автономии команд; обычно выигрывает «мощёная дорога» с разумными значениями по умолчанию.
S2Head sampling, tail sampling или без сэмплирования: как решить?
Отталкивайтесь от вопросов и бюджета. Если трафик низкий, храните всё: это проще всего, и вы никогда не теряете данные. На больших объёмах head sampling с parent-based ratio-сэмплером дёшев, не требует памяти Collector и сохраняет трейсы целыми между сервисами, но он «слепой»: редкие ошибки отбрасываются с той же частотой, что и успешные запросы. Tail sampling сохраняет важное (ошибки, медленные запросы, конкретных тенантов) и отбрасывает скучный трафик, но требует stateful-слоя Collector с балансировкой по trace ID, памяти под окно решения и добавляет задержку перед появлением данных. Многие команды комбинируют: щедрый head sampling для ограничения объёма от очень горячих сервисов, tail sampling для умного отбора и метрики из спанов, вычисляемые до сэмплирования, чтобы агрегированные цифры оставались верными.
S3Как связать трейсы OpenTelemetry с логами в уже существующей системе логирования?
Цель — чтобы каждая строка лога, записанная внутри запроса, содержала trace_id и span_id. В Node.js пакеты инструментации для pino и winston автоматически встраивают их в записи логов; в PHP, Java и Python есть похожие интеграции или OTel logs bridge. Оставьте свой текущий логгер: API логов OTel рассчитан на мост из привычных библиотек, а не на прямой вызов. Затем либо отправляйте логи через Collector по OTLP, либо продолжайте отправлять их JSON-файлами и убедитесь, что поле trace_id проиндексировано. В бэкенде настройте переход из просмотра трейса к запросу логов с фильтром по trace_id и из строк логов — к трейсам. Компромисс — объём: отправка всех логов через OTLP централизует конвейер, но увеличивает нагрузку на Collector, поэтому фильтруйте debug-логи как можно раньше.
Глоссарий
- Span
- Одна операция с замеренным временем внутри трейса: имя, длительность, статус, атрибуты и родительский span.
- Трейс (Trace)
- Все спаны с общим trace ID, показывающие путь одного запроса через систему.
- OTLP
- OpenTelemetry Protocol для отправки трейсов, метрик и логов по gRPC (порт 4317) или HTTP (порт 4318).
- Collector
- Отдельный сервис, который принимает, обрабатывает и экспортирует телеметрию в один или несколько бэкендов.
- Ресурс (Resource)
- Атрибуты, описывающие источник телеметрии: service.name, версия и окружение.
- Semantic conventions
- Стандартные имена атрибутов (http.request.method, db.system.name), чтобы инструменты понимали телеметрию из любого источника.
- Context propagation
- Передача trace ID и span ID между сервисами, обычно в заголовке W3C traceparent.
- Tail sampling
- Выбор, какие трейсы сохранить, после их завершения — например, все ошибки и медленные запросы.
- Кардинальность (Cardinality)
- Число уникальных комбинаций значений атрибутов в метрике; высокая кардинальность умножает стоимость хранения.
Что изучить дальше
Есть идея продукта?Давайте создадим его.
Расскажите о своей идее, продукте или команде. Обычно отвечаю в течение одного рабочего дня.