Без единого стандарта телеметрии вы теряете до 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=otlpSpring 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







