При внедрении сложных доработок в систему 1С часто возникает необходимость отслеживать изменения конкретных полей в нескольких связанных документах. Стандартные механизмы, такие как Журнал регистрации или полное Версионирование объектов, могут быть избыточны, создавать лишнюю нагрузку на базу данных или быть неудобными для оперативного анализа. Рассмотрим ситуацию, когда нам нужно записывать изменения всего десяти реквизитов в трех типах документов, и сделаем это максимально эффективно, избегая блокировок системы.
Это классический и наиболее надежный способ хранения логов внутри самой базы 1С. Разберем, почему автор темы в итоге остановился именно на нем. Основное преимущество заключается в том, что данные структурированы и к ним можно легко построить отчет на СКД.
Для реализации этого метода выполним следующие шаги:
РегистрСведений. Важно установить свойство Режим записи в значение Независимый. Это позволит нам записывать данные без привязки к регистратору и минимизировать транзакционные блокировки.ДатаВремя (тип Дата), Пользователь (СправочникСсылка.Пользователи) и ОбъектМетаданных (ЛюбаяСсылка).Проанализируем пример кода, который можно разместить в модуле объекта документа в процедуре ПриЗаписи или в подписке на событие:
МенеджерЗаписи = РегистрыСведений.ЛогИзмененийДокументов.СоздатьМенеджерЗаписи();
МенеджерЗаписи.Период = ТекущаяДатаСеанса();
МенеджерЗаписи.Пользователь = ПараметрыСеанса.ТекущийПользователь;
МенеджерЗаписи.Объект = ЭтотОбъект.Ссылка;
// Заполняем наши реквизиты
МенеджерЗаписи.Значение1 = ЭтотОбъект.Реквизит1;
МенеджерЗаписи.Значение2 = ЭтотОбъект.Реквизит2;
МенеджерЗаписи.Записать();
Чтобы запись происходила быстрее, можно использовать свойство ОбменДанными.Загрузка = Истина. Это отключит лишние проверки платформы при записи в регистр.
Если мы хотим вынести логи за пределы основной базы данных (чтобы не раздувать её размер), идеальным вариантом будет SQLite. Начиная с версии 8.3.24, в 1С появилась нативная поддержка этой СУБД. Это позволяет хранить логи в обычном файле на диске, сохраняя возможность работы через SQL-запросы.
Рассмотрим, как это работает. Мы создаем объект БазаДанныхSQLite, открываем соединение и выполняем команду CREATE TABLE, если файл еще не создан. Далее, при каждом изменении документа, мы просто выполняем INSERT.
Преимущества такого подхода очевидны: база 1С не растет, блокировки исключены, а скорость записи в локальный файл крайне высока. Для анализа данных можно написать внешнюю обработку, которая будет подключаться к этому .db файлу.
Если создание отдельной базы данных кажется слишком сложным, воспользуемся текстовым логированием, но в формате JSON. Это современная альтернатива XML, которая работает значительно быстрее и потребляет меньше памяти.
Выясним причину, по которой JSON удобен для логирования: метод ЗаписьJSON позволяет записывать данные потоком. Чтобы избежать проблем с одновременным доступом нескольких пользователей к одному файлу, применим следующую стратегию:
ПутьКФайлу = "C:\Logs\DocumentChanges.json";
Запись = Новый ЗаписьJSON;
ПараметрыЗаписи = Новый ПараметрыЗаписиJSON(,,, ЭлементыЭкранированияJSON.СимволыВнеASCII);
Попытка
Запись.ОткрытьФайл(ПутьКФайлу, , , РежимОткрытияФайла.Дополнение);
Запись.ЗаписатьНачалоОбъекта();
Запись.ЗаписатьИмяСвойства("Дата");
Запись.ЗаписатьЗначение(ТекущаяДата());
Запись.ЗаписатьИмяСвойства("Пользователь");
Запись.ЗаписатьЗначение(Строка(ПользователиИнформационнойБазы.ТекущийПользователь()));
// Запись реквизитов...
Запись.ЗаписатьКонецОбъекта();
Запись.Закрыть();
Исключение
// Если файл занят другим пользователем, можно подождать долю секунды или записать в локальный временный файл
КонецПопытки;
Использование РежимОткрытияФайла.Дополнение критически важно — это позволяет дописывать данные в конец файла, не перечитывая его целиком.
Рассмотрим штатный механизм 1С, который часто путают с обычным версионированием. История данных — это более современная и производительная технология. Она позволяет настроить логирование на уровне метаданных очень гибко.
Разберем по шагам, как настроить его только для нужных полей:
Преимущество этого метода в том, что 1С сама оптимизирует хранение этих данных в СУБД. Проанализируем ситуацию с точки зрения программиста: вам не нужно писать ни одной строчки кода для записи. Для чтения же можно использовать встроенные стандартные отчеты или программный интерфейс ИсторияДанных.
Если вы не хотите менять структуру конфигурации (добавлять регистры) и не хотите работать с внешними файлами, можно использовать стандартный метод ЗаписьЖурналаРегистрации. Вопреки расхожему мнению, он позволяет записывать не только системные события, но и любые ваши данные.
Посмотрим на пример формирования записи:
СтруктураЛога = Новый Структура;
СтруктураЛога.Вставить("Сумма", ЭтотОбъект.СуммаДокумента);
СтруктураЛога.Вставить("Контрагент", ЭтотОбъект.Контрагент);
// Упаковываем структуру в строку для хранения
ДанныеДляЗаписи = ЗначениеВСтрокуВнутр(СтруктураЛога);
ЗаписьЖурналаРегистрации("Доработка.ИзменениеРеквизитов",
УровеньЖурналаРегистрации.Информация,
ЭтотОбъект.Метаданные(),
ЭтотОбъект.Ссылка,
ДанныеДляЗаписи);
При таком подходе вы сможете легко отфильтровать журнал по событию "Доработка.ИзменениеРеквизитов" и программно извлечь данные из колонки "Данные" с помощью ЗначениеИзСтрокиВнутр. Это самый "чистый" способ с точки зрения невмешательства в архитектуру БД.
Чтобы не прописывать код логирования в каждом документе, правильно будет использовать объект ПодпискаНаСобытие.
Создадим одну подписку для всех интересующих нас документов на событие ПриЗаписи. В качестве источника укажем общие типы (например, ДокументОбъект). Таким образом, весь код по сохранению логов (в регистр, файл или SQLite) будет сосредоточен в одном общем модуле, что значительно упрощает поддержку системы.
Резюме: выбор метода зависит от ваших приоритетов. Если важна простота анализа внутри 1С — выбирайте независимый регистр сведений. Если критична производительность и объем базы — используйте SQLite или JSON. Если же нужно решение "из коробки" с минимальными трудозатратами — настраивайте Историю данных только для выбранных реквизитов.