Skip to content

ИнтерфейсПроцессорЛогов ​

Интерфейс процессора записей лога (LogRecordProcessor) — методы, которые SDK вызывает у процессора.

Описание ​

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

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

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

Процессор регистрируется в провайдере логирования:

Процессоры вызываются в порядке регистрации.

Проверка реализации ​

SDK реализацию не проверяет: ДобавитьПроцессор принимает любой объект, а аннотация &Реализует — объявление, которое во время работы не проверяется. Методы ищутся по имени при вызове, и ошибка реализации проявляется так:

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

Проверить класс заранее, например в тесте, можно валидатором библиотеки extends: он бросает исключение, если класс, объявивший &Реализует("ИнтерфейсПроцессорЛогов"), не определяет какой-либо метод интерфейса или метод нельзя вызвать с числом параметров метода интерфейса (лишние параметры допустимы, если они необязательные). Так тесты SDK проверяют встроенные процессоры.

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

// Процессор - объект проверяемого класса
Валидатор = Новый ВалидаторРеализации();
Валидатор.ИнтерфейсыРеализованыКорректно(Процессор);

Методы ​

ПриПоявлении ​

Обрабатывает запись лога (OnEmit). Логгер вызывает метод через цепочку процессоров провайдера в Записать — синхронно, в потоке, который записал лог. При записи логов из нескольких потоков (фоновых заданий) метод вызывается одновременно, поэтому общее состояние процессора нужно защищать.

  • Запись изменяема (ReadWriteLogRecord): во время вызова процессор может её менять, например добавить атрибут через УстановитьАтрибут. Изменения видны процессорам, зарегистрированным после него (спецификация, раздел OnEmit). После прохода всей цепочки логгер фиксирует запись: сеттеры больше ничего не меняют, поэтому запись, сохранённую для обработки позже, можно только читать.
  • Не переприсваивайте параметры: новое значение ЗаписьЛога или Контекст получат и следующие процессоры.
  • Метод не должен блокироваться и бросать исключения (спецификация, раздел OnEmit): сбои обработки и экспорта пишите в лог. Исключение композитный процессор перехватывает и пишет в лог предупреждением, следующие процессоры запись получают.
  • Фильтровать записи нужно здесь: Записать не опрашивает Включен процессоров.
  • После закрытия провайдера логгеры записи не передают, но запись из другого потока, начатая до закрытия, может прийти уже после Закрыть процессора. Такую запись нужно игнорировать, как это делают встроенные процессоры (спецификация, раздел ShutDown).
ПараметрТипПо умолчаниюОписание
ЗаписьЛогаОтелЗаписьЛога—Запись лога
КонтекстФиксированноеСоответствие, Соответствие, НеопределеноНеопределеноРазрешённый контекст: переданный в Логгер.Записать или текущий контекст потока. Из него можно взять, например, текущий спан (ОтелКонтекст.СпанИзКонтекста)

Включен ​

Сообщает, будет ли процессор обрабатывать запись с такими параметрами (Enabled). Логгер вызывает метод из Логгер.Включен, если провайдер не закрыт и в нём есть процессоры. Процессоры опрашиваются по порядку до первого, вернувшего Истина; Логгер.Включен возвращает Ложь, только если все процессоры вернули Ложь.

  • Возвращайте Ложь, если запись с такими параметрами процессор отбросит, иначе Истина — в том числе при неопределённом состоянии, например пока не загружена конфигурация (спецификация, раздел Enabled процессора логов). Если метода Включен у процессора нет, композитный процессор считает процессор включённым, но реализуйте метод явно — так поведение не зависит от обработки ошибки вызова.
  • Не изменяйте переданные объекты. Логгер передаёт неизменяемый контекст и копию области, а композитный процессор даёт каждому процессору свои копии параметров: переприсваивание параметра не видно ни следующим процессорам, ни вызывающему.
  • Включен не заменяет фильтрацию в ПриПоявлении: вызывать его перед Записать необязательно. Процессор-обёртка может передать Включен вложенному процессору, но в ПриПоявлении не должен вызывать Включен вложенного — фильтрует сам ПриПоявлении.
  • Метод, который бросает исключение или отсутствует, означает «процессор включён».
ПараметрТипПо умолчаниюОписание
КонтекстФиксированноеСоответствие, НеопределеноНеопределеноКонтекст, переданный в Логгер.Включен, или текущий контекст потока
ОбластьИнструментированияОтелОбластьИнструментированияНеопределеноКопия области логгера или области, переданной в Логгер.Включен
СтепеньСерьезностиЧисло0Номер серьезности, переданный в Логгер.Включен; 0 — не указан
ИмяСобытияСтрока""Имя события, переданное в Логгер.Включен; "" — не указано

Возвращает: Булево — Истина, если процессор обработает запись с такими параметрами


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

Как можно скорее завершает обработку записей, полученных до вызова (ForceFlush): например, экспортирует накопленные записи и сбрасывает буфер экспортера (спецификация, раздел ForceFlush процессора логов). Срок важнее полноты: процессор должен уложиться в таймаут, даже если часть записей не успеет уйти.

Вызывается из СброситьБуфер и ПринудительноВыгрузитьСРезультатом провайдера (и из ОтелSdk.СброситьБуфер). Провайдер вызывает метод у каждого процессора — даже после исключения в предыдущем и после истечения срока — и передаёт время, оставшееся до общего срока (после срока — 1 мс). Если провайдеру передан таймаут 0, метод вызывается без параметра, а композитный процессор передаёт таймаут всегда, поэтому параметр ТаймаутМс нужен и должен быть необязательным, как в интерфейсе.

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

Возвращает: ОтелРезультатЭкспорта — ОтелРезультатыЭкспорта.Успех(), Ошибка() или Таймаут(). Провайдер сводит результаты процессоров: ошибка, если хотя бы один вернул ошибку или Ложь либо бросил исключение; иначе таймаут; иначе успех (Неопределено — успех). Композитный процессор значение без метода Успешно (например, Булево) считает ошибкой


Закрыть ​

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

Вызывается из Закрыть провайдера (и из ОтелSdk.Закрыть) один раз: повторное закрытие провайдера процессоры не вызывает. Провайдер вызывает метод у каждого процессора — даже после исключения в предыдущем и после истечения срока: тогда процессор получает 1 мс и должен завершиться без ожидания. Если провайдеру передан таймаут 0, метод вызывается без параметра, поэтому параметр ТаймаутМс должен быть необязательным.

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

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

Пример ​

Процессор-обёртка, который передаёт вложенному процессору только записи не ниже заданной серьезности:

bsl
// Файл ФильтрПоСерьезности.os
Перем Вложенный;
Перем МинимальнаяСерьезность;

Процедура ПриПоявлении(ЗаписьЛога, Контекст = Неопределено) Экспорт
    // Записать не опрашивает Включен: фильтровать запись нужно здесь
    Если НижеМинимальной(ЗаписьЛога.НомерСерьезности()) Тогда
        Возврат;
    КонецЕсли;
    Вложенный.ПриПоявлении(ЗаписьЛога, Контекст);
КонецПроцедуры

Функция Включен(Контекст = Неопределено, ОбластьИнструментирования = Неопределено,
        СтепеньСерьезности = 0, ИмяСобытия = "") Экспорт
    Если НижеМинимальной(СтепеньСерьезности) Тогда
        Возврат Ложь;
    КонецЕсли;
    Возврат Вложенный.Включен(Контекст, ОбластьИнструментирования, СтепеньСерьезности, ИмяСобытия);
КонецФункции

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

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

// Серьезность 0 не указана: такую запись фильтр не отбрасывает
Функция НижеМинимальной(Серьезность)
    Возврат Серьезность <> 0 И Серьезность < МинимальнаяСерьезность;
КонецФункции

&Реализует("ИнтерфейсПроцессорЛогов")
Процедура ПриСозданииОбъекта(НовыйВложенный, НоваяМинимальнаяСерьезность)
    Вложенный = НовыйВложенный;
    МинимальнаяСерьезность = НоваяМинимальнаяСерьезность;
КонецПроцедуры

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

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

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

Экспортер = Новый ОтелЭкспортерЛогов(Новый ОтелHttpТранспорт("http://localhost:4318"));
Фильтр = Новый ФильтрПоСерьезности(Новый ОтелПростойПроцессорЛогов(Экспортер),
    ОтелСтепеньСерьезности.Warn());

Провайдер = Новый ОтелПостроительПровайдераЛогирования()
    .ДобавитьПроцессор(Фильтр)
    .Построить();

Логгер = Провайдер.ПолучитьЛоггер("my-library");
Логгер.Включен(, , ОтелСтепеньСерьезности.Debug()); // Ложь: Debug ниже Warn

Провайдер.Закрыть();

См. также ​