Выгрузка журнала регистрации из кода: отборы, примеры, права
Содержание
Прочитать журнал регистрации 1С программно можно одним методом платформы — ВыгрузитьЖурналРегистрации(). Он выгружает события в таблицу значений или XML-файл и принимает структуру отбора: период, события, пользователь, объект метаданных, конкретная ссылка. Метод работает только на сервере (а также в толстом клиенте и во внешнем соединении), поэтому код пишут в общем модуле или в процедуре формы с директивой &НаСервере.
Типичная ситуация: главбух просит выяснить, кто в пятницу перепровёл реализации за прошлый квартал. Через стандартную форму журнала это долго — сотни строк, ручные отборы. Десять строк кода дают готовый список «пользователь — документ — время», который можно свернуть, отфильтровать и отправить отчётом.
Как устроен журнал регистрации и какие события он хранит
Журнал хранится вне базы данных — в файлах каталога 1Cv8Log. Для файловой базы этот каталог лежит рядом с 1Cv8.1CD. Для клиент-серверной — на сервере 1С в каталоге кластера: srvinfo\reg_1541\<GUID базы>\1Cv8Log.
Форматов два:
- 📄 Последовательный — файлы
.lgf(справочник пользователей , компьютеров, метаданных) и.lgp(сами события, разбитые по периодам). Текстовый формат, его можно разбирать сторонними парсерами. - 🗃️ SQLite — один файл
.lgd. Появился в 8.3.5, но на больших объёмах работает медленнее, поэтому в новых версиях платформы по умолчанию снова используется последовательный формат.
Формат переключают в конфигураторе: Администрирование → Настройка журнала регистрации. Там же задают, какие уровни событий писать и по каким периодам делить файлы.
Коды системных событий
В отборе и в колонке Событие фигурируют не русские названия, а служебные коды. Основные:
| Код события | Что означает |
|---|---|
_$Data$_.New | Добавление объекта |
_$Data$_.Update | Изменение объекта |
_$Data$_.Delete | Удаление объекта |
_$Data$_.Post | Проведение документа |
_$Data$_.Unpost | Отмена проведения |
_$Session$_.Start | Начало сеанса |
_$Session$_.Finish | Завершение сеанса |
_$Session$_.Authentication | Успешная аутентификация |
_$Session$_.AuthenticationError | Ошибка входа |
_$User$_.New, .Update, .Delete | Изменения пользователей ИБ |
_$InfoBase$_.ConfigUpdate | Изменение конфигурации |
_$InfoBase$_.DBConfigUpdate | Обновление конфигурации БД |
Плюс пользовательские события, которые пишет конфигурация. В типовых решениях на БСП их десятки: обновление информационной базы, регламентные задания, обмены данными. Названия у них обычные строки, например «Обновление информационной базы».
Полный перечень событий конкретной базы не нужно угадывать. Его возвращает ПолучитьЗначенияОтбораЖурналаРегистрации("Событие") — соответствие «код → представление».
Чтение журнала регистрации через ВыгрузитьЖурналРегистрации
Синтаксис метода:
ВыгрузитьЖурналРегистрации(<Приемник>, <Отбор>, <Колонки>, <ИмяФайлаЖурнала>, <КоличествоСобытий>)
- Приемник —
ТаблицаЗначенийили строка с именем XML-файла. - Отбор —
Структурас условиями (подробно ниже). - Колонки — строка с именами колонок через запятую. Не указана — выгружаются все.
- ИмяФайлаЖурнала — путь к выгруженному ранее журналу, если читать нужно не текущий журнал базы.
- КоличествоСобытий — ограничение числа строк результата.
Пример: кто менял и удалял данные за день
Код для общего модуля с флагом «Сервер»:
Функция ИзмененияЗаДень(Дата) Экспорт
События = Новый Массив;
События.Добавить("_$Data$_.Update");
События.Добавить("_$Data$_.Delete");
События.Добавить("_$Data$_.Post");
Отбор = Новый Структура;
Отбор.Вставить("ДатаНачала", НачалоДня(Дата));
Отбор.Вставить("ДатаОкончания", КонецДня(Дата));
Отбор.Вставить("Событие", События);
Таблица = Новый ТаблицаЗначений;
ВыгрузитьЖурналРегистрации(Таблица, Отбор,
"Дата,ИмяПользователя,Компьютер,Событие,ПредставлениеМетаданных,Данные,ПредставлениеДанных,Комментарий");
Возврат Таблица;
КонецФункции
Таблицу значений нельзя передать на клиент. Если результат нужен на форме, загрузите его в реквизит формы типа «Таблица значений» на сервере или верните массив структур.
Колонки результата
Чаще всего нужны:
- 🕒
Дата— момент события; - 👤
Пользователь(уникальный идентификатор) иИмяПользователя(строка); - 💻
Компьютер,ИмяПриложения,Сеанс; - 🏷️
Событие(код) иПредставлениеСобытия; - 📦
Метаданные,ПредставлениеМетаданных,Данные(ссылка на объект),ПредставлениеДанных; - ⚙️
Уровень,Транзакция,СтатусТранзакции,Комментарий; - 🌐
РабочийСервер,ОсновнойIPПорт,ВспомогательныйIPПорт.
Колонка Данные хранит ссылку, если объект ещё существует. Для удалённого объекта ссылка становится «битой», поэтому для отчёта надёжнее брать ПредставлениеДанных.
Фильтрация событий журнала: пользователь, объект, уровень
Ключи структуры отбора совпадают с именами колонок. Значением может быть одно значение или массив — тогда условие работает как «одно из».
| Ключ отбора | Что передавать |
|---|---|
ДатаНачала, ДатаОкончания | Дата |
Событие | Код события или массив кодов |
Пользователь | ПользовательИнформационнойБазы, имя, идентификатор или массив |
Метаданные | Объект метаданных или массив |
Данные | Ссылка на объект |
Уровень | Значение УровеньЖурналаРегистрации или массив |
Компьютер, ИмяПриложения | Строка |
Комментарий | Строка, поиск по вхождению |
Сеанс | Номер сеанса |
Все действия с одним документом
Отбор = Новый Структура;
Отбор.Вставить("Данные", ДокументСсылка);
Таблица = Новый ТаблицаЗначений;
ВыгрузитьЖурналРегистрации(Таблица, Отбор, "Дата,ИмяПользователя,ПредставлениеСобытия");
Таблица.Сортировать("Дата");
Только ошибки за неделю
Отбор = Новый Структура;
Отбор.Вставить("ДатаНачала", ТекущаяДатаСеанса() - 7 * 86400);
Отбор.Вставить("Уровень", УровеньЖурналаРегистрации.Ошибка);
Свёртка: сколько изменений сделал каждый пользователь
Таблица.Колонки.Добавить("Количество", Новый ОписаниеТипов("Число"));
Таблица.ЗаполнитьЗначения(1, "Количество");
Таблица.Свернуть("ИмяПользователя,Событие", "Количество");
Таблица.Сортировать("Количество Убыв");
Отсекайте отменённые транзакции
Если документ записывался внутри транзакции, которая потом откатилась, событие в журнале всё равно есть. Для аудита оставляйте строки, где СтатусТранзакции равен СтатусТранзакцииЗаписиЖурналаРегистрации.Зафиксирована или НетТранзакции. Иначе в отчёт попадут изменения, которых в базе нет.
Свои события для удобного поиска
Чтобы потом легко найти действия своей обработки, пишите их в журнал с понятным именем:
ЗаписьЖурналаРегистрации("МояЗагрузка.Цены",
УровеньЖурналаРегистрации.Информация,
Метаданные.РегистрыСведений.ЦеныНоменклатуры,
,
"Загружено строк: " + Формат(КоличествоСтрок, "ЧГ=0"));
Потом отбор Событие = "МояЗагрузка.Цены" вернёт ровно эти записи. Имена с точкой удобно группировать: «Подсистема.Действие».
Изменения регистров накопления: что видно в журнале
Регистры накопления пишутся движениями документа-регистратора. В журнале при проведении появляется событие _$Data$_.Post с ссылкой на документ в колонке Данные. Отдельной строки на каждую запись регистра нет, и журнал не хранит ни старых, ни новых значений ресурсов.
Отсюда рабочий порядок для расследования «кто испортил остатки»:
- Найдите в регистре регистраторы за нужный период запросом к основной таблице регистра (поле
Регистратор). - Передайте массив этих ссылок в отбор журнала по ключу
Данные. - Получите, кто и когда проводил или отменял проведение каждого документа.
Запрос = Новый Запрос(
"ВЫБРАТЬ РАЗЛИЧНЫЕ
| Т.Регистратор КАК Регистратор
|ИЗ
| РегистрНакопления.ТоварыНаСкладах КАК Т
|ГДЕ
| Т.Период МЕЖДУ &Начало И &Конец");
Запрос.УстановитьПараметр("Начало", НачалоМесяца(Дата));
Запрос.УстановитьПараметр("Конец", КонецМесяца(Дата));
Регистраторы = Запрос.Выполнить().Выгрузить().ВыгрузитьКолонку("Регистратор");
Отбор = Новый Структура("Данные", Регистраторы);
Имя регистра ТоварыНаСкладах замените на свой — в каждой конфигурации регистры называются по-разному.
Если нужно знать именно содержание правок, журнала мало. Есть три пути:
- 🗂️ План обмена с авторегистрацией — фиксирует факт изменения набора записей; его «таблица изменений» отвечает на вопрос «что менялось с момента последней выгрузки».
- 🕰️ История данных — механизм платформы (с 8.3.11), хранит версии объектов; включается для объектов в конфигураторе.
- 📚 Версионирование объектов из БСП — в типовых конфигурациях, хранит версии документов и справочников.
Чтение журнала из внешней программы
Когда журнал нужно забирать в систему мониторинга или аналитики, вариантов три.
COM-соединение
Создайте общий модуль с флагами «Сервер» и «Внешнее соединение», в нём экспортную функцию, которая возвращает результат строкой JSON. Внешний скрипт подключается и вызывает её:
$connector = New-Object -ComObject V83.COMConnector
$base = $connector.Connect('Srvr="srv1c";Ref="buh";Usr="robot";Pwd="***";')
$json = $base.ЖурналСервер.ИзмененияЗаДеньJSON("20261007")
Нужна зарегистрированная comcntr.dll той же разрядности, что и скрипт (regsvr32 от администратора). Каждый вызов занимает сеанс и лицензию.
HTTP-сервис
Тот же код оборачивают в HTTP-сервис конфигурации и публикуют на веб-сервере. Внешняя система получает JSON по GET-запросу с параметрами периода. Это удобнее COM: не нужен клиент 1С на стороне потребителя.
Прямое чтение файлов
Файлы .lgf/.lgp разбирают сторонние парсеры и агенты сбора логов. Формат не документирован официально и может меняться между версиями платформы. Файл .lgd — обычная база SQLite, но схема тоже не описана.
Работайте с копией файлов, а не с живым журналом. Сервер 1С пишет в них постоянно, и блокировка со стороны вашего инструмента может помешать записи.
Три задачи аудита, которые решает выгрузка журнала
Кто удалил документ
Здесь есть ловушка. Пометка на удаление — это запись объекта, в журнале она видна как _$Data$_.Update. Событие _$Data$_.Delete появляется только при физическом удалении, например при обработке «Удаление помеченных объектов».
Поэтому ищите в два прохода:
- Отбор по
_$Data$_.Deleteи нужному объекту метаданных — кто и когда удалил физически. - Отбор по
_$Data$_.Updateс той же ссылкой вДанные— последняя запись перед удалением обычно и есть установка пометки.
Подбор паролей и чужие входы
Отбор по событию _$Session$_.AuthenticationError за сутки, затем свёртка по колонкам ИмяПользователя и Компьютер. Десятки ошибок с одного компьютера за несколько минут — повод сменить пароль
и проверить, кто сидит за этим рабочим местом.
Кто обновлял конфигурацию
События _$InfoBase$_.ConfigUpdate и _$InfoBase$_.DBConfigUpdate показывают, когда меняли конфигурацию и применяли изменения к базе. Сопоставьте их со временем появления ошибок у пользователей: часто сбой начинается сразу после такого обновления.
Как ускорить выгрузку журнала регистрации
На базе с журналом в десятки гигабайт вызов без отбора может работать минутами и съесть память рабочего процесса. Что помогает:
- Всегда задавайте период.
ДатаНачалаиДатаОкончанияпозволяют платформе не открывать лишние файлы.lgp. - Делите журнал по периодам в настройке журнала (например, по дням). Чем мельче файлы, тем меньше читается при узком отборе.
- Ограничивайте колонки. Строка «Дата,ИмяПользователя,Событие» вместо всех колонок заметно уменьшает объём таблицы.
- Ставьте лимит строк пятым параметром, особенно в интерактивных отчётах.
- Читайте порциями. Для выгрузки за месяц идите циклом по дням и обрабатывайте каждый кусок отдельно.
- Сокращайте старый журнал. В конфигураторе
Администрирование → Журнал регистрации → Сократить— с выгрузкой удаляемых событий в файл, если они нужны для архива.
| Подход | Когда подходит | Риски |
|---|---|---|
ВыгрузитьЖурналРегистрации в таблицу | Отчёты, разовые расследования | Память рабочего процесса при широком отборе |
| Выгрузка в XML-файл | Архив, передача на анализ | Файлы большого размера |
Внешний парсер .lgp | Мониторинг в реальном времени | Недокументированный формат |
Регламентное задание, которое раз в час выгружает свежие события в регистр сведений, решает проблему скорости для частых отчётов: дальше работает обычный запрос с индексами.
Права доступа и безопасность при чтении журнала
Для вызова ВыгрузитьЖурналРегистрации у пользователя должно быть право «Журнал регистрации» (оно задаётся в роли, у роли с правом «Администрирование» оно есть). Без него метод выдаст ошибку нарушения прав.
Обычный приём в обработках — УстановитьПривилегированныйРежим(Истина) перед вызовом. Он снимает проверку прав, и вот тут нужна осторожность:
- 🔒 Журнал содержит имена пользователей, компьютеры, IP-адреса и представления документов с суммами и контрагентами. Это персональные и коммерческие данные.
- 🚪 Функцию с привилегированным режимом не делайте вызываемой с клиента без проверки роли. Иначе любой пользователь получит журнал целиком.
- 🌐 HTTP-сервис с журналом публикуйте только с аутентификацией и под отдельным пользователем с минимальными правами.
- 🗄️ Каталог
1Cv8Logна сервере закройте от общего доступа по сети: файлы читаются и без 1С.
Отдельно стоит фиксировать в журнале сам факт выгрузки — своим событием через ЗаписьЖурналаРегистрации с именем пользователя и периодом. Тогда видно, кто и когда смотрел аудит.
Частые вопросы
Можно ли прочитать журнал регистрации из тонкого клиента?
&НаСервере или функцию общего серверного модуля.Как прочитать журнал другой базы или выгруженный файл?
ИмяФайлаЖурнала. Так анализируют архивы после сокращения журнала.Почему в журнале нет нужных событий за прошлый месяц?
Администрирование → Настройка журнала регистрации в конфигураторе.Как программно включить запись только ошибок?
УстановитьИспользованиеЖурналаРегистрации() с массивом уровней. Текущее значение возвращает ПолучитьИспользованиеЖурналаРегистрации().