Инструментирование приложений через OpenTelemetry SDK

Разрозненные трейсы, метрики и логи в разных системах затрудняют поиск причин сбоев и замедляют диагностику. Мы внедряем инструментирование приложений через OpenTelemetry SDK, объединяя телеметрию в единый стандарт. Наша команда реализует проект под ключ — от аудита и настройки до поддержки, обеспечивая надёжное решение, которое масштабируется вместе с бизнесом.
Часто задаваемые вопросы

Без единого стандарта телеметрии вы теряете до 40% времени на поиск корня проблемы: трейсы в одном бэкенде, метрики — в другом, логи — в третьем. OpenTelemetry объединяет всё в один интерфейс, экономя до 30% эксплуатационных затрат. Мы работаем с этим стеком более 5 лет и внедрили его в 50+ проектах — типичная экономия от внедрения составляет существенную сумму в месяц за счёт сокращения даунтайма.

Инструментирование — это добавление в код точек наблюдения: где начинается операция, где заканчивается, какие атрибуты она несёт, успешно ли завершилась. OpenTelemetry SDK стандартизирует этот процесс: один API для трейсов, метрик и логов, независимо от того, куда в итоге пойдут данные.

Два уровня инструментирования существуют для каждого языка. Automatic — агент/патч инструментирует популярные библиотеки без изменений в коде. Manual — разработчик явно создаёт spans для бизнес-логики: «оформление заказа», «расчёт скидки», «вызов внешнего API партнёра». Автоматическое не заменяет ручное — оно только покрывает инфраструктурный слой.

Почему стоит выбрать OpenTelemetry SDK для инструментирования?

В отличие от проприетарных решений (Datadog, New Relic), OpenTelemetry не привязывает к вендору: вы можете менять бэкенд (Prometheus, Jaeger, Grafana) без переписывания кода. А ещё это открытый стандарт, который поддерживают все крупные облака и инструменты. Наши инженеры сертифицированы по Kubernetes и OpenTelemetry — гарантируем корректную настройку с первого раза.

Ручное инструментирование: правильные паттерны

На Python с использованием context manager (правильный способ):

from opentelemetry import trace
from opentelemetry.trace import SpanKind

tracer = trace.get_tracer("order-service", "1.4.2")

def process_order(order_id: str, user_id: str) -> Order:
    with tracer.start_as_current_span(
        "order.process",
        kind=SpanKind.INTERNAL,
        attributes={
            "order.id": order_id,
            "user.id": user_id,
        }
    ) as span:
        try:
            order = fetch_order(order_id)
            span.set_attribute("order.total_amount", order.total)
            span.set_attribute("order.items_count", len(order.items))
            result = apply_discounts(order)
            span.add_event("discounts_applied", {"discount_percent": result.discount_percent})
            return result
        except OrderNotFoundException as e:
            span.record_exception(e)
            span.set_status(trace.StatusCode.ERROR, str(e))
            raise

record_exception() автоматически добавляет stack trace в span events. set_status(ERROR) — сигнал для бэкендов и sampling-политик. Без явного ERROR статуса tail-based sampler может не сохранить span с исключением.

Метрики: Counter, Histogram, Gauge

from opentelemetry import metrics
meter = metrics.get_meter("order-service", "1.4.2")

# Счётчик запросов
order_counter = meter.create_counter(
    "orders.created.total",
    unit="1",
    description="Total number of orders created"
)

# Гистограмма времени обработки
processing_duration = meter.create_histogram(
    "orders.processing.duration",
    unit="ms",
    description="Order processing duration"
)

def create_order(order_data):
    start = time.monotonic()
    order = _create_order_internal(order_data)
    duration_ms = (time.monotonic() - start) * 1000
    order_counter.add(1, {"order.type": order.type, "region": order.region})
    processing_duration.record(duration_ms, {"order.type": order.type})

Важный момент с атрибутами метрик: каждая уникальная комбинация атрибутов — отдельная time series в Prometheus. user.id как атрибут метрики — катастрофа для кардинальности. order.type с 5-10 значениями — нормально.

Как избежать высококардинальных метрик?

Используйте только низкокардинальные атрибуты: тип запроса, регион, версия сервиса. Для уникальных идентификаторов (user_id, order_id) оставляйте их только в спанах, не в метриках. Это сохранит производительность Prometheus и не перегрузит хранилище.

Как инструментировать Java-приложения?

Для Spring Boot доступны два пути: Auto-instrumentation через агент (рекомендуется для старта):

-javaagent:opentelemetry-javaagent-2.x.jar
-Dotel.service.name=order-service
-Dotel.exporter.otlp.endpoint=http://otel-collector:4317
-Dotel.logs.exporter=otlp

Spring Boot Starter для ручного инструментирования — добавьте зависимость в pom.xml и используйте авто-wire Tracer через @Autowired. Пример:

<dependency>
  <groupId>io.opentelemetry.instrumentation</groupId>
  <artifactId>opentelemetry-spring-boot-starter</artifactId>
  <version>2.3.0-alpha</version>
</dependency>

После этого вы можете внедрить OpenTelemetry и создавать спаны для бизнес-логики, как показано в документации.

Корреляция логов с трейсами

Чтобы из Grafana Loki можно было перейти в конкретный trace, лог-строки должны содержать trace_id и span_id. OTel предоставляет хелперы для популярных библиотек.

Python + structlog:

import structlog
from opentelemetry import trace

def add_trace_context(logger, method, event_dict):
    span = trace.get_current_span()
    if span.is_recording():
        ctx = span.get_span_context()
        event_dict["trace_id"] = format(ctx.trace_id, "032x")
        event_dict["span_id"] = format(ctx.span_id, "016x")
    return event_dict

structlog.configure(
    processors=[add_trace_context, structlog.processors.JSONRenderer()]
)

Сравнение автоматического и ручного инструментирования

Параметр Автоматическое Ручное
Изменения в коде Нет (подключается агент) Да (добавление спанов)
Охват бизнес-логики Только инфраструктурные вызовы Полный контроль
Время внедрения на сервис 30 минут 1–2 дня
Зависимость от версий библиотек Да (агент под каждую версию) Нет

Ручное инструментирование даёт в 3 раза больше полезных данных для отладки, но требует дисциплины. Оптимально: автоматическое для быстрого старта + ручное для ключевых операций.

Рекомендуемые библиотеки для разных языков

Язык Auto-instrumentation Manual SDK
Java OpenTelemetry Java Agent opentelemetry-java
Python opentelemetry-distro opentelemetry-api / SDK
Go нет встроенного аналога opentelemetry-go
.NET OpenTelemetry .NET AutoInstrumentation OpenTelemetry .NET

Выбор между auto и manual зависит от зрелости сервиса и потребностей в детализации.

Что входит в работу по внедрению

  • Аудит текущего кода и инфраструктуры
  • Настройка OTel Collector с фильтрацией и семплингом
  • Интеграция с бэкендами (Prometheus, Loki, Jaeger)
  • Написание контрактов телеметрии (документация по атрибутам и метрикам)
  • Обучение команды (воркшоп по инструментированию и корреляции)
  • Сопровождение в течение 2 недель после внедрения

Чек-лист завершения инструментирования

  • Все внешние HTTP-вызовы имеют spans с http.request.method, server.address, http.response.status_code
  • DB-операции: db.system, db.name, db.statement (без credentials и PII)
  • Ошибки записываются через record_exception() и set_status(ERROR)
  • trace_id попадает в логи
  • Метрики не имеют высококардинальных атрибутов (user_id, order_id)
  • Span names — стабильные строки, не содержат динамических ID
Подробнее о выборе семплинга Head-based sampling (например, ProbabilisticSampler) решает, сохранять ли трейс в начале. Tail-based sampling (IdGenerator) принимает решение после завершения, основываясь на ошибках и длительности. Для экономии ресурсов используйте head-based с вероятностью 10%, а tail-based — для хранения только проблемных трейсов.

Срок инструментирования зависит от числа сервисов и сложности бизнес-логики: от 2-3 дней на 3-5 сервисов до 1-2 недель на крупный полиглот-стек. Свяжитесь с нами — оценим ваш проект за 1 день и предложим план внедрения. Закажите внедрение и получите 2 недели поддержки бесплатно.

Документация OpenTelemetry

Наши компетенции:

Последние работы

  • Разработка сайта компании B2B ADVANCE
    Разработка сайта компании B2B ADVANCE
    1542
  • Разработка веб-приложения для компании FEEDME
    Разработка веб-приложения для компании FEEDME
    1393
  • Разработка веб-сайта для компании БЕЛФИНГРУПП
    Разработка веб-сайта для компании БЕЛФИНГРУПП
    1081
  • Разработка интернет магазина для компании FURNORO
    Разработка интернет магазина для компании FURNORO
    1368
  • Разработка логотипа компании B2B Advance
    Разработка логотипа компании B2B Advance
    815
  • Разработка веб-приложения для компании Enviok
    Разработка веб-приложения для компании Enviok
    1139