Настройки логирования#
Механизм управления логированием на уровне отдельных методов класса обеспечивает контроль над записью в журнал событий без вмешательства в бизнес-логику приложения.
Он позволяет включать логирование точечно — только для нужных методов, типов документов или уровней сообщений (INFO, WARNING и т.д.).
Это используется для:
Отладки — логирование включается только для проблемного сценария, не засоряя общий лог.
Мониторинга ошибок — можно настроить логирование только для WARNING и ERROR, игнорируя информационные сообщения.
Аудита — все изменения важных объектов фиксируются с привязкой к контексту и тегами.
Всё это работает без изменения кода и перезапуска — настройки применяются динамически.
Для формирования механизма управления логированием разработчик в коде:
Регистрирует настройки логирования для методов класса.
Задаёт условия применения логирования для этих настроек.
Использует логирующую сессию, чтобы записи в лог учитывали настройки и условия.
Совет
В стандартной поставке существует ограниченный набор классов, на которых включено логирование.
Настройки можно открыть через раздел Сущности - Классы, открыть карточку нужного класса, в карточке открыть закладку Настройки логирования.
Ключевые возможности#
Логирование можно настроить точечно для конкретных методов, типов объектов или подклассов.
Поддержка иерархического дерева методов, при котором активность настроек наследуется от родительских узлов, а условия проверяются только для текущего метода.
Автоматическая фильтрация записей по уровню логирования (ошибка, информационное сообщение, предупреждение и др.) с учётом иерархии, заданной пользователем.
Регистрация настроек программно через API.
Структура#
Лог#
Btk_Log «Лог» — V-коллекция, используемая для хранения записей о событиях, действиях пользователей и системных операциях в Global. В отличие от стандартного аудита, лог позволяет выполнить пользовательскую настройку записываемых в таблицу сообщений.
Структура данных Btk_Log позволяет сохранять информацию о:
Объекте-источнике (экземпляр класса).
Вызываемой процедуре (процедуре, инициировавшей запись в лог).
Типе лога.
Логирующей сессии (транзакции, в рамках которой была произведена вставка в лог).
Теге (служит для структурирования информации).
Тексте лога.
Вызываемом методе (текстовое поле, в котором описана цепочка вызовов методов, приведших к записи).
Пример:api1.proc1 -> api2.proc2.Дополнительных характеристиках (в формате JSON).
Использования лога#
Для обеспечения записи сообщения в лог необходимо выполнить следующие шаги:
Определить класс, к которому подключается
Btk_Log, объекты которого будут выступать в качестве источника записи в лог.В программный код добавить создание логирующей сессии.
В программный код добавить обработку, выполняющую вставку записи в таблицу
Btk_Logпри срабатывании соответствующего триггера события.Выполнить настройку логирования для разграничения записей.
Для консультантов по внедрению Global ERP:
Для обеспечения записи сообщения в лог необходимо создать задачу (ДП) с указанием класса, к которому необходимо подключить Btk_Log, и описанием содержимого лога (значения, устанавливаемые в поля лога).
Дерево настроек логирования#
На закладке «Настройка логирования» для класса отображается дерево последовательно вызванных методов, на которых происходит запись в лог.

Pm_CBStatementDocApi.processDocsByCBS (родитель)
└── Pm_CBStatementDocApi.processDocs (дочерний метод)
Ниже приведена ER-диаграмма связи Btk_Log, настроечных классов и непосредственно самого класса, на котором необходимо включить логирование.

Условия логирования#
Условия логирования определяют, разрешено ли записывать сообщения определённого уровня (например, INFO, WARNING) для конкретного метода с учётом контекста выполнения: класса, подкласса или типа объекта.
Открыть условия можно через кнопку ... в колонке Настройки логирования.

Зачем нужны условия?
Фильтрация записей в лог в зависимости от:
Уровня важности (INFO, WARNING, ERROR и т.д.).
Типа объекта (например, только для документов типа «Выписка банка»).
Подкласса (например, только для исходящих документов).
Сокращение объёма логов в продакшене.
Включение детального логирования только для определённых сценариев или объектов.
Как работают условия?
Регистрация условия происходит через
Btk_LogClassSettingCondApi()или через интерфейс.При записи в лог (с
bUseSetting = trueи внутри сессии) система:Определяет, какой метод вызывает
insertMsg.Проверяет, есть ли для него зарегистрированные условия.
Сравнивает тип логирования сообщения с разрешёнными типами в условиях.
Применяет иерархию уровней: если разрешён INFO, то разрешены и WARNING, ERROR. Если разрешён WARNING — INFO не разрешён.
Условия не наследуются от родителей — каждый метод должен иметь свои условия.
Условия для дочернего метода проверяются только в том случае, если все вышестоящие методы в иерархии имеют активные настройки логирования (даже если для них не заданы условия).
Логирующая сессия#
Логирующая сессия — это выполненная пользователем транзакция, в рамках которой система отслеживает стек вызовов методов и применяет зарегистрированные и активные для класса настройки логирования.
Без логирующей сессии:
Запись в лог происходит напрямую, как обычный вызов
insertMsg.Настройки класса игнорируются полностью, даже если указано
bUseSetting = true.Нет возможности применить фильтрацию по типу объекта, подклассу или уровню логирования.
Зачем нужна сессия:
Объединение нескольких логируемых сообщений в одну сессию.
Изоляция настроек — сессия гарантирует, что настройки одного потока/процесса не влияют на другие. Даже если создается дочерняя логирующая сессия для записи лога, то исходная сессия не изменится.
Определение контекста вызова — система знает, в каком методе происходит запись и кто его вызвал.
Применение условий — только внутри сессии система проверяет, разрешено ли писать лог для текущего метода, типа объекта, уровня логирования и т.д.
Как работает:
При вызове Btk_LogApi().withLogSession(...) система:
Сохраняет в контексте имя метода и его идентификатор.
Контекст (последовательность вызовов) отслеживается для каждого класса отдельно, что предотвращает дублирование цепочек при использовании методов из других классов.
Начинает отслеживать все последующие вызовы
insertMsg(..., bUseSetting = true)внутри блока.При записи в лог:
Проверяет, зарегистрирован ли метод в дереве настроек.
Проверяет, активны ли все его родители.
Применяет только его собственные условия.
Принимает решение о записи сообщения в лог.
Ключевые API:#
Btk_LogApi (основной API для записи логов)
├── Btk_LogClassSettingApi (регистрация методов в дереве настроек)
├── Btk_LogTypeApi (управление типами логов)
├── Btk_LogClassSettingCondApi (управление условиями логирования)
└── Btk_LogSession (управление контекстом логирования)
Создание#
Создание настроек#
Настройку можно задать через код и через интерфейс системы. По умолчанию рекомендуется создавать настройки через код — именно этот способ используется в стандартной реализации.
Настройка через интерфейс предназначена для нетиповых сценариев, когда требуется создать пользовательские методы, отличные от тех, что создаются по умолчанию (например, JEXL-скрипты).
Данный метод следует использовать исключительно при наличии обоснованного сценария и полного понимания его влияния на систему.
Регистрация методов, на которых происходит запись в лог:
//Регистрация верхнеуровневой (родительской) настройки для метода Pm_CBStatementDocApi.processDocsByCBS
val idSettingParent = Btk_LogClassSettingApi().register("Pm_CBStatementDocApi.processDocsByCBS", idClass)
//Регистрация дочерней настройки для метода Pm_CBStatementDocApi.processDocs вызываемого из метода Pm_CBStatementDocApi.processDocsByCBS (с указанием родителя)
val idSettingChild = Btk_LogClassSettingApi().register("Pm_CBStatementDocApi.processDocs", idClass, idSettingParent)
Создание условии#
Условия можно задать через код и через интерфейс системы.
Регистрация условий, по которым проверяется настройка логирования:
//Регистрация условия на классе
Btk_LogClassSettingCondApi().registerByClass(idSettingParent, Btk_LogTypeApi().findByMnemoCode("INFO"))
//Регистрация условия на типе объекта
Btk_LogClassSettingCondApi().registerByObjectType(idSettingChild, Btk_LogTypeApi().findByMnemoCode("INFO"), idOTCBStatementDoc)
//Регистрация условия на подклассе
Btk_LogClassSettingCondApi().registerBySubClass(idSettingChild, Btk_LogTypeApi().findByMnemoCode("WARINING"), idSBCBStatementDoc)
Создание логирующей сессии#
Логирующая сессия задается только из кода.
Пример регистрации логирующей сессии и записи в лог с учетом настроек:
// Открытие логирующей сессии от объекта логирования
def processDocsByCBS(idpCBStatement: NLong): Unit = {
val ropvCBStatement = Pm_ClientBankStatementApi().load(idpCBStatement)
// Открытия логирующей сессии
Btk_LogApi().withLogSession("Pm_CBStatementDocApi.processDocsByCBS", ropvCBStatement.gid) {
// Запись в лог
Btk_LogApi().insertMsg(
"INFO"
,ropvCBStatement
,"Начало обработки банковской выписки"
,"Обработка банковской выписки"
,bUseSetting = true // Параметр указывает, что при записи учитывается настройка на классе
)
// исполняемая процедура
processDocs(refreshByParent(ropvCBStatement).map(_.get(_.id)).toList)
}
}
// Открытие логирующей сессии от класса
def processDocs(idapCBStatementDoc: List[NLong]): Unit = {
// Открытия логирующей сессии
Btk_LogApi().withLogSession("Pm_CBStatementDocApi.processDocsByCBS", idClass) {
// исполняемая процедура
// Запись в лог
Btk_LogApi().insertMsg(
"INFO"
,ropvCBStatementDoc
,"Завершение обработки банковской выписки"
,"Обработка банковской выписки"
,bUseSetting = true // Параметр указывает, что при записи учитывается настройка на классе
)
}
}
Примечание
Для избежания ошибок в коде настройки, регистрируемой на классе и указываемой на сессии, рекомендуется создавать на классе поле с кодом.
Пример:
lazy val sLogSettingProcessDocsByCBS = "Pm_CBStatementDocApi.processDocsByCBS" // sLSProcessDocsByCBS
lazy val sLogSettingProcessDocs = "Pm_CBStatementDocApi.processDocs" // sLSProcessDocs
Использование#
Примеры использования#
Интерпретация банковской выписки:
def processDocsByCBS(idpCBStatement: NLong): Unit = {
val ropvCBStatement = Pm_ClientBankStatementApi().load(idpCBStatement)
Btk_LogApi().withLogSession(sLogSettingProcessDocsByCBS, ropvCBStatement.gid) {
val sStartProcMsg = s"Запущена интерпретация выписки ${ropvCBStatement.get(_.sNum)} (${ropvCBStatement.gid}) от ${ropvCBStatement.get(_.dStatement).toString("dd.MM.yyyy hh:mm:ss")}."
Btk_LogApi().atInsertMsg("INFO", ropvCBStatement, sStartProcMsg, "", bUseSetting = true)
Btk_InfoLogPkg().info(sStartProcMsg)
val idavCBStatementDoc = refreshByParent(ropvCBStatement).map(_.get(_.id))
processDocs(idavCBStatementDoc.toList)
val sFinishProcMsg = s"Завершена интерпретация выписки ${ropvCBStatement.get(_.sNum)} (${ropvCBStatement.gid}) от ${ropvCBStatement.get(_.dStatement).toString("dd.MM.yyyy hh:mm:ss")}."
Btk_LogApi().atInsertMsg("INFO", ropvCBStatement, sFinishProcMsg, "", bUseSetting = true)
Btk_InfoLogPkg().info(sFinishProcMsg)
}
}
Вынесение логики в отдельный метод:
def isDocProcessed(rop: Pm_CBStatementDocApi#ApiRop): Boolean = {
val ropvCBStatement = Pm_ClientBankStatementApi().load(rop.get(_.idClientBankStatement))
Btk_LogApi().withLogSession(sLogSettingIsDocProcessed, rop.gid) {
if (rop.get(_.idStateMC) > 100.nr) {
val sErrorMsg = s"Процедура интерпретации позиции банковской выписки ${rop.get(_.sNumDoc)} по документу ${ropvCBStatement.get(_.sNum)} (${ropvCBStatement.gid}) от ${ropvCBStatement.get(_.dStatement).toString("dd.MM.yyyy hh:mm:ss")} невозможна, так как она уже обработана пользователем"
Btk_LogApi().atInsertMsg("ERROR", rop, sErrorMsg, "", bUseSetting = true)
Btk_InfoLogPkg().error(sErrorMsg)
true
} else {
val sInfoMsg = s"Проверка пользовательской обработки позиции выписки ${rop.get(_.sNumDoc)} по документу ${ropvCBStatement.get(_.sNum)} (${ropvCBStatement.gid}) от ${ropvCBStatement.get(_.dStatement).toString("dd.MM.yyyy hh:mm:ss")}"
Btk_LogApi().atInsertMsg("INFO", rop, sInfoMsg, "", bUseSetting = true)
Btk_InfoLogPkg().info(sInfoMsg)
false
}
}
}
Дополнительные примеры настройки и использования можно посмотреть в реализации:
ru.bitec.app.pm.clientbank.Pm_CBStatementDocApi#regLogSetting
ru.bitec.app.pm.clientbank.Pm_CBStatementDocApi#processDocs
Результат логирования#
Результат логирования сохраняется в журнале событий, который настраивается со стороны заказчика.

Все логи системы лежат в Настройки системы - Сущности - Классы - btk_log.
Чистка журнала логов#
Очистка логов для классов с преднастроенным логированием выполняется автоматически. Она настроена в типовом задании очистки устаревших данных с окном хранения 10 дней в менеджере заданий.
Примечание
Для ручной очистки реализован API-метод clearBtkLog(), принимающий на вход системное имя класса и количество дней сдвига. К нему подключен джоб, автоматически очищающий таблицу.
При создании новых методов логирования необходимо зарегистрировать соответствующую запись в этом задании. Это обеспечивает автоматическое удаление устаревших записей логов и предотвращает неконтролируемый рост объема данных.
Детальнее про задания очистки смотри в разделе «Менеджер заданий»
Расширение#
Для добавления новых методов в систему логирования:
Зарегистрируйте метод через
Btk_LogClassSettingApi().register().Определите родительский метод в иерархии вызовов.
Настройте условия логирования через
Btk_LogClassSettingCondApi().Используйте константы для имен методов во избежание ошибок.
Ограничения#
Уровень WARNING не включает INFO — фильтрация работает только на повышение уровня (INFO включает WARNING и ERROR; WARNING включает только WARNING и ERROR).
Нет автоматического построения дерева вызовов — вся иерархия регистрируется вручную.
Нет встроенной валидации — можно зарегистрировать несуществующий метод.
Запись в лог происходит только при выполнении всех условий:
Метод присутствует в дереве настроек.
Все вышестоящие методы активны.
Для текущего метода выполняются условия логирования.