Телеметрия ERP

Пакет ru.bgcrm.telemetry предоставляет единый API для прикладных метрик и трассировок ERP. Реализация OpenTelemetryImpl использует OpenTelemetry SDK:

  • метрики публикуются встроенным HTTP-сервером в формате Prometheus;

  • трассировки при включённой настройке отправляются в OTLP HTTP collector;

  • OpenTelemetry logs в текущей реализации не используются.

Поток данных

прикладной код ────────────────> ITelemetry ──> OpenTelemetry SDK
       │                                           │
       └─> событие EventProcessor                  ├─> /metrics для Prometheus
                 │                                 └─> OTLP HTTP для traces
                 └─> TelemetryListener ──> ITelemetry

Часть подсистем обращается к ServerContext.telemetry напрямую. HTTP-запросы, Retrofit, обращения к биллингу, Camel, AsyncWorker и SingleFlight сначала публикуют событие, а TelemetryListener превращает его в счётчик и гистограмму.

ServerContext.telemetry — ленивый singleton. Во время инициализации системных listener создаётся TelemetryListener, обращается к singleton и тем самым поднимает Prometheus-сервер. Отдельной кнопки включения метрик нет.

Конфигурация

Ключ По умолчанию Назначение

server.telemetry.port

9090

Порт отдельного HTTP-сервера Prometheus.

server.telemetry.trace.endpoint

пустая строка

Полный URL OTLP HTTP endpoint, например http://<collector>:4318/v1/traces. Пустое значение отключает трассировки.

server.instance.id

вычисляется настройками сервера

Входит в scope инструментов erp-instance-<id> и в ресурс трассировки service.instance.id.

Метрики доступны по адресу:

http://<host>:<server.telemetry.port>/metrics

Порт принадлежит отдельному серверу, а не встроенному Tomcat. Конфликт порта при инициализации не отключает только телеметрию: исключение может прервать запуск ERP.

Инструменты ITelemetry

ITelemetry доступен через ServerContext.telemetry и содержит четыре операции:

Операция Поведение

counter(name)

Возвращает монотонный счётчик. increment(value, attributes) добавляет значение к серии с заданными атрибутами.

timer(name)

Возвращает гистограмму в миллисекундах. record { …​ } измеряет блок через System.nanoTime(), включая завершение с исключением. recordUnit(…​) принимает готовую длительность.

gauge(name, provider)

Регистрирует callback для текущего значения. Результат Double преобразуется в Long.

span(name, attributes) { …​ }

Создаёт внутренний span, делает его текущим, отмечает исключение как ERROR, завершает span и повторно выбрасывает исключение. При отключённых traces просто выполняет блок.

Счётчики, таймеры и gauge создаются при первом обращении и кэшируются по имени. Повторный gauge() с тем же именем не заменяет ранее зарегистрированный callback.

Как имена выглядят в Prometheus

OpenTelemetry преобразует имена инструментов при экспорте:

  • к счётчику добавляется _total, если такого суффикса ещё нет;

  • гистограмма с unit ms получает основу <name>_milliseconds и серии _bucket, _count, _sum;

  • gauge сохраняет имя;

  • ко всем сериям добавляется otel_scope_name="erp-instance-<id>".

Например, инструмент http_request_count публикуется как http_request_count_total, а http_request_duration — как http_request_duration_milliseconds_bucket, _count и _sum.

Полный перечень штатных инструментов приведён в каталоге метрик.

Гистограммы времени

Для всех таймеров используется один набор границ в миллисекундах:

5, 50, 100, 500, 1000, 5000, 10000, 30000, 90000, 200000, +Inf

Набор применяется глобально, независимо от природы операции. Отдельной настройки bucket для конкретной метрики нет.

Трассировки

При непустом server.telemetry.trace.endpoint создаётся OTLP HTTP exporter с пакетной отправкой. Ресурс каждого span содержит:

  • service.name=erp;

  • service.instance.id=<server.instance.id>.

Автоматической трассировки servlet, SQL, Retrofit или Camel нет. Сейчас ITelemetry.span() использует планировщик: каждый запуск задачи создаёт span scheduler.task с идентификатором, названием, классом, признаком ручного запуска и номером попытки.

Подробности планировщика приведены в его документации.

Связанные разделы