Інструментування застосунків через 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 тижні підтримки безкоштовно.

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

Останні роботи

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