Как программно записать системное событие в журнал регистрации 1С?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

Разработчики, переходящие с платформы 1С:Предприятие 7.7 на версию 8, часто сталкиваются с неожиданным поведением журнала регистрации. В старой версии программная запись системных событий не вызывала проблем, однако в современных версиях (8.2, 8.3) попытка "подделать" системную запись приводит к дублированию категорий в фильтрах. В этой статье мы подробно разберем, почему это происходит, как устроена архитектура журнала регистрации и какие существуют корректные способы решения задачи логирования.

Анализ проблемы: почему дублируются события?

Рассмотрим ситуацию: программисту необходимо зафиксировать в журнале регистрации факт изменения данных, который произошел в фоновом задании или при специфической программной обработке. Естественным желанием является использование стандартного системного представления события, например, Данные.Изменение. Однако при использовании метода ЗаписьЖурналаРегистрации с таким строковым параметром разработчик обнаруживает, что в стандартном диалоге настройки фильтра ЖР появляется две одинаковые строки "Данные.Изменение".

Проанализируем причину этого явления. Платформа 1С:Предприятие 8 жестко разделяет системные события и события, созданные пользователем (программистом). Системные события имеют внутренние зарезервированные префиксы (например, _$Data$_.Update), которые недоступны для записи через встроенный язык. Когда мы передаем строку "Данные.Изменение" в первый параметр метода, платформа воспринимает её как новое пользовательское событие. Несмотря на визуальное сходство в интерфейсе, внутренние идентификаторы (UUID) этих событий в базе данных журнала различаются, что и приводит к "раздвоению" фильтра.

Техническое устройство журнала регистрации (.lgp и .lgd)

Для глубокого понимания проблемы разберем, как хранятся данные в разных форматах журнала регистрации:

  1. Старый текстовый формат (.lgp): Каждая запись представляет собой строку текста. В теории, внешними средствами редактирования файла можно было бы имитировать системную запись, но платформа кэширует дескрипторы файлов, и прямое вмешательство чревато повреждением индекса лога.
  2. Современный формат SQLite (.lgd): Начиная с версии 8.3.5, журнал представляет собой базу данных SQLite. Внутри этой базы есть служебная таблица EventNames. При попытке записи нового события платформа проверяет наличие имени в этой таблице. Если вы передаете текст, совпадающий с системным представлением, платформа все равно создает новую запись, так как системные имена хранятся во внутреннем формате ядра.

Таким образом, мимикрия под системное событие невозможна из-за архитектурных особенностей платформы, направленных на обеспечение достоверности аудита системы.

Решение №1: Создание собственной иерархии событий

Вместо попыток обмануть систему, рассмотрим наиболее правильный путь — создание собственной структуры событий. Это позволит избежать путаницы в фильтрах и сделает лог более читаемым. Выясним, как это сделать на практике.

В методе ЗаписьЖурналаРегистрации первым параметром передается имя события. Мы можем использовать точку для создания иерархии, аналогично системным записям. Рассмотрим пример:


// Пример записи собственного события с иерархией
ЗаписьЖурналаРегистрации(
    "ОбменДанными.ОшибкаЗагрузки",
    УровеньЖурналаРегистрации.Ошибка,
    Метаданные.Справочники.Номенклатура,
    СсылкаНаОбъект,
    "Ошибка при попытке создания объекта в фоновом задании"
);

В данном случае в фильтре журнала регистрации появится ветка ОбменДанными, внутри которой будет событие ОшибкаЗагрузки. Это семантически понятно и не конфликтует с системной веткой Данные.

Решение №2: Связывание через параметр "Данные"

Часто программисту нужно записать системное событие только для того, чтобы оно отображалось при фильтрации по конкретному объекту (например, по конкретной накладной). Разберем, как реализовать это правильно. Метод ЗаписьЖурналаРегистрации имеет параметр Данные. Если передать туда ссылку на объект метаданных, то при просмотре журнала с установленным отбором по этой ссылке будут видны все события: и системные (кто и когда изменил), и ваши программные (почему произошла ошибка в фоновом процессе).

Посмотрим на пример кода:


// Фиксация программного предупреждения, связанного с объектом
Процедура ЗаписатьПредупреждениеПоОбъекту(ОбъектСсылка, ТекстСообщения)
    ЗаписьЖурналаРегистрации(
        "БизнесЛогика.ПроверкаДанных",
        УровеньЖурналаРегистрации.Предупреждение,
        ОбъектСсылка.Метаданные(),
        ОбъектСсылка,
        ТекстСообщения
    );
КонецПроцедуры

При таком подходе администратор системы, открыв историю по конкретному документу, увидит целостную картину происходящего, несмотря на то что события имеют разные категории. Для удобного просмотра такой истории по объекту можно использовать обработку для вывода записей журнала регистрации по документу или справочнику.

Особенности работы в транзакциях и фоновых заданиях

Проанализируем важный нюанс, упомянутый в обсуждении: различие в моменте записи события. Системные события, связанные с изменением данных (Данные.Изменение, Данные.Добавление), фиксируются в журнале только после успешного завершения транзакции. Если в процессе записи произойдет отказ (Отказ = Истина в ПередЗаписью), системная запись в журнале не появится.

Программная же запись через ЗаписьЖурналаРегистрации по умолчанию выполняется немедленно, вне зависимости от исхода транзакции. Если вы хотите, чтобы ваша запись вела себя так же, как системная, необходимо использовать режим транзакции:


// Запись в журнал, которая сохранится только при успехе транзакции
ЗаписьЖурналаРегистрации(
    "Событие",
    УровеньЖурналаРегистрации.Информация,
    ,
    ,
    "Это сообщение появится только если транзакция зафиксирована",
    РежимТранзакцииЗаписиЖурналаРегистрации.Транзакционная
);

Это критически важно при реализации логики в модулях объектов, работающих в составе обменов или сложных фоновых процессов.

Выводы и рекомендации

Подводя итог, можно сказать, что невозможность программной записи системных событий — это не ошибка, а осознанное ограничение безопасности платформы 8-й версии. Для эффективной работы рекомендуем придерживаться следующих правил:

  1. Не дублируйте системные имена. Избегайте строк "Данные. Изменение" и подобных в параметрах вызова.
  2. Используйте логические имена событий. Вместо технического "записал объект" пишите "ЗагрузкаИзМаркетплейса" или "ПроверкаЦен". Это значительно упрощает аудит.
  3. Всегда заполняйте объект данных. Это единственный надежный способ связать ваши записи с системными в рамках одного бизнес-объекта.
  4. Помните о транзакциях. Используйте параметр РежимТранзакцииЗаписиЖурналаРегистрации, чтобы ваш лог не вводил в заблуждение в случае откатов транзакций.

Использование этих подходов позволит вам создавать надежные и информативные системы логирования, которые будут понятны как разработчикам, так и системным администраторам. Для организации комплексного аудита без ручного программирования событий можно использовать расширение для детального логирования изменений данных.

← На главную