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

· 9 мин

Содержание

Прочитать журнал регистрации 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 с ссылкой на документ в колонке Данные. Отдельной строки на каждую запись регистра нет, и журнал не хранит ни старых, ни новых значений ресурсов.

Отсюда рабочий порядок для расследования «кто испортил остатки»:

  1. Найдите в регистре регистраторы за нужный период запросом к основной таблице регистра (поле Регистратор).
  2. Передайте массив этих ссылок в отбор журнала по ключу Данные.
  3. Получите, кто и когда проводил или отменял проведение каждого документа.
Запрос = Новый Запрос(
"ВЫБРАТЬ РАЗЛИЧНЫЕ
|    Т.Регистратор КАК Регистратор
|ИЗ
|    РегистрНакопления.ТоварыНаСкладах КАК Т
|ГДЕ
|    Т.Период МЕЖДУ &Начало И &Конец");
Запрос.УстановитьПараметр("Начало", НачалоМесяца(Дата));
Запрос.УстановитьПараметр("Конец", КонецМесяца(Дата));
Регистраторы = Запрос.Выполнить().Выгрузить().ВыгрузитьКолонку("Регистратор");

Отбор = Новый Структура("Данные", Регистраторы);

Имя регистра ТоварыНаСкладах замените на свой — в каждой конфигурации регистры называются по-разному.

Если нужно знать именно содержание правок, журнала мало. Есть три пути:

  • 🗂️ План обмена с авторегистрацией — фиксирует факт изменения набора записей; его «таблица изменений» отвечает на вопрос «что менялось с момента последней выгрузки».
  • 🕰️ История данных — механизм платформы (с 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 появляется только при физическом удалении, например при обработке «Удаление помеченных объектов».

Поэтому ищите в два прохода:

  1. Отбор по _$Data$_.Delete и нужному объекту метаданных — кто и когда удалил физически.
  2. Отбор по _$Data$_.Update с той же ссылкой в Данные — последняя запись перед удалением обычно и есть установка пометки.

Подбор паролей и чужие входы

Отбор по событию _$Session$_.AuthenticationError за сутки, затем свёртка по колонкам ИмяПользователя и Компьютер. Десятки ошибок с одного компьютера за несколько минут — повод сменить пароль и проверить, кто сидит за этим рабочим местом.

Кто обновлял конфигурацию

События _$InfoBase$_.ConfigUpdate и _$InfoBase$_.DBConfigUpdate показывают, когда меняли конфигурацию и применяли изменения к базе. Сопоставьте их со временем появления ошибок у пользователей: часто сбой начинается сразу после такого обновления.

Как ускорить выгрузку журнала регистрации

На базе с журналом в десятки гигабайт вызов без отбора может работать минутами и съесть память рабочего процесса. Что помогает:

  1. Всегда задавайте период. ДатаНачала и ДатаОкончания позволяют платформе не открывать лишние файлы .lgp.
  2. Делите журнал по периодам в настройке журнала (например, по дням). Чем мельче файлы, тем меньше читается при узком отборе.
  3. Ограничивайте колонки. Строка «Дата,ИмяПользователя,Событие» вместо всех колонок заметно уменьшает объём таблицы.
  4. Ставьте лимит строк пятым параметром, особенно в интерактивных отчётах.
  5. Читайте порциями. Для выгрузки за месяц идите циклом по дням и обрабатывайте каждый кусок отдельно.
  6. Сокращайте старый журнал. В конфигураторе Администрирование → Журнал регистрации → Сократить — с выгрузкой удаляемых событий в файл, если они нужны для архива.
ПодходКогда подходитРиски
ВыгрузитьЖурналРегистрации в таблицуОтчёты, разовые расследованияПамять рабочего процесса при широком отборе
Выгрузка в XML-файлАрхив, передача на анализФайлы большого размера
Внешний парсер .lgpМониторинг в реальном времениНедокументированный формат

Регламентное задание, которое раз в час выгружает свежие события в регистр сведений, решает проблему скорости для частых отчётов: дальше работает обычный запрос с индексами.

Права доступа и безопасность при чтении журнала

Для вызова ВыгрузитьЖурналРегистрации у пользователя должно быть право «Журнал регистрации» (оно задаётся в роли, у роли с правом «Администрирование» оно есть). Без него метод выдаст ошибку нарушения прав.

Обычный приём в обработках — УстановитьПривилегированныйРежим(Истина) перед вызовом. Он снимает проверку прав, и вот тут нужна осторожность:

  • 🔒 Журнал содержит имена пользователей, компьютеры, IP-адреса и представления документов с суммами и контрагентами. Это персональные и коммерческие данные.
  • 🚪 Функцию с привилегированным режимом не делайте вызываемой с клиента без проверки роли. Иначе любой пользователь получит журнал целиком.
  • 🌐 HTTP-сервис с журналом публикуйте только с аутентификацией и под отдельным пользователем с минимальными правами.
  • 🗄️ Каталог 1Cv8Log на сервере закройте от общего доступа по сети: файлы читаются и без 1С.

Отдельно стоит фиксировать в журнале сам факт выгрузки — своим событием через ЗаписьЖурналаРегистрации с именем пользователя и периодом. Тогда видно, кто и когда смотрел аудит.

Частые вопросы

Можно ли прочитать журнал регистрации из тонкого клиента?
Напрямую нет: метод недоступен на клиенте. Вызывайте серверную процедуру с директивой &НаСервере или функцию общего серверного модуля.
Как прочитать журнал другой базы или выгруженный файл?
Передайте путь к файлу журнала четвёртым параметром ИмяФайлаЖурнала. Так анализируют архивы после сокращения журнала.
Почему в журнале нет нужных событий за прошлый месяц?
Чаще всего журнал сократили или в настройке выбран уровень «Не регистрировать» либо «Регистрировать ошибки». Проверьте Администрирование → Настройка журнала регистрации в конфигураторе.
Как программно включить запись только ошибок?
Методом УстановитьИспользованиеЖурналаРегистрации() с массивом уровней. Текущее значение возвращает ПолучитьИспользованиеЖурналаРегистрации().
Видно ли в журнале, какую сумму изменил пользователь в документе?
Нет. Журнал фиксирует только факт записи или проведения. Старые и новые значения хранят история данных или версионирование объектов, если их включили заранее.