gifts2017

Регистрация запуска обработок во внешнем источнике данных

Опубликовал Валерий Сухих (vsuh) в раздел Администрирование - Сервисные утилиты

На нашем предприятии эксплуатируется три информационные базы, в которые по просьбам трудящихся постоянно создаются и добавляются новые внешние отчеты и обработки. Некоторые из них устаревают сразу же после их первого использования, другие чуть позже, какие-то используются постоянно.
Давно хотел получить инструмент, позволяющий отслеживать статистику использования внешних отчетов и обработок.

Итак, регистрацию решено производить в таблице базы mysql. Таблица должна хранить время запуска, имя пользователя, название обработки, режим регистрации и имя информационной базы.

CREATE TABLE IF NOT EXISTS `OuterProgsUsage` (
  `idRec` int(11) NOT NULL AUTO_INCREMENT,
  `MDname` varchar(90) NOT NULL COMMENT 'Имя отчета/обработки',
  `date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP,
  `variant` varchar(30) NOT NULL,
  `userCode` varchar(50) NOT NULL,
  `userName` varchar(90) NOT NULL,
  `comment` varchar(12000) NOT NULL,
  `action` enum('open','form') NOT NULL,
  `ibName` varchar(20) NOT NULL,
  `version` varchar(32) NOT NULL,
  `prgType` varchar(15) NOT NULL COMMENT '"Обработка" | "Отчет"',
  PRIMARY KEY (`idRec`),  KEY `MDname` (`MDname`),
  KEY `userCode` (`userCode`),
  KEY `MDvariant` (`MDname`,`variant`),
  KEY `ibName` (`ibName`)
) ENGINE=InnoDB  DEFAULT CHARSET=utf8 AUTO_INCREMENT=1;

Далее, в дереве конфигурации добавим внешний источник данных с описанием созданной таблицы

 

 

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

Функция ЗафиксироватьЗапускВнешнейОбработки(
	НазваниеОбработки // ОбъектОбработки.Метаданные().Родитель().Имя
	, ТипФайла = "Обработка"
	, Вариант = ""
	, Комментарий = ""
	, Действие = "open" // "open"|"form"
	) Экспорт
	
	ПараметрыСоединения = Новый ПараметрыСоединенияВнешнегоИсточникаДанных;
	ПараметрыСоединения.СтрокаСоединения = "Driver={MySQL ODBC 5.3 Unicode Driver}
|;Server=192.168.xx.xxx
|;Database=base
|;username=us8
|;password=mysqlpwd
|;option=3;";
	ПараметрыСоединения.АутентификацияСтандартная	= Истина;
	ПараметрыСоединения.ИмяПользователя		= "us8";
	ПараметрыСоединения.Пароль			= "mysqlpwd";
	Вид = ВнешниеИсточникиДанных.ахПротоколИспользованияВнешнихОбработок;
	Вид.УстановитьОбщиеПараметрыСоединения(ПараметрыСоединения);
	ом = Вид.Таблицы.OuterProgsUsage.СоздатьОбъект();
	ом.MDname 		= НазваниеОбработки;
	ом.prgType		= ТипФайла;
	ом.action 		= Действие;
	ом.comment 		= Комментарий;
	ом.date 		= ТекущаяДата();
	ом.userCode 	= ПараметрыСеанса.ТекущийПользователь.Код;
	ом.userName 	= ПараметрыСеанса.ТекущийПользователь.Наименование;
	ом.variant 		= Вариант;
	ом.ibName 		= ВРег(НСтр(СтрокаСоединенияИнформационнойБазы(), "Ref"));
	Попытка
	ом.Записать();	
	Исключение
	КонецПопытки;
КонецФункции

Из тестовой обработки или Консоли кода(ИР) вызовем функцию:

тестовый вызов функции

 

 и убедимся, что в таблице OuterProgsUsage появилась соответствующая запись:

запись о регистрации

 Механизм работает, теперь нужно в каждую обработку из справочника ВнешниеОбработки добавить строку вызова функции ЗафиксироватьЗапускВнешнейОбработки. Можно, конечно, сохранять файлы по одному на диске и редактировать их в соответствующем (понятно почему?) конфигураторе, но так неинтересно. Я пошел своим путем. Сначала был написан скрипт на языке 1Script от уважаемого Evil Beaver. Скрипт умеет выгружать файлы внешних обработок из справочника ВнешниеОбработки и загружать измененные файлы обратно в справочник.

ExtRepsLoad.os

Из-за размера скрипта добавлю его в файлы.

Для регистрации факта открытия/запуска обработки, вызов функции ЗафиксироватьЗапускВнешнейОбработки решил добавить в конец каждого модуля объекта отчета/обработки.

///////// РЕГИСТРАЦИЯ ЗАПУСКА ///////////// #$#20151019#$# - ключ для исключения повторного добавления фрагмента
Попытка
	ФайлОбработки = Новый Файл(ИспользуемоеИмяФайла);
	ИспользуемоеИмя = ?(Найти(ВРег(ИспользуемоеИмяФайла), ".TMP")>0, ИспользуемоеИмя, ФайлОбработки.Имя);
	ВидФайла = ?(Найти(ВРег(ИспользуемоеИмя), ".ERF")>0 ,"Отчет", "Обработка");
	Комментарий = "";
	ИспользуемоеИмя = Лев(ИспользуемоеИмя,  Найти(ИспользуемоеИмя, ".")-1);
	тИмяОбр = Метаданные().Имя;
	тСиноним = Метаданные().Синоним;
	Если Лев(ВРег(тИмяОбр),5) = "ВНЕШН" Тогда
		Комментарий = "Имя обработки: "+тИмяОбр+""+?(ПустаяСтрока(тСиноним),", Пустой синоним", ", Синоним: """+тСиноним+"""");
		ИмяОбработки = ИспользуемоеИмя;
	Иначе
		ИмяОбработки = тИмяОбр;
	КонецЕсли;
	ВнешниеИсточникиДанных.ахПротоколИспользованияВнешнихОбработок.Таблицы.OuterProgsUsage.ЗафиксироватьЗапускВнешнейОбработки(ИмяОбработки, ВидФайла,,Комментарий);
Исключение
	ЗаписьЖурналаРегистрации("Ошибка регистрации исполнения внешней обработки", УровеньЖурналаРегистрации.Предупреждение, ,ЭтотОбъект.Метаданные().ПолноеИмя(), ОписаниеОшибки()); 
КонецПопытки;
//////////////////////////////////////////

Опять же, вручную можно таким образом обработать 20-50 файлов, у меня их оказалось около 500. Поэтому, процесс добавления, хоть и однократный, тоже захотелось автоматизировать, а чтобы труд даром не пропал, результатом поделиться с сообществом.

Для того, чтобы добраться до модуля объекта обработки, ее нужно распаковать программой v8Unpack, правда, бинарников по ссылке не найти, но их можно вынуть из макетов мощного инструмента v8Reader.

В тестовом каталоге e:\ooo были созданы каталоги

  • reps - для извлеченных из справочника ВнешниеОбработки файлов
  • in - для тех-же файлов, приготовленных для распаковки
  • out - для каталогов распакованных v8Unpack обработок
  • ok - для собранных файлов обработок, готовых к загрузке в справочник
  • v8 - для файлов v8unpack.exe и zlib1.dll 

Распаковка проводилась скриптом 01_РаспаковкаФайловОбработок.cmd 

@echo off
md in out ok >nul 2>&1
cls&del log.*

echo %date% %time% ^*^*^* распаковка файлов отчетов
for %%I in (in\*) do ( 
		echo %%~nI >>log.log 
		v8\v8unpack.exe -parse "%%I" "out\%%~nxI" >>log.log 
	)

Из каждого файла обработки создался каталог с распакованными внутренностями в каталоге out.

Модуль объекта ищется очень просто:

1. в каталоге обработки открывается файл root, в нем записано имя файла со свойствами обработки (в виде GUID)

root

2. в полученном файле свойств, нужно найти выражение, состоящее из GUID-а и имени объекта (обработки)

где живет нофелет

3. в каталоге, соответствующем прочитанному GUIDу с расширением .0 должен лежать файл text с текстом модуля объекта, куда мы и будем добавлять наш код для регистрации запуска обработки.

Но сначала, нужно выявить объекты (каталоги), у которых нет модуля объекта, соответственно, и каталога, и файла text. Делаем это вторым скриптом 02_ВыявлениеОбъектовБезМодуляОбъекта.cmd:

@echo off
@SETLOCAL enabledelayedexpansion

del log.absent 2>nul
echo %date% %time% ^*^*^* выявление отчетов с пустым модулем объекта
@for /D %%I in ("out\*") do (
	dir /b /s "%%I"|find "text">nul
	if NOT !ERRORLEVEL! EQU 0 (
		 @echo @md	"%%I\">>log.absent
		 @echo @touch	"%%I\\text">>log.absent
	)
)
ENDLOCAL
if exist log.absent type log.absent

Скрипт создает заготовку скрипта для создания необходимых пустых файлов text в каталогах, которые нужно выявить и прописать вручную.

Результат работы скрипта (log.absent):

@md	"out\000000230#Список наград.erf\"
@touch	"out\000000230#Список наград.erf\\text"

Результат ручной подстановки (make_text.cmd):

@md	"out\000000230#Список наград.erf\19f3a161-1fd9-415b-a43a-e6313eb8df83.0"
@touch	"out\000000230#Список наград.erf\19f3a161-1fd9-415b-a43a-e6313eb8df83.0\text"

 

После выявления и создания недостающих файлов text, выполняется скрипт 03_ДобавлениеТекстаВМодульОбъекта.cmd, добавляющий в конец текста модуля объекта необходимый нам текст.

@echo off
@SETLOCAL enabledelayedexpansion
@Set tt=%temp%\ttEXT.txt.$$$.killme
rem.>%tt% & rem.>%tt%$$$

if exist make_text.cmd call make_text.cmd
echo %date% %time% ^*^*^* добавление текста к модулю объекта...
for /R out %%K in (text) do (
	find "#$#%date:~6,4%%date:~3,2%%date:~0,2%#$#" %%H >nul
	if NOT !ERRORLEVEL! EQU 0 (
		if exist %%~fK  echo %%K>>%tt% 
	) 
) 

type %tt%|sed "s/E\:\\ooo\\out\\.*\#//;s/\\[-0-9a-z]*\.0\\text//">%tt%$$$ 
oscript add2module.os %tt% %tt%$$$ addition.txt

В подкаталогах out ищется файл text, если текст этого файла не содержит ключ для исключения повторного добавления фрагмента, который выглядит как текущая дата в формате YYYYMMDD, то путь добавляется в файл %tt%, затем, из этого файла извлекаются имена обработок и записываются во второй файл. 

Для добавления текста в модуль объекта пришлось написать еще один скрипт на 1Script. Дело в том, что прикладное решение при запуске обработки из справочника ВнешниеОбработки восстанавливает файл обработки из реквизита ХранилищеВнешнейОбработки элемента справочника в файл во временном каталоге клиента с именем, совпадающим с уникальным идентификатором ссылки элемента справочника и расширением .tmp, нам такие данные для регистрации не нужны, поэтому скрипт add2module дописывает строку типа ИспользуемоеИмя = "Список наград.erf"; перед добавляемым, для регистрации программным текстом.

Скрипт add2module.os выглядит так:

Если АргументыКоманднойСтроки.Количество() <> 3 Тогда
	ВызватьИсключение "требуется три параметра: список файлов, список имен обработок, файл с добавкой к модулю";
КонецЕсли;
спФайлыМодулейОбъектов 	= АргументыКоманднойСтроки[0];
спИменОбработок 		= АргументыКоманднойСтроки[1];
ФайлСТекстомДобавки 	= АргументыКоманднойСтроки[2];

СписокМодулей = Новый ЧтениеТекста(спФайлыМодулейОбъектов, КодировкаТекста.OEM);
СписокИменОбр = Новый ЧтениеТекста(спИменОбработок, КодировкаТекста.OEM);
ФайлДобавки =  Новый ЧтениеТекста(ФайлСТекстомДобавки, КодировкаТекста.UTF8);
ТекстДобавки = ФайлДобавки.Прочитать();


ПутьДоМодуля = СписокМодулей.ПрочитатьСтроку();
ИмяОбработки = СписокИменОбр.ПрочитатьСтроку();

Пока ПутьДоМодуля <> Неопределено Цикл
	//Сообщить(""+ИмяОбработки+" ### "+ПутьДоМодуля);
	СтарыйТекст = Новый ЧтениеТекста(ПутьДоМодуля, КодировкаТекста.UTF8);
	Стр = СтарыйТекст.Прочитать();
	СтарыйТекст.Закрыть();
	текстМодуля = Новый ЗаписьТекста(ПутьДоМодуля, КодировкаТекста.UTF8);
	
	текстМодуля.ЗаписатьСтроку(Стр);
	текстМодуля.ЗаписатьСтроку("");
	текстМодуля.ЗаписатьСтроку("ИспользуемоеИмя = """+ИмяОбработки+""";");
	текстМодуля.ЗаписатьСтроку(ТекстДобавки);
	текстМодуля.Закрыть();


	ПутьДоМодуля = СписокМодулей.ПрочитатьСтроку();
	ИмяОбработки = СписокИменОбр.ПрочитатьСтроку();
	
КонецЦикла;

Полученные каталоги распакованных обработок с измененными текстами модулей объектов, собираются опять программой v8Upack.exe, но уже в каталог ok 04_СборкаИзмененныхОбработокВФайлы.cmd

@echo off
@SETLOCAL enabledelayedexpansion

echo %date% %time% ^*^*^* сборка файлов отчетов
for /D %%I in (out\*) do (
	echo %%~nI >>log.log 
	v8\v8unpack.exe -build "%%I" "ok\%%~nxI" >>log.log
	if NOT !ERRORLEVEL! EQU 0 echo ERROR: $$$$$$$$$$$ %%I >>log.log
	)

ENDLOCAL

Затем, скриптом, ExtRepsLoad.os загружаются в справочник ВнешниеОбработки.

Update:

Для добавления вызова регистрирующей функции в модули объектов, встроенных в конфигурацию написал еще два скрипта:

Для выгрузки файлов с текстами модулей 1_unload.bat:

 

@echo off

Set cf=%~n1%
Set lg=log.log
if _%cf%_==__ echo parameter missing && @exit
md out 2>nul
del /q out\*>nul

del %lg%>nul
Set fl=file.lst
Set c1exe=C:\Progra~2\1cv8\common\1cestart.exe

Set stdcm=DESIGNER /s c1Server\%cf% /n adm /p pwd /Out %lg% /Visible
Set addst=/DumpConfigFiles out -Module

%c1exe% %stdcm% %addst%

Модули, традиционно складываются в каталог out.

Для изменения текстов модулей и загрузки их обратно в информационную базу 2_load.bat:

@echo off
@SETLOCAL enabledelayedexpansion

if _%1_==__ echo parametes missing && @exit
Set cf=%~n1%
Set lg=%cf%_log.log
Set fl=file.lst
Set c1exe=C:\Progra~2\1cv8\common\1cestart.exe
Set stdcm=DESIGNER /Visible /s c1Server\%cf% /n adm /p pwr /Out %lg%
Set instd=/LoadConfigFiles out -Module /UpdateDBCfg -Server


rem.>%lg% && rem.>%fl%
@exit

for %%I in (out\отчет.*модульобъ*.*) do @echo %%I >>%fl%
for %%I in (out\обработка.*модульобъ*.*) do @echo %%I >>%fl%
echo Обработка файлов модулей отчетов и обработок
for /f %%H in (%fl%) do (
	find "#$#%date:~6,4%%date:~3,2%%date:~0,2%#$#" %%H >nul
	if NOT !ERRORLEVEL! EQU 0 (
		echo ^>^> %%H 
		type addition.txt >> %%H
	)
)

echo Начинать загрузку файлов модулей в ИБ %cf%? && timeout -1
%c1exe% %stdcm% %instd%

Сначала имена файлов модулей объектов обработок и отчетов записываются в файл, затем, если текст файла не содержит ключ для исключения задвоения, в него добавляется содержимое файла addition.txt

Спасибо.

При создании статьи были использованы материалы:

Скачать файлы

Наименование Файл Версия Размер Кол. Скачив.
1Script загрузка-выгрузка файлов из справочника ВнешниеОбработки
.os 10,94Kb
23.10.15
4
.os 1.2.2 10,94Kb 4 Скачать

См. также

Подписаться Добавить вознаграждение

Комментарии

1. Андрей Овсянкин (Evil Beaver) 28.10.15 14:51
Отличная идея, сама по себе - автоматизировать доработку модулей внешних обработок. Плюсую, однозначно!

Но по реализации, имхо, не лучшая идея мешать "одинэсникочитаемый" код 1Script вместе с кодом BAT-скриптов. Ну а "контрольный в голову" в виде sed - это совсем негуманная жестокость )))

Кроме того, если воспользоваться наработками проекта precommit1c, то можно на выходе получить уже человекочитаемые имена файлов метаданных, а не внутренние 1С-овские.
Для написания сообщения необходимо авторизоваться
Прикрепить файл
Дополнительные параметры ответа