Введение
Всем доброго времени суток!
В данной статье я предлагаю рассмотреть практические примеры возможностей актуальной библиотеки стандартных подсистем (БСП) в области функционала работы с "Журналом регистрации конфигурации". На момент написания статьи - я использую БСП версии 3.1.5.208. Все практические примеры статьи были реализованы на указанной версии БСП, использую платформу 1с 8.3.19.1264.
Публикация будет полезна всем разработчикам- программистам и администраторам баз данных, ну а так же любым пользователям, желающим познакомиться с основным функционалом журнал регистрации и методами записи и получения информации из него в типовых современных конфигурациях (работающих на БСП).
Примеры статьи актуальны для серверных и файловых баз.
Материал статьи я разделил на две части - в первой части описаны методы записи в журнал, а во второй - получение данных из журнала посредством методов библиотеки стандартных подсистем.
Итак, перейдем к первой части - методам записи в журнал регистрации:
Часть 1. Методы записи в журнал регистрации.
Самый простой метод регистрации в журнале возможен при выполнении такой процедуры
Процедура ДобавитьСообщениеДляЖурналаРегистрации(Знач ИмяСобытия, Знач ПредставлениеУровня = "Информация", Знач Комментарий = "", Знач ДатаСобытия = "", Знач ЗаписатьСобытия = Ложь) Экспорт
код исполнения выглядит вот так:
&НаКлиенте
Процедура ВыполнитьЗаписьНаКлиенте()
ИмяСобытия = "Событие тестовое строкой на клиенте";
ПредставлениеУровня = "Ошибка"; //представление уровня записи - "Информация", "Ошибка", "Предупреждение", "Примечание".
Комментарий = "Комментарий к записи на клиенте";
// ДатаСобытия = ТекущаяДата();
ЖурналРегистрацииКлиент.ДобавитьСообщениеДляЖурналаРегистрации(ИмяСобытия, ПредставлениеУровня, Комментарий,,Истина);
КонецПроцедуры
Результат исполнения процедуры записи выглядит вот так:
Рис.1. Данная запись создана процедурой ДобавитьСообщениеДляЖурналаРегистрации.
Рассмотрим еще один способ пакетной записи в журнал регистрации через структуру с помощью процедуры ЗаписатьСобытияВЖурналРегистрации(СобытияДляЖурналаРегистрации) Экспорт.
код исполнения выглядит вот так:
&НаСервере
Процедура ВыполнитьНаСервере()
СтруктураСобытий = Новый Структура("ИмяСобытия, ПредставлениеУровня, Комментарий,ДатаСобытия");
СтруктураСобытий.ИмяСобытия = "Тестовая запись в журнал";
СтруктураСобытий.ПредставлениеУровня = "Предупреждение"; //"Информация", "Ошибка", "Предупреждение", "Примечание".
СтруктураСобытий.Комментарий = "Комментарий к событию";
//СтруктураСобытий.ДатаСобытия = ТекущаяДата();
СобытияДляЖурналаРегистрации = Новый СписокЗначений();
СобытияДляЖурналаРегистрации.Добавить(СтруктураСобытий);
ЖурналРегистрации.ЗаписатьСобытияВЖурналРегистрации(СобытияДляЖурналаРегистрации);
КонецПроцедуры
Убедимся, что работает. Результат исполнения данной процедуры аналогичен предыдущей - запись появилась.
Рис.2. Данная запись создана процедурой ЗаписатьСобытияВЖурналРегистрации.
С методами записи в журнал считаю, что достаточно. Предлагаю перейти ко второй части статью - методам получения информации из журнала регистрации.
Часть 2. Методы получения информации из журнала регистрации.
Для начала рассмотрим самый простой способ получения информации по отбору в форме самого журнала. Для этого воспользуемся процедурой ОткрытьЖурналРегистрации(Знач Отбор = Неопределено, Владелец = Неопределено) Экспорт
Код с отбором выглядит вот так:
&НаКлиенте
Процедура ОткрытьПоОтбору(Команда)
// Отбор - Структура:
// Пользователь - Строка
// - СписокЗначений - имя или список пользователей информационной базы.
// СобытиеЖурналаРегистрации - Строка, Массив - идентификатор события.
// ДатаНачала - Дата - начало интервала отображаемых событий.
// ДатаОкончания - Дата - конец интервала отображаемых событий.
// Данные - Произвольный - данные любого типа.
// Сеанс - СписокЗначений - список выбираемых сеансов.
// Уровень - Строка, Массив - представление уровня важности события журнала регистрации.
// ИмяПриложения - Массив - массив идентификаторов приложения.
Отбор = Новый Структура("Пользователь, СобытиеЖурналаРегистрации, ДатаНачала, ДатаОкончания, Данные, Сеанс, Уровень");
Отбор.Пользователь = "Администратор";
Отбор.ДатаНачала = НачалоДня(ТекущаяДата());
Отбор.ДатаОкончания = КонецДня(ТекущаяДата());
Отбор.Уровень = "Ошибка";
Отбор.СобытиеЖурналаРегистрации = "Событие тестовое строкой1";
ЖурналРегистрацииКлиент.ОткрытьЖурналРегистрации(Отбор, ЭтаФорма);
КонецПроцедуры
Результат выполнения кода вот такой:
Рис.3. Программное открытие формы журнала регистрации с заданным отбором.
Здесь все просто - программно открывается форма журнала и мы видим все события по заданному отбору. Далее, давайте рассмотрим более сложный метод получения информации из технологического журнала - в структуру.
Для этого воспользуемся стандартной процедурой БСП ПрочитатьСобытияЖурналаРегистрации, которая вернет нам структуру записей журнала. Да-Да, именно вернет.
Данная типовая процедура помещает результат выполнения (в данном случае - это структура записей журнала регистрации) в хранилище. Код этой типовой процедуры выглядит вот так:
Процедура ПрочитатьСобытияЖурналаРегистрации(ПараметрыОтчета, АдресХранилища) Экспорт
ОтборЖурналаНаКлиенте = ПараметрыОтчета.ОтборЖурналаРегистрации;
КоличествоСобытий = ПараметрыОтчета.КоличествоПоказываемыхСобытий;
МенеджерВладельца = ПараметрыОтчета.МенеджерВладельца;
ДобавлятьДополнительныеКолонки = ПараметрыОтчета.ДобавлятьДополнительныеКолонки;
// Проверяем параметры на корректность.
ДатаНачала = Неопределено;
ДатаОкончания = Неопределено;
ДатыОтбораУказаны = ОтборЖурналаНаКлиенте.Свойство("ДатаНачала", ДатаНачала) И ОтборЖурналаНаКлиенте.Свойство("ДатаОкончания", ДатаОкончания)
И ЗначениеЗаполнено(ДатаНачала) И ЗначениеЗаполнено(ОтборЖурналаНаКлиенте.ДатаОкончания);
Если ДатыОтбораУказаны И ДатаНачала > ДатаОкончания Тогда
ВызватьИсключение НСтр("ru = 'Некорректно заданы условия отбора журнала регистрации. Дата начала больше даты окончания.'");
КонецЕсли;
СмещениеВремениСервера = СмещениеВремениСервера();
// Подготовка отбора
Отбор = Новый Структура;
Для Каждого ЭлементОтбора Из ОтборЖурналаНаКлиенте Цикл
Отбор.Вставить(ЭлементОтбора.Ключ, ЭлементОтбора.Значение);
КонецЦикла;
ПреобразованиеОтбора(Отбор, СмещениеВремениСервера);
// Выгрузка отбираемых событий и формирование структуры таблицы.
СобытияЖурнала = Новый ТаблицаЗначений;
ВыгрузитьЖурналРегистрации(СобытияЖурнала, Отбор, , , КоличествоСобытий);
СобытияЖурнала.Колонки.Дата.Имя = "ДатаНаСервере";
СобытияЖурнала.Колонки.Добавить("Дата", Новый ОписаниеТипов("Дата"));
СобытияЖурнала.Колонки.Добавить("НомерРисунка", Новый ОписаниеТипов("Число"));
СобытияЖурнала.Колонки.Добавить("АдресДанных", Новый ОписаниеТипов("Строка"));
Если ОбщегоНазначения.ДоступноИспользованиеРазделенныхДанных() Тогда
СобытияЖурнала.Колонки.Добавить("РазделениеДанныхСеанса", Новый ОписаниеТипов("Строка"));
СобытияЖурнала.Колонки.Добавить("ПредставлениеРазделенияДанныхСеанса", Новый ОписаниеТипов("Строка"));
КонецЕсли;
Если ДобавлятьДополнительныеКолонки Тогда
МенеджерВладельца.ДобавитьДополнительныеКолонкиСобытия(СобытияЖурнала);
КонецЕсли;
Если ОбщегоНазначения.РазделениеВключено()
И ОбщегоНазначения.ДоступноИспользованиеРазделенныхДанных()
И ОбщегоНазначения.ПодсистемаСуществует("ТехнологияСервиса.БазоваяФункциональность") Тогда
МодульРаботаВМоделиСервиса = ОбщегоНазначения.ОбщийМодуль("РаботаВМоделиСервиса");
ПсевдонимыПользователей = Новый Соответствие();
Иначе
МодульРаботаВМоделиСервиса = Неопределено;
ПсевдонимыПользователей = Неопределено;
КонецЕсли;
Для Каждого СобытиеЖурнала Из СобытияЖурнала Цикл
СобытиеЖурнала.Дата = СобытиеЖурнала.ДатаНаСервере - СмещениеВремениСервера;
// Заполнение номеров картинок строк.
МенеджерВладельца.УстановитьНомерРисунка(СобытиеЖурнала);
Если ДобавлятьДополнительныеКолонки Тогда
// Заполнение дополнительных полей, определенных только у владельца.
МенеджерВладельца.ЗаполнитьДополнительныеКолонкиСобытия(СобытиеЖурнала);
КонецЕсли;
// Преобразование массива метаданных в список значений.
СписокПредставленийМетаданных = Новый СписокЗначений;
Если ТипЗнч(СобытиеЖурнала.ПредставлениеМетаданных) = Тип("Массив") Тогда
СписокПредставленийМетаданных.ЗагрузитьЗначения(СобытиеЖурнала.ПредставлениеМетаданных);
СобытиеЖурнала.ПредставлениеМетаданных = СписокПредставленийМетаданных;
Иначе
СобытиеЖурнала.ПредставлениеМетаданных = Строка(СобытиеЖурнала.ПредставлениеМетаданных);
КонецЕсли;
// Преобразование массива "ПредставлениеРазделенияДанныхСеанса" в список значений.
Если ОбщегоНазначения.РазделениеВключено()
И Не ОбщегоНазначения.ДоступноИспользованиеРазделенныхДанных() Тогда
ПолноеПредставлениеРазделенияДанныхСеанса = "";
РазделениеДанныхСеанса = СобытиеЖурнала.РазделениеДанныхСеанса;
СписокРеквизитовРазделенияДанных = Новый СписокЗначений;
Для Каждого РазделительСеанса Из РазделениеДанныхСеанса Цикл
ПредставлениеРазделителя = Метаданные.ОбщиеРеквизиты.Найти(РазделительСеанса.Ключ).Синоним;
ПредставлениеРазделителя = ПредставлениеРазделителя + " = " + РазделительСеанса.Значение;
ЗначениеРазделителя = РазделительСеанса.Ключ + "=" + РазделительСеанса.Значение;
СписокРеквизитовРазделенияДанных.Добавить(ЗначениеРазделителя, ПредставлениеРазделителя);
ПолноеПредставлениеРазделенияДанныхСеанса = ?(Не ПустаяСтрока(ПолноеПредставлениеРазделенияДанныхСеанса),
ПолноеПредставлениеРазделенияДанныхСеанса + "; ", "")
+ ПредставлениеРазделителя;
КонецЦикла;
СобытиеЖурнала.РазделениеДанныхСеанса = СписокРеквизитовРазделенияДанных;
СобытиеЖурнала.ПредставлениеРазделенияДанныхСеанса = ПолноеПредставлениеРазделенияДанныхСеанса;
КонецЕсли;
// Обработка данных специальных событий.
Если СобытиеЖурнала.Событие = "_$Access$_.Access" Тогда
УстановитьСтрокуАдресаДанных(СобытиеЖурнала);
Если СобытиеЖурнала.Данные <> Неопределено Тогда
СобытиеЖурнала.Данные = ?(СобытиеЖурнала.Данные.Данные = Неопределено, "", "...");
КонецЕсли;
ИначеЕсли СобытиеЖурнала.Событие = "_$Access$_.AccessDenied" Тогда
УстановитьСтрокуАдресаДанных(СобытиеЖурнала);
Если СобытиеЖурнала.Данные <> Неопределено Тогда
Если СобытиеЖурнала.Данные.Свойство("Право") Тогда
СобытиеЖурнала.Данные = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
НСтр("ru = 'Право: %1'"),
СобытиеЖурнала.Данные.Право);
Иначе
ДанныеЖурнала = СобытиеЖурнала.Данные; // Структура
СобытиеЖурнала.Данные = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(
НСтр("ru = 'Действие: %1%2'"),
ДанныеЖурнала.Действие, ?(СобытиеЖурнала.Данные.Данные = Неопределено, "", ", ...") );
КонецЕсли;
КонецЕсли;
ИначеЕсли СобытиеЖурнала.Событие = "_$Session$_.Authentication"
Или СобытиеЖурнала.Событие = "_$Session$_.AuthenticationError" Тогда
УстановитьСтрокуАдресаДанных(СобытиеЖурнала);
СобытиеЖурналаДанные = "";
Если СобытиеЖурнала.Данные <> Неопределено Тогда
Для Каждого КлючИЗначение Из СобытиеЖурнала.Данные Цикл
Если ЗначениеЗаполнено(СобытиеЖурналаДанные) Тогда
СобытиеЖурналаДанные = СобытиеЖурналаДанные + ", ...";
Прервать;
КонецЕсли;
СобытиеЖурналаДанные = КлючИЗначение.Ключ + ": " + КлючИЗначение.Значение;
КонецЦикла;
КонецЕсли;
СобытиеЖурнала.Данные = СобытиеЖурналаДанные;
ИначеЕсли СобытиеЖурнала.Событие = "_$User$_.Delete" Тогда
УстановитьСтрокуАдресаДанных(СобытиеЖурнала);
СобытиеЖурналаДанные = "";
Если СобытиеЖурнала.Данные <> Неопределено Тогда
Для каждого КлючИЗначение Из СобытиеЖурнала.Данные Цикл
СобытиеЖурналаДанные = КлючИЗначение.Ключ + ": " + КлючИЗначение.Значение;
Прервать;
КонецЦикла;
КонецЕсли;
СобытиеЖурнала.Данные = СобытиеЖурналаДанные;
ИначеЕсли СобытиеЖурнала.Событие = "_$User$_.New"
ИЛИ СобытиеЖурнала.Событие = "_$User$_.Update" Тогда
УстановитьСтрокуАдресаДанных(СобытиеЖурнала);
ИмяПользователяИБ = "";
Если СобытиеЖурнала.Данные <> Неопределено Тогда
СобытиеЖурнала.Данные.Свойство("Имя", ИмяПользователяИБ);
КонецЕсли;
СобытиеЖурнала.Данные = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр("ru = 'Имя: %1, ...'"), ИмяПользователяИБ);
КонецЕсли;
УстановитьПривилегированныйРежим(Истина);
// Уточнение имени пользователя.
Если СобытиеЖурнала.Пользователь = Новый УникальныйИдентификатор("00000000-0000-0000-0000-000000000000") Тогда
СобытиеЖурнала.ИмяПользователя = НСтр("ru = '<Неопределен>'");
ИначеЕсли СобытиеЖурнала.ИмяПользователя = "" Тогда
СобытиеЖурнала.ИмяПользователя = Пользователи.ПолноеИмяНеУказанногоПользователя();
ИначеЕсли ПользователиИнформационнойБазы.НайтиПоУникальномуИдентификатору(СобытиеЖурнала.Пользователь) = Неопределено Тогда
СобытиеЖурнала.ИмяПользователя = СтроковыеФункцииКлиентСервер.ПодставитьПараметрыВСтроку(НСтр("ru = '%1 <Удален>'"), СобытиеЖурнала.ИмяПользователя);
КонецЕсли;
Если МодульРаботаВМоделиСервиса <> Неопределено Тогда
Если ПсевдонимыПользователей.Получить(СобытиеЖурнала.Пользователь) = Неопределено Тогда
ПсевдонимПользователя = МодульРаботаВМоделиСервиса.ПсевдонимПользователяИнформационнойБазы(СобытиеЖурнала.Пользователь);
ПсевдонимыПользователей.Вставить(СобытиеЖурнала.Пользователь, ПсевдонимПользователя);
Иначе
ПсевдонимПользователя = ПсевдонимыПользователей.Получить(СобытиеЖурнала.Пользователь);
КонецЕсли;
Если ЗначениеЗаполнено(ПсевдонимПользователя) Тогда
СобытиеЖурнала.ИмяПользователя = ПсевдонимПользователя;
КонецЕсли;
КонецЕсли;
// Преобразование идентификатора в имя для использования в дальнейшем при установке отборе.
ПользовательИБ = ПользователиИнформационнойБазы.НайтиПоУникальномуИдентификатору(СобытиеЖурнала.Пользователь);
Если ПользовательИБ <> Неопределено Тогда
СобытиеЖурнала.Пользователь = ПользовательИБ.Имя;
КонецЕсли;
УстановитьПривилегированныйРежим(Ложь);
КонецЦикла;
// Успешное завершение
Результат = Новый Структура;
Результат.Вставить("СобытияЖурнала", СобытияЖурнала);
ПоместитьВоВременноеХранилище(Результат, АдресХранилища);
КонецПроцедуры
Чтобы получить результат, воспользуемся возможностями БСП - ДлительныеОперации. Общий код получения выглядит вот так:
&НаСервере
Функция ПараметрыОтчета() // конструктор отбора для выполнения процедуры
ОтборЖурналаРегистрации = Новый Структура("ДатаНачала, ДатаОкончания");
ОтборЖурналаРегистрации.ДатаНачала = НачалоДня(ТекущаяДата());
ОтборЖурналаРегистрации.ДатаОкончания = КонецДня(ТекущаяДата());
ПараметрыОтчета = Новый Структура;
ПараметрыОтчета.Вставить("ОтборЖурналаРегистрации", ОтборЖурналаРегистрации);
ПараметрыОтчета.Вставить("КоличествоПоказываемыхСобытий", 1000);
ПараметрыОтчета.Вставить("УникальныйИдентификатор", УникальныйИдентификатор);
ПараметрыОтчета.Вставить("МенеджерВладельца", Обработки.ЖурналРегистрации);
ПараметрыОтчета.Вставить("ДобавлятьДополнительныеКолонки", Ложь);
//ПараметрыОтчета.Вставить("Журнал", РеквизитФормыВЗначение("Журнал"));
Возврат ПараметрыОтчета;
КонецФункции
&НаСервере
Процедура СобытияЖурнала()
ПараметрыОтчета = ПараметрыОтчета();
ПараметрыВыполнения = ДлительныеОперации.ПараметрыВыполненияВФоне(УникальныйИдентификатор);
ПараметрыВыполнения.ОжидатьЗавершение = 0;
ПараметрыВыполнения.НаименованиеФоновогоЗадания = НСтр("ru = 'Обновление журнала регистрации'");
РезультатВыполнения = ДлительныеОперации.ВыполнитьВФоне("ЖурналРегистрации.ПрочитатьСобытияЖурналаРегистрации", ПараметрыОтчета, ПараметрыВыполнения);
СтруктураЗаписейЖурнала = ПолучитьИЗВременногоХранилища(РезультатВыполнения.АдресРезультата);
КонецПроцедуры
Результат, который мы получим (вернули структуру с записями журнала):
Рис.4. Структура записей событий журнала.
В данной части мы рассмотрели два способа получения информации из журнала регистрации - по форме отбора и через структуру по средству функционала ДлительнойОперации. Теперь, перейдем заключению и выводам.
Заключение и выводы
В данной статье я рассмотрел основные возможности методов работы библиотеки стандартных подсистем с журналом регистрации в конфигурации. Примеры методов вы можете использовать в любой стандартной конфигурации 1С, основой которой является БСП.
Так же в статье затронута еще одна подсистема конфигурации - ДлительныеОперации. О ДлительныхОперациях вы можете прочитать мои статьи. Список полезных статей приведен в конце статьи.
Все эксперименты для написания этой статьи проводились на платформе 1С - 8.3.19.1264 и "чистой конфигурации" БСП 3.1.5.208.
Спасибо за прочтение данного материала. Если статья вам понравилась - прошу поддержать ее.
Другие мои материалы по подсистемам БСП
Также прошу ознакомиться с другими моими статьями по функционалу библиотеки стандартных подсистем и типовым конфигурациям по разделам:
Длительные операции:
БСП - рабочие примеры асинхронного запуска функций и процедур
Работа со штрихкодами и печатными макетами:
Генерация штрихкодов с помощью БСП для программистов
Печать макета MS Word в любом документе с помощью БСП
Администрирование баз с помощью БСП:
Базовые приемы работы с кластером 1С при помощи БСП