ИнтерфейсПроцессорСпанов
Интерфейс процессора спанов (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:
Перем КлючBaggage;
Процедура ПриНачале(Спан, РодительскийКонтекст = Неопределено) Экспорт
Baggage = ОтелКонтекст.BaggageИзКонтекста(РодительскийКонтекст);
Если Baggage = Неопределено Тогда
Возврат;
КонецЕсли;
Значение = Baggage.Получить(КлючBaggage);
Если Значение <> Неопределено Тогда
Спан.УстановитьАтрибут(КлючBaggage, Значение);
КонецЕсли;
КонецПроцедуры
Процедура ПриЗавершении(Спан) Экспорт
КонецПроцедуры
Функция СброситьБуфер(ТаймаутМс = 0) Экспорт
Возврат ОтелРезультатыЭкспорта.Успех();
КонецФункции
Функция Закрыть(ТаймаутМс = 0) Экспорт
Возврат ОтелРезультатыЗакрытия.Успех();
КонецФункции
&Реализует("ИнтерфейсПроцессорСпанов")
Процедура ПриСозданииОбъекта(Ключ)
КлючBaggage = Ключ;
КонецПроцедурыРегистрация процессора:
#Использовать opentelemetry
ПодключитьСценарий(ОбъединитьПути(ТекущийСценарий().Каталог, "ПроцессорBaggage.os"), "ПроцессорBaggage");
Экспортер = Новый ОтелЭкспортерСпанов(Новый ОтелHttpТранспорт("http://localhost:4318"));
Провайдер = Новый ОтелПостроительПровайдераТрассировки()
.ДобавитьПроцессор(Новый ПроцессорBaggage("tenant.id"))
.ДобавитьПроцессор(Новый ОтелПростойПроцессорСпанов(Экспортер))
.Построить();Проверка реализации в тесте:
#Использовать extends
// opentelemetry и класс ПроцессорBaggage подключены, как в примере выше;
// при ошибке реализации валидатор выбрасывает исключение
Валидатор = Новый ВалидаторРеализации();
Валидатор.ИнтерфейсыРеализованыКорректно(Новый ПроцессорBaggage("tenant.id"));