В процессе администрирования информационных систем 1С часто возникает задача аудита активности пользователей. Например, когда необходимо выявить «реально работающих» сотрудников за последний год при большой текучке кадров. Стандартные интерактивные отчеты журнала регистрации не всегда удобны для этой цели, так как они показывают каждое событие в отдельности, что приводит к огромным спискам с дублями. В этой статье мы подробно разберем, как решить эту задачу программно, используя встроенные механизмы платформы 1С:Предприятие 8.3.
Основным инструментом для решения нашей задачи является метод ВыгрузитьЖурналРегистрации. Этот метод позволяет извлечь записи из системного лога во внешнюю таблицу значений или XML-файл. Рассмотрим наиболее эффективный способ — выгрузку в ТаблицаЗначений. Для начала проанализируем, какие параметры нам понадобятся для формирования корректного запроса к журналу.
При работе с журналом регистрации важно настроить структуру отбора. Если мы просто выгрузим весь журнал за год, система может аварийно завершить работу из-за нехватки оперативной памяти. Поэтому мы должны четко ограничить выборку только событиями аутентификации.
Рассмотрим пошаговый алгоритм создания программного кода:
Структура для хранения фильтров.Посмотрим на пример реализации:
// Подготовим переменные для периода
ДатаНачала = ДобавитьМесяц(ТекущаяДата(), -12); // За последний год
ДатаОкончания = ТекущаяДата();
// Настроим структуру отбора
ОтборЖурнала = Новый Структура;
ОтборЖурнала.Вставить("ДатаНачала", ДатаНачала);
ОтборЖурнала.Вставить("ДатаОкончания", ДатаОкончания);
// Нас интересуют только события входа в систему
МассивСобытий = Новый Массив;
МассивСобытий.Добавить("_$Session$_.Authentication");
ОтборЖурнала.Вставить("Событие", МассивСобытий);
// Создаем таблицу, куда попадут данные
ЖурТаб = Новый ТаблицаЗначений;
// Выполняем выгрузку
ВыгрузитьЖурналРегистрации(ЖурТаб, ОтборЖурнала);
После выполнения метода ВыгрузитьЖурналРегистрации, переменная ЖурТаб будет содержать тысячи строк (по числу каждого входа пользователя). Чтобы получить список уникальных имен, проанализируем ситуацию и воспользуемся методом Свернуть. Этот метод агрегирует данные, удаляя повторяющиеся комбинации значений в указанных колонках.
Для корректной работы нам может потребоваться добавить вспомогательную колонку для подсчета количества входов или просто свернуть таблицу по именам пользователей. Рассмотрим, как это сделать:
// Добавим колонку для счетчика, если хотим знать интенсивность работы
ЖурТаб.Колонки.Добавить("КоличествоСобытий");
ЖурТаб.ЗаполнитьЗначения(1, "КоличествоСобытий");
// Сворачиваем таблицу по колонке "ИмяПользователя"
// Если нужно знать активность по часам, можно оставить колонку даты,
// предварительно приведя ее к нужному формату.
ЖурТаб.Свернуть("ИмяПользователя", "КоличествоСобытий");
// Теперь ЖурТаб содержит только уникальных пользователей
Для Каждого СтрокаПользователь Из ЖурТаб Цикл
Сообщить("Пользователь: " + СтрокаПользователь.ИмяПользователя + " входил " + СтрокаПользователь.КоличествоСобытий + " раз.");
КонецЦикла;
Выясним причину возможных «зависаний» системы при выполнении этого кода. Журнал регистрации за год в крупной базе может занимать несколько гигабайт. При выгрузке в ТаблицаЗначений 1С пытается поместить все эти данные в оперативную память текущего сеанса. Если записей слишком много, мы получим ошибку "Недостаточно памяти".
Чтобы избежать этой проблемы, разберем более безопасный подход — порционное чтение. Мы можем считывать данные не за весь год сразу, а по месяцам или используя параметр КоличествоСобытий.
Пример порционного чтения данных:
// Пример получения только последних 100 000 записей
КоличествоЗаписей = 100000;
ВыгрузитьЖурналРегистрации(ЖурТаб, ОтборЖурнала, , , КоличествоЗаписей);
Если же данных критически много, рекомендуется использовать выгрузку во временный XML-файл. Это позволит обрабатывать данные последовательно через ЧтениеXML, не нагружая память.
При выборе событий для анализа важно понимать разницу между _$Session$_.Authentication и _$Session$_.Start. Рассмотрим подробнее:
Важный нюанс: если в вашей организации пользователи работают через терминальный сервер и часто не закрывают программу на ночь (просто разрывают RDP-соединение), то событие аутентификации может быть зафиксировано один раз в неделю или даже реже. В таком случае список пользователей за «последние 3 дня» может оказаться неполным. Для более точного анализа работающих пользователей стоит включать в отбор оба типа событий.
Проанализируем ситуацию с удаленными пользователями. Журнал регистрации хранит историю вечно (или до момента сокращения журнала), даже если учетная запись пользователя в базе была удалена. Поэтому в итоговой таблице могут появиться люди, которых уже нет в списке ПользователиИнформационнойБазы.
Чтобы получить список только тех, кто существует в базе на текущий момент, выполним сопоставление:
АктуальныеПользователи = ПользователиИнформационнойБазы.ПолучитьПользователей();
МассивАктуальныхИмен = Новый Массив;
Для Каждого ТекПользователь Из АктуальныеПользователи Цикл
МассивАктуальныхИмен.Добавить(ТекПользователь.Имя);
КонецЦикла;
// В цикле по ЖурТаб проверяем наличие
Индекс = ЖурТаб.Количество() - 1;
Пока Индекс >= 0 Цикл
Если МассивАктуальныхИмен.Найти(ЖурТаб[Индекс].ИмяПользователя) = Неопределено Тогда
ЖурТаб.Удалить(Индекс);
КонецЕсли;
Индекс = Индекс - 1;
КонецЦикла;
Поскольку работа с журналом регистрации за длительные периоды — это всегда ресурсоемкая операция, рассмотрим архитектурно правильный способ решения этой задачи на будущее. Вместо того чтобы каждый раз «прочесывать» логи, мы можем фиксировать факт входа пользователя в Регистре сведений.
Создадим непериодический регистр сведений СтатистикаПользователей с измерением Пользователь и ресурсом ДатаПоследнегоВхода. В модуле управляемого приложения в процедуре ПриНачалеРаботыСистемы добавим запись в этот регистр. В этом случае задача «получить список всех, кто входил за год» превращается в простейший и мгновенный запрос к базе данных, который не зависит от размера журнала регистрации и не нагружает сервер.
Мы рассмотрели основной метод программной работы с журналом регистрации через функцию ВыгрузитьЖурналРегистрации. Мы выяснили, что для корректной работы необходимо правильно настроить Структура отбора и уметь обрабатывать данные в ТаблицаЗначений с помощью метода Свернуть. Также мы изучили способы оптимизации памяти и альтернативные подходы к хранению статистики активности пользователей. Помните, что при работе с большими объемами данных в 1С всегда следует отдавать приоритет порционному чтению или специализированным регистрам.