Логирование
OpenTelemetry Logs API позволяет собирать структурированные записи логов и экспортировать их в формате OTLP. Логи автоматически коррелируют с трассировкой через контекст — в каждую запись автоматически добавляются TraceId и SpanId текущего активного спана.
Архитектура
ОтелПровайдерЛогирования
└── ОтелЛоггер
└── ОтелЗаписьЛога- ОтелПровайдерЛогирования — точка входа, создаёт логгеры.
- ОтелЛоггер — создаёт и отправляет записи логов.
- ОтелЗаписьЛога — запись с телом, уровнем серьёзности и атрибутами.
Создание провайдера через построитель
#Использовать opentelemetry
Ресурс = ОтелРесурсы.ПоУмолчанию();
Ресурс.Атрибуты().Установить("service.name", "my-service");
Транспорт = Новый ОтелHttpТранспорт("http://localhost:4318");
Экспортер = Новый ОтелЭкспортерЛогов(Транспорт);
Базовый = Новый ОтелБазовыйПакетныйПроцессор(Экспортер, "logs", 2048, 512, 1000);
Процессор = Новый ПостроительНаследника(Новый ОтелПакетныйПроцессорЛогов(), Базовый).Построить();
Процессор.ЗапуститьФоновыйЭкспорт();
Провайдер = Новый ОтелПостроительПровайдераЛогирования()
.УстановитьРесурс(Ресурс)
.ДобавитьПроцессор(Процессор)
.Построить();
Логгер = Провайдер.ПолучитьЛоггер("my-library", "1.0.0");Создание записей лога
ОтелЗаписьЛога строится через Fluent API:
Запись = Логгер.СоздатьЗаписьЛога();
Запись.УстановитьТело("Пользователь авторизован")
.УстановитьСерьезность(ОтелСтепеньСерьезности.Info());
Логгер.Записать(Запись);Запись = Логгер.СоздатьЗаписьЛога();
Запись.УстановитьТело("Запрос выполнен")
.УстановитьСерьезность(ОтелСтепеньСерьезности.Info())
.УстановитьАтрибут("user.id", "12345")
.УстановитьАтрибут("http.method", "POST")
.УстановитьАтрибут("http.status_code", 201);
Логгер.Записать(Запись);Попытка
// ... работа ...
Исключение
Запись = Логгер.СоздатьЗаписьЛога();
Запись.УстановитьТело(ОписаниеОшибки())
.УстановитьСерьезность(ОтелСтепеньСерьезности.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() | 1 | 1–4 | Детальная трассировка |
ОтелСтепеньСерьезности.Debug() | 5 | 5–8 | Отладочная информация |
ОтелСтепеньСерьезности.Info() | 9 | 9–12 | Информационное сообщение |
ОтелСтепеньСерьезности.Warn() | 13 | 13–16 | Предупреждение |
ОтелСтепеньСерьезности.Error() | 17 | 17–20 | Ошибка |
ОтелСтепеньСерьезности.Fatal() | 21 | 21–24 | Критическая ошибка |
Корреляция с трассировкой
Корреляция происходит автоматически. Если в момент записи лога активен спан, его TraceId и SpanId добавляются в запись:
// Трассировка уже инициализирована
Спан = Трассировщик.НачатьСпан("обработка", ОтелВидСпана.Внутренний());
Область = Спан.СделатьТекущим();
// Запись лога автоматически получит TraceId и SpanId из контекста
Запись = Логгер.СоздатьЗаписьЛога();
Запись.УстановитьТело("Начало обработки")
.УстановитьСерьезность(ОтелСтепеньСерьезности.Info());
Логгер.Записать(Запись);
Область.Закрыть();
Спан.Завершить();События и события спана
Событие — запись лога с именем события (УстановитьИмяСобытия). Семантические соглашения записывают исключения событиями: exception или имя операции с суффиксом .exception, например db.client.operation.exception. Чтобы исключение было видно и в трассе, процессор ОтелПроцессорСобытийВСобытияСпана переносит событие в событие текущего спана, если запись относится к этому спану и спан ещё записывается. Запись при этом экспортируется логом как обычно.
Автоконфигурация включает процессор по умолчанию. Выключить его — OTEL_OSCRIPT_EVENT_TO_SPAN_EVENT_BRIDGE_ENABLED=false, например когда бэкенд показывает логи рядом со спаном и дублировать исключение в спане не нужно. Обычные записи без имени события процессор не трогает.
Интеграция с logos
ОтелАппендерLogos перенаправляет все сообщения библиотеки logos в OpenTelemetry. Это позволяет использовать привычный API logos, не меняя код.
#Использовать opentelemetry
#Использовать logos
Ресурс = ОтелРесурсы.ПоУмолчанию();
Ресурс.Атрибуты().Установить("service.name", "my-service");
Транспорт = Новый ОтелHttpТранспорт("http://localhost:4318");
Экспортер = Новый ОтелЭкспортерЛогов(Транспорт);
Процессор = Новый ОтелПростойПроцессорЛогов(Экспортер);
Провайдер = Новый ОтелПровайдерЛогирования(Ресурс, Процессор);
ОтелЛоггер = Провайдер.ПолучитьЛоггер("my-library", "1.0.0");
// Создаём аппендер и добавляем его к logos-логу
Аппендер = Новый ОтелАппендерLogos(ОтелЛоггер);
Лог = Логирование.ПолучитьЛог("oscript.app.myapp");
Лог.ДобавитьСпособВывода(Аппендер);
// Теперь все сообщения logos отправляются в OpenTelemetry
Лог.Информация("Приложение запущено");
Лог.Предупреждение("Конфигурация не найдена, используются значения по умолчанию");
Лог.Ошибка("Произошла ошибка: файл не найден");Маппинг уровней logos → ОтелСтепеньСерьезности:
| logos | OTel Severity |
|---|---|
Отладка | Debug |
Информация | Info |
Предупреждение | Warn |
Ошибка | Error |
Процессоры логов
Простой процессор (для разработки)
Процессор = Новый ОтелПростойПроцессорЛогов(Экспортер);Пакетный процессор (для продакшена)
Процессор собирается через ПостроительНаследника из ОтелБазовыйПакетныйПроцессор. Параметры: экспортер, имя сигнала, размер очереди, размер пакета, интервал экспорта (мс). Для сигнала "logs" интервал по умолчанию 1000 мс, как в спецификации; размер пакета больше размера очереди ограничивается размером очереди.
Базовый = Новый ОтелБазовыйПакетныйПроцессор(Экспортер, "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.
Процессор событий в события спана
Переносит события в события текущего спана, см. События и события спана. Ставится перед процессором экспорта:
Процессоры = Новый Массив();
Процессоры.Добавить(Новый ОтелПроцессорСобытийВСобытияСпана());
Процессоры.Добавить(ПакетныйПроцессор);
Процессор = Новый ОтелКомпозитныйПроцессорЛогов(Процессоры);Композитный процессор
// ПакетныйПроцессор — пакетный процессор логов, собранный как показано выше,
// ОтладочныйЭкспортер — второй экспортер логов
Процессоры = Новый Массив();
Процессоры.Добавить(ПакетныйПроцессор);
Процессоры.Добавить(Новый ОтелПростойПроцессорЛогов(ОтладочныйЭкспортер));
Процессор = Новый ОтелКомпозитныйПроцессорЛогов(Процессоры);Смотрите также
- Автоконфигурация — настройка через
OTEL_LOGS_EXPORTER - Трассировка — корреляция логов со спанами
- Экспорт — эндпоинт
/v1/logs - API: ОтелЛоггер
- API: ОтелЗаписьЛога
