В процессе сопровождения крупных корпоративных систем перед разработчиком или системным администратором часто возникает задача контроля действий пользователей. Один из важных аспектов такого контроля — аудит формирования отчетов. Зачем это нужно? Во-первых, для выявления неиспользуемых или дублирующих отчетов (особенно созданных под конкретного «эффективного» менеджера, который потом о них забывает). Во-вторых, для анализа нагрузки на сервер базы данных — выявление «тяжелых» запросов, которые вешают систему в разгар рабочего дня. В-третьих, это требования информационной безопасности, когда необходимо точно знать, кто и когда выгружал конфиденциальные коммерческие данные.
В этой статье мы подробно разберем, как реализовать механизм контроля формирования отчетов в конфигурациях старого поколения на обычных формах (например, в «Управлении торговым предприятием» — УТП, «Управлении производственным предприятием» — УПП 1.3 или «Управлении торговлей» версии 10.3) под управлением современной платформы «1С:Предприятие 8.3».
Основная сложность задачи заключается в том, что в конфигурациях на обычных формах (толстый клиент) отсутствуют многие удобные механизмы современных управляемых форм (например, глобальные подписки на события создания форм на сервере). Нам необходимо фиксировать:
Рассмотрим подробнее три основных архитектурных подхода к реализации этой задачи:
Пользователь, Отчет, Дата и ресурсом для хранения настроек.Выясним преимущества и недостатки каждого метода и пошагово разберем их техническую реализацию.
---
Это компромиссное решение, которое выбрал автор темы на форуме. Оно отлично подходит, если аудит требуется проводить периодически, и нет необходимости строить сложные интерактивные диаграммы активности пользователей прямо внутри 1С.
Для записи события используется стандартный метод глобального контекста ЗаписьЖурналаРегистрации(). Разберем по шагам, как настроить такую запись.
При формировании отчета (например, в обработчике кнопки «Сформировать» или в модуле объекта при компоновке результата) нам нужно вызвать процедуру записи. Пример кода выглядит следующим образом:
Процедура ЗаписатьВЖурналРегистрацииФормированиеОтчета(ИмяОтчета, НастройкиОтчета) Экспорт
// Формируем текстовое представление критически важных настроек
СтрокаНастроек = "";
Для Каждого ЭлементОтбора Из НастройкиОтчета.Отбор Цикл
Если ЭлементОтбора.Использование Тогда
СтрокаНастроек = СтрокаНастроек + ЭлементОтбора.Представление + ": " + Строка(ЭлементОтбора.Значение) + "; ";
КонецЕсли;
КонецЦикла;
КомментарийЖР = "Сформирован отчет: " + ИмяОтчета + Символы.ПС + "Настройки: " + СтрокаНастроек;
ЗаписьЖурналаРегистрации(
"Отчеты.Формирование",
УровеньЖурналаРегистрации.Информация,
,
,
КомментарийЖР
);
КонецПроцедуры
Преимущества метода:
Недостатки метода:
ВыгрузитьЖурналРегистрации() может занять значительное время и заблокировать интерфейс.---
Если мы хотим построить качественную систему аналитики (например, отчет по популярности отчетов среди менеджеров или отчет по неиспользуемым формам), то лучшим выбором будет создание собственного регистра сведений. Рассмотрим, как правильно его спроектировать.
Создадим новый непериодический регистр сведений СтатистикаИспользованияОтчетов со следующей структурой:
Пользователь (Тип: СправочникСсылка.Пользователи).Отчет (Тип: Строка, длина 150 или СправочникСсылка.ПроизвольныйСправочникСОтчетами).ДатаВремя (Тип: Дата, состав даты: Время и дата).Настройки (Тип: ХранилищеЗначения).Обратите внимание на тип ресурса Настройки. Мы рекомендуем использовать именно ХранилищеЗначения, а не текстовое поле. Это позволит нам сериализовать объект настроек отчета целиком (будь то настройки ПостроителяОтчета или КомпоновщикаНастроек СКД) и сохранять его в бинарном виде.
Рассмотрим пример кода, который выполняет сериализацию настроек Системы компоновки данных (СКД) и осуществляет запись в регистр сведений при компоновке результата отчета:
Процедура ЗаписатьСтатистикуВРегистр(ИмяОтчета, КомпоновщикНастроек)
// Получаем текущие настройки компоновщика
ТекущиеНастройки = КомпоновщикНастроек.ПолучитьНастройки();
// Сериализуем настройки в XML для точной записи
ЗаписьXML = Новый ЗаписьXML;
ЗаписьXML.УстановитьСтроку();
СериализаторXDTO.ЗаписатьXML(ЗаписьXML, ТекущиеНастройки, "settings", "http://v8.1c.ru/8.1/data-composition-system/settings");
СтрокаXML = ЗаписьXML.Закрыть();
// Помещаем XML-строку в ХранилищеЗначения
ХранилищеНастроек = Новый ХранилищеЗначения(СтрокаXML, Новый СжатиеДанных(9));
// Записываем данные в регистр сведений
НаборЗаписей = РегистрыСведений.СтатистикаИспользованияОтчетов.СоздатьНаборЗаписей();
НоваяЗапись = НаборЗаписей.Добавить();
НоваяЗапись.Пользователь = ПараметрыСеанса.ТекущийПользователь;
НоваяЗапись.Отчет = ИмяОтчета;
НоваяЗапись.ДатаВремя = ТекущаяДата();
НоваяЗапись.Настройки = ХранилищеНастроек;
НаборЗаписей.Записать(Ложь); // Записываем без замещения существующих данных
КонецПроцедуры
Почему это технологично? При таком подходе вы можете сделать в админ-панели кнопку «Открыть отчет с настройками пользователя». По нажатию кнопки система считает XML из регистра, десериализует его обратно в настройки СКД и откроет отчет ровно в том виде, в котором его сформировал менеджер в конкретный день и час!
---
Как справедливо заметил один из участников обсуждения на форуме (Сообщение 9), в обычных формах события ОтчетМенеджер ограничены (доступны только ОбработкаПолученияФормы, ОбработкаПолученияПолейПредставления и ОбработкаПолученияПредставления). Стандартные подписки на события объектов не позволяют перехватить момент интерактивного нажатия кнопки пользователем на форме.
Неужели придется дорабатывать сотни отчетов конфигурации вручную? Нет, этого можно избежать, если использовать особенности архитектуры типовых конфигураций старого поколения.
Большинство типовых аналитических отчетов в УТП, УПП и УТ 10.3 построены на базе единого универсального отчета (использует ПостроительОтчета). Вместо изменения каждого отчета нам достаточно найти общую точку вызова.
Проанализируем структуру конфигурации и обратим внимание на общий модуль ТиповыеОтчеты или модуль объекта самого отчета УниверсальныйОтчет. Нам нужно внедрить наш вызов логирования в процедуру СформироватьОтчет() модуля объекта УниверсальныйОтчет. Достаточно добавить всего одну строку вызова нашей процедуры логирования, и система начнет собирать статистику по 90% отчетов в информационной базе.
Даже если конфигурация работает на обычных формах, современная платформа 8.3 позволяет использовать механизм **расширений конфигурации**. Это избавляет от необходимости снимать типовые объекты с поддержки.
Рассмотрим по шагам, как перехватить формирование отчета через расширение:
ТиповыеОтчеты.&После.Пример кода в расширении:
&После("СформироватьТиповойОтчет")
Процедура Расш1_СформироватьТиповойОтчет(ПостроительОтчета, ИсточникДанных, ВыводитьДетализацию)
// Получаем имя отчета из параметров построителя
ИмяОтчета = ПостроительОтчета.ИсточникДанных.ИмяШаблона;
// Вызываем логирование
ЗаписатьСтатистикуВРегистр(ИмяОтчета, ПостроительОтчета);
КонецПроцедуры
---
Если перед вами стоит задача отслеживать не просто "кто открыл отчет", а предотвратить утечку персональных данных или коммерческой тайны, то лучше использовать встроенные низкоуровневые возможности платформы.
Платформа 1С:Предприятие 8.3 позволяет логировать непосредственный доступ к полям базы данных без написания какого-либо программного кода.
При формировании любого отчета, который обращается к этим данным, платформа автоматически запишет в Журнал регистрации событие доступа _$Data$_.Read с указанием пользователя, времени и списка прочитанных полей данных.
Если менеджеры перегружают сервер формированием огромных отчетов за несколько лет без отборов, код менять не нужно. Настройте файл конфигурации технологического журнала logcfg.xml на сервере 1С.
Пример настройки секции для сбора событий выполнения тяжелых запросов (продолжительностью более 10 секунд):
<config xmlns="http://v8.1c.ru/v8/tech-log">
<log location="C:\v8\logs" history="24">
<event filter="DBMSSQL">
<query duration="10000"/>
</event>
<event filter="CALL">
<eq property="Context" value="Отчет."/>
</event>
<property name="all"/>
</log>
</config>
ТЖ зафиксирует точный контекст вызова на встроенном языке: от имени пользователя до строки модуля конкретного отчета, которая инициировала тяжелый SQL-запрос.
---
Подведем итоги нашего анализа. Выбор метода контроля зависит от ваших конечных целей:
УниверсальныйОтчет.