Как программно прочитать журнал регистрации 1с
В данной статье я предлагаю рассмотреть практические примеры возможностей актуальной библиотеки стандартных подсистем (БСП) в области функционала работы с "Журналом регистрации конфигурации". На момент написания статьи - я использую БСП версии 3.1.5.208. Все практические примеры статьи были реализованы на указанной версии БСП, использую платформу 1с 8.3.19.1264.
Публикация будет полезна всем разработчикам- программистам и администраторам баз данных, ну а так же любым пользователям, желающим познакомиться с основным функционалом журнал регистрации и методами записи и получения информации из него в типовых современных конфигурациях (работающих на БСП).
Примеры статьи актуальны для серверных и файловых баз.
Материал статьи я разделил на две части - в первой части описаны методы записи в журнал, а во второй - получение данных из журнала посредством методов библиотеки стандартных подсистем.
Итак, перейдем к первой части - методам записи в журнал регистрации:
Часть 1. Методы записи в журнал регистрации.
Самый простой метод регистрации в журнале возможен при выполнении такой процедуры
код исполнения выглядит вот так:
Результат исполнения процедуры записи выглядит вот так:
Рассмотрим еще один способ пакетной записи в журнал регистрации через структуру с помощью процедуры ЗаписатьСобытияВЖурналРегистрации(СобытияДляЖурналаРегистрации) Экспорт.
код исполнения выглядит вот так:
Убедимся, что работает. Результат исполнения данной процедуры аналогичен предыдущей - запись появилась.
Рис.2. Данная запись создана процедурой ЗаписатьСобытияВЖурналРегистрации.
С методами записи в журнал считаю, что достаточно. Предлагаю перейти ко второй части статью - методам получения информации из журнала регистрации.
Часть 2. Методы получения информации из журнала регистрации.
Для начала рассмотрим самый простой способ получения информации по отбору в форме самого журнала. Для этого воспользуемся процедурой ОткрытьЖурналРегистрации(Знач Отбор = Неопределено, Владелец = Неопределено) Экспорт
Код с отбором выглядит вот так:
Результат выполнения кода вот такой:
Рис.3. Программное открытие формы журнала регистрации с заданным отбором.
Здесь все просто - программно открывается форма журнала и мы видим все события по заданному отбору. Далее, давайте рассмотрим более сложный метод получения информации из технологического журнала - в структуру.
Для этого воспользуемся стандартной процедурой БСП ПрочитатьСобытияЖурналаРегистрации, которая вернет нам структуру записей журнала. Да-Да, именно вернет.
Данная типовая процедура помещает результат выполнения (в данном случае - это структура записей журнала регистрации) в хранилище. Код этой типовой процедуры выглядит вот так:
Чтобы получить результат, воспользуемся возможностями БСП - ДлительныеОперации. Общий код получения выглядит вот так:
Результат, который мы получим (вернули структуру с записями журнала):
Рис.4. Структура записей событий журнала.
В данной части мы рассмотрели два способа получения информации из журнала регистрации - по форме отбора и через структуру по средству функционала ДлительнойОперации. Теперь, перейдем заключению и выводам.
Заключение и выводы
В данной статье я рассмотрел основные возможности методов работы библиотеки стандартных подсистем с журналом регистрации в конфигурации. Примеры методов вы можете использовать в любой стандартной конфигурации 1С, основой которой является БСП.
Так же в статье затронута еще одна подсистема конфигурации - ДлительныеОперации. О ДлительныхОперациях вы можете прочитать мои статьи. Список полезных статей приведен в конце статьи.
Все эксперименты для написания этой статьи проводились на платформе 1С - 8.3.19.1264 и "чистой конфигурации" БСП 3.1.5.208.
Спасибо за прочтение данного материала. Если статья вам понравилась - прошу поддержать ее.
Другие мои материалы по подсистемам БСП
Также прошу ознакомиться с другими моими статьями по функционалу библиотеки стандартных подсистем и типовым конфигурациям по разделам:
Стандартный журнал регистрации платформы 1С имеет относительно большие возможности по записи информации о событиях в информационной базе. Эта информация может быть полезной при диагностике работы системы, расследования причин изменения данных в базе и многих других случаев.
Работать с журналом регистрации можно как встроенными в платформу инструментами, так и с помощью обработок из подсистем БСП. Также можно использовать нестандартные инструменты, например отчет "Просмотр и анализ журнала регистрации (отчет на СКД)".
Все было бы хорошо, но есть одна проблема. При большом размере данных в журнале работа с ним превращается в настоящий кошмар. Поиск данных в нем может занимать длительное время, причем не всегда можно дождаться результата. При получении данных из журнала и поиске необходимой информации могут появляться критически проблемы производительности в работе сервера 1С вплоть до его полного зависания, как это не раз уже освещалось на Инфостарт.
Есть несколько путей решения этих проблем:
- Не использовать его. Это не наш путь, но если он Вам не нужен - тогда это идеальное решение. При этом встречался со случаями, когда вместо него создавали регистры сведений и записывали нужные данные туда. Не будем касаться этой темы, у нее есть свои плюсы и минусы.
- Выгружать данные журнала в отдельную базу средствами платформы 1С. Создаем регламентное задание (а может и не одно) для выгрузки данных в какую-либо внешнюю базу. Решение рабочее и может функционировать весьма эффективно. Главными недостатками являются: недостаточная производительность при большом объеме данных, влияние на рабочий сервер 1С (иногда значительное), а также потенциально большой лаг по времени выгрузки.
- Использовать регулярные выражения для поиска данных. Для этого переводим формат журнала в текстовый и парсим его с помощью регулярных выражений. Производительность на высоте, но вот сопровождение такого решения требует значительных трудозатрат. К тому же отдать такое в использование рядовым пользователям тоже не просто.
Не первое решение
Еще в далеком 2013 году (уже 7 лет прошло!) Алексей Бочков предложил решение для сообщества в виде приложения "EventLogLoader" на Visual Basic, которое напрямую парсит файлы (для старого формата журнала регистрации) или получает данные из SQLite-базы журнала (для нового формата) После отправляет в одно из возможных хранилищ данных (база SQL Server, MySQL или индекс ElasticSearch).
В статье "Периодическая загрузка событий из журналов регистрации в базу MS SQL Server (с исходниками)" дано описание работы инструмента и, судя по статистике, он пользуется некоторой востребованностью.
В этой статье будет предложено фактически то же решение по прямому чтению данных из файлов журнала регистрации, но в несколько другом виде. Поехали!
Пройдемте в библиотеку
Чем же отличается предлагаемое решение от того, что было сделано столько лет назад? Главными особенностями будут следующие:
Помощник чтения данных журнала регистрации
Библиотека "YY.EventLogReaderAssistant" позволяет читать данные файлов журнала регистрации как старого текстового формата (*.lgf, *.lgp), так и нового формата SQLite-базы (*.lgd). На следующем листинге продемонстрирован простой пример ее использования в виде консольного приложения.
Тут все просто. Создаем экземпляр класса "EventLogReader", передав путь к каталогу с файлами данных журнала регистрации. Далее подписываемся на события:
- После чтения файла (AfterReadFile)
- После чтения события (AfterReadEvent)
- Перед чтением события (BeforeReadEvent)
- Перед чтением файла (BeforeReadFile)
- При ошибке (OnErrorEvent)
С их помощью можно обрабатывать прочитанные данные из журнала и привязать любую другую логику. Непосредственно чтение данных выполняется в потоке, что позволяет экономить память и начать чтение данных с определенной позиции. То есть можно прочитать половину файла, а через некоторое время продолжить чтение с последнего прочитанного события. Для этого используются методы "GetCurrentPosition" и "SetCurrentPosition", но подробнее на этом останавливаться не будем. Код в репозитории ответит на все вопросы.
Непосредственно получить данные события можно из свойства "CurrentRow", которое содержит:
- Период
- Идентификатор записи
- Уровень события
- Идентификатор соединения
- Идентификатор сеанса
- Статус транзакции
- Дату транзакции
- Идентификатор транзакции
- Пользователь
- Компьютер
- Приложение
- Событие
- Комментарий
- Метаданные
- Произвольные данные
- Идентификатор ссылочных данных
- Представление данных
- Рабочий сервер
- Первичный порт
- Вторичный порт
То есть это практически те же самые поля, что доступны и штатными средствами платформы (за исключением полей разделения данных и некоторых других). Данные читаются только последовательно, начиная с установленной позиции (или с начала файла данных, если позиция начала чтения явно не была указана).
Что делать со считанными данными - решать Вам. А пока перейдем к библиотекам экспорта данных.
Помощник экспорта журнала регистрации
Библиотека "YY.EventLogExportAssistant", а точнее набор библиотек, созданных для возможности экспорта данных журнала регистрации. Использует библиотеку чтения данных журнала, о которой шла речь выше. Решение содержит следующие части:
- YY.EventLogExportAssistant.Core - базовый пакет. В нем реализована основная логика по чтению и передаче данных в указанное хранилище.
- YY.EventLogExportAssistant.SQLServer - пакет для экспорта данных журнала регистрации в базу данных SQL Server. Зависит от базовой библиотеки.
- YY.EventLogExportAssistant.PostgreSQL - пакет для экспорта данных журнала регистрации в базу данных PostgreSQL. Зависит от базовой библиотеки.
Решение не только передает данные в хранилища, но и содержит алгоритмы инициализации баз данных с минимальным набором индексов и другими настройками (но никто не мешает создать эти базы вручную). В репозитории Вы можете ознакомиться с реализацией более подробно, а сейчас посмотрим на листинг с примером использования.
Вспоминаем про функциональность внешних источников данных.
Соединяем два механизма и получаем такой вот результат:
Не забываем скачать и установить ODBC-драйвер для SQLite нужной разрядности.
Обращаю внимание на параметр в строке подключения " BigInt=1", только так, поле хранящее дату будет возвращать корректный результат. Кстати, дата хранится как целое число. Например, если дата равна 635453673444260, то чтобы перевести в привычный тип Дата, нужно сделать так:
Если остались вопросы, просто посмотрите ЖР.cf и встроенную обработку "Пример".
Спасибо за внимание.
Специальные предложения
Очень интересный подход через внешниии источники данных. По сути можно иметь it-базу и там анализировать журналы разных баз.
Но есть один нюанс. Единожды переключив журнал в новый формат - обратно не вернешься. А текущие версии КИПа не поддерживают новый журнал регистрации в принципе %)
(4) awk,
То что это ускоряет чтение не надо быть 7 пядей во лбу
Интересно как запись , есть ли блокировки из за этого - т.к. стандартно 1С пишет каждый чих пользователя,
SQLLite при записи блокируют всю таблицу
(7) BabySG, В SQLite нет блокировок таблиц. Есть блокировка баз. Только один пользователь может писать. Остальные только читают.
(6) kiruha, Сомнительно, что там вообще накладываются блокировки - ибо нафига? Кого может волновать грязное чтение журнала регистрации?
Причем тут устройство или неустройство SQLlite? Так устроен любой SQL - если запись в таблицу, то блокируется вся таблица. А журнал - это практически одна основная таблица.
Классно. Интересно, если базы с более старой платформы 1С переводить на 8.3, то к уже имеющийся журнал регистрации как перегнать в SQLLite?
(17) ediks,
Ну вот ток что на тестовой базе перевел на новый формат, старые файлы журнала поудалял - вся старая информация осталась.
(19) Не, я предполагал, что не нужно нажимать никакие кнопки. Типа само, без участия оператора все происходит.
А так я тоже конвертнул - появился новый файл 1Cv8.lgd. Скачал конфигу и посмотрел, что получается.
Вот только вопрос - сколько будет конвертироваться журнал размером 120 Гб (все, что нажито нелегким трудом за много лет)?
И какой будет размер базы данных журнала? У меня после конвертации тестового журнала размером 10 Мб получилась база размером 17 Мб.
(20) ediks,
Режьте его серпом по корень ) Все равно в старом журнале разобраться в 120 гигах практически нереально )
(22) Пока только вопрос стоит об архивировании этого гигантского журнала. Вопрос о конвертации такого журнала был поставлен с чисто теоретической, познавательной целью.
У нас и мальчика-то 1С 8.3.5 нет :)
А скриншот есть что на выходе получаем? Так как таблица есть EventLog там все поля по -английски называются и информация в таблице невнятная.
(13) zombi81, Да, имена таблиц и полей используют английские названия. В своем примере, я как раз частично их перевел для внешнего источника, используя в основном устоявшиеся термины. Можете изучить ЖР.cf и я думаю станет понятнее.
зачем держать такие журналы? они все равно не используемы.. забэкапил то что нажито и ничего переносить не надо. ИМХО
Для файловой базы все работает, а вот для серверной версии не работает. Хочу вытянуть список документов которые изменял пользователь. Даже через режим "Конфигуратор" не могу подключится для получение структуры. В файловой все ок.
А вот сама идея вести лог сразу в базу данных sqlite - мне кажется, 1С облажалась, как всегда, пытаясь выдумать свой велосипед.
Во всём мире журналы логов пишутся максимально быстро в обычные текстовые файлы, которые уже потом периодически засасываются в различные конвертеры и анализаторы.
Задача стоит только в том, чтобы реализовать возможность инкрементальной перекачки из текстовых файлов в анализатор. Самое простое - каждые сутки/час/неделю заводить новый файл.
Нет необходимости "на лету" писать в формате, пригодном для анализа. Тем более, что sqlite - не самый быстрый способ писать в файлы.
Например, apache, ngnix спокойно и не парясь ведет лог в текстовые файлы. Хотя, о чём это я - nginix быстрый, ему так надо. А для 1С наверняка запись в журнал регистрации не является "бутылочным горлышком" платформы, и ускорять запись в этом месте нет особого смысла, потому что это копейки по сравнению с другими тормозными местами.
29.10.2013 Как мы улучшили журнал регистрации
Реализовано в версии 8.3.5.1068.
Мы значительно переработали журнал регистрации для того, чтобы увеличить скорость выполнения запросов к журналу и повысить надёжность хранения данных.
Для этого, в том числе, потребовалось изменить формат хранения журнала регистрации. Теперь он хранится в одном файле базы данных SQLite. Этот файл имеет расширение lgd.
Наши тесты показывают, что практически по всем условиям отбора выборка данных ускорилась. При некоторых условиях выборка ускорилась существенно. Например, в случае отбора по пользователю, разделителям и по данным, представленным одним значением. Что касается записи, то скорость однопоточной записи тоже немного ускорилась. А вот скорость многопоточной записи возросла почти в полтора раза. Как в файловом варианте, так и в клиент-серверном.
Создавая новую реализацию журнала, мы стремились учесть пожелания по архивированию журнала и сокращению его размера. Теперь во встроенном языке есть два метода, которые позволяют копировать данные журнала регистрации или удалять их, используя условия фильтрации. Это методы СкопироватьЖурналРегистрации() и ОчиститьЖурналРегистрации(). С их помощью архивирование или очистку журнала можно выполнять автоматически, регламентными заданиями, в период наименьшей загрузки системы.
Также мы ввели в журнале ещё одно изменение. Время событий хранится теперь в формате всемирного координированного времени (UTC). Это позволят избежать проблем, связанных с работой в разных часовых поясах.
Это как писать надо было, что бы дозапись в файл тормазила. :))))
Кто может подсказать?. Есть большой журнал регистраций ~ 30 Gb, пользователей много+ работает автоматическая выгрузка из другой системы. В общем, в лог постоянно что-то пишется.
Посмотреть историю изменений по документу просто нереально, журнал повисает и вешает за собой базу. Есть какие то пути решения? Хочется смотреть журнал на горячую при работающей базе.
При попытке читать лог ОДНОЙ БАЗЫ блокируется запись в него, что приводит к остановке работы rmngr, что в свою очередь, приводит к остановке обслуживания ВСЕХ БАЗ СЕРВЕРА.
Дадад, это не баг, это фича.
Почему она не срабатывает? Куда капать? ODBC-драйвер для SQLite установил
1С 8.3 Программное чтение записей журнала регистрации
Функция ПрочитатьСобытияЖурналаРегистрации ( Результат , НачДата , КонДата ) Экспорт
ИмяФайлаXML = ПолучитьИмяВременногоФайла ( "XML" );
Результат . Очистить ();
ОтборСобытий = Новый Структура ;
ОтборСобытий . Вставить ( "ДатаНачала" , НачДата );
ОтборСобытий . Вставить ( "ДатаОкончания" , КонДата );
ОтборСобытий . Вставить ( "Событие" , "_$Data$_.Post" );
// Выгрузка журнала:
ВыгрузитьЖурналРегистрации ( ИмяФайлаXML , ОтборСобытий , "Дата, Метаданные, Данные, ПредставлениеДанных, ИмяПользователя" );
// Чтение журнала;
XML = Новый ЧтениеXML ;
XML . ОткрытьФайл ( ИмяФайлаXML );
Построитель_DOM = Новый ПостроительDOM ;
Документ_DOM = Построитель_DOM . Прочитать ( XML );
Запись = Документ_DOM . ПолучитьЭлементыПоИмени ( "v8e:Event" );
Для НомерЗаписи = 0 По Запись . Количество ()- 1 Цикл
Узлы = Запись [ НомерЗаписи ]. ДочерниеУзлы ;
Для Каждого Узел Из Узлы Цикл
Если Узел . ИмяУзла = "v8e:Date" Тогда
ДатаУзла = СтрЗаменить ( Узел . ТекстовоеСодержимое , "T" , "" );
ДатаУзла = СтрЗаменить ( ДатаУзла , ":" , "" );
ДатаУзла = Дата ( СтрЗаменить ( ДатаУзла , "-" , "" ));
ИначеЕсли Узел . ИмяУзла = "v8e:MetadataName" Тогда
МетаданныеДокумента = СтрЗаменить ( Узел . ТекстовоеСодержимое , "Document." , "" );
ИначеЕсли Узел . ИмяУзла = "v8e:Data" Тогда
УИИД = Узел . ТекстовоеСодержимое ;
ИначеЕсли Узел . ИмяУзла = "v8e:DataPresentation" Тогда
ПредставлениеДанных = Узел . ТекстовоеСодержимое ;
ИначеЕсли Узел . ИмяУзла = "v8e:UserName" Тогда
ИмяПользователя = Узел . ТекстовоеСодержимое ;
КонецЕсли;
КонецЦикла;
Ссылка = Документы [ МетаданныеДокумента ]. ПолучитьСсылку ( Новый УникальныйИдентификатор ( УИИД ));
ОбъектДата = Ссылка . Дата ;
Результат = Результат . Добавить ();
Результат . ДатаСобытия = ДатаУзла ;
Результат . ДатаОбъекта = ОбъектДата ;
Результат . ПредставлениеДанных = ПредставлениеДанных ;
Результат . Пользователь = ИмяПользователя ;
Результат . РазностьДат = Окр (( ДатаУзла - ОбъектДата )/ 86400 );
Результат . Ссылка = Ссылка ;
КонецЦикла;
При выгрузке БД журнал не сохраняется. Он не храниться в базе данных, а находиться в её каталоге в подпапке 1Cv8Log в файле 1Cv8.lgf - если база файловая, " C:\Program Files\1cv8\srvinfo\\1Cv8Log " - если база расположена на сервере SQL. Работа с журналом регистрации также возможна и в программной среде 1С 8.3. Настройки регистрации в журнале следует выполнять при включенном монопольном режиме. Если изменения настроек регистрации выполнено в текущем сеансе, то они применятся только после перезапуска всех активных сеансов БД.
&НаСервере
Процедура УправлениеРегистрациейСобытий ()
// Запись событий журнала рекомендуется включать/выключать с помощью:
// гл.контекст - ПолучитьИспользованиеСобытияЖурналаРегистрации()
// гл.контекст - УстановитьИспользованиеСобытияЖурналаРегистрации()
ИспользСобытия = Новый ИспользованиеСобытияЖурналаРегистрации (); // Объект
ИспользСобытия . Использование = Ложь;
// Выключение регистрации события "_Ошибка выполнения_"
УстановитьИспользованиеСобытияЖурналаРегистрации ( "_$PerformError$_" , ИспользСобытия );
// "_$Access$_.Access_" - Доступ
// "_$Access$_.AccessDenied_" - Отказ в доступе
// _$PerformError$_" - Ошибка выполнения
// УстановитьИспользованиеСобытияЖурналаРегистрации не работает с событиями, связанными с транзакциями
&НаСервере
Процедура НастройкаПараметровДоступаКСправочнику ()
Спр_Контрагенты = Новый ОписаниеИспользованияСобытияДоступЖурналаРегистрации ();
// Объект, доступ к которому будет регистрироваться
Спр_Контрагенты . Объект = "Справочник.Контрагенты" ;
// Поля доступа:
Спр_Контрагенты . ПоляДоступа . Добавить ( "УНП" );
Спр_Контрагенты . ПоляДоступа . Добавить ( "Адрес.ЮрАдрес" ); //Табл.часть
// Поля регистрации:
Спр_Контрагенты . ПоляРегистрации . Добавить ( "УНП" );
Спр_Контрагенты . ПоляРегистрации . Добавить ( "Адрес.ПочтАдрес" ); //Табл.часть
АльтерПолей = Новый Массив ();
АльтерПолей . Добавить ( "Страна" );
АльтерПолей . Добавить ( "Область" );
АльтерПолей . Добавить ( "Район" );
// Для настройки объекта метаданных
Спр_Контрагенты . ПоляРегистрации . Добавить ( АльтерПолей );
НастройкаМетаданных = Новый Массив ();
НастройкаМетаданных . Добавить ( Спр_Контрагенты );
&НаСервере
Процедура НастройкаПараметровОтказаДоступаКСправочнику ()
Спр_Контрагенты = Новый ОписаниеИспользованияСобытияОтказВДоступеЖурналаРегистрации ();
// Объект, доступ к которому будет регистрироваться
Спр_Контрагенты . Объект = "Справочник.Контрагенты" ;
// Поля доступа:
Спр_Контрагенты . ПоляРегистрации . Добавить ( "УНП" );
Спр_Контрагенты . ПоляРегистрации . Добавить ( "Адрес.ЮрАдрес" );
АльтерПолей = Новый Массив ();
АльтерПолей . Добавить ( "Страна" );
АльтерПолей . Добавить ( "Область" );
АльтерПолей . Добавить ( "Район" );
Спр_Контрагенты . ПоляРегистрации . Добавить ( АльтерПолей );
&НаСервере
Процедура НастройкаПараметровДоступаКРегистру ()
Рег_Сведений = Новый ОписаниеИспользованияСобытияДоступЖурналаРегистрации ();
// Объект, доступ к которому будет регистрироваться
Рег_Сведений . Объект = "РегистрСведений.ВидыЗаключенныхДоговоров" ;
// Поля доступа:
Рег_Сведений . ПоляДоступа . Добавить ( "РентабельностьСделки" );
// Поля регистрации:
Рег_Сведений . ПоляРегистрации . Добавить ( "Менеджер" );
// Для настройки объекта метаданных
НастройкаМетаданных = Новый Массив ();
НастройкаМетаданных . Добавить ( Рег_Сведений );
Читайте также: