Skip to content

Логирование ​

OpenTelemetry Logs API позволяет собирать структурированные записи логов и экспортировать их в формате OTLP. Логи автоматически коррелируют с трассировкой через контекст — в каждую запись автоматически добавляются TraceId и SpanId текущего активного спана.

Архитектура ​

ОтелПровайдерЛогирования
    └── ОтелЛоггер
            └── ОтелЗаписьЛога
  • ОтелПровайдерЛогирования — точка входа, создаёт логгеры.
  • ОтелЛоггер — создаёт и отправляет записи логов.
  • ОтелЗаписьЛога — запись с телом, уровнем серьёзности и атрибутами.

Создание провайдера через построитель ​

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

Ресурс = ОтелРесурсы.ПоУмолчанию();
Ресурс.Атрибуты().Установить("service.name", "my-service");

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

Базовый = Новый ОтелБазовыйПакетныйПроцессор(Экспортер, "logs", 2048, 512, 1000);
Процессор = Новый ПостроительНаследника(Новый ОтелПакетныйПроцессорЛогов(), Базовый).Построить();
Процессор.ЗапуститьФоновыйЭкспорт();

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

Логгер = Провайдер.ПолучитьЛоггер("my-library", "1.0.0");

Создание записей лога ​

ОтелЗаписьЛога строится через Fluent API:

bsl
Запись = Логгер.СоздатьЗаписьЛога();
Запись.УстановитьТело("Пользователь авторизован")
    .УстановитьСерьезность(ОтелСтепеньСерьезности.Info());

Логгер.Записать(Запись);
bsl
Запись = Логгер.СоздатьЗаписьЛога();
Запись.УстановитьТело("Запрос выполнен")
    .УстановитьСерьезность(ОтелСтепеньСерьезности.Info())
    .УстановитьАтрибут("user.id", "12345")
    .УстановитьАтрибут("http.method", "POST")
    .УстановитьАтрибут("http.status_code", 201);

Логгер.Записать(Запись);
bsl
Попытка
    // ... работа ...
Исключение
    Запись = Логгер.СоздатьЗаписьЛога();
    Запись.УстановитьТело(ОписаниеОшибки())
        .УстановитьСерьезность(ОтелСтепеньСерьезности.Error())
        .УстановитьИсключение(ИнформацияОбОшибке());
    Логгер.Записать(Запись);
КонецПопытки

УстановитьИсключение сохраняет информацию об ошибке, а атрибуты exception.message, exception.stacktrace и exception.type заполняет Логгер.Записать(): до этого вызова в Запись.Атрибуты() их нет. Тип — машинный код ошибки библиотеки errors (ФабрикаОшибок.Создать("config.invalid_port", ...) даст config.invalid_port, код находится и через обертки ФабрикаОшибок). Нативная ошибка OneScript без кода получает код библиотеки native-errors: деление на ноль — numeric.division_by_zero, отказ в соединении — network.connection.refused. У нераспознанной ошибки без кода exception.type не заполняется; явно заданный атрибут записи главнее, и тогда ошибка не классифицируется.

Уровни серьёзности ​

ОтелСтепеньСерьезности соответствует спецификации OpenTelemetry (числовые значения 1–24). Промежуточные значения уровня (например, 10–12 для INFO) передаются в УстановитьСерьезность числом. Запись без заданной серьезности имеет номер 0 (SEVERITY_NUMBER_UNSPECIFIED) и пустой текст серьезности.

МетодЧисловое значениеДиапазон уровняОписание
ОтелСтепеньСерьезности.Trace()11–4Детальная трассировка
ОтелСтепеньСерьезности.Debug()55–8Отладочная информация
ОтелСтепеньСерьезности.Info()99–12Информационное сообщение
ОтелСтепеньСерьезности.Warn()1313–16Предупреждение
ОтелСтепеньСерьезности.Error()1717–20Ошибка
ОтелСтепеньСерьезности.Fatal()2121–24Критическая ошибка

Корреляция с трассировкой ​

Корреляция происходит автоматически. Если в момент записи лога активен спан, его TraceId и SpanId добавляются в запись:

bsl
// Трассировка уже инициализирована
Спан = Трассировщик.НачатьСпан("обработка", ОтелВидСпана.Внутренний());
Область = Спан.СделатьТекущим();

// Запись лога автоматически получит TraceId и SpanId из контекста
Запись = Логгер.СоздатьЗаписьЛога();
Запись.УстановитьТело("Начало обработки")
    .УстановитьСерьезность(ОтелСтепеньСерьезности.Info());
Логгер.Записать(Запись);

Область.Закрыть();
Спан.Завершить();

События и события спана ​

Событие — запись лога с именем события (УстановитьИмяСобытия). Семантические соглашения записывают исключения событиями: exception или имя операции с суффиксом .exception, например db.client.operation.exception. Чтобы исключение было видно и в трассе, процессор ОтелПроцессорСобытийВСобытияСпана переносит событие в событие текущего спана, если запись относится к этому спану и спан ещё записывается. Запись при этом экспортируется логом как обычно.

Автоконфигурация включает процессор по умолчанию. Выключить его — OTEL_OSCRIPT_EVENT_TO_SPAN_EVENT_BRIDGE_ENABLED=false, например когда бэкенд показывает логи рядом со спаном и дублировать исключение в спане не нужно. Обычные записи без имени события процессор не трогает.

Интеграция с logos ​

ОтелАппендерLogos перенаправляет все сообщения библиотеки logos в OpenTelemetry. Это позволяет использовать привычный API logos, не меняя код.

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

Ресурс = ОтелРесурсы.ПоУмолчанию();
Ресурс.Атрибуты().Установить("service.name", "my-service");

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

Провайдер = Новый ОтелПровайдерЛогирования(Ресурс, Процессор);
ОтелЛоггер = Провайдер.ПолучитьЛоггер("my-library", "1.0.0");

// Создаём аппендер и добавляем его к logos-логу
Аппендер = Новый ОтелАппендерLogos(ОтелЛоггер);

Лог = Логирование.ПолучитьЛог("oscript.app.myapp");
Лог.ДобавитьСпособВывода(Аппендер);

// Теперь все сообщения logos отправляются в OpenTelemetry
Лог.Информация("Приложение запущено");
Лог.Предупреждение("Конфигурация не найдена, используются значения по умолчанию");
Лог.Ошибка("Произошла ошибка: файл не найден");

Маппинг уровней logos → ОтелСтепеньСерьезности:

logosOTel Severity
ОтладкаDebug
ИнформацияInfo
ПредупреждениеWarn
ОшибкаError

Процессоры логов ​

Простой процессор (для разработки) ​

bsl
Процессор = Новый ОтелПростойПроцессорЛогов(Экспортер);

Пакетный процессор (для продакшена) ​

Процессор собирается через ПостроительНаследника из ОтелБазовыйПакетныйПроцессор. Параметры: экспортер, имя сигнала, размер очереди, размер пакета, интервал экспорта (мс). Для сигнала "logs" интервал по умолчанию 1000 мс, как в спецификации; размер пакета больше размера очереди ограничивается размером очереди.

bsl
Базовый = Новый ОтелБазовыйПакетныйПроцессор(Экспортер, "logs", 2048, 512, 1000);
Процессор = Новый ПостроительНаследника(Новый ОтелПакетныйПроцессорЛогов(), Базовый).Построить();
Процессор.ЗапуститьФоновыйЭкспорт();

При автоконфигурации пакетный процессор логов настраивается переменными OTEL_BLRP_*: OTEL_BLRP_MAX_QUEUE_SIZE, OTEL_BLRP_SCHEDULE_DELAY (по умолчанию 1000 мс), OTEL_BLRP_MAX_EXPORT_BATCH_SIZE, OTEL_BLRP_EXPORT_TIMEOUT.

Процессор событий в события спана ​

Переносит события в события текущего спана, см. События и события спана. Ставится перед процессором экспорта:

bsl
Процессоры = Новый Массив();
Процессоры.Добавить(Новый ОтелПроцессорСобытийВСобытияСпана());
Процессоры.Добавить(ПакетныйПроцессор);
Процессор = Новый ОтелКомпозитныйПроцессорЛогов(Процессоры);

Композитный процессор ​

bsl
// ПакетныйПроцессор — пакетный процессор логов, собранный как показано выше,
// ОтладочныйЭкспортер — второй экспортер логов
Процессоры = Новый Массив();
Процессоры.Добавить(ПакетныйПроцессор);
Процессоры.Добавить(Новый ОтелПростойПроцессорЛогов(ОтладочныйЭкспортер));
Процессор = Новый ОтелКомпозитныйПроцессорЛогов(Процессоры);

Смотрите также ​