Skip to content

ИнтерфейсПроцессорСпанов ​

Интерфейс процессора спанов (SpanProcessor): контракт встроенных и своих процессоров.

Описание ​

Процессор спанов получает спаны провайдера трассировки: каждый записывающий спан — при начале (ПриНачале) и при завершении (ПриЗавершении). Встроенные процессоры — ОтелПростойПроцессорСпанов, ОтелПакетныйПроцессорСпанов и ОтелКомпозитныйПроцессорСпанов. Свой процессор пишут, например, чтобы дополнять спаны атрибутами или отбирать спаны для экспорта. Аналог Java SDK: SpanProcessor.

Интерфейс — класс ИнтерфейсПроцессорСпанов с аннотацией &Интерфейс библиотеки extends: ПриНачале и ПриЗавершении в нём пустые, СброситьБуфер и Закрыть возвращают успех. Встроенные процессоры объявляют реализацию аннотацией &Реализует("ИнтерфейсПроцессорСпанов") у конструктора ПриСозданииОбъекта.

Регистрация процессора ​

Процессор добавляют в провайдер трассировки:

  • ДобавитьПроцессор построителя провайдера — при создании провайдера;
  • ДобавитьПроцессор провайдера — в работающий провайдер, например Сдк.ПровайдерТрассировки().ДобавитьПроцессор(Процессор): процессор получает спаны, начатые после добавления;
  • в составе композитного процессора, добавленного в провайдер.

Провайдер вызывает процессоры в порядке добавления.

Реализацию интерфейса SDK не проверяет: при добавлении не проверяются ни аннотация &Реализует, ни наличие методов — провайдер вызывает методы по имени. Если метода нет, ошибка проявится при вызове: для ПриНачале и ПриЗавершении — предупреждением в логе на каждом спане, для СброситьБуфер и Закрыть — ошибкой в результате провайдера. Проверить класс заранее, например в тестах, можно валидатором библиотеки extends: метод ИнтерфейсыРеализованыКорректно(Процессор) объекта ВалидаторРеализации выбрасывает исключение, если у класса с аннотацией &Реализует("ИнтерфейсПроцессорСпанов") нет метода интерфейса или у метода неподходящее число параметров. Так в тестах библиотеки проверяются встроенные процессоры.

Потоки, исключения и результаты ​

ПриНачале и ПриЗавершении вызываются синхронно в потоке, который начинает или завершает спан. Спаны могут начинаться и завершаться в нескольких потоках (фоновых заданиях) одновременно, поэтому общие данные процессора защищайте блокировкой. СброситьБуфер и Закрыть вызываются в потоке, который вызвал метод провайдера (у СброситьБуферАсинхронно и ЗакрытьАсинхронно провайдера — в фоновом задании).

Исключение из ПриНачале или ПриЗавершении перехватывает композитный процессор провайдера и пишет в лог предупреждением: спан создаётся и завершается, остальные процессоры вызываются. СброситьБуфер и Закрыть провайдер вызывает у каждого процессора, даже если предыдущий выбросил исключение, и сводит результаты: ошибка, если хотя бы один процессор вернул ошибку или Ложь либо выбросил исключение; иначе таймаут, если процессор вернул таймаут или истёк общий срок; иначе успех. Результат Неопределено (метод-процедура) считается успехом, метод без параметра ТаймаутМс вызывается без срока.

ОтелКомпозитныйПроцессорСпанов вызывает СброситьБуфер строже: с параметром ТаймаутМс и с проверкой Успешно() у результата, поэтому метод без параметра, метод-процедуру или результат Булево он считает ошибкой. Повторяйте сигнатуры интерфейса — тогда процессор работает и в провайдере, и в композитном процессоре.

Методы ​

ПриНачале ​

Вызывается при начале спана (OnStart), до того как метод трассировщика или построителя спана вернёт спан. У спана уже заданы имя, вид, начальные атрибуты, линки и время начала. Процессор получает тот же объект спана, что и приложение: ссылку можно сохранить, а спан — изменить, например установить атрибут.

Вызывается только для записывающих спанов: спаны, отброшенные сэмплером, и спаны в API-режиме (SDK не сконфигурирован или трассировщик получен после закрытия провайдера) процессоры не получают. Спаны с решением сэмплера РешениеЗаписать процессоры получают, хотя флаг sampled у них не установлен; экспортер такие спаны получать не должен (спецификация Trace SDK, раздел Sampling), поэтому встроенные процессоры их не экспортируют.

Метод не должен блокировать поток и выбрасывать исключения (спецификация Trace SDK, раздел OnStart): пока он работает, спан не возвращается приложению.

ПараметрТипПо умолчаниюОписание
СпанОтелСпан—Начатый спан
РодительскийКонтекстФиксированноеСоответствиеНеопределеноКонтекст (Context), в котором начат спан: переданный контекст родителя или текущий контекст; у спана из НачатьКорневойСпан — текущий контекст, в котором спан заменён невалидным. Из него можно прочитать Baggage — ОтелКонтекст.BaggageИзКонтекста(РодительскийКонтекст)

ПриЗавершении ​

Вызывается при завершении спана (OnEnd) внутри Спан.Завершить(), один раз для каждого спана. Время окончания уже установлено, спан завершён: методы записи игнорируются, данные спана можно только читать.

Метод не должен блокировать поток и выбрасывать исключения (спецификация Trace SDK, раздел OnEnd(Span)): пока он работает, Завершить не возвращает управление. Долгую работу, например отправку спанов, выполняйте в фоне, как пакетный процессор.

Процессор, добавленный в провайдер, пока спан был открыт, получает ПриЗавершении для спана, ПриНачале которого он не получал.

ПараметрТипПо умолчаниюОписание
СпанОтелСпан—Завершённый спан

СброситьБуфер ​

Принудительно завершает обработку спанов, полученных до вызова (ForceFlush): процессор с экспортером экспортирует ещё не отправленные спаны и сбрасывает буфер экспортера. Провайдер вызывает метод из своих СброситьБуфер, ПринудительноВыгрузитьСРезультатом и СброситьБуферАсинхронно; СброситьБуфер провайдера вызывает его и после закрытия провайдера.

Срок: провайдер передаёт время, оставшееся до общего срока операции, а после истечения срока — 1 мс, чтобы процессор завершился без ожидания. Без общего срока метод вызывается без параметра — действует значение по умолчанию из сигнатуры. Соблюдение срока важнее завершения всей работы (спецификация Trace SDK, раздел ForceFlush()): не успев за срок, процессор возвращает таймаут. Результат возвращается, когда выгрузка закончена: результат «в процессе» (с обещанием) провайдер не ожидает и считает ошибкой.

ПараметрТипПо умолчаниюОписание
ТаймаутМсЧисло0Срок в миллисекундах, 0 — без ограничения

Возвращает: ОтелРезультатЭкспорта — ОтелРезультатыЭкспорта.Успех(), Ошибка() или Таймаут()


Закрыть ​

Завершает работу процессора (Shutdown). Закрытие включает эффект СброситьБуфер: процессор экспортирует оставшиеся спаны, затем освобождает ресурсы, например закрывает экспортер (спецификация Trace SDK, раздел Shutdown()). Провайдер вызывает метод один раз — при первом Закрыть провайдера (в том числе из ОтелSdk.Закрыть). Срок передаётся так же, как в СброситьБуфер.

После Закрыть процессор ещё может получать ПриНачале и ПриЗавершении — от трассировщиков, полученных до закрытия провайдера, — и СброситьБуфер. Такие вызовы процессору следует игнорировать без исключений (там же).

ПараметрТипПо умолчаниюОписание
ТаймаутМсЧисло0Срок в миллисекундах, 0 — без ограничения

Возвращает: ОтелРезультатЗакрытия — ОтелРезультатыЗакрытия.Успех(), Ошибка(Описание) или Таймаут()

Пример ​

Процессор, который копирует запись Baggage в атрибут спана, — класс приложения в файле ПроцессорBaggage.os:

bsl
Перем КлючBaggage;

Процедура ПриНачале(Спан, РодительскийКонтекст = Неопределено) Экспорт
    Baggage = ОтелКонтекст.BaggageИзКонтекста(РодительскийКонтекст);
    Если Baggage = Неопределено Тогда
        Возврат;
    КонецЕсли;
    Значение = Baggage.Получить(КлючBaggage);
    Если Значение <> Неопределено Тогда
        Спан.УстановитьАтрибут(КлючBaggage, Значение);
    КонецЕсли;
КонецПроцедуры

Процедура ПриЗавершении(Спан) Экспорт
КонецПроцедуры

Функция СброситьБуфер(ТаймаутМс = 0) Экспорт
    Возврат ОтелРезультатыЭкспорта.Успех();
КонецФункции

Функция Закрыть(ТаймаутМс = 0) Экспорт
    Возврат ОтелРезультатыЗакрытия.Успех();
КонецФункции

&Реализует("ИнтерфейсПроцессорСпанов")
Процедура ПриСозданииОбъекта(Ключ)
    КлючBaggage = Ключ;
КонецПроцедуры

Регистрация процессора:

bsl
#Использовать opentelemetry

ПодключитьСценарий(ОбъединитьПути(ТекущийСценарий().Каталог, "ПроцессорBaggage.os"), "ПроцессорBaggage");

Экспортер = Новый ОтелЭкспортерСпанов(Новый ОтелHttpТранспорт("http://localhost:4318"));

Провайдер = Новый ОтелПостроительПровайдераТрассировки()
    .ДобавитьПроцессор(Новый ПроцессорBaggage("tenant.id"))
    .ДобавитьПроцессор(Новый ОтелПростойПроцессорСпанов(Экспортер))
    .Построить();

Проверка реализации в тесте:

bsl
#Использовать extends

// opentelemetry и класс ПроцессорBaggage подключены, как в примере выше;
// при ошибке реализации валидатор выбрасывает исключение
Валидатор = Новый ВалидаторРеализации();
Валидатор.ИнтерфейсыРеализованыКорректно(Новый ПроцессорBaggage("tenant.id"));

См. также ​