//ирПортативный Перем ирПортативный Экспорт; //ирПортативный Перем ирОбщий Экспорт; //ирПортативный Перем ирСервер Экспорт; //ирПортативный Перем ирКэш Экспорт; //ирПортативный Перем ирКлиент Экспорт; Перем мТаблицаКолонок Экспорт; Перем мСписокКолонок Экспорт; //Перем КлючиЗагруженныхСтрок; Перем мСвойстваСИменамиБД Экспорт; Перем RegExpПараметры; Перем RegExpМета; Перем шБуква; Перем шГраничныйСимволИмени; //Перем МинимальнаяДатаЗагрузки Экспорт; //Перем мЧисловыеСвойства; Перем мИменаВозвращаемыхСвойств Экспорт; Перем мТипСУБД Экспорт; Перем мПлатформа Экспорт; Перем мКартыФайлов Экспорт; Перем мНепустыеКолонкиЖурнала Экспорт; Перем мСерверныеТипыПроцессов Экспорт; //Перем мСоставСвойствСобытий Экспорт; Перем мСвойстваСобытий Экспорт; Перем мАдресЧужойСхемыБД Экспорт; Перем КонецПериодаКлиента Экспорт; Перем НачалоПериодаКлиента Экспорт; Перем КонецПериодаСервера Экспорт; Перем НачалоПериодаСервера Экспорт; Перем мИдентификаторТрассы Экспорт; Перем мЛиТрассаПоПользователю Экспорт; Перем мТрассаСУБДXML; Перем мСоответствиеКолонок; Перем мСоединениеАДО; Перем мИдентификаторБазыДанных; Перем мУдержательСоединенияБД; Перем мИдентификаторСоединенияБД; Перем мЛиСерверMSSQLПоддерживаетТрассировку; Перем мТаблицаЖурнала; Перем мСтруктураХраненияСРазмерами; // СдвигВремени - Число - в секундах задается, нужно для компенсации разницы времени между компьютерами // ОтборПоПроцессу частично игнорируются когда ЗагружатьТолькоТекущийСеанс = Истина Функция ПрочитатьПроизвольныйЖурнал(СообщитьРазмер = Неопределено, СдвигВремени = 0, ОтборПоПроцессу = Неопределено, ОтборПоСеансу = Неопределено, НаСервере = Неопределено) #Если Сервер И Не Сервер Тогда мПлатформа = Обработки.ирПлатформа.Создать(); #КонецЕсли НеизвестныеСвойства = Новый Соответствие(); Если Ложь Или (НаСервере <> Неопределено И Не мЛиТрассаПоПользователю) Или Не ЗначениеЗаполнено(КаталогЖурнала) Тогда КаталогЖурнала = ПолучитьКаталогТекущегоЖурнала(НаСервере = Истина); Если Не ЗначениеЗаполнено(КаталогЖурнала) Тогда Возврат Ложь; КонецЕсли; КонецЕсли; Если Не ирОбщий.ЛиКаталогДоступенЛкс(КаталогЖурнала) Тогда Возврат Ложь; КонецЕсли; Если НаСервере <> Истина Тогда ОтборПоСеансу = Неопределено; КонецЕсли; Если мЛиТрассаПоПользователю Тогда ОтборПоПользователю = ИмяПользователя(); КонецЕсли; Если ЗагружатьТолькоТекущийСеанс Тогда Если Ложь Или ирКэш.ЛиФайловаяБазаЛкс() Или НаСервере <> Истина Тогда ОтборПоПроцессу = ирКэш.ИдентификаторПроцессаОСЛкс(); КонецЕсли; Если ОтборПоСеансу = Неопределено Тогда ОтборПоПользователю = ИмяПользователя(); КонецЕсли; КонецЕсли; лПоследнееВремяНачалаЗагрузки = ТекущаяДата(); Если ПериодПоследниеМинуты > 0 Тогда НачалоПериода = лПоследнееВремяНачалаЗагрузки - 60 * ПериодПоследниеМинуты; КонецПериода = Неопределено; КонецЕсли; //Если ТаблицаЖурнала.Количество() = 0 Тогда // МинимальнаяДатаЗагрузки = ТекущаяДата() + 100000; //КонецЕсли; //Если МинимальнаяДатаЗагрузки > НачалоПериода Тогда // ТаблицаЖурнала.Очистить(); //КонецЕсли; //РежимДозагрузки = Истина // И ТаблицаЖурнала.Количество() > 0 // И МинимальнаяДатаЗагрузки <= НачалоПериода; Если СообщитьРазмер = Неопределено Тогда СообщитьРазмер = (мКартыФайлов.Количество() = 0) Или КомментироватьЗагрузку; КонецЕсли; ирОбщий.ЛиКаталогТехножурналаНедоступенЛкс(КаталогЖурнала); ФайлыЖурнала = НайтиФайлы(КаталогЖурнала, "*.log", Истина); ОбщийРазмер = 0; Для Каждого ФайлЖурнала Из ФайлыЖурнала Цикл ОбщийРазмер = ОбщийРазмер + ФайлЖурнала.Размер(); КонецЦикла; Если СообщитьРазмер Тогда ирОбщий.СообщитьЛкс("В каталоге """ + КаталогЖурнала + """ обнаружено для обработки " + Формат(Цел(ОбщийРазмер / 1024), "ЧН=") + "КБ логов"); ПредставлениеОтбора = ""; Если СписокЗагружаемыхТиповСобытий.Количество() > 0 Тогда ПредставлениеОтбора = ПредставлениеОтбора + " события " + СписокЗагружаемыхТиповСобытий; КонецЕсли; ПредставлениеПериода = ирОбщий.ПредставлениеПериодаЛкс(НачалоПериода, КонецПериода); Если ЗначениеЗаполнено(ПредставлениеПериода) Тогда ПредставлениеОтбора = ПредставлениеОтбора + " " + ПредставлениеПериода; КонецЕсли; Если ЗначениеЗаполнено("" + ФильтрЗагрузки) Тогда Если ЗначениеЗаполнено(ПредставлениеОтбора) Тогда ПредставлениеОтбора = ПредставлениеОтбора + " И"; КонецЕсли; ПредставлениеОтбора = ПредставлениеОтбора + " " + ФильтрЗагрузки; КонецЕсли; Если ЗначениеЗаполнено(ОтборПоПроцессу) Тогда Если ЗначениеЗаполнено(ПредставлениеОтбора) Тогда ПредставлениеОтбора = ПредставлениеОтбора + " И"; КонецЕсли; ПредставлениеОтбора = ПредставлениеОтбора + " Процесс=" + XMLСтрока(ОтборПоПроцессу); КонецЕсли; Если ЗначениеЗаполнено(ОтборПоСеансу) Тогда Если ЗначениеЗаполнено(ПредставлениеОтбора) Тогда ПредставлениеОтбора = ПредставлениеОтбора + " И"; КонецЕсли; ПредставлениеОтбора = ПредставлениеОтбора + " Сеанс=" + XMLСтрока(ОтборПоСеансу); КонецЕсли; Если ЗначениеЗаполнено(ОтборПоПользователю) Тогда Если ЗначениеЗаполнено(ПредставлениеОтбора) Тогда ПредставлениеОтбора = ПредставлениеОтбора + " И"; КонецЕсли; ПредставлениеОтбора = ПредставлениеОтбора + " Пользователь=""" + ОтборПоПользователю + """"; КонецЕсли; Если ЗначениеЗаполнено(ПредставлениеОтбора) Тогда ирОбщий.СообщитьЛкс("Отбор загрузки:" + ПредставлениеОтбора); КонецЕсли; // Проверяем только на клиенте для снижения вероятности ошибки "Не найден файл внешней компоненты" https://www.hostedredmine.com/issues/937706 #Если Клиент Тогда Если мПлатформа.ИдентификаторыПроцессовОтладчиков().Количество() > 0 Тогда ирОбщий.СообщитьЛкс("Возможно подключен отладчик и тогда он замедляет загрузку логов. Отключите отладчик для ускорения загрузки."); КонецЕсли; #КонецЕсли КонецЕсли; //лНачалоПериода = НачалоПериода; //Если Не РежимДозагрузки Тогда // //ТаблицаЖурнала.Очистить(); // КлючиЗагруженныхСтрок = Новый Соответствие; //Иначе // Если НаСервере = Истина Тогда // лДатаЗагрузки = ПоследнееВремяНачалаЗагрузкиСервера; // Иначе // лДатаЗагрузки = ПоследнееВремяНачалаЗагрузки; // КонецЕсли; // Если ЗначениеЗаполнено(лДатаЗагрузки) Тогда // лНачалоПериода = лДатаЗагрузки - НаложениеПриДозагрузкеСекунд; // КонецЕсли; //КонецЕсли; Если УдалятьДанныеВнеПериода Тогда ТаблицаЖурнала.Сортировать("МоментВремени"); КоличествоСтрок = ТаблицаЖурнала.Количество(); Пока Истина И КоличествоСтрок > 0 И ТаблицаЖурнала[0].Дата < НачалоПериода Цикл ТаблицаЖурнала.Удалить(0); КоличествоСтрок = КоличествоСтрок - 1; КонецЦикла; Если ЗначениеЗаполнено(КонецПериода) Тогда ИндексСтроки = КоличествоСтрок - 1; Пока Истина И КоличествоСтрок > 0 И ТаблицаЖурнала[ИндексСтроки].Дата > КонецПериода Цикл ТаблицаЖурнала.Удалить(ИндексСтроки); ИндексСтроки = ИндексСтроки - 1; КонецЦикла; КонецЕсли; КонецЕсли; #Если Сервер И Не Сервер Тогда ЗагрузитьРезультатЧтенияФайлаВПотоке(); ПрочитатьФайлЖурнала(); #КонецЕсли СтруктураПотоков = ирОбщий.НоваяСтруктураМногопоточнойОбработкиЛкс("ПрочитатьФайлЖурнала", ЭтотОбъект, "ЗагрузитьРезультатЧтенияФайлаВПотоке", 1, КоличествоПотоков); Если СтруктураПотоков.ФактическоеКоличествоПотоков > 1 Тогда ЗаголовокИндикации = "Выполняем загрузку в " + СтруктураПотоков.ФактическоеКоличествоПотоков + " потоков"; КонецЕсли; Индикатор = ирОбщий.ПолучитьИндикаторПроцессаЛкс(ОбщийРазмер, "Загрузка журнала"); РазмерОбработанныхДанных = 0; Для Каждого ФайлЖурнала Из ФайлыЖурнала Цикл #Если Сервер И Не Сервер Тогда ФайлЖурнала = Новый Файл; #КонецЕсли Попытка РазмерФайла = ФайлЖурнала.Размер(); Исключение ирОбщий.СообщитьЛкс("Пропускаем недоступный файл " + ФайлЖурнала.ПолноеИмя, СтатусСообщения.Внимание); Продолжить; КонецПопытки; РазмерОбработанныхДанных = РазмерОбработанныхДанных + РазмерФайла; Если ирОбщий.ОбработатьИндикаторЛкс(Индикатор, РазмерОбработанныхДанных) Тогда Если ирОбщий.ЛиПрерватьФоновоеЗаданиеЛкс(Индикатор) Тогда Прервать; КонецЕсли; КонецЕсли; ПолноеИмяКаталогаПроцесса = Лев(ФайлЖурнала.Путь, СтрДлина(ФайлЖурнала.Путь) - 1); Длина1 = СтрДлина(ПолноеИмяКаталогаПроцесса); СтрокаЧасаЗаписи = "20" + Сред(ФайлЖурнала.ПолноеИмя, Длина1 + 2, 8); ДатаЧасЗаписи = Дата(СтрокаЧасаЗаписи + "0000"); ИдентификаторПроцессаСтрока = ирОбщий.СтрокаБезКонцаЛкс(ирОбщий.ПоследнийФрагментЛкс(ФайлЖурнала.Путь, "_"), 1); Попытка ИдентификаторПроцесса = Число(ИдентификаторПроцессаСтрока); Исключение Если КомментироватьЗагрузку Тогда ирОбщий.СообщитьЛкс("Пропускаем файл " + ФайлЖурнала.ПолноеИмя + " из каталога с некорректным именем", СтатусСообщения.Внимание); КонецЕсли; Продолжить; КонецПопытки; //ЛиДатаВИнтервале = ирОбщий.ЛиДатаВИнтервалеСГраницамиЛкс(ДатаЧасЗаписи, НачалоЧаса(лНачалоПериода), НачалоЧаса(КонецПериода)); ЛиДатаВИнтервале = ирОбщий.ЛиДатаВИнтервалеСГраницамиЛкс(ДатаЧасЗаписи, НачалоЧаса(НачалоПериода), НачалоЧаса(КонецПериода)); Если Ложь Или Не ЛиДатаВИнтервале Или (Истина И ОтборПоПроцессу <> Неопределено И ИдентификаторПроцесса <> ОтборПоПроцессу) Тогда Продолжить; КонецЕсли; Попытка ЧтениеТекста = Новый ЧтениеТекста(ФайлЖурнала.ПолноеИмя, КодировкаТекста.UTF8, ,,Ложь); //ТекстовыйДокумент.Прочитать(ФайлЖурнала.ПолноеИмя, КодировкаТекста.UTF8); Исключение ирОбщий.СообщитьЛкс("Не удалось прочитать открыть для чтения файл " + ФайлЖурнала.ПолноеИмя, СтатусСообщения.Внимание); Продолжить; КонецПопытки; СигнатураФайла = ЧтениеТекста.Прочитать(20); // Для идентификации файла Если ПустаяСтрока(СигнатураФайла) Тогда Продолжить; КонецЕсли; ЧтениеТекста.Закрыть(); ПараметрыОбработкиФайла = Новый Структура; ПараметрыОбработкиФайла.Вставить("ОтборПоПроцессу", ОтборПоПроцессу); ПараметрыОбработкиФайла.Вставить("ОтборПоСеансу", ОтборПоСеансу); ПараметрыОбработкиФайла.Вставить("ОтборПоПользователю", ОтборПоПользователю); ПараметрыОбработкиФайла.Вставить("СдвигВремени", СдвигВремени); ПараметрыОбработкиФайла.Вставить("ФильтрЗагрузки", ФильтрЗагрузки); ПараметрыОбработкиФайла.Вставить("НомерСеанса", НомерСеансаИнформационнойБазы()); ПараметрыОбработкиФайла.Вставить("мКартыФайлов", мКартыФайлов); ПараметрыОбработкиФайла.Вставить("КоличествоЗагруженныхСобытий", мТаблицаЖурнала.Количество()); ПараметрыОбработкиФайла.Вставить("ФайлЖурнала", ФайлЖурнала.ПолноеИмя); ЛокальныеПараметры = Новый Структура; ЛокальныеПараметры.Вставить("Индикатор", Индикатор); ЛокальныеПараметры.Вставить("РазмерОбработанныхДанных", РазмерОбработанныхДанных); ирОбщий.ДобавитьОбъектВОчередьМногопоточнойОбработкиЛкс(СтруктураПотоков, ПараметрыОбработкиФайла, ЛокальныеПараметры, РазмерФайла < 100000); Если ТаблицаЖурнала.Количество() > МаксТысячСобытий * 1000 Тогда ирОбщий.СообщитьЛкс("Загрузка прервана по достижению предела числа загружаемых событий (""Не более тыс."")"); Прервать; КонецЕсли; КонецЦикла; ирОбщий.ОжидатьЗавершенияВсехПотоковОбработкиЛкс(СтруктураПотоков); ирОбщий.ОсвободитьИндикаторПроцессаЛкс(); УдалитьСтрокиВнеФильтра(); //КлючиЗагруженныхСтрок = НовыеКлючиЗагруженныхСтрок; //Если НаСервере = Истина Тогда // ЭтотОбъект.ПоследнееВремяНачалаЗагрузкиСервера = лПоследнееВремяНачалаЗагрузки; //Иначе // ЭтотОбъект.ПоследнееВремяНачалаЗагрузки = лПоследнееВремяНачалаЗагрузки; //КонецЕсли; //МинимальнаяДатаЗагрузки = Мин(НачалоПериода, МинимальнаяДатаЗагрузки); ТаблицаЖурнала.Сортировать("МоментВремени"); //ТаблицаЖурнала.Сортировать("МоментВремениНачала"); ОпределитьНепустыеКолонки(); Возврат Истина; КонецФункции // Параметры: // ОтборПоПроцессу - ? - // ОтборПоСеансу - Число - // РазмерФайла - Примитивный - // СдвигВремени - ? - // ФайлЖурнала - Файл - // ФильтрЗагрузки - ? - // ТипВыхода - Строка - Служебный параметр для перехода после вызова метода Функция ПрочитатьФайлЖурнала(Параметры) Экспорт мКартыФайлов = Параметры.мКартыФайлов; ОтборПоПроцессу = Параметры.ОтборПоПроцессу; ОтборПоСеансу = Параметры.ОтборПоСеансу; ОтборПоПользователю = Параметры.ОтборПоПользователю; СдвигВремени = Параметры.СдвигВремени; ФайлЖурнала = Параметры.ФайлЖурнала; ФильтрЗагрузки = Параметры.ФильтрЗагрузки; КоличествоЗагруженныхСобытий = Параметры.КоличествоЗагруженныхСобытий; ВозвращатьРезультат = Параметры.НомерСеанса <> НомерСеансаИнформационнойБазы(); ДостигнутоПредельноеКоличество = Ложь; ДобавитьОбязательныеНепустыеКолонки(); ФайлЖурнала = Новый Файл(ФайлЖурнала); РазмерФайла = ФайлЖурнала.Размер(); РегВыражение1 = мПлатформа.RegExp; РегВыражение2 = мПлатформа.RegExp2; #Если Сервер И Не Сервер Тогда РегВыражение1 = Обработки.ирОболочкаРегВыражение.Создать(); РегВыражение2 = РегВыражение1; мПлатформа = Обработки.ирПлатформа.Создать(); мТаблицаЖурнала = ТаблицаЖурнала; #КонецЕсли шСимвол = "[" + шБуква + "\d\._#{}-]"; //ШаблонСвойствоЗначение = "([\w\:]+)=(?:'\s*((?:.|\n|\r)*?)'|""\s*([^""]*)""|([^'""\n\r,]*))(?:,|\r|$)"; // Так были очень большие трассы вычисления RegExp ШаблонСвойствоЗначение = "([\w\:]+)=(?:'\s*([\s\S]*?)'|""\s*((?:""""|[^""])*)""|([^'""\n\r,]*))(?:,|\r|\n|$)+"; Шаблон = "(\d\d:\d\d)\.(\d+)-(\d+),(" + шСимвол + "+),(\d+),((?:" + ШаблонСвойствоЗначение + ")*)"; РегВыражение1.Pattern = Шаблон; //RegExp.Multiline = Истина; РегВыражение1.Global = Истина; РегВыражение2.Pattern = ШаблонСвойствоЗначение; РегВыражение2.Global = Истина; ПустаяДата = Дата("00010101"); МаксКоличествоСобытий = КоличествоЗагруженныхСобытий + МаксТысячСобытий * 1000; //НовыеКлючиЗагруженныхСтрок = Новый Соответствие(); Если КомментироватьЗагрузку Тогда ирОбщий.СообщитьЛкс("Читаем " + ФайлЖурнала.ПолноеИмя + ", размер - " + РазмерФайла); КонецЕсли; ПолноеИмяКаталогаПроцесса = Лев(ФайлЖурнала.Путь, СтрДлина(ФайлЖурнала.Путь) - 1); Длина1 = СтрДлина(ПолноеИмяКаталогаПроцесса); СтрокаЧасаЗаписи = "20" + Сред(ФайлЖурнала.ПолноеИмя, Длина1 + 2, 8); ДатаЧасЗаписи = Дата(СтрокаЧасаЗаписи + "0000"); ИдентификаторПроцессаСтрока = ирОбщий.СтрокаБезКонцаЛкс(ирОбщий.ПоследнийФрагментЛкс(ФайлЖурнала.Путь, "_"), 1); ИдентификаторПроцесса = Число(ИдентификаторПроцессаСтрока); //ЛиФайлВИнтервалеПолностью = ирОбщий.ЛиДатаВИнтервалеБезГраницЛкс(ДатаЧасЗаписи, НачалоЧаса(лНачалоПериода), НачалоЧаса(КонецПериода)); //ЛиДатаВИнтервале = ирОбщий.ЛиДатаВИнтервалеСГраницамиЛкс(ДатаЧасЗаписи, НачалоЧаса(лНачалоПериода), НачалоЧаса(КонецПериода)); ЛиФайлВИнтервалеПолностью = ирОбщий.ЛиДатаВИнтервалеБезГраницЛкс(ДатаЧасЗаписи, НачалоЧаса(НачалоПериода), НачалоЧаса(КонецПериода)); ЛиДатаВИнтервале = ирОбщий.ЛиДатаВИнтервалеСГраницамиЛкс(ДатаЧасЗаписи, НачалоЧаса(НачалоПериода), НачалоЧаса(КонецПериода)); ТекстФайла = ""; // Уничтожаем старый текст, т.к. он может быть очень большим Попытка ЧтениеТекста = Новый ЧтениеТекста(ФайлЖурнала.ПолноеИмя, КодировкаТекста.UTF8, ,,Ложь); //ТекстовыйДокумент.Прочитать(ФайлЖурнала.ПолноеИмя, КодировкаТекста.UTF8); Исключение ирОбщий.СообщитьЛкс("Не удалось прочитать данные из файла " + ФайлЖурнала.ПолноеИмя, СтатусСообщения.Внимание); Возврат Неопределено; КонецПопытки; СигнатураФайла = ЧтениеТекста.Прочитать(20); // Для идентификации файла Если ПустаяСтрока(СигнатураФайла) Тогда Возврат Неопределено; КонецЕсли; РазмерПорции = 2 * 1000 * 1000; // Подобрано экспериментально КраткоеИмяКаталогаПроцесса = ирОбщий.ПоследнийФрагментЛкс(ПолноеИмяКаталогаПроцесса, "\"); ЧислоПорций = Цел(РазмерФайла / РазмерПорции) + 1; ЧтениеТекста = Новый ЧтениеТекста(ФайлЖурнала.ПолноеИмя, КодировкаТекста.UTF8, ,,Ложь); АбсолютнаяПозицияВФайле = 0; КлючКарты = Новый Структура("ИмяКаталогаПроцесса, ИмяТекущегоФайла, СигнатураТекущегоФайла, ОтборПоСеансу", КраткоеИмяКаталогаПроцесса, ФайлЖурнала.Имя, СигнатураФайла, "" + ЗагружатьТолькоТекущийСеанс + ОтборПоСеансу); СтрокиКарт = мКартыФайлов.НайтиСтроки(КлючКарты); Если СтрокиКарт.Количество() > 0 Тогда КартаФайла = СтрокиКарт[0]; Иначе КартаФайла = мКартыФайлов.Добавить(); ЗаполнитьЗначенияСвойств(КартаФайла, КлючКарты); КартаФайла.КонецПериода = Дата(1000, 1, 1); КонецЕсли; Если ирОбщий.ЛиДатаВИнтервалеСГраницамиЛкс(НачалоПериода, КартаФайла.НачалоПериода, КартаФайла.КонецПериода) Тогда АбсолютнаяПозицияВФайле = КартаФайла.ПозицияКонца; ИначеЕсли Ложь Или НачалоПериода > КартаФайла.НачалоПериода Или КонецПериода < КартаФайла.КонецПериода Тогда // Периоды не сшиваются. Очищаем карту. КартаФайла.ПозицияНачала = -1; КартаФайла.ПозицияКонца = -1; КартаФайла.НачалоПериода = НачалоПериода; КартаФайла.КонецПериода = КонецПериода; КартаФайла.ДатаИзмененияФайла = Неопределено; КонецЕсли; Если АбсолютнаяПозицияВФайле > 0 Тогда Если ЗначениеЗаполнено(КартаФайла.ДатаИзмененияФайла) Тогда Если КартаФайла.ДатаИзмененияФайла = ФайлЖурнала.ПолучитьВремяИзменения() + ирКэш.ПолучитьСмещениеВремениЛкс() Тогда Возврат Неопределено; КонецЕсли; КонецЕсли; ЧтениеТекста.Прочитать(АбсолютнаяПозицияВФайле); КонецЕсли; ПозицияНачалаСчитанныхДанных = -1; Если ЧислоПорций > 1 Тогда ИндикаторФайла = ирОбщий.ПолучитьИндикаторПроцессаЛкс(ЧислоПорций, "" + КраткоеИмяКаталогаПроцесса + "\" + ФайлЖурнала.Имя); Иначе ИндикаторФайла = Неопределено; КонецЕсли; РазрешенныеТипыСобытий = Неопределено; Если СписокЗагружаемыхТиповСобытий.Количество() > 0 Тогда РазрешенныеТипыСобытий = Новый Структура; Для Каждого ТипСобытия Из СписокЗагружаемыхТиповСобытий.ВыгрузитьЗначения() Цикл РазрешенныеТипыСобытий.Вставить(ТипСобытия); КонецЦикла; КонецЕсли; СтрокаТЧ = Неопределено; РазмерТекущейПорции = 0; _РежимОтладки = ирКэш.РежимОтладкиЛкс(); ПоследниеСобытияПоТипам = Новый Соответствие; Пока Истина Цикл КартаФайла.ДатаИзмененияФайла = ФайлЖурнала.ПолучитьВремяИзменения() + ирКэш.ПолучитьСмещениеВремениЛкс(); ПорцияТекстаФайла = ЧтениеТекста.Прочитать(РазмерПорции); Если Ложь Или ПорцияТекстаФайла = Неопределено Или ПустаяСтрока(ПорцияТекстаФайла) Тогда Прервать; КонецЕсли; Если ИндикаторФайла <> Неопределено Тогда Если ирОбщий.ОбработатьИндикаторЛкс(ИндикаторФайла) Тогда Если ирОбщий.ЛиПрерватьФоновоеЗаданиеЛкс(ИндикаторФайла) Тогда Прервать; КонецЕсли; КонецЕсли; КонецЕсли; Если Истина И АбсолютнаяПозицияВФайле >= КартаФайла.ПозицияНачала И АбсолютнаяПозицияВФайле + СтрДлина(ПорцияТекстаФайла) + СтрДлина(ТекстФайла) < КартаФайла.ПозицияКонца Тогда АбсолютнаяПозицияВФайле = АбсолютнаяПозицияВФайле + СтрДлина(ПорцияТекстаФайла) + СтрДлина(ТекстФайла); Продолжить; КонецЕсли; ТекстФайла = ТекстФайла + ПорцияТекстаФайла; РазборТекстаРазрешен = Истина; ОписаниеОшибки = ""; МаксимальныйРазмерТекстДляАнализа = 20000000; // Экспериментально подобрано http://devtool1c.ucoz.ru/forum/2-270-1#1145 Если СтрДлина(ТекстФайла) > МаксимальныйРазмерТекстДляАнализа Тогда Если Истина И РазмерТекущейПорции = РазмерПорции И СтрокаТЧ <> Неопределено Тогда СтрокаТЧ.ТекстSDBL = ""; СтрокаТЧ.ТекстСУБД = ""; ирОбщий.СообщитьЛкс("При анализе файла """ + ФайлЖурнала.ПолноеИмя + """ некоторые свойства события пропущены, т.к. оно превышает допустимый размер " + XMLСтрока(Цел(МаксимальныйРазмерТекстДляАнализа/1024/1024)) + "МБ: " + Лев(СокрЛ(СтрЗаменить(ТекстФайла, Символы.ПС, "")), 80) + "..."); Иначе ОписаниеОшибки = "Событие превышает допустимый размер 20МБ"; КонецЕсли; РазборТекстаРазрешен = Ложь; Иначе Если Истина И РазмерТекущейПорции = РазмерПорции И СтрокаТЧ <> Неопределено Тогда мТаблицаЖурнала.Удалить(СтрокаТЧ); КонецЕсли; КонецЕсли; Вхождения = РегВыражение1.НайтиВхождения(""); Если РазборТекстаРазрешен Тогда Попытка Вхождения = РегВыражение1.НайтиВхождения(ТекстФайла); Исключение ОписаниеОшибки = ОписаниеОшибки(); КонецПопытки; КонецЕсли; Если ОписаниеОшибки <> "" Тогда ирОбщий.СообщитьЛкс("При анализе файла """ + ФайлЖурнала.ПолноеИмя + """ пропущена порция """ + Лев(СокрЛ(СтрЗаменить(ТекстФайла, Символы.ПС, "")), 80) + "..."": | " + ОписаниеОшибки); Иначе Если КомментироватьЗагрузку Тогда ирОбщий.СообщитьЛкс("Анализ порции " + СтрДлина(ТекстФайла) + " символов обнаружил " + Вхождения.Количество() + " событий"); КонецЕсли; КонецЕсли; СтрокаТекущегоКонтекста = Неопределено; СтрокаТЧ = Неопределено; Вхождение = Неопределено; Для Каждого Вхождение Из Вхождения Цикл #Если Клиент Тогда ОбработкаПрерыванияПользователя(); #КонецЕсли СтрокаТЧ = Неопределено; АбсолютнаяПозицияВхождения = АбсолютнаяПозицияВФайле + Вхождение.FirstIndex; Если Истина И КартаФайла.ПозицияНачала > -1 И АбсолютнаяПозицияВхождения >= КартаФайла.ПозицияНачала И АбсолютнаяПозицияВхождения < КартаФайла.ПозицияКонца Тогда Продолжить; КонецЕсли; СтрокаВремениЗаписи = СтрокаЧасаЗаписи + СтрЗаменить(Вхождение.SubMatches(0), ":", ""); ДатаТекущегоСобытия = Дата(СтрокаВремениЗаписи); Если Не ЛиФайлВИнтервалеПолностью Тогда //ЛиДатаВИнтервале = ирОбщий.ЛиДатаВИнтервалеСГраницамиЛкс(ДатаТекущегоСобытия, лНачалоПериода, КонецПериода); //Если Не ЛиДатаВИнтервале Тогда // Продолжить; //КонецЕсли; Если Истина И ЗначениеЗаполнено(НачалоПериода) И ДатаТекущегоСобытия < НачалоПериода Тогда Продолжить; КонецЕсли; Если Истина И ЗначениеЗаполнено(КонецПериода) И ДатаТекущегоСобытия > КонецПериода Тогда Вхождение = Неопределено; Прервать; КонецЕсли; КонецЕсли; ТипСобытия = ВРег(Вхождение.SubMatches(3)); Если Истина И РазрешенныеТипыСобытий <> Неопределено И Не РазрешенныеТипыСобытий.Свойство(ТипСобытия) Тогда Продолжить; КонецЕсли; Если ПозицияНачалаСчитанныхДанных = -1 Тогда ПозицияНачалаСчитанныхДанных = АбсолютнаяПозицияВхождения; КонецЕсли; КонецМикросекунды = Вхождение.SubMatches(1); //КлючСтроки = МоментВремени + ";" + ФайлЖурнала.ПолноеИмя; //Если РежимДозагрузки Тогда // Если КлючиЗагруженныхСтрок[КлючСтроки] = 1 Тогда // Продолжить; // КонецЕсли; //КонецЕсли; Если СтрДлина(КонецМикросекунды) = 6 Тогда //Это 8.3 ЧислоМикросекунд = Число(КонецМикросекунды); ПродолжительностьВМикросекундах = Число(Вхождение.SubMatches(2)); Иначе //Это 8.2 ЧислоМикросекунд = Число(КонецМикросекунды) * 100; ПродолжительностьВМикросекундах = Число(Вхождение.SubMatches(2)) * 100; КонецЕсли; Если мТаблицаЖурнала.Количество() = МаксКоличествоСобытий Тогда УдалитьСтрокиВнеФильтра(); Если мТаблицаЖурнала.Количество() = МаксКоличествоСобытий Тогда ДостигнутоПредельноеКоличество = Истина; Прервать; КонецЕсли; КонецЕсли; СтрокаТЧ = мТаблицаЖурнала.Добавить(); ТекстДинамическихСвойств = Вхождение.SubMatches(5); ПоследнееСобытиеТипа = ПоследниеСобытияПоТипам[ТипСобытия]; ДинамическиеСвойстваВзятыИзКэша = Истина И ПоследнееСобытиеТипа <> Неопределено И ПоследнееСобытиеТипа.ТекстДинамическихСвойств = ТекстДинамическихСвойств И мТаблицаЖурнала.Индекс(ПоследнееСобытиеТипа.СтрокаТаблицы) >= 0; // Строку, на которую ссылается кэш, могли удалить на стыке порций. Поэтому проверяем ее существование Если ДинамическиеСвойстваВзятыИзКэша Тогда Если ТипЗнч(ПоследнееСобытиеТипа.СписокСвойств) = Тип("Массив") Тогда ПоследнееСобытиеТипа.СписокСвойств = ирОбщий.СтрСоединитьЛкс(ПоследнееСобытиеТипа.СписокСвойств); КонецЕсли; ЗаполнитьЗначенияСвойств(СтрокаТЧ, ПоследнееСобытиеТипа.СтрокаТаблицы, ПоследнееСобытиеТипа.СписокСвойств); Иначе ДинамическиеСвойстваВзятыИзКэша = Ложь; КонецЕсли; СтрокаТЧ.ИмяФайлаЛога = ФайлЖурнала.ПолноеИмя; СтрокаТЧ.ПроцессОС = ИдентификаторПроцесса; СтрокаТЧ.Событие = ТипСобытия; СтрокаТЧ.Дата = ДатаТекущегоСобытия - СдвигВремени; СтрокаТЧ.МоментВремени = ПолучитьМоментВремени(СтрокаТЧ.Дата, КонецМикросекунды); //СтрокаТЧ.ТекстЖурнала = Вхождение.Value; // Теперь это только для отладки будем включать СтрокаТЧ.Длительность = ПродолжительностьВМикросекундах / 1000; // Переводим длительность в миллисекунды Длительность1Секунды = Цел(ПродолжительностьВМикросекундах / 1000000); Длительность1Микросекунды = ПродолжительностьВМикросекундах - Длительность1Секунды * 1000000; ДатаНачала = СтрокаТЧ.Дата - Длительность1Секунды; НачалоМикросекунды = КонецМикросекунды - Длительность1Микросекунды; Если НачалоМикросекунды < 0 Тогда ДатаНачала = ДатаНачала - 1; НачалоМикросекунды = 1000000 + НачалоМикросекунды; КонецЕсли; СтрокаТЧ.ДатаНачала = ДатаНачала; СтрокаТЧ.МоментВремениНачала = ПолучитьМоментВремени(ДатаНачала, НачалоМикросекунды); СтрокаТЧ.Вложенность = Число(Вхождение.SubMatches(4)); Если Не ДинамическиеСвойстваВзятыИзКэша Тогда СписокСвойств = Новый Массив; ВхожденияСвойств = РегВыражение2.НайтиВхождения(ТекстДинамическихСвойств,, Истина); Если _РежимОтладки Тогда // Пассивный оригинал расположенного ниже однострочного кода. Выполняйте изменения синхронно в обоих вариантах. Для Каждого ВхождениеСвойства Из ВхожденияСвойств Цикл //Для Индекс = 0 По мТаблицаКолонок.Количество() - 1 Цикл ИмяСвойства = ВхождениеСвойства.SubMatches(0); ЗначениеСвойства = ВхождениеСвойства.SubMatches(3); Если ЗначениеСвойства = Неопределено Тогда // Скорость критична ЗначениеСвойства = ВхождениеСвойства.SubMatches(2); КонецЕсли; Если ЗначениеСвойства = Неопределено Тогда // Скорость критична ЗначениеСвойства = ВхождениеСвойства.SubMatches(1); КонецЕсли; Если ЗначениеСвойства = Неопределено Тогда // Скорость критична Продолжить; КонецЕсли; ИмяКолонкиТЧ = мСоответствиеКолонок[НРег(ИмяСвойства)]; Если ИмяКолонкиТЧ = Неопределено Тогда СтрокаТЧ.НеизвестныеСвойства = СтрокаТЧ.НеизвестныеСвойства + ИмяСвойства + "=" + ЗначениеСвойства + ", "; СписокСвойств.Добавить("НеизвестныеСвойства"); Иначе //Если мЧисловыеСвойства.Свойство(ИмяКолонкиТЧ) Тогда // Если Не ЗначениеЗаполнено(ЗначениеСвойства) Тогда // ЗначениеСвойства = 0; // Иначе // Попытка // ЗначениеСвойства = Число(ЗначениеСвойства); // Исключение // ВызватьИсключение "Некорректное представление """ + ЗначениеСвойства + """ значения числового свойства """ + ИмяКолонкиТЧ + """"; // КонецПопытки; // КонецЕсли; //КонецЕсли; Если ТипЗнч(СтрокаТЧ[ИмяКолонкиТЧ]) = Тип("Булево") Тогда ЗначениеСвойства = ?(ЗначениеСвойства = "1" Или Нрег(ЗначениеСвойства) = "true", Истина, Ложь); КонецЕсли; Если Не мНепустыеКолонкиЖурнала.Свойство(ИмяКолонкиТЧ) Тогда Если ЗначениеЗаполнено(ЗначениеСвойства) Тогда мНепустыеКолонкиЖурнала.Вставить(ИмяКолонкиТЧ); КонецЕсли; КонецЕсли; Попытка СтрокаТЧ[ИмяКолонкиТЧ] = ЗначениеСвойства; Исключение ВызватьИсключение "Некорректное представление """ + ЗначениеСвойства + """ значения свойства """ + ИмяКолонкиТЧ + """"; КонецПопытки; СписокСвойств.Добавить(ИмяКолонкиТЧ); КонецЕсли; КонецЦикла; Иначе // Однострочный код использован для ускорения. Выше расположен оригинал. Выполняйте изменения синхронно в обоих вариантах. Преобразовано консолью кода из подсистемы "Инструменты разработчика" (http://devtool1c.ucoz.ru) Для Каждого ВхождениеСвойства Из ВхожденияСвойств Цикл     ИмяСвойства = ВхождениеСвойства.SubMatches(0);   ЗначениеСвойства = ВхождениеСвойства.SubMatches(3);   Если ЗначениеСвойства = Неопределено Тогда   ЗначениеСвойства = ВхождениеСвойства.SubMatches(2);   КонецЕсли;   Если ЗначениеСвойства = Неопределено Тогда   ЗначениеСвойства = ВхождениеСвойства.SubMatches(1);   КонецЕсли;   Если ЗначениеСвойства = Неопределено Тогда   Продолжить;   КонецЕсли;   ИмяКолонкиТЧ = мСоответствиеКолонок[НРег(ИмяСвойства)];   Если ИмяКолонкиТЧ = Неопределено Тогда   СтрокаТЧ.НеизвестныеСвойства = СтрокаТЧ.НеизвестныеСвойства + ИмяСвойства + "=" + ЗначениеСвойства + ", ";   СписокСвойств.Добавить("НеизвестныеСвойства");   Иначе                         Если ТипЗнч(СтрокаТЧ[ИмяКолонкиТЧ]) = Тип("Булево") Тогда   ЗначениеСвойства = ?(ЗначениеСвойства = "1" Или Нрег(ЗначениеСвойства) = "true", Истина, Ложь);   КонецЕсли;   Если Не мНепустыеКолонкиЖурнала.Свойство(ИмяКолонкиТЧ) Тогда   Если ЗначениеЗаполнено(ЗначениеСвойства) Тогда   мНепустыеКолонкиЖурнала.Вставить(ИмяКолонкиТЧ);   КонецЕсли;   КонецЕсли;   Попытка   СтрокаТЧ[ИмяКолонкиТЧ] = ЗначениеСвойства;   Исключение   ВызватьИсключение "Некорректное представление """ + ЗначениеСвойства + """ значения свойства """ + ИмяКолонкиТЧ + """";   КонецПопытки;   СписокСвойств.Добавить(ИмяКолонкиТЧ);   КонецЕсли;   КонецЦикла;   КонецЕсли; //АбсолютнаяПозицияВФайле = АбсолютнаяПозицияВФайле + Вхождение.Length; Если Ложь Или (Истина И ОтборПоСеансу <> Неопределено И СтрокаТЧ.Сеанс <> ОтборПоСеансу) Или (Истина И ОтборПоПользователю <> Неопределено И СтрокаТЧ.Пользователь <> ОтборПоПользователю) Тогда мТаблицаЖурнала.Удалить(СтрокаТЧ); СтрокаТЧ = Неопределено; #Если Сервер И Не Сервер Тогда СтрокаТЧ = мТаблицаЖурнала.Добавить(); #КонецЕсли Продолжить; КонецЕсли; //Если НаСервере <> Неопределено Тогда // СтрокаТЧ.НаСервере = НаСервере; //Иначе Если Ложь Или ТипСобытия = "SCOM" Тогда СтрокаТЧ.НаСервере = Истина; Иначе ИмяТипаПроцесса = "_" + СтрЗаменить(СтрокаТЧ.ТипПроцессаОС, "#", ""); Попытка СтрокаТЧ.НаСервере = мСерверныеТипыПроцессов.Свойство(ИмяТипаПроцесса); Исключение // Бывают типы процессов с UID, к сожалению тогда невозможно определить КонецПопытки; КонецЕсли; //КонецЕсли; Если СтрокаТЧ.Контекст <> "" Тогда КонтекстТД = Новый ТекстовыйДокумент; КонтекстТД.УстановитьТекст(СтрокаТЧ.Контекст); СтрокаТЧ.СтрокаМодуля = СокрЛП(КонтекстТД.ПолучитьСтроку(КонтекстТД.КоличествоСтрок())); Если БазовыйУровеньСтека > 0 Тогда ЗаполнитьСтрокуБазовогоУровня(СтрокаТЧ); КонецЕсли; КонецЕсли; ПоследниеСобытияПоТипам[ТипСобытия] = Новый Структура("СтрокаТаблицы, ТекстДинамическихСвойств, СписокСвойств", СтрокаТЧ, ТекстДинамическихСвойств, СписокСвойств); КонецЕсли; //Если ДатаТекущегоСобытия > лПоследнееВремяНачалаЗагрузки - НаложениеПриДозагрузкеСекунд Тогда // НовыеКлючиЗагруженныхСтрок[КлючСтроки] = 1; //КонецЕсли; Если ирОбщий.СтрокиРавныЛкс(ТипСобытия, "Context") Тогда // Встроим контекст в предыдущие события Индекс = мТаблицаЖурнала.Количество() - 2; Пока Индекс >= 0 Цикл СтрокаБезКонтекста = мТаблицаЖурнала[Индекс]; Индекс = Индекс - 1; Если Ложь Или СтрокаБезКонтекста.Сеанс <> СтрокаТЧ.Сеанс Или СтрокаБезКонтекста.Инфобаза <> СтрокаТЧ.Инфобаза Тогда Прервать; КонецЕсли; Если СтрокаБезКонтекста.СтрокаМодуля <> "" Тогда Прервать; КонецЕсли; ЗаполнитьЗначенияСвойств(СтрокаБезКонтекста, СтрокаТЧ, "СтрокаМодуля, Контекст"); КонецЦикла; КонецЕсли; КонецЦикла; Если ДостигнутоПредельноеКоличество Тогда Прервать; КонецЕсли; // Для отката к началу последнего события РазмерТекущейПорции = СтрДлина(ПорцияТекстаФайла); АбсолютнаяПозицияВФайле = АбсолютнаяПозицияВФайле + СтрДлина(ТекстФайла); Если РазмерТекущейПорции = РазмерПорции Тогда //Если СтрокаТЧ <> Неопределено Тогда // ТаблицаЖурнала.Удалить(ТаблицаЖурнала.Количество() - 1); //КонецЕсли; Если Вхождение <> Неопределено Тогда ТекстФайла = Сред(ТекстФайла, Вхождение.FirstIndex); Иначе ТекстФайла = Прав(ТекстФайла, 1000); // Страховка КонецЕсли; АбсолютнаяПозицияВФайле = АбсолютнаяПозицияВФайле - СтрДлина(ТекстФайла); Иначе ТекстФайла = ""; КонецЕсли; КонецЦикла; Если ИндикаторФайла <> Неопределено Тогда ирОбщий.ОсвободитьИндикаторПроцессаЛкс(); КонецЕсли; Если ДостигнутоПредельноеКоличество Тогда ТекстСообщения = "Загрузка остановлена по достижению максимального количества событий в таблице"; Если Не ЗначениеЗаполнено("" + ФильтрЗагрузки) Тогда ТекстСообщения = ТекстСообщения + ". Если задать фильтр отображения таблицы, то будет предложено применить его при загрузке нового журнала."; КонецЕсли; ирОбщий.СообщитьЛкс(ТекстСообщения); Иначе КартаФайла.ПозицияКонца = АбсолютнаяПозицияВФайле; Если Истина И ПозицияНачалаСчитанныхДанных <> -1 И (Ложь Или КартаФайла.ПозицияНачала = -1 Или КартаФайла.ПозицияНачала > ПозицияНачалаСчитанныхДанных) Тогда КартаФайла.ПозицияНачала = ПозицияНачалаСчитанныхДанных; КонецЕсли; Если Ложь Или Не ЗначениеЗаполнено(КонецПериода) Или КонецПериода > КартаФайла.КонецПериода Тогда КартаФайла.КонецПериода = КонецПериода; КонецЕсли; Если Ложь Или Не ЗначениеЗаполнено(НачалоПериода) Или НачалоПериода < КартаФайла.НачалоПериода Тогда КартаФайла.НачалоПериода = НачалоПериода; КонецЕсли; КонецЕсли; Результат = Неопределено; Если ВозвращатьРезультат Тогда Результат = Новый Структура; Результат.Вставить("КлючКарты", КлючКарты); Результат.Вставить("КартаФайла", ирОбщий.СтруктураИзСтрокиТаблицыИлиДереваИлиВыборкиЛкс(КартаФайла)); Результат.Вставить("ТаблицаЖурнала", мТаблицаЖурнала); Результат.Вставить("РазмерФайла", РазмерФайла); Результат.Вставить("НепустыеКолонкиЖурнала", мНепустыеКолонкиЖурнала); КонецЕсли; Возврат Результат; КонецФункции Процедура ЗагрузитьРезультатЧтенияФайлаВПотоке(Знач Результат, Знач ЛокальныеПараметры) Экспорт Если Результат = Неопределено Тогда Возврат; КонецЕсли; мТаблицаЖурнала = ирОбщий.ОбъединитьТаблицыЗначенийЛкс(Результат.ТаблицаЖурнала, мТаблицаЖурнала, Результат.НепустыеКолонкиЖурнала, мНепустыеКолонкиЖурнала); ирОбщий.СкопироватьУниверсальнуюКоллекциюЛкс(Результат.НепустыеКолонкиЖурнала, мНепустыеКолонкиЖурнала); СтрокиКарт = мКартыФайлов.НайтиСтроки(Результат.КлючКарты); Если СтрокиКарт.Количество() > 0 Тогда КартаФайла = СтрокиКарт[0]; Иначе КартаФайла = мКартыФайлов.Добавить(); КонецЕсли; ЗаполнитьЗначенияСвойств(КартаФайла, Результат.КартаФайла); КонецПроцедуры Функция _СписокСвойствИзСтруктуры(Знач СтруктураСвойств) #Если Сервер И Не Сервер Тогда СтруктураСвойств = Новый Структура; #КонецЕсли МассивСвойств = Новый Массив; Для Каждого КлючИЗначение Из СтруктураСвойств Цикл МассивСвойств.Добавить(КлючИЗначение.Ключ); КонецЦикла; СписокСвойств1 = ирОбщий.СтрСоединитьЛкс(МассивСвойств); Возврат СписокСвойств1; КонецФункции Функция РеквизитыДляСервера(Параметры) Экспорт //Результат = ирОбщий.РеквизитыОбработкиЛкс(ЭтотОбъект); // ИменаПередаваемыхСвойств = мИменаВозвращаемыхСвойств + ", |мАдресЧужойСхемыБД, |НачалоПериодаКлиента, |КонецПериодаКлиента, |НачалоПериодаСервера, |КонецПериодаСервера, |мИдентификаторТрассы"; Результат = Новый Структура(ИменаПередаваемыхСвойств); ЗаполнитьЗначенияСвойств(Результат, ЭтотОбъект, ИменаПередаваемыхСвойств); Для Каждого МетаРеквизит Из Метаданные().Реквизиты Цикл Результат.Вставить(МетаРеквизит.Имя, ЭтотОбъект[МетаРеквизит.Имя]); КонецЦикла; Возврат Результат; КонецФункции Процедура УдалитьСтрокиВнеФильтра() Если ЗначениеЗаполнено("" + ФильтрЗагрузки) Тогда Построитель = Новый ПостроительЗапроса; Построитель.ИсточникДанных = Новый ОписаниеИсточникаДанных(ТаблицаЖурнала); ирОбщий.СкопироватьОтборПостроителяЛкс(Построитель.Отбор, ФильтрЗагрузки); ТаблицаЖурнала.Загрузить(Построитель.Результат.Выгрузить()); КонецЕсли; КонецПроцедуры Процедура ОпределитьНепустыеКолонки() Экспорт Если мНепустыеКолонкиЖурнала.Количество() = 0 Тогда // Загрузили данные из файла // Долгая операция Для Каждого Реквизит Из Метаданные().ТабличныеЧасти.ТаблицаЖурнала.Реквизиты Цикл Если ТаблицаЖурнала.НайтиСтроки(Новый Структура(Реквизит.Имя, Реквизит.Тип.ПривестиЗначение())).Количество() < ТаблицаЖурнала.Количество() Тогда мНепустыеКолонкиЖурнала.Вставить(Реквизит.Имя); КонецЕсли; КонецЦикла; КонецЕсли; ДобавитьОбязательныеНепустыеКолонки(); //Пустота производных колонок Если мНепустыеКолонкиЖурнала.Свойство("Контекст") Тогда мНепустыеКолонкиЖурнала.Вставить("СтрокаМодуля"); мНепустыеКолонкиЖурнала.Вставить("СтрокаБазовогоМодуля"); КонецЕсли; КонецПроцедуры Процедура ДобавитьОбязательныеНепустыеКолонки() Экспорт мНепустыеКолонкиЖурнала.Вставить("Событие"); мНепустыеКолонкиЖурнала.Вставить("ИмяФайлаЛога"); мНепустыеКолонкиЖурнала.Вставить("ПроцессОС"); мНепустыеКолонкиЖурнала.Вставить("НаСервере"); мНепустыеКолонкиЖурнала.Вставить("Вложенность"); мНепустыеКолонкиЖурнала.Вставить("Длительность"); мНепустыеКолонкиЖурнала.Вставить("Дата"); мНепустыеКолонкиЖурнала.Вставить("ДатаНачала"); мНепустыеКолонкиЖурнала.Вставить("МоментВремени"); мНепустыеКолонкиЖурнала.Вставить("МоментВремениНачала"); мНепустыеКолонкиЖурнала.Вставить("СтрокаМодуля"); мНепустыеКолонкиЖурнала.Вставить("НеизвестныеСвойства"); //мНепустыеКолонкиЖурнала.Вставить("Картинка"); КонецПроцедуры Функция ПолучитьМоментВремени(Дата, Микросекунды) Экспорт Результат = Формат(Дата, "ДФ=yyyyMMddHHmmss") + Формат(Микросекунды, "ЧЦ=6; ЧВН=; ЧГ="); Возврат Результат; КонецФункции Функция РазностьМоментовВремени(МоментВремениУменьшаемый, МоментВремениВычитаемый) Экспорт Если СтрДлина(МоментВремениВычитаемый) <> СтрДлина(МоментВремениВычитаемый) Тогда ВызватьИсключение "Размерность моментов времени не совпадает"; КонецЕсли; ДлинаЧастиДаты = 14; ДатаУменьшаемая = Дата(Лев(МоментВремениУменьшаемый, ДлинаЧастиДаты)); ДатаВычитаемая = Дата(Лев(МоментВремениВычитаемый, ДлинаЧастиДаты)); РазрядностьДолейСекунд = СтрДлина(МоментВремениУменьшаемый) - ДлинаЧастиДаты; РазностьСекунд = ДатаУменьшаемая - ДатаВычитаемая; Результат = РазностьСекунд; Для Счетчик = 1 По РазрядностьДолейСекунд Цикл Результат = Результат * 10; КонецЦикла; Результат = Результат + Число(Сред(МоментВремениУменьшаемый, ДлинаЧастиДаты + 1)) - Число(Сред(МоментВремениВычитаемый, ДлинаЧастиДаты + 1)); Возврат Результат; КонецФункции // РазностьМоментовВремени() Функция ЗаполнитьСтрокуБазовогоУровня(СтрокаТЧ) Если БазовыйУровеньСтека > 0 Тогда //МаркерБазовогоМодуля = Символы.Таб + мИмяБазовогоМодуля + " : "; //ПозицияМаркераМодуля = Найти(СтрокаТЧ.Контекст, МаркерБазовогоМодуля); //КонецСтроки = Сред(СтрокаТЧ.Контекст, ПозицияМаркераМодуля + СтрДлина(МаркерБазовогоМодуля)); НовоеЗначение = СокрЛ(СтрПолучитьСтроку(СтрокаТЧ.Контекст, БазовыйУровеньСтека)); Иначе НовоеЗначение = ""; КонецЕсли; ирОбщий.ПрисвоитьЕслиНеРавноЛкс(СтрокаТЧ.СтрокаМодуляБазовогоУровня, НовоеЗначение); Возврат Неопределено; КонецФункции // ПопытокЧтения - Число, используется только при РежимТрассы = Истина Функция ПрочитатьСобственныйЖурналДвухСторон(УдалитьДополнительныеСобытия = Истина, ИменаНеполезныхКолонок = "", РежимТрассы = Истина, ЖдатьСекунд = 2, СмещениеБазовогоУровня = Неопределено, ОтборПоСеансу = Неопределено) Если РежимТрассы Тогда Если мИдентификаторТрассы = Неопределено Тогда Если Не ирКэш.ЛиФайловаяБазаЛкс() Тогда ирОбщий.ЛиТехножурналВключенЛкс(Истина, Истина, Истина, мЛиТрассаПоПользователю); КонецЕсли; ирОбщий.ЛиТехножурналВключенЛкс(, Истина, Истина, мЛиТрассаПоПользователю); Возврат Ложь; КонецЕсли; //ЭтотОбъект.ЗагружатьЖурналКлиента = Истина; //ЭтотОбъект.ЗагружатьЖурналСервера = Не ирКэш.ЛиФайловаяБазаЛкс(); //ЭтотОбъект.ЗагружатьТолькоТекущийСеанс = Истина; КонецЕсли; ВыраниватьДатуПоСерверу = Ложь; #Если Клиент Тогда ВыраниватьДатуПоСерверу = ирОбщий.ВосстановитьЗначениеЛкс("ирАнализТехножурнала.ВыраниватьДатуПоСерверу") = Истина; #КонецЕсли Если РежимТрассы Тогда РазницаВремениКлиентСервер = НачалоПериодаКлиента - НачалоПериодаСервера; Иначе РазницаВремениКлиентСервер = ирОбщий.РазницаВремениКлиентСерверЛкс(); КонецЕсли; Если Истина И Не ирКэш.Получить().ЭтоФайловаяБаза И ЗагружатьЖурналСервера Тогда ЭтотОбъект.КаталогЖурнала = ""; Если ВыраниватьДатуПоСерверу Тогда СдвигВремени = 0; Иначе СдвигВремени = -РазницаВремениКлиентСервер; КонецЕсли; РезультатСервера = ПрочитатьСобственныйЖурналОднойСтороны(НачалоПериодаСервера, КонецПериодаСервера, Истина, СдвигВремени, РежимТрассы, ЖдатьСекунд, СмещениеБазовогоУровня, ОтборПоСеансу); Если РезультатСервера = Неопределено Тогда ирОбщий.СообщитьЛкс("Не удалось найти маркеры трассы в логах техножурнала сервера " + КаталогЖурнала + ". Проверьте включенность регистрации события QERR в настройке техножурнала"); КонецЕсли; КонецЕсли; РезультатКлиента = Неопределено; Если Ложь Или Не РежимТрассы Или Не мЛиТрассаПоПользователю Или ирКэш.Получить().ЭтоФайловаяБаза Тогда #Если Клиент Тогда Если ЗагружатьЖурналКлиента Тогда ЭтотОбъект.КаталогЖурнала = ""; Если ВыраниватьДатуПоСерверу Тогда СдвигВремени = РазницаВремениКлиентСервер; Иначе СдвигВремени = 0; КонецЕсли; РезультатКлиента = ПрочитатьСобственныйЖурналОднойСтороны(НачалоПериодаКлиента, КонецПериодаКлиента, Ложь, СдвигВремени, РежимТрассы, ЖдатьСекунд, СмещениеБазовогоУровня, ОтборПоСеансу); Если РезультатКлиента = Неопределено Тогда ирОбщий.СообщитьЛкс("Не удалось найти маркеры трассы в логах техножурнала клиента " + КаталогЖурнала + ". Проверьте включенность регистрации события QERR в настройке техножурнала"); КонецЕсли; КонецЕсли; #КонецЕсли КонецЕсли; Если УдалитьДополнительныеСобытия Тогда УдалитьСтрокиПоОтборуЛкс(Новый Структура("Действие", "getExecSQLStatistics")); УдалитьСтрокиПоОтборуЛкс(Новый Структура("Событие", "CONTEXT")); КонецЕсли; Если РежимТрассы Тогда ЭтотОбъект.ВключитьСвойстваСИменамиМетаданных = Истина; КонецЕсли; Если Истина И РезультатКлиента = Неопределено И РезультатСервера = Неопределено Тогда Если мТаблицаЖурнала.Количество() = 0 Тогда Возврат Ложь; КонецЕсли; КонецЕсли; //Если ВключитьСвойстваСИменамиМетаданных Тогда // ОбновитьСвойстваВТерминахМетаданных(); //КонецЕсли; //ОбновитьСтрокиБазовогоУровня(); Возврат Истина; КонецФункции Функция ПрочитатьСобственныйЖурналОднойСтороны(НачалоПериода = Неопределено, КонецПериода = Неопределено, НаСервере = Истина, СдвигВремени = 0, РежимТрассы = Истина, ЖдатьСекунд = 2, СмещениеБазовогоУровня = Неопределено, ОтборПоСеансу = Неопределено) Если НачалоПериода <> Неопределено Тогда ЭтотОбъект.НачалоПериода = НачалоПериода; КонецЕсли; Если КонецПериода <> Неопределено Тогда ЭтотОбъект.КонецПериода = КонецПериода; КонецЕсли; ТехножурналВключен = ирОбщий.ЛиТехножурналВключенЛкс(НаСервере,, Истина, РежимТрассы И мЛиТрассаПоПользователю); Если Истина И Не ТехножурналВключен И РежимТрассы Тогда Возврат Неопределено; КонецЕсли; МассивТиповСУБД = Новый Массив(); Если ирКэш.ЛиФайловаяБазаЛкс() Тогда МассивТиповСУБД.Добавить("DBV8DBENG"); //ОтборТЧ = Новый Структура("Событие", "SDBL"); Иначе МассивТиповСУБД.Добавить("DBMSSQL"); МассивТиповСУБД.Добавить("DBPOSTGRS"); МассивТиповСУБД.Добавить("DBORACLE"); МассивТиповСУБД.Добавить("DB2"); //ОтборТЧ = Новый Структура("Событие", "CONTEXT"); КонецЕсли; СообщитьРазмер = Неопределено; МаркерНачалаНайден = Ложь; ДлительностьОднойПаузы = 0.5; Для Счетчик = 1 По ЖдатьСекунд / ДлительностьОднойПаузы + 1 Цикл #Если Клиент Тогда ОбработкаПрерыванияПользователя(); #КонецЕсли Если Счетчик > 1 Тогда ирОбщий.СостояниеЛкс("Ожидание техножурнала " + КаталогЖурнала + "..."); ирОбщий.ПаузаЛкс(ДлительностьОднойПаузы); СообщитьРазмер = Ложь; КонецЕсли; ЖурналСчитан = ПрочитатьПроизвольныйЖурнал(СообщитьРазмер, СдвигВремени, , ОтборПоСеансу, НаСервере); Если Не ЖурналСчитан Тогда Возврат Неопределено; КонецЕсли; //ТехножурналВключен = ирОбщий.ЛиТехножурналВключенЛкс(Истина,, Истина); //Если ТехножурналВключен Тогда // Если АвтоочисткаТехножурнала Тогда // КаталогТекущегоЖурнала = ПолучитьКаталогТекущегоЖурнала(); // Если ЗначениеЗаполнено(КаталогТекущегоЖурнала) Тогда // ирОбщий.ОчиститьКаталогТехножурналаЛкс(КаталогТекущегоЖурнала, Истина, Ложь); // КонецЕсли; // КонецЕсли; //КонецЕсли; Если РежимТрассы Тогда Если Ложь Или Не ирКэш.ЛиПортативныйРежимЛкс() Или Не НаСервере Тогда МаркерНачала = Новый Структура("Описание", "{(1, 1)}: Ожидается выражение ""ВЫБРАТЬ"" |<>НачалоТрассы_" + мИдентификаторТрассы); МаркерКонца = Новый Структура("Описание", "{(1, 1)}: Ожидается выражение ""ВЫБРАТЬ"" |<>КонецТрассы_" + мИдентификаторТрассы); Иначе МаркерНачала = Новый Структура("ТекстSDBL", "SELECT |""НачалоТрассы_" + мИдентификаторТрассы + """ |"); МаркерКонца = Новый Структура("ТекстSDBL", "SELECT |""КонецТрассы_" + мИдентификаторТрассы + """ |"); КонецЕсли; // Удаляем лишние строки до маркера начала и после маркера конца Если Не МаркерНачалаНайден Тогда НайденныеСтроки = мТаблицаЖурнала.НайтиСтроки(МаркерНачала); Если НайденныеСтроки.Количество() = 0 Тогда Продолжить; КонецЕсли; НачальнаяСтрока = НайденныеСтроки[0]; #Если Сервер И Не Сервер Тогда НачальнаяСтрока = мТаблицаЖурнала.Добавить(); #КонецЕсли Если СмещениеБазовогоУровня <> Неопределено Тогда ЭтотОбъект.БазовыйУровеньСтека = СтрЧислоСтрок(НачальнаяСтрока.Контекст) + СмещениеБазовогоУровня; КонецЕсли; КонечныйИндекс = мТаблицаЖурнала.Индекс(НачальнаяСтрока); Для Индекс = 0 По КонечныйИндекс Цикл //Если мТаблицаЖурнала[0].НаСервере = НаСервере Тогда мТаблицаЖурнала.Удалить(0); //КонецЕсли; КонецЦикла; МаркерНачалаНайден = Истина; КонецЕсли; НайденныеСтроки = мТаблицаЖурнала.НайтиСтроки(МаркерКонца); Если НайденныеСтроки.Количество() = 0 Тогда Продолжить; КонецЕсли; КонечнаяСтрока = НайденныеСтроки[0]; НачальныйИндекс = мТаблицаЖурнала.Индекс(КонечнаяСтрока); Если Ложь Или НаСервере Или ирКэш.ЛиФайловаяБазаЛкс() Тогда КонечнаяСтрока1 = мТаблицаЖурнала[НачальныйИндекс]; Если МассивТиповСУБД.Найти(КонечнаяСтрока1.Событие) <> Неопределено Тогда // Опасно. Учитывается регистр букв мТипСУБД = КонечнаяСтрока1.Событие; НачальныйИндекс = НачальныйИндекс - 1; КонецЕсли; КонецЕсли; НачальноеКоличество = мТаблицаЖурнала.Количество(); Для Индекс = 1 По НачальноеКоличество - НачальныйИндекс Цикл СтрокаЖурнала = мТаблицаЖурнала[НачальноеКоличество - Индекс]; Если СтрокаЖурнала.НаСервере = НаСервере Тогда мТаблицаЖурнала.Удалить(СтрокаЖурнала); КонецЕсли; КонецЦикла; Пока Истина И мТаблицаЖурнала.Количество() > 0 И мТаблицаЖурнала[0].НаСервере = НаСервере И Найти(мТаблицаЖурнала[0].Контекст, "Обработка.ирАнализТехножурнала.МодульОбъекта") > 0 Цикл мТаблицаЖурнала.Удалить(0); КонецЦикла; Пока Истина И мТаблицаЖурнала.Количество() > 0 И мТаблицаЖурнала[мТаблицаЖурнала.Количество() - 1].НаСервере = НаСервере И Найти(мТаблицаЖурнала[мТаблицаЖурнала.Количество() - 1].Контекст, "Обработка.ирАнализТехножурнала.МодульОбъекта") > 0 Цикл мТаблицаЖурнала.Удалить(мТаблицаЖурнала.Количество() - 1); КонецЦикла; КонецЕсли; Прервать; КонецЦикла; Если РежимТрассы Тогда Если КонечнаяСтрока = Неопределено Тогда Возврат Неопределено; КонецЕсли; // ФрагментыНачальнойСтрокиМодуля = ирОбщий.СтрРазделитьЛкс(мТаблицаЖурнала[0].СтрокаМодуля, ":", Истина); // ФрагментыКонечнойСтрокиМодуля = ирОбщий.СтрРазделитьЛкс(мТаблицаЖурнала[мТаблицаЖурнала.Количество() - 1].СтрокаМодуля, ":", Истина); // ИмяМодуляНачальнойСтроки = ФрагментыНачальнойСтрокиМодуля[0]; // ИмяМодуляКонечнойСтроки = ФрагментыКонечнойСтрокиМодуля[0]; // НомерНачальнойСтроки = Число(ФрагментыНачальнойСтрокиМодуля[1]); // НомерКонечнойСтроки = Число(ФрагментыКонечнойСтрокиМодуля[1]); // ЕстьВызовыМетодовМодулей = Ложь // Или ИмяМодуляНачальнойСтроки <> ИмяМодуляНачальнойСтроки // Или НомерНачальнойСтроки > НомерКонечнойСтроки; // СтрокиВызововМетодов = НайтиВызовыМетодовМодулей(ИмяМодуляНачальнойСтроки, НомерНачальнойСтроки, НомерКонечнойСтроки, Истина); // Если СтрокиВызововМетодов.Количество() > 0 Тогда // Ответ = Вопрос("В трассе обнаружены вызовы методов модулей. Хотите удалить их из трассы?", РежимДиалогаВопрос.ДаНет); // Если Ответ = КодВозвратаДиалога.Да Тогда // СтрокиВызововМетодов = НайтиВызовыМетодовМодулей(ИмяМодуляНачальнойСтроки, НомерНачальнойСтроки, НомерКонечнойСтроки, Ложь); // Для Каждого СтрокаВызоваМетода Из СтрокиВызововМетодов Цикл // мТаблицаЖурнала.Удалить(СтрокаВызоваМетода); // КонецЦикла; // КонецЕсли; // КонецЕсли; КонецЕсли; Возврат Истина; КонецФункции Функция ПрочитатьЖурнал(Параметры) Экспорт ЭтотОбъект.ФильтрЗагрузки = Параметры.ФильтрЗагрузки; УдалитьДополнительныеСобытия = Параметры.УдалитьДополнительныеСобытия; ИменаНеполезныхКолонок = Параметры.ИменаНеполезныхКолонок; РежимТрассы = Параметры.РежимТрассы; ЖдатьСекунд = Параметры.ЖдатьСекунд; ОтборПоСеансу = Параметры.ОтборПоСеансу; СмещениеБазовогоУровня = Параметры.СмещениеБазовогоУровня; Если Не РежимТрассы Тогда ЭтотОбъект.КонецПериодаСервера = Неопределено; ЭтотОбъект.КонецПериодаКлиента = Неопределено; ЭтотОбъект.НачалоПериодаСервера = Неопределено; ЭтотОбъект.НачалоПериодаКлиента = Неопределено; КонецЕсли; Если Ложь Или ЗагружатьЖурналКлиента Или ЗагружатьЖурналСервера Тогда ЖурналПрочитан = ПрочитатьСобственныйЖурналДвухСторон(УдалитьДополнительныеСобытия, ИменаНеполезныхКолонок, РежимТрассы, ЖдатьСекунд, СмещениеБазовогоУровня, ОтборПоСеансу); Иначе ЖурналПрочитан = ПрочитатьПроизвольныйЖурнал(,,, ОтборПоСеансу); Если ВключитьСвойстваСИменамиМетаданных Тогда ОбновитьСвойстваВТерминахМетаданных(); КонецЕсли; КонецЕсли; Результат = Новый Структура(мИменаВозвращаемыхСвойств); ЗаполнитьЗначенияСвойств(Результат, ЭтотОбъект); Результат.Вставить("Успех", ЖурналПрочитан); Результат.Вставить("ТаблицаЖурнала", мТаблицаЖурнала); Возврат Результат; КонецФункции // ТолькоПустые - заполнять только ранее не заполненные свойства Функция ЗаполнитьСвойстваСИменамиМетаданных(ВыбраннаяСтрока, Принудительно = Ложь) Экспорт Если Не Принудительно И ВыбраннаяСтрока.СвойстваСИменамиМетаданныхАктуальны Тогда Возврат Ложь; КонецЕсли; Попытка Инфобаза = ВыбраннаяСтрока.Инфобаза; Исключение Инфобаза = ""; КонецПопытки; ЧужаяСхемаБД = ирОбщий.ПолучитьЧужуюСхемуБДЛкс(мАдресЧужойСхемыБД); ЭтоГарантированоСобытиеВыбраннойЧужойБазы = Истина И ЗначениеЗаполнено(Инфобаза) И ЧужаяСхемаБД <> Неопределено И ирОбщий.СтрокиРавныЛкс(Инфобаза, НСтр(ЧужаяСхемаБД.СтрокаСоединения, "Ref")); ЭтоГарантированоСобытиеСобственнойБазы = Истина И ЗначениеЗаполнено(Инфобаза) И Не ЭтоГарантированоСобытиеВыбраннойЧужойБазы И ирОбщий.СтрокиРавныЛкс(Инфобаза, НСтр(СтрокаСоединенияИнформационнойБазы(), "Ref")); НайденныеТаблицы = Новый ТаблицаЗначений; Для Каждого КлючИЗначение Из мСвойстваСИменамиБД Цикл ИмяСвойства = КлючИЗначение.Ключ; Если Найти(ИмяСвойства, "Шаблон") > 0 Тогда Продолжить; КонецЕсли; Попытка Пустышка = ТипЗнч(ВыбраннаяСтрока[ИмяСвойства]); // т.к. строки длинные, то их копирование в новую переменную накладно Исключение // Такого свойства нет - пропускаем Продолжить; КонецПопытки; ЗначениеСвойства = ВыбраннаяСтрока[ИмяСвойства]; // Берем только имя базы, т.к. кластер может быть по-разному написан Если Истина И ЗначениеЗаполнено(ЗначениеСвойства) И (Ложь Или Инфобаза = "" Или ЭтоГарантированоСобытиеСобственнойБазы Или ЭтоГарантированоСобытиеВыбраннойЧужойБазы) Тогда ЛиМенаБД = КлючИЗначение.Значение; Если Не ЛиМенаБД Тогда ТипСУБД = ""; Иначе Попытка ТипСУБД = ВыбраннаяСтрока.Событие; Исключение ТипСУБД = Сред(ИмяСвойства, СтрДлина("Текст") + 1); // Опасно КонецПопытки; КонецЕсли; //Попытка ТекстМета = ПеревестиТекстБДВТерминыМетаданных(ЗначениеСвойства, , , ТипСУБД, НайденныеТаблицы,, Ложь,, ЭтоГарантированоСобытиеСобственнойБазы); //Исключение // ТекстМета = ""; //КонецПопытки; //Если ТекстМета <> "" Тогда ВыбраннаяСтрока[ИмяСвойства + "Мета"] = ТекстМета; //КонецЕсли; Иначе // База чужая. Не делаем преобразования //ВыбраннаяСтрока[ИмяСвойства + "Мета"] = ЗначениеСвойства; КонецЕсли; КонецЦикла; Если НайденныеТаблицы.Количество() > 0 Тогда НайденныеТаблицы.Свернуть("ИмяМета"); НайденныеТаблицы.Сортировать("ИмяМета"); мНепустыеКолонкиЖурнала.Вставить("ТаблицыМетаданных"); ИменаТаблицСтрокой = ирОбщий.СтрСоединитьЛкс(НайденныеТаблицы.ВыгрузитьКолонку("ИмяМета")); Попытка ВыбраннаяСтрока.ТаблицыМетаданных = ИменаТаблицСтрокой; Исключение // Строка итогов БлокировкиУпр КонецПопытки; КонецЕсли; Попытка ТекстSDBLШаблонМета = ВыбраннаяСтрока.ТекстSDBLШаблонМета; Исключение ТекстSDBLШаблонМета = Неопределено; КонецПопытки; Если ТекстSDBLШаблонМета <> Неопределено Тогда Инфобаза = ""; ТекстSDBLМета = ""; Попытка Инфобаза = ВыбраннаяСтрока.Инфобаза; ТекстSDBLМета = ВыбраннаяСтрока.ТекстSDBLМета; Исключение КонецПопытки; Если Ложь Или Инфобаза = "" Или ЭтоГарантированоСобытиеСобственнойБазы Или ЭтоГарантированоСобытиеВыбраннойЧужойБазы Тогда Если Истина И ТекстSDBLМета <> "" Тогда ВыбраннаяСтрока.ТекстSDBLШаблонМета = ПолучитьШаблонТекстаБД(ТекстSDBLМета); Иначе ВыбраннаяСтрока.ТекстSDBLШаблонМета = ПеревестиТекстБДВТерминыМетаданных(ВыбраннаяСтрока.ТекстSDBLШаблон,,,,,, Ложь,, ЭтоГарантированоСобытиеСобственнойБазы); КонецЕсли; КонецЕсли; КонецЕсли; Попытка ТекстСУБДШаблонМета = ВыбраннаяСтрока.ТекстСУБДШаблонМета; Исключение ТекстСУБДШаблонМета = Неопределено; КонецПопытки; Если ТекстСУБДШаблонМета <> Неопределено Тогда Инфобаза = ""; ТекстСУБДМета = ""; Попытка Инфобаза = ВыбраннаяСтрока.Инфобаза; ТекстСУБДМета = ВыбраннаяСтрока.ТекстСУБДМета; Исключение КонецПопытки; Если Ложь Или Инфобаза = "" Или ЭтоГарантированоСобытиеСобственнойБазы Или ЭтоГарантированоСобытиеВыбраннойЧужойБазы Тогда Если Истина И ТекстСУБДМета <> "" Тогда ВыбраннаяСтрока.ТекстСУБДШаблонМета = ПолучитьШаблонТекстаБД(ТекстСУБДМета); Иначе ВыбраннаяСтрока.ТекстСУБДШаблонМета = ПеревестиТекстБДВТерминыМетаданных(ВыбраннаяСтрока.ТекстСУБДШаблон,,, мТипСУБД,,, Ложь,, ЭтоГарантированоСобытиеСобственнойБазы); КонецЕсли; КонецЕсли; КонецЕсли; ВыбраннаяСтрока.СвойстваСИменамиМетаданныхАктуальны = Истина; Возврат Истина; КонецФункции Функция ПолучитьКаталогТекущегоЖурнала(НаСервере) Экспорт Результат = ирОбщий.КаталогЧтенияТехножурналаЛкс(НаСервере, Истина, мЛиТрассаПоПользователю); Если Не ЗначениеЗаполнено(Результат) Тогда Если НаСервере Тогда ТекстКлиентСервер = "сервера"; Иначе ТекстКлиентСервер = "клиента"; КонецЕсли; ирОбщий.СообщитьЛкс("Технологический журнал " + ТекстКлиентСервер + " выключен. Невозможно определить каталог журнала по умолчанию."); Возврат Неопределено; КонецЕсли; Если НаСервере Тогда КлиентЗапущенНаКомпьютереСервера = ирОбщий.ЛиКлиентЗапущенНаКомпьютереСервераЛкс(); Если Не КлиентЗапущенНаКомпьютереСервера Тогда Если ЭтоЛокальныйПутьЛкс(Результат) Тогда ирОбщий.СообщитьЛкс("Клиент запущен не на компьютере сервера (" + ирСервер.ИмяКомпьютераЛкс() + "), а в серверной настройке техножурнала указан локальный каталог. Необходимо указать сетевой путь к техножурналу сервера"); #Если Клиент Тогда ФормаНастройки = ПолучитьФорму("НастройкаЧтения"); РезультатНастройки = ФормаНастройки.ОткрытьМодально(); Если РезультатНастройки = Истина Тогда Если мЛиТрассаПоПользователю Тогда Результат = ирОбщий.ВосстановитьЗначениеЛкс("ирАнализТехножурнала.КаталогТрассыПоПользователю"); Иначе Результат = ирОбщий.ВосстановитьЗначениеЛкс("ирАнализТехножурнала.КаталогЖурналаСервера"); КонецЕсли; Иначе Результат = Неопределено; КонецЕсли; #КонецЕсли КонецЕсли; КонецЕсли; КонецЕсли; Возврат Результат; КонецФункции Функция ЭтоЛокальныйПутьЛкс(Путь) Экспорт ЭтоЛокальныйРесурс = Ложь Или Найти(НРег(Путь), "\\localhost") = 1 Или Найти(НРег(Путь), "\\127.0.0.1") = 1 Или Лев(Путь, 2) <> "\\"; Возврат ЭтоЛокальныйРесурс; КонецФункции // ЭтоЛокальныйПуть() Функция ОткрытьСПараметрами(пКаталогЖурнала) Экспорт Форма = ПолучитьФорму(); Форма.Открыть(); ЭтотОбъект.ЗагружатьТолькоТекущийСеанс = Ложь; ЭтотОбъект.ЗагружатьЖурналСервера = Ложь; ЭтотОбъект.ЗагружатьЖурналКлиента = Ложь; Форма.ОбновитьДоступность(); Форма.КаталогЖурнала = пКаталогЖурнала; Возврат Форма; КонецФункции Функция ОткрытьСОтбором(НачалоПериода = Неопределено, КонецПериода = Неопределено, СтруктураОтбора = Неопределено) Экспорт Форма = ПолучитьФорму(,,); Форма.Открыть(); Отбор = Форма.ЭлементыФормы.ТаблицаЖурнала.ОтборСтрок; Отбор.Сбросить(); Если НачалоПериода <> Неопределено Тогда Форма.НачалоПериода = НачалоПериода; КонецЕсли; Если КонецПериода <> Неопределено Тогда Форма.КонецПериода = КонецПериода; КонецЕсли; Если СтруктураОтбора <> Неопределено Тогда Для Каждого КлючИЗначение Из СтруктураОтбора Цикл Отбор[КлючИЗначение.Ключ].Установить(КлючИЗначение.Значение); КонецЦикла; КонецЕсли; Возврат Форма; КонецФункции Функция ПолучитьИмяСвойстваБезМета(Знач МестноеИмя) Экспорт Если ирОбщий.СтрокиРавныЛкс(Прав(МестноеИмя, 4), "мета") Тогда МестноеИмя = Лев(МестноеИмя, СтрДлина(МестноеИмя) - 4); КонецЕсли; Возврат МестноеИмя; КонецФункции Процедура ОбновитьСвойстваВТерминахМетаданных() Экспорт ВыбранныеСтроки = мТаблицаЖурнала.НайтиСтроки(Новый Структура("СвойстваСИменамиМетаданныхАктуальны", Ложь)); Индикатор = ирОбщий.ПолучитьИндикаторПроцессаЛкс(ВыбранныеСтроки.Количество(), "Перевод в термины метаданных"); Для Каждого СтрокаТаблицыЖурнала Из ВыбранныеСтроки Цикл ирОбщий.ОбработатьИндикаторЛкс(Индикатор); ЗаполнитьСвойстваСИменамиМетаданных(СтрокаТаблицыЖурнала); КонецЦикла; ирОбщий.ОсвободитьИндикаторПроцессаЛкс(); КонецПроцедуры Процедура ОбновитьСтрокиБазовогоУровня() Экспорт //Индикатор = ирОбщий.ПолучитьИндикаторПроцессаЛкс(мТаблицаЖурнала.Количество()); Для Каждого СтрокаТаблицыЖурнала Из мТаблицаЖурнала Цикл //ирОбщий.ОбработатьИндикаторЛкс(Индикатор); ЗаполнитьСтрокуБазовогоУровня(СтрокаТаблицыЖурнала); КонецЦикла; //Для Каждого СтрокаКонтекста Из Контексты Цикл // ЗаполнитьСтрокуБазовогоУровня(СтрокаКонтекста); //КонецЦикла; КонецПроцедуры Функция ПолучитьШаблонТекстаБД(ТекстБД, Знач ЗаменаПеременныхФрагментов = "7") Экспорт #Если Сервер И Не Сервер Тогда RegExpПараметры = Обработки.ирОболочкаРегВыражение.Создать(); #КонецЕсли СложнаяЗамена = RegExpПараметры.ТекущийДвижок() = "PCRE2"; Если СложнаяЗамена Тогда // https://www.hostedredmine.com/issues/928414 Префикс = "[!@!~=+]"; ЗаменаПеременныхФрагментов = Префикс + ЗаменаПеременныхФрагментов; КонецЕсли; ШаблонТекстаБД = RegExpПараметры.Заменить(ТекстБД, "$1$2" + ЗаменаПеременныхФрагментов); Если СложнаяЗамена Тогда ШаблонТекстаБД = СтрЗаменить(ШаблонТекстаБД, Префикс, ""); КонецЕсли; Возврат ШаблонТекстаБД; КонецФункции Процедура ЗаполнитьСвойстваШаблоны() Экспорт Индикатор = ирОбщий.ПолучитьИндикаторПроцессаЛкс(ТаблицаЖурнала.Количество()); Для Каждого СтрокаТаблицыЖурнала Из ТаблицаЖурнала Цикл ирОбщий.ОбработатьИндикаторЛкс(Индикатор); Если Истина И СтрокаТаблицыЖурнала.ТекстSDBL <> "" И СтрокаТаблицыЖурнала.ТекстSDBLШаблон = "" Тогда СтрокаТаблицыЖурнала.ТекстSDBLШаблон = ПолучитьШаблонТекстаБД(СтрокаТаблицыЖурнала.ТекстSDBL); КонецЕсли; Если Истина И СтрокаТаблицыЖурнала.ТекстСУБД <> "" И СтрокаТаблицыЖурнала.ТекстСУБДШаблон = "" Тогда СтрокаТаблицыЖурнала.ТекстСУБДШаблон = ПолучитьШаблонТекстаБД(СтрокаТаблицыЖурнала.ТекстСУБД); КонецЕсли; Если Истина И СтрокаТаблицыЖурнала.Описание <> "" И СтрокаТаблицыЖурнала.ОписаниеШаблон = "" Тогда СтрокаТаблицыЖурнала.ОписаниеШаблон = ПолучитьШаблонТекстаБД(СтрокаТаблицыЖурнала.Описание); КонецЕсли; КонецЦикла; КонецПроцедуры Процедура ОставитьТолькоСтрокиПоОтбору(СтруктураОтбора) Экспорт НужныеСтроки = ТаблицаЖурнала.НайтиСтроки(СтруктураОтбора); КоличествоСтрок = ТаблицаЖурнала.Количество(); Для Счетчик = 1 По КоличествоСтрок Цикл Индекс = КоличествоСтрок - Счетчик; СтрокаЖурнала = ТаблицаЖурнала[Индекс]; Если НужныеСтроки.Найти(СтрокаЖурнала) = Неопределено Тогда ТаблицаЖурнала.Удалить(СтрокаЖурнала); КонецЕсли; КонецЦикла; КонецПроцедуры Процедура УдалитьСтрокиПоОтборуЛкс(СтруктураОтбора) Экспорт НенужныеСтроки = мТаблицаЖурнала.НайтиСтроки(СтруктураОтбора); Для Каждого НенужнаяСтрока Из НенужныеСтроки Цикл мТаблицаЖурнала.Удалить(НенужнаяСтрока); КонецЦикла; КонецПроцедуры Процедура ЗаписатьМаркерВТехножурнал(Маркер, ДляКлиента = Истина, ДляСервера = Истина, выхТекущаяДатаКлиента = Неопределено, выхТекущаяДатаСервера = Неопределено) Экспорт ЗапросМаркер = Новый Запрос(); выхТекущаяДатаКлиента = ТекущаяДата(); выхТекущаяДатаСервера = выхТекущаяДатаКлиента; Если ДляКлиента Тогда ЗапросМаркер.Текст = Маркер; Попытка ЗапросМаркер.Выполнить(); // Генерируем для клиента маркер-событие QERR Исключение КонецПопытки; КонецЕсли; Если Истина И ДляСервера И Не ирКэш.ЛиФайловаяБазаЛкс() Тогда Если Не ирКэш.ЛиПортативныйРежимЛкс() Тогда Попытка ирСервер.ВыполнитьЗапросЛкс(Маркер,,,, выхТекущаяДатаСервера); // Генерируем для сервера маркер-событие QERR Исключение КонецПопытки; Иначе ЗапросМаркер.Текст = "ВЫБРАТЬ """ + Маркер + """"; Попытка ЗапросМаркер.Выполнить(); // Генерируем для клиента маркер-событие SDBL Исключение // Может возникнуть ошибка "В данной транзакции уже происходили ошибки!" КонецПопытки; КонецЕсли; КонецЕсли; КонецПроцедуры Функция ИдентификаторТрассыБД() Экспорт ДатаМиллисекунды = ТекущаяУниверсальнаяДатаВМиллисекундах(); Генератор = Новый ГенераторСлучайныхЧисел(ДатаМиллисекунды); СгенерированноеЧисло = Генератор.СлучайноеЧисло(100000000, 900000000); Возврат СгенерированноеЧисло; КонецФункции Функция НачатьТрассу(ПрефиксТрассы = "", ВыводитьСообщения = Ложь, выхТекущаяДатаСервера = Неопределено) Экспорт Если ВыводитьСообщения Тогда // Попробовать сделать проверку регистрации событий QERR в настройке техножурнала на сервере // Вызовы ЛиТехножурналВключенЛкс могут быть очень долгими, если в анализе техножурнала пользователь сохранил сетевой путь к логам на сервере и он недоступен Если Не ирКэш.ЛиФайловаяБазаЛкс() Тогда ТехножурналСервераВключен = ирОбщий.ЛиТехножурналВключенЛкс(Истина, ВыводитьСообщения,, мЛиТрассаПоПользователю); КонецЕсли; ТехножурналКлиентаВключен = ирОбщий.ЛиТехножурналВключенЛкс(, ВыводитьСообщения,, мЛиТрассаПоПользователю); Если Истина И ТехножурналСервераВключен <> Истина И Не ТехножурналКлиентаВключен Тогда Возврат Ложь; КонецЕсли; КонецЕсли; ЭтотОбъект.КонецПериодаСервера = Неопределено; ЭтотОбъект.КонецПериодаКлиента = Неопределено; ИспользоватьТрассуСУБД = Истина И ирОбщий.ПараметрыСоединенияADOЭтойБДЛкс().СобиратьТрассу = Истина #Если Клиент Тогда И ирКлиент.ЛиПровайдерАДОДляЭтойБазыГотовЛкс() #КонецЕсли И ЛиСерверMSSQLПоддерживаетТрассировку(); мИдентификаторТрассы = ПрефиксТрассы + "_" + СтрЗаменить(Новый УникальныйИдентификатор(), "-", ""); ЗаписатьМаркерВТехножурнал("НачалоТрассы_" + мИдентификаторТрассы,,, НачалоПериодаКлиента, НачалоПериодаСервера); выхТекущаяДатаСервера = НачалоПериодаСервера; мУдержательСоединенияБД = Неопределено; мИдентификаторСоединенияБД = Неопределено; Если ИспользоватьТрассуСУБД Тогда // https://www.hostedredmine.com/issues/926150 мИдентификаторБазыДанных = ИдентификаторБазыДанных(); ТекстЗапроса = ПолучитьМакет("SQLServer_СкриптОчисткиДанных").ПолучитьТекст(); ирОбщий.ВыполнитьЗапросКЭтойБазеЧерезADOЛкс(ТекстЗапроса,,,,,, мСоединениеАДО); ИдентификаторТрассы = XMLСтрока(ИдентификаторТрассыБД()); ИдентификаторСессии = XMLСтрока(НомерСеансаИнформационнойБазы()); ЗапросСозданияСессии = ПолучитьМакет("SQLServer_СкриптСессииОпределенияСессииСУБД").ПолучитьТекст(); ЗапросСозданияСессии = ирОбщий.СтрЗаменитьЛкс(ЗапросСозданияСессии, "{ИдентификаторСессии}", ИдентификаторСессии); ЗапросСозданияСессии = ирОбщий.СтрЗаменитьЛкс(ЗапросСозданияСессии, "{ИдентификатоЗапроса}", XMLСтрока(ИдентификаторТрассы)); ЗапросСозданияСессии = ирОбщий.СтрЗаменитьЛкс(ЗапросСозданияСессии, "{ИдентификаторБазыДанных}", мИдентификаторБазыДанных); ирОбщий.ВыполнитьЗапросКЭтойБазеЧерезADOЛкс(ЗапросСозданияСессии,,,,,, мСоединениеАДО); мУдержательСоединенияБД = Новый МенеджерВременныхТаблиц; ЗапросУдержаниеСоединения = Новый Запрос; ЗапросУдержаниеСоединения.МенеджерВременныхТаблиц = мУдержательСоединенияБД; ЗапросУдержаниеСоединения.Текст = "ВЫБРАТЬ ПЕРВЫЕ " + ИдентификаторТрассы + " | " + ИдентификаторТрассы + " КАК Число, | 0293843834892983011884662710842 КАК ДополнительноеЧисло |ПОМЕСТИТЬ ВТ_ПроизвольныеЗначения"; ЗапросУдержаниеСоединения.Выполнить(); ЗапросДанныеСессии = ПолучитьМакет("SQLServer_СкриптПолученияДанныхРасширенныхСобытий").ПолучитьТекст(); ЗапросДанныеСессии = ирОбщий.СтрЗаменитьЛкс(ЗапросДанныеСессии, "{ИмяСессии}", "getSessionForQuery"); ЗапросДанныеСессии = ирОбщий.СтрЗаменитьЛкс(ЗапросДанныеСессии, "{ИдентификаторСессии}", ИдентификаторСессии); РезультатЗапроса = ирОбщий.ВыполнитьЗапросКЭтойБазеЧерезADOЛкс(ЗапросДанныеСессии,,,,,, мСоединениеАДО); Для Каждого СтрокаРезультата Из РезультатЗапроса Цикл ЧтениеXML = Новый ЧтениеXML; ЧтениеXML.УстановитьСтроку(СтрокаРезультата.Data); ПостроительDOM = Новый ПостроительDOM; ДокументDOM = ПостроительDOM.Прочитать(ЧтениеXML); Разыменователь = Новый РазыменовательПространствИменDOM(ДокументDOM); НайденныеСобытия = ДокументDOM.ВычислитьВыражениеXPath("/RingBufferTarget/event", ДокументDOM, Разыменователь, ТипРезультатаDOMXPath.Любой); УзелСобытие = НайденныеСобытия.ПолучитьСледующий(); Пока УзелСобытие <> Неопределено Цикл СвойстваСобытия = Новый Соответствие; Для Каждого ЭлементСобытия Из УзелСобытие.ДочерниеУзлы Цикл ИмяСвойства = СокрЛП(ЭлементСобытия.Атрибуты.ПолучитьИменованныйЭлемент("name").Значение); ЗначениеСвойства = СокрЛП(ЭлементСобытия.ПоследнийДочерний.ТекстовоеСодержимое); Если Не ЗначениеЗаполнено(ЗначениеСвойства) Тогда ЗначениеСвойства = СокрЛП(ЭлементСобытия.ТекстовоеСодержимое); КонецЕсли; СвойстваСобытия.Вставить(ИмяСвойства, ЗначениеСвойства); КонецЦикла; ТекстЗапроса = СвойстваСобытия["batch_text"]; Если Не ЗначениеЗаполнено(ТекстЗапроса) Тогда ТекстЗапроса = СвойстваСобытия["statement"]; КонецЕсли; Если Не ЗначениеЗаполнено(ТекстЗапроса) Тогда ТекстЗапроса = СвойстваСобытия["sql_text"]; КонецЕсли; Если Найти(ТекстЗапроса, "CREATE EVENT SESSION") > 0 Тогда УзелСобытие = НайденныеСобытия.ПолучитьСледующий(); Продолжить; ИначеЕсли Найти(ТекстЗапроса, ИдентификаторТрассы) > 0 Тогда мИдентификаторСоединенияБД = СвойстваСобытия["session_id"]; Прервать; КонецЕсли; УзелСобытие = НайденныеСобытия.ПолучитьСледующий(); КонецЦикла; КонецЦикла; ЗапросУдалениеСессии = ПолучитьМакет("SQLServer_СкриптУдаленияСессииСбораДанных").ПолучитьТекст(); ЗапросУдалениеСессии = ирОбщий.СтрЗаменитьЛкс(ЗапросУдалениеСессии, "{ИмяСессии}", "getSessionForQuery"); ЗапросУдалениеСессии = ирОбщий.СтрЗаменитьЛкс(ЗапросУдалениеСессии, "{ИдентификаторСессии}", ИдентификаторСессии); ирОбщий.ВыполнитьЗапросКЭтойБазеЧерезADOЛкс(ЗапросУдалениеСессии,,,,,, мСоединениеАДО); Если Не ЗначениеЗаполнено(мИдентификаторСоединенияБД) Тогда мУдержательСоединенияБД = Неопределено; ирОбщий.СообщитьЛкс("Не удалось определить идентификатор соединения СУБД. Трасса СУБД будет недоступна."); КонецЕсли; Если мИдентификаторСоединенияБД <> Неопределено Тогда ЗапросСозданияСессии = ПолучитьМакет("SQLServer_СкриптСбораДанныхОЗапросах").ПолучитьТекст(); ЗапросСозданияСессии = ирОбщий.СтрЗаменитьЛкс(ЗапросСозданияСессии, "{ИдентификаторСессии}", ИдентификаторСессии); ЗапросСозданияСессии = ирОбщий.СтрЗаменитьЛкс(ЗапросСозданияСессии, "{ИдентификаторСоединения}", XMLСтрока(мИдентификаторСоединенияБД)); ЗапросСозданияСессии = ирОбщий.СтрЗаменитьЛкс(ЗапросСозданияСессии, "{ИдентификаторБазыДанных}", мИдентификаторБазыДанных); ирОбщий.ВыполнитьЗапросКЭтойБазеЧерезADOЛкс(ЗапросСозданияСессии,,,,,, мСоединениеАДО); КонецЕсли; КонецЕсли; Возврат Истина; КонецФункции Функция ИдентификаторБазыДанных() Если мИдентификаторБазыДанных <> Неопределено Тогда Возврат мИдентификаторБазыДанных; КонецЕсли; РезультатЗапроса = ирОбщий.ВыполнитьЗапросКЭтойБазеЧерезADOЛкс("SELECT DB_ID() AS DatabaseId",,,,,, мСоединениеАДО); мИдентификаторБазыДанных = РезультатЗапроса[0][0]; Возврат мИдентификаторБазыДанных; КонецФункции Функция ЛиСерверMSSQLПоддерживаетТрассировку() Экспорт Если мЛиСерверMSSQLПоддерживаетТрассировку <> Неопределено Тогда Возврат мЛиСерверMSSQLПоддерживаетТрассировку; КонецЕсли; мЛиСерверMSSQLПоддерживаетТрассировку = Ложь; РезультатЗапроса = ирОбщий.ВыполнитьЗапросКЭтойБазеЧерезADOЛкс("SELECT @@VERSION AS SQLServerVersion",,,,,, мСоединениеАДО); Если РезультатЗапроса <> Неопределено Тогда ВерсияСУБД = РезультатЗапроса[0][0]; Если Найти(ВерсияСУБД, "Microsoft SQL Server 2008") = 0 Тогда мЛиСерверMSSQLПоддерживаетТрассировку = Истина; КонецЕсли; КонецЕсли; Возврат мЛиСерверMSSQLПоддерживаетТрассировку; КонецФункции Функция КончитьТрассу(выхТекущаяДатаСервера = Неопределено) Экспорт Если ЗначениеЗаполнено(ЭтотОбъект.КонецПериодаКлиента) Тогда Возврат Ложь; КонецЕсли; Если мИдентификаторСоединенияБД <> Неопределено Тогда Попытка ИдентификаторСессии = XMLСтрока(НомерСеансаИнформационнойБазы()); ЗапросДанныеСессии = ПолучитьМакет("SQLServer_СкриптПолученияДанныхРасширенныхСобытий").ПолучитьТекст(); ЗапросДанныеСессии = ирОбщий.СтрЗаменитьЛкс(ЗапросДанныеСессии, "{ИмяСессии}", "getQueriesInfo"); ЗапросДанныеСессии = ирОбщий.СтрЗаменитьЛкс(ЗапросДанныеСессии, "{ИдентификаторСессии}", ИдентификаторСессии); РезультатБД = ирОбщий.ВыполнитьЗапросКЭтойБазеЧерезADOЛкс(ЗапросДанныеСессии,,,,,, мСоединениеАДО); Если РезультатБД.Количество() = 0 Тогда ирОбщий.СообщитьЛкс("Трасса СУБД пуста. Вероятно была получена другим экземляром инструмента."); Иначе мТрассаСУБДXML = РезультатБД[0][0]; КонецЕсли; Исключение ирОбщий.СообщитьЛкс(ОписаниеОшибки()); КонецПопытки; ТекстЗапроса = ПолучитьМакет("SQLServer_СкриптОчисткиДанных").ПолучитьТекст(); ирОбщий.ВыполнитьЗапросКЭтойБазеЧерезADOЛкс(ТекстЗапроса,,,,,, мСоединениеАДО); КонецЕсли; ЗаписатьМаркерВТехножурнал("КонецТрассы_" + мИдентификаторТрассы,,, КонецПериодаКлиента, КонецПериодаСервера); выхТекущаяДатаСервера = КонецПериодаСервера; мУдержательСоединенияБД = Неопределено; мИдентификаторСоединенияБД = Неопределено; Возврат Истина; КонецФункции Процедура ЗагрузитьТрассуСУБД() Экспорт Если Не ЗначениеЗаполнено(мТрассаСУБДXML) Тогда Возврат; КонецЕсли; ИдентификаторСессии = XMLСтрока(НомерСеансаИнформационнойБазы()); НомерПоПорядку = 1; ЧтениеXML = Новый ЧтениеXML; ЧтениеXML.УстановитьСтроку(мТрассаСУБДXML); ПостроительDOM = Новый ПостроительDOM; ДокументDOM = ПостроительDOM.Прочитать(ЧтениеXML); Разыменователь = Новый РазыменовательПространствИменDOM(ДокументDOM); РезультатПоискаСобытий = ДокументDOM.ВычислитьВыражениеXPath("/RingBufferTarget/event", ДокументDOM, Разыменователь, ТипРезультатаDOMXPath.Любой); МассивОператоров = Новый Массив; МассивИДПланов = Новый Массив; УзелСобытие = РезультатПоискаСобытий.ПолучитьСледующий(); НачальныйИндексСтроки = мТаблицаЖурнала.Количество(); Пока УзелСобытие <> Неопределено Цикл ИмяСобытия = СокрЛП(УзелСобытие.Атрибуты.ПолучитьИменованныйЭлемент("name").ТекстовоеСодержимое); СвойстваСобытия = Новый Соответствие; Для Каждого ЭлементСобытия Из УзелСобытие.ДочерниеУзлы Цикл ИмяСвойства = СокрЛП(ЭлементСобытия.Атрибуты.ПолучитьИменованныйЭлемент("name").Значение); ЗначениеСвойства = СокрЛП(ЭлементСобытия.ПоследнийДочерний.ТекстовоеСодержимое); Если НЕ ЗначениеЗаполнено(ЗначениеСвойства) Тогда ЗначениеСвойства = СокрЛП(ЭлементСобытия.ТекстовоеСодержимое); КонецЕсли; СвойстваСобытия.Вставить(ИмяСвойства, ЗначениеСвойства); КонецЦикла; ТекстЗапроса = СвойстваСобытия["statement"]; Если НЕ ЗначениеЗаполнено(ТекстЗапроса) Тогда ТекстЗапроса = СвойстваСобытия["batch_text"]; КонецЕсли; Если НЕ ЗначениеЗаполнено(ТекстЗапроса) Тогда ТекстЗапроса = СвойстваСобытия["sql_text"]; КонецЕсли; Если Найти(ТекстЗапроса, "CREATE EVENT SESSION") > 0 Тогда УзелСобытие = РезультатПоискаСобытий.ПолучитьСледующий(); Продолжить; КонецЕсли; Если ИмяСобытия = "rpc_completed" ИЛИ ИмяСобытия = "sql_batch_completed" Тогда КонецМилисекунды = ""; ДатаСобытияСтрока = СокрЛП(УзелСобытие.Атрибуты.ПолучитьИменованныйЭлемент("timestamp").ТекстовоеСодержимое); ДатаСобытияСтрока = ирОбщий.ПервыйФрагментЛкс(ДатаСобытияСтрока, "Z"); ДатаСобытия = МестноеВремя(ПреобразоватьКДате(ДатаСобытияСтрока, КонецМилисекунды)); ДлительностьМикросекунд = СвойстваСобытия["duration"]; ДатаНачала = ДатаСобытия - Цел(ДлительностьМикросекунд / 1000000); МоментВремени = Формат(ДатаСобытия, "ДФ=ггггММддЧЧммсс") + КонецМилисекунды + Формат(НомерПоПорядку, "ЧЦ=3; ЧВН="); НачалоМилисекунды = КонецМилисекунды - Цел(ДлительностьМикросекунд / 1000); Если НачалоМилисекунды < 0 Тогда ДатаНачала = ДатаНачала - 1; НачалоМилисекунды = 1000 + НачалоМилисекунды; КонецЕсли; МоментВремениНачала = Формат(ДатаНачала, "ДФ=ггггММддЧЧммсс") + НачалоМилисекунды + Формат(НомерПоПорядку, "ЧЦ=3; ЧВН="); СтрокаТаблицы = мТаблицаЖурнала.Добавить(); СтрокаТаблицы.МоментВремени = МоментВремени; СтрокаТаблицы.Дата = ДатаСобытия; СтрокаТаблицы.ДатаНачала = ДатаНачала; СтрокаТаблицы.Длительность = ДлительностьМикросекунд / 1000; СтрокаТаблицы.НаСервере = Истина; СтрокаТаблицы.ТипПроцессаОС = "sqlservr"; СтрокаТаблицы.МоментВремениНачала = МоментВремениНачала; СтрокаТаблицы.CPUTime = СвойстваСобытия["cpu_time"] / 1000; СтрокаТаблицы.ЛогическиПрочитано = СвойстваСобытия["logical_reads"]; СтрокаТаблицы.ФизическиПрочитано = СвойстваСобытия["physical_reads"]; СтрокаТаблицы.ЛогическиЗаписано = СвойстваСобытия["writes"]; //СтрокаТаблицы.ИмяОбъекта = СвойстваСобытия["object_name"]; //СтрокаТаблицы.Приложение = СвойстваСобытия["client_app_name"]; //СтрокаТаблицы.ИдентификаторЯдраПроцессора = СвойстваСобытия["cpu_id"]; //СтрокаТаблицы.Соединение_ = СвойстваСобытия["client_pid"]; //СтрокаТаблицы.Системный = ПреобразоватьКБулево(СвойстваСобытия["is_system"]); СтрокаТаблицы.ЧислоСтрок = СвойстваСобытия["row_count"]; СтрокаТаблицы.ТекстСУБД = ТекстЗапроса; Если МассивОператоров.Количество() = 1 Тогда ИдентификаторПланаЗапроса = МассивОператоров.Получить(0).Получить("plan_handle"); НачалоИдентификатораПланаЗапроса = " = @([\w]+) ([^']+?)(?='|$|,@) // + <шКорень> = exec sp_executesql N'([^']+)',N'((?:<шТипПараметра>,)*<шТипПараметра>)'((?:,<шЗначениеПараметра>)+) // {Шаблон.Конец} шЗначениеПараметра = "(N?'([^']*)'|[^',]+)"; шТипПараметра = "@([\w]+) ([^']+?)(?='|$|,@)"; шКорень = "exec sp_executesql N'([^']+)',N'((?:" + шТипПараметра + ",)*" + шТипПараметра + ")'((?:," + шЗначениеПараметра + ")+)"; // {ОписаниеРегулярногоВыражения.Конец} Вхождения = ирОбщий.НайтиРегулярноеВыражениеЛкс(Текст, шКорень, "ТекстЗапроса, ТипыПараметров", Ложь,,, Ложь); #Если Сервер И Не Сервер Тогда Вхождения = Обработки.ирПлатформа.Создать().ВхожденияРегВыражения; #КонецЕсли Для каждого Вхождение Из Вхождения Цикл Текст = Вхождение.ТекстЗапроса; ВложенныеВхождения = ирОбщий.НайтиРегулярноеВыражениеЛкс(Вхождение.ТипыПараметров, шТипПараметра, "Имя, Тип",,,, Ложь); #Если Сервер И Не Сервер Тогда Вхождения = Обработки.ирПлатформа.Создать().ВхожденияРегВыражения; #КонецЕсли Для каждого ВложенноеВхождение Из ВложенныеВхождения Цикл СтрокаПараметра = ТаблицаПараметров.Добавить(); СтрокаПараметра.Имя = ВложенноеВхождение.Имя; СтрокаПараметра.Метаданные = ВложенноеВхождение.Тип; КонецЦикла; ВложенныеВхождения = ирОбщий.НайтиРегулярноеВыражениеЛкс(Вхождение.Подгруппы[6], шЗначениеПараметра,,,,, Ложь); #Если Сервер И Не Сервер Тогда Вхождения = Обработки.ирПлатформа.Создать().ВхожденияРегВыражения; #КонецЕсли ИндексПараметра = 0; Для каждого ВложенноеВхождение Из ВложенныеВхождения Цикл СтрокаПараметра = ТаблицаПараметров[ИндексПараметра]; ИндексПараметра = ИндексПараметра + 1; СтрокаПараметра.Значение = ВложенноеВхождение.ТекстВхождения; КонецЦикла; КонецЦикла; КонецЕсли; Иначе RegExp.Pattern = "([A-F0-9]+):([A-F0-9]+|0x[A-F0-9]+)"; // замена ссылочных констант Вхождения = RegExp.НайтиВхождения(Текст); Для Каждого Вхождение Из Вхождения Цикл ЗначениеSDBL = Вхождение.Value; Если СтрДлина(ЗначениеSDBL) < 32 Тогда // Защита от частей литерала Дата Продолжить; КонецЕсли; Если ТаблицаПараметров.Найти(ЗначениеSDBL, "ЗначениеSDBL") = Неопределено Тогда шЗначениеПараметра = ирОбщий.ПреобразоватьЗначениеИзSDBLЛкс(ЗначениеSDBL, мАдресЧужойСхемыБД, Истина); СтрокаПараметра = ирОбщий.НайтиДобавитьПараметрСсылкуВТаблицуЛкс(ТаблицаПараметров,,, шЗначениеПараметра); СтрокаПараметра.ЗначениеSDBL = ЗначениеSDBL; ОбъектМД = ирОбщий.ПолучитьМетаданныеЛкс(шЗначениеПараметра); Если ОбъектМД <> Неопределено Тогда СтрокаПараметра.Метаданные = ОбъектМД.ПолноеИмя(); КонецЕсли; Если ПереводитьВМета Тогда Текст = СтрЗаменить(Текст, ЗначениеSDBL, "&" + СтрокаПараметра.Имя); КонецЕсли; КонецЕсли; КонецЦикла; КонецЕсли; Если ЗаменитьHexЛитералы Тогда RegExp.Pattern = "0x[\da-z]+"; // замена значений констант Вхождения = RegExp.НайтиВхождения(Текст); СоответствиеКонстант = Новый Соответствие; Для Каждого Вхождение Из Вхождения Цикл ЗначениеСУБД = Вхождение.Value; Если СоответствиеКонстант[ЗначениеСУБД] = Неопределено Тогда ЗаменаСтроки = "_" + ЗначениеСУБД; СоответствиеКонстант[ЗначениеСУБД] = ЗаменаСтроки; Текст = СтрЗаменить(Текст, ЗначениеСУБД, ЗаменаСтроки); КонецЕсли; КонецЦикла; КонецЕсли; //RegExp.Pattern = "#(T[\d_A-Z]+)"; // имена временных таблиц //Текст = RegExp.Заменить(Текст, "_$1"); RegExp.Pattern = "\{ts '(\d+)-(\d+)-(\d+) (\d+):(\d+):(\d+)'\}"; // литералы Дата DBV8DBEng Текст = RegExp.Заменить(Текст, "DATETIME($1,$2,$3,$4,$5,$6)"); ТаблицаТаблиц = Новый ТаблицаЗначений; Если ПереводитьВМета Тогда RegExp.Pattern = "N'([^']*)'"; // для замены юникодных литералов типа Строка MSSQL Текст = RegExp.Заменить(Текст, """$1"""); КонецЕсли; ТекстМета = ПеревестиТекстБДВТерминыМетаданных(Текст,,, ТипСУБД, ТаблицаТаблиц, 999999, ПеревестиИндексы, ПереводитьВМета); Если Не ПереводитьВМета Тогда ТекстМета = Текст; КонецЕсли; ТаблицаТаблиц.Сортировать("ИмяМета"); ЧастьПараметров = ""; Если ЗначениеЗаполнено(ТипСУБД) Тогда ДиалектSQL = "MSSQL"; ПозицияНачалаПараметров = Найти(ТекстМета, "p_0:"); Если ПозицияНачалаПараметров > 0 Тогда ЧастьПараметров = Сред(ТекстМета, ПозицияНачалаПараметров); ТекстМета = Лев(ТекстМета, ПозицияНачалаПараметров - 1); КонецЕсли; Иначе ДиалектSQL = "1С"; КонецЕсли; ШаблонИмениПараметра = "Parameter"; Если ЗначениеЗаполнено(ЧастьПараметров) Тогда ТекстовыйДокумент = Новый ТекстовыйДокумент; ТекстовыйДокумент.УстановитьТекст(ЧастьПараметров); Для Счетчик = 1 По ТекстовыйДокумент.КоличествоСтрок() Цикл СтрокаПараметра = ТаблицаПараметров.Добавить(); Фрагменты = ирОбщий.СтрРазделитьЛкс(ТекстовыйДокумент.ПолучитьСтроку(Счетчик), ":"); СтрокаПараметра.Имя = СокрЛП(Фрагменты[0]); СтрокаПараметра.Значение = СокрЛП(Фрагменты[1]); КонецЦикла; КонецЕсли; МаркерСтрокиВРодномMSSQL = "N'"; МаркерБинариВРодномMSSQL = "0x"; Для Каждого СтрокаПараметра Из ТаблицаПараметров Цикл Если ТипСУБД = "DBMSSQL" Тогда ЛитералЗначения = СтрокаПараметра.Значение; Если ЗначениеЗаполнено(СтрокаПараметра.Метаданные) Тогда // ТипСобытия = sp_executesql Если ирОбщий.СтрНачинаетсяСЛкс(ЛитералЗначения, МаркерСтрокиВРодномMSSQL) Тогда ЛитералЗначения = ирОбщий.СтрокаБезКонцаЛкс(Сред(ЛитералЗначения, СтрДлина(МаркерСтрокиВРодномMSSQL) + 1), 1); СтрокаПараметра.Значение1С = ЛитералЗначения; ИначеЕсли ирОбщий.СтрНачинаетсяСЛкс(ЛитералЗначения, "'") Тогда ЛитералЗначения = ирОбщий.СтрокаБезКонцаЛкс(Сред(ЛитералЗначения, 2), 1); Попытка СтрокаПараметра.Значение1С = ирОбщий.СтрокаВДатуЛкс(ЛитералЗначения); Исключение Пустышка = 0; КонецПопытки; Иначе Попытка СтрокаПараметра.Значение1С = Число(ЛитералЗначения); Исключение КонецПопытки; КонецЕсли; Иначе // ТипСобытия = DBMSSQL Если Прав(ЛитералЗначения, 1) = "N" Тогда ЛитералЗначения = ирОбщий.СтрокаБезКонцаЛкс(ЛитералЗначения, 1); Попытка СтрокаПараметра.Значение1С = Число(ЛитералЗначения); СтрокаПараметра.Метаданные = Тип("Число"); Исключение Пустышка = 0; КонецПопытки; ИначеЕсли Лев(ЛитералЗначения, 1) = "'" Тогда СтрокаПараметра.Значение1С = Сред(ирОбщий.СтрокаБезКонцаЛкс(ЛитералЗначения, 1), 2); СтрокаПараметра.Метаданные = Тип("Строка"); ИначеЕсли СтрДлина(ЛитералЗначения) = СтрДлина("20010101000000") Тогда ЛитералЗначения = "" + (Число(Лев(ЛитералЗначения, 1)) - 2) + Сред(ЛитералЗначения, 2); Попытка СтрокаПараметра.Значение1С = Дата(ЛитералЗначения); СтрокаПараметра.Метаданные = Тип("Дата"); Исключение Пустышка = 0; КонецПопытки; Иначе СтрокаПараметра.Значение1С = ЛитералЗначения; СтрокаПараметра.Метаданные = Тип("ДвоичныеДанные"); КонецЕсли; КонецЕсли; КонецЕсли; КонецЦикла; // Встроим имена парамаетров вместо знаков "?" ЗаписьXML = Новый ЗаписьXML; ЗаписьXML.УстановитьСтроку(""); ИндексПараметра = 0; СтрокаПоиска = "?"; Пока ТекстМета <> "" Цикл ПозицияПараметра = Найти(ТекстМета, СтрокаПоиска); Если ПозицияПараметра > 0 Тогда Если ИндексПараметра < ТаблицаПараметров.Количество() Тогда СтрокаПараметра = ТаблицаПараметров[ИндексПараметра]; Иначе СтрокаПараметра = ТаблицаПараметров.Добавить(); СтрокаПараметра.Имя = ШаблонИмениПараметра + XMLСтрока(ТаблицаПараметров.Количество()); КонецЕсли; ЗаписьXML.ЗаписатьБезОбработки(Лев(ТекстМета, ПозицияПараметра - 1) + СтрокаПоиска + СтрокаПараметра.Имя); ТекстМета = Сред(ТекстМета, ПозицияПараметра + СтрДлина(СтрокаПоиска)); ИндексПараметра = ИндексПараметра + 1; Иначе ЗаписьXML.ЗаписатьБезОбработки(ТекстМета); ТекстМета = ""; КонецЕсли; КонецЦикла; ТекстМета = ЗаписьXML.Закрыть(); Если Истина И ПересобратьТекст И ЗначениеЗаполнено(ТекстМета) Тогда ПолеТекста = ирОбщий.СоздатьОбъектПоПолномуИмениМетаданныхЛкс("Обработка.ирКлсПолеТекстаПрограммы"); ПолеТекста.ИнициализироватьНеинтерактивно(1); КонструкторЗапроса = ПолеТекста.ПолучитьФорму("КонструкторЗапроса"); КонструкторЗапроса.Английский1С = Не ПереводитьВМета; ИменованныеПараметры = Истина; Если ПолеТекста.ЗагрузитьТекстВКонструктор(ТекстМета, КонструкторЗапроса,, ДиалектSQL, ИменованныеПараметры) Тогда ТекстМета = КонструкторЗапроса.СобратьПолныйТекст(, Истина); КонецЕсли; КонецЕсли; Если ВстраиватьПараметры Тогда ЗаписьXML = Новый ЗаписьXML; ЗаписьXML.УстановитьСтроку(""); ИндексПараметра = 0; Пока ТекстМета <> "" Цикл ПозицияПараметра = 0; Если ИндексПараметра < ТаблицаПараметров.Количество() Тогда СтрокаПоиска = "?" + ТаблицаПараметров[ИндексПараметра].Имя; ПозицияПараметра = Найти(ТекстМета, СтрокаПоиска); КонецЕсли; Если Истина И ПозицияПараметра > 0 Тогда ЗаписьXML.ЗаписатьБезОбработки(Лев(ТекстМета, ПозицияПараметра - 1) + ТаблицаПараметров[ИндексПараметра].Значение); ИндексПараметра = ИндексПараметра + 1; ТекстМета = Сред(ТекстМета, ПозицияПараметра + СтрДлина(СтрокаПоиска)); Иначе ЗаписьXML.ЗаписатьБезОбработки(ТекстМета); ТекстМета = ""; КонецЕсли; КонецЦикла; ТекстМета = ЗаписьXML.Закрыть(); КонецЕсли; Результат = Новый Структура(); Результат.Вставить("Текст", ТекстМета); Результат.Вставить("Параметры", ТаблицаПараметров); Результат.Вставить("Таблицы", ТаблицаТаблиц); Возврат Результат; КонецФункции Функция НайтиВызовыМетодовМодулей(ИмяМодуля, НомерНачальнойСтроки, НомерКонечнойСтроки, ТолькоОдну = Истина) Результат = Новый Массив(); Для Каждого СтрокаТаблицы Из ТаблицаЖурнала Цикл ФрагментыНачальнойСтрокиМодуля = ирОбщий.СтрРазделитьЛкс(СтрокаТаблицы.СтрокаМодуля, ":", Истина); Если ФрагментыНачальнойСтрокиМодуля[0] <> ИмяМодуля Тогда Результат.Вставить(0, СтрокаТаблицы); Если ТолькоОдну Тогда Прервать; КонецЕсли; КонецЕсли; НомерСтрокиМодуля = Число(ФрагментыНачальнойСтрокиМодуля[1]); Если Ложь Или НомерСтрокиМодуля < НомерНачальнойСтроки Или НомерСтрокиМодуля > НомерКонечнойСтроки Тогда Результат.Вставить(0, СтрокаТаблицы); Если ТолькоОдну Тогда Прервать; КонецЕсли; КонецЕсли; КонецЦикла; Возврат Результат; КонецФункции // Получить словарь имен таблиц входящих в запрос и соответствующих // шаблонам словаря метаданных // // Параметры: // ТекстЗапроса - Строка, текст запроса для которого строится словарь // СловарьШаблоновМетаданных - Соответствие, словарь шаблонов метаданных // ТипСУБД - Строка (Перечисление.ТипСУБД) // // Возвращаемое значение: // Соответствие - Словарь имен таблиц запроса // Функция ИменаМетаданныхЗапросаСУБД(Знач ТекстЗапроса, СловарьШаблоновМетаданных, ТипСУБД = "") Экспорт Результат = Новый ТаблицаЗначений; Результат.Колонки.Добавить("Имя"); Результат.Колонки.Добавить("Длина"); ТекстЗапроса = НРег(ТекстЗапроса); //Если НРег(ТипСУБД) = НРег("DB2") Тогда // ТекстЗапроса = ВРег(ТекстЗапроса); //КонецЕсли; Для Каждого СтрокаСловаряМетаданных Из СловарьШаблоновМетаданных Цикл Если Найти(ТекстЗапроса, СтрокаСловаряМетаданных.БыстрыйМаркер) = 0 Тогда Продолжить; КонецЕсли; ТаблицаВхождений = ирОбщий.НайтиРегулярноеВыражениеЛкс(ТекстЗапроса,,,,,,, Истина, СтрокаСловаряМетаданных.Вычислитель); #Если Сервер И Не Сервер Тогда ТаблицаВхождений = Обработки.ирПлатформа.Создать().ВхожденияРегВыражения; #КонецЕсли Для Каждого СтрокаВхождения Из ТаблицаВхождений Цикл НоваяСтрока = Результат.Добавить(); НоваяСтрока.Имя = СтрокаВхождения.ТекстВхождения; НоваяСтрока.Длина = СтрДлина(НоваяСтрока.Имя); КонецЦикла; КонецЦикла; Результат.Сортировать("Длина Убыв"); Результат.Свернуть("Имя"); Возврат Результат; КонецФункции // ПолучитьСловарьЗапроса() // Получить число из строки в которой число находится в начале строки // // Праметры: // ИсходнаяСтрока - Строка, строка в которой находится число // // Возвращаемое значение: // Число - если оно есть, неопределено, если числа нет // Функция ПолучитьЧислоСтрокой(ИсходнаяСтрока, КоличествоСимволов) КоличествоСимволов = 0; ДлинаСтроки = СтрДлина(ИсходнаяСтрока); Для Сч = 1 По ДлинаСтроки Цикл ТекущийСимвол = КодСимвола(Сред(ИсходнаяСтрока, Сч, 1)); Если 48 <= ТекущийСимвол И ТекущийСимвол <= 57 Тогда КоличествоСимволов = КоличествоСимволов + 1; Иначе Прервать; КонецЕсли; КонецЦикла; Если КоличествоСимволов > 0 Тогда Возврат Лев(ИсходнаяСтрока, КоличествоСимволов); Иначе Возврат Неопределено; КонецЕсли; КонецФункции // ПолучитьЧислоСтрокой() // Перевести часть запроса из терминов СУБД в термины метаданных // // Параметры: // Запрос - Строка, сапрос в терминах СУБД // СтруктураХраненияБазыДанных - ТаблицаЗначений // СловарьШаблоновМетаданных - Соответствие, подробности в функции // ПолучитьСловарьШаблоновМетаданных() // ТипСУБД - Строка, (Перечисление.ТипСУБД) // выхТаблицы - ТаблицаЗначений, *Неопределено - описание использованных в тексте таблиц, заполняется только если таблица передана (без колонок) // // Возвращаемое значение: // Строка, запрос в терминах метаданных // Функция ПеревестиТекстБДВТерминыМетаданных(Знач Текст, СтруктураХраненияБазыДанных = Неопределено, СловарьШаблоновМетаданных = Неопределено, Знач ТипСУБД = "", выхТаблицы = Неопределено, ДопустимыйРазмер = 20000, ПереводитьИндексы = Истина, ПереводитьВМета = Истина, ЭтоГарантированоТекстСобственнойБазы = Ложь) Экспорт Если выхТаблицы <> Неопределено Тогда #Если Сервер И Не Сервер Тогда выхТаблицы = Новый ТаблицаЗначений; #КонецЕсли //выхТаблицы.Колонки.Очистить(); Если выхТаблицы.Колонки.Найти("ИмяБД") = Неопределено Тогда выхТаблицы.Колонки.Добавить("ИмяБД", Новый ОписаниеТипов("Строка")); КонецЕсли; Если выхТаблицы.Колонки.Найти("ИмяМета") = Неопределено Тогда выхТаблицы.Колонки.Добавить("ИмяМета", Новый ОписаниеТипов("Строка")); КонецЕсли; КонецЕсли; Если Ложь Или Не ЗначениеЗаполнено(Текст) Тогда Возврат ""; КонецЕсли; Если Истина И ДопустимыйРазмер > 0 И СтрДлина(Текст) > ДопустимыйРазмер И ПереводитьВМета Тогда Возврат РезультатПереводаСлишкомБольшогоТекста(); КонецЕсли; Если ирОбщий.СтрокиРавныЛкс(ТипСУБД, "sdbl") Тогда ТипСУБД = ""; КонецЕсли; АдресЧужойСхемыБД = ""; Если Не ЭтоГарантированоТекстСобственнойБазы Тогда АдресЧужойСхемыБД = мАдресЧужойСхемыБД; КонецЕсли; Если СтруктураХраненияБазыДанных = Неопределено Тогда СтруктураХраненияБазыДанных = ирКэш.СтруктураХраненияБДЛкс(ЗначениеЗаполнено(ТипСУБД), АдресЧужойСхемыБД); КонецЕсли; Если СловарьШаблоновМетаданных = Неопределено Тогда СловарьШаблоновМетаданных = ирКэш.СловарьШаблоновХраненияБДЛкс(ЗначениеЗаполнено(ТипСУБД), АдресЧужойСхемыБД); КонецЕсли; Текст = Текст + Символы.ПС; ИменаМетаданныхЗапроса = ИменаМетаданныхЗапросаСУБД(Текст, СловарьШаблоновМетаданных, ТипСУБД); Если НРег(ТипСУБД) = НРег("DB2") Тогда Текст = ВРег(Текст); КонецЕсли; // Поиск имен таблиц в строке запроса Если ИменаМетаданныхЗапроса.Количество() > 10 Тогда Индикатор = ирОбщий.ПолучитьИндикаторПроцессаЛкс(ИменаМетаданныхЗапроса.Количество(), "Преобразование в имена метаданных"); КонецЕсли; Для Каждого ИмяМетаданного Из ИменаМетаданныхЗапроса Цикл Если Индикатор <> Неопределено Тогда ирОбщий.ОбработатьИндикаторЛкс(Индикатор); КонецЕсли; ОписаниеТаблицы = Неопределено; Если выхТаблицы <> Неопределено Тогда Если Найти(ИмяМетаданного.Имя, ".") = 0 Тогда ОписаниеТаблицы = выхТаблицы.Добавить(); ОписаниеТаблицы.ИмяБД = ИмяМетаданного.Имя; КонецЕсли; КонецЕсли; // Получить имя таблицы СтрокаСтруктуры = СтруктураХраненияБазыДанных.Найти(ирОбщий.ПоследнийФрагментЛкс(ИмяМетаданного.Имя), "КраткоеИмяТаблицыХранения"); Если СтрокаСтруктуры = Неопределено Тогда // Видимо чужие метаданные Продолжить; КонецЕсли; ИмяТаблицы = СтрокаСтруктуры.КраткоеИмяТаблицыХранения; МетаПолноеИмяТаблицы = СтрокаСтруктуры.ИмяТаблицы; Если ОписаниеТаблицы <> Неопределено Тогда ОписаниеТаблицы.ИмяМета = МетаПолноеИмяТаблицы; КонецЕсли; Если Не ПереводитьВМета Тогда Продолжить; КонецЕсли; Синонимы = ПолучитьСинонимы(Текст, ИмяТаблицы, МетаПолноеИмяТаблицы, ТипСУБД); //Синонимы.Вставить(ИмяТаблицы, МетаИмяТаблицы); ЭтоТабличнаяЧасть = СтрокаСтруктуры.Назначение = "ТабличнаяЧасть"; Для Каждого СтрокаПоля Из СтрокаСтруктуры.Поля Цикл Если Найти(Текст, СтрокаПоля.ИмяПоляХранения) = 0 Тогда Продолжить; КонецЕсли; ПредставлениеПоля = ирОбщий.ПредставлениеПоляБДЛкс(СтрокаПоля, ТипСУБД <> "", ЭтоТабличнаяЧасть); Если Не ЗначениеЗаполнено(ПредставлениеПоля) Тогда Продолжить; КонецЕсли; RegExpМета.Pattern = шГраничныйСимволИмени + СтрокаПоля.ИмяПоляХранения + "([^&" + шБуква + "\d]|Balance|Turnover|Receipt|Expense|^|$)"; // Можно оптимизировать путем создания шаблона мультизамены Текст = RegExpМета.Заменить(Текст, "$1" + ПредставлениеПоля + "$2"); КонецЦикла; Если ПереводитьИндексы Тогда Для Каждого СтрокаИндекса Из СтрокаСтруктуры.Индексы Цикл ирОбщий.ЗаполнитьИмяИндексаХраненияЛкс(СтрокаИндекса, ТипСУБД <> "", СтрокаСтруктуры); ПредставлениеИндекса = СтрокаИндекса.ИмяИндекса; СтрокаДляЗамены = СтрокаИндекса.ИмяИндексаХранения; Если ирОбщий.СтрокиРавныЛкс(ТипСУБД, "DBPOSTGRS") Тогда СтрокаДляЗамены = ВРег(СтрокаИндекса.ИмяИндексаХранения); ИначеЕсли ирОбщий.СтрокиРавныЛкс(ТипСУБД, "DBV8DBEng") Тогда СтрокаДляЗамены = ВРег(СтрокаИндекса.ИмяИндексаХранения); КонецЕсли; // Имена индексов достаточно уникальны, чтобы использовать СтрЗаменить Текст = СтрЗаменить(Текст, СтрокаДляЗамены, ПредставлениеИндекса); КонецЦикла; КонецЕсли; Для Каждого Синоним Из Синонимы Цикл // Заменить псевдоним таблицы RegExpМета.Pattern = шГраничныйСимволИмени + Синоним.Ключ + шГраничныйСимволИмени; Текст = RegExpМета.Заменить(Текст, "$1" + Синоним.Значение + "$2"); //RegExpМета.Pattern = ИмяТаблицы + " " + Синоним.Ключ + шГраничныйСимволИмени; //Запрос = RegExpМета.Заменить(Текст, ИмяТаблицы + " AS " + Синоним.Значение + "$1"); КонецЦикла; // Заменить имя таблицы RegExpМета.Pattern = шГраничныйСимволИмени + СтрокаСтруктуры.ИмяТаблицыХранения + шГраничныйСимволИмени; Текст = RegExpМета.Заменить(Текст, "$1" + МетаПолноеИмяТаблицы + "$2"); Если НРег(СтрокаСтруктуры.ИмяТаблицыХранения) <> СтрокаСтруктуры.КраткоеИмяТаблицыХранения Тогда RegExpМета.Pattern = шГраничныйСимволИмени + СтрокаСтруктуры.КраткоеИмяТаблицыХранения + шГраничныйСимволИмени; Текст = RegExpМета.Заменить(Текст, "$1" + ирОбщий.ПоследнийФрагментЛкс(МетаПолноеИмяТаблицы) + "$2"); КонецЕсли; КонецЦикла; Если Индикатор <> Неопределено Тогда ирОбщий.ОсвободитьИндикаторПроцессаЛкс(Индикатор); КонецЕсли; // Заменим приведение к ссылочному типу Если Не ЗначениеЗаполнено(ТипСУБД) Тогда Текст = СтрЗаменить(Текст, "AS REF(", "AS ("); КонецЕсли; Текст = СокрП(Текст); Возврат Текст; КонецФункции Функция РезультатПереводаСлишкомБольшогоТекста() Экспорт Возврат "<Текст слишком большой для быстрого перевода>" КонецФункции // Получить синонимы имени таблицы в запросе // // Параметры: // Запрос - Строка, текст запроса // ИмяТаблицы - Строка, имя таблицы для которой ищутся синонимы // МетаИмяТаблицы - Строка, имя таблицы в терминах метаданных // // Возвращаемое занчение: // Соответствие, имена синонимов и их мета имена // Функция ПолучитьСинонимы(Запрос, ИмяТаблицы, МетаИмяТаблицы, ТипСУБД = "") Экспорт // Построить список синонимом ими таблицы Синонимы = Новый Соответствие; RegExpМета.Pattern = ИмяТаблицы + " " + "(?:([" + шБуква + "\d]+)|\(([" + шБуква + "\d]+)\))" + шГраничныйСимволИмени; Вхождения = RegExpМета.НайтиВхождения(Запрос); ПсевдонимТаблицы = ирОбщий.ПоследнийФрагментЛкс(МетаИмяТаблицы, "."); Для Каждого Вхождение Из Вхождения Цикл Синоним = Вхождение.SubMatches(0); Если Синоним = Неопределено Тогда Синоним = Вхождение.SubMatches(1); КонецЕсли; Если Ложь Или (Истина И ирОбщий.СтрокиРавныЛкс(ТипСУБД, "DBMSSQL") И ирОбщий.СтрокиРавныЛкс(Синоним, "WITH")) Или ирОбщий.СтрокиРавныЛкс(Синоним, "WHERE") Или ирОбщий.СтрокиРавныЛкс(Синоним, "GROUP") Или ирОбщий.СтрокиРавныЛкс(Синоним, "HAVING") Или ирОбщий.СтрокиРавныЛкс(Синоним, "SET") Или ирОбщий.СтрокиРавныЛкс(Синоним, "ORDER") Или ирОбщий.СтрокиРавныЛкс(Синоним, "THEN") Тогда Продолжить; КонецЕсли; Синонимы.Вставить(Синоним, ПсевдонимТаблицы + "_" + Синоним); КонецЦикла; Возврат Синонимы; КонецФункции // ПолучитьСинонимы() //ирПортативный лФайл = Новый Файл(ИспользуемоеИмяФайла); //ирПортативный ПолноеИмяФайлаБазовогоМодуля = Лев(лФайл.Путь, СтрДлина(лФайл.Путь) - СтрДлина("Модули\")) + "ирПортативный.epf"; //ирПортативный #Если Клиент Тогда //ирПортативный Контейнер = Новый Структура(); //ирПортативный Оповестить("ирПолучитьБазовуюФорму", Контейнер); //ирПортативный Если Не Контейнер.Свойство("ирПортативный", ирПортативный) Тогда //ирПортативный ирПортативный = ВнешниеОбработки.ПолучитьФорму(ПолноеИмяФайлаБазовогоМодуля); //ирПортативный ирПортативный.Открыть(); //ирПортативный КонецЕсли; //ирПортативный #Иначе //ирПортативный ирПортативный = ВнешниеОбработки.Создать(ПолноеИмяФайлаБазовогоМодуля, Ложь); // Это будет второй экземпляр объекта //ирПортативный #КонецЕсли //ирПортативный ирОбщий = ирПортативный.ПолучитьОбщийМодульЛкс("ирОбщий"); //ирПортативный ирКэш = ирПортативный.ПолучитьОбщийМодульЛкс("ирКэш"); //ирПортативный ирСервер = ирПортативный.ПолучитьОбщийМодульЛкс("ирСервер"); //ирПортативный ирКлиент = ирПортативный.ПолучитьОбщийМодульЛкс("ирКлиент"); мПлатформа = ирКэш.Получить(); ЭтотОбъект.КоличествоПотоков = 8; мНепустыеКолонкиЖурнала = Новый Структура(); //ЭтотОбъект.НаложениеПриДозагрузкеСекунд = 30; RegExpПараметры = ирОбщий.НовыйВычислительРегВыражений(); Если RegExpПараметры <> Неопределено Тогда RegExpПараметры.IgnoreCase = Истина; RegExpПараметры.Global = Истина; RegExpПараметры.Pattern = "([^A-ZА-ЯЁ_0-9]|^)(?:[A-F0-9]+:[A-F0-9]+|0x[A-F0-9]+|[A-F0-9]+(?:-[A-F0-9]+)+-[A-F0-9]+|(#TT?)[_A-F0-9]+|[0-9]+)"; // для стирания констант и имен временных таблиц RegExpМета = ирОбщий.НовыйВычислительРегВыражений(); RegExpМета.IgnoreCase = Истина; RegExpМета.Global = Истина; КонецЕсли; мСписокКолонок = Новый СписокЗначений; //мСписокКолонок.Добавить("Name", "Событие"); // В некоторых случаях нужно мСписокКолонок.Добавить("SrcName", "Источник"); мСписокКолонок.Добавить("OSThread", "ПотокОС"); мСписокКолонок.Добавить("process", "ТипПроцессаОС"); мСписокКолонок.Добавить("p:processName", "Инфобаза"); мСписокКолонок.Добавить("t:clientID", "Соединение_"); мСписокКолонок.Добавить("t:applicationName", "Приложение"); мСписокКолонок.Добавить("t:computerName", "Компьютер"); мСписокКолонок.Добавить("t:connectID", "TCPСоединение"); мСписокКолонок.Добавить("SessionID", "Сеанс"); мСписокКолонок.Добавить("Usr", "Пользователь"); мСписокКолонок.Добавить("OSException", "ИсключениеОС"); мСписокКолонок.Добавить("Interface", "Интерфейс"); мСписокКолонок.Добавить("Method", "Метод"); мСписокКолонок.Добавить("Exception", "ТипИсключения"); мСписокКолонок.Добавить("Descr", "Описание"); мСписокКолонок.Добавить("ClientComputerName", "КомпьютерКлиента"); мСписокКолонок.Добавить("ServerComputerName", "КомпьютерСервера"); мСписокКолонок.Добавить("UserName", "Пользователь"); мСписокКолонок.Добавить("ConnectString", "СтрокаСоединения"); мСписокКолонок.Добавить("ProcessName", "ТипПроцессаОС"); мСписокКолонок.Добавить("SrcProcessName", "Инфобаза"); //мСписокКолонок.Добавить("Trans", "Транзакция"); мСписокКолонок.Добавить("Func", "Действие"); мСписокКолонок.Добавить("Sdbl", "ТекстSDBL"); мСписокКолонок.Добавить("dbpid", "ПроцессСУБД"); мСписокКолонок.Добавить("Sql", "ТекстСУБД"); мСписокКолонок.Добавить("NParams", "КоличествоПараметров"); мСписокКолонок.Добавить("Rows", "ЧислоСтрок"); мСписокКолонок.Добавить("RowsAffected", "ЧислоИзменныхСтрок"); мСписокКолонок.Добавить("planSQLText", "ПланСУБД"); мСписокКолонок.Добавить("Context", "Контекст"); мСписокКолонок.Добавить("CatName", "КаталогСУБД"); мСписокКолонок.Добавить("WaitConnections", "Блокираторы"); мСписокКолонок.Добавить("FileName", "ФайлСУБД"); мСписокКолонок.Добавить("DeadlockConnectionIntersections", "Взаимоблокировка"); мСписокКолонок.Добавить("Finish", "ПричинаЗавершения"); мСписокКолонок.Добавить("Err", "ТипСообщения"); мСписокКолонок.Добавить("Txt", "ТекстСообщения"); мСписокКолонок.Добавить("URI", "Ресурс"); мСписокКолонок.Добавить("Administrator", "Администратор"); мСписокКолонок.Добавить("Body", "РазмерЗапроса"); мСписокКолонок.Добавить("Cluster", "НомерПорта"); мСписокКолонок.Добавить("Val", "ЗначениеПараметра"); // Свойства найденные экспериментально. Они не документированы. мСписокКолонок.Добавить("Query", "ТекстЗапроса1С"); // События: QERR мСписокКолонок.Добавить("From", "From_"); // События: DBV8DBENG //мСписокКолонок.Добавить("AppID", "AppID"); // События: QERR, DBMSSQL (дублируется t:applicationName), SDBL (дублирует t:applicationName) мСписокКолонок.Добавить("Index", "Index_"); //мСписокКолонок.Добавить("setUnhandledExceptionFilter", "setUnhandledExceptionFilter"); мСписокКолонок.Добавить("Module", "МодульКонфигурации"); // События: EXCPCNTX мСписокКолонок.Добавить("ClientID", "Клиент"); // События: EXCPCNTX, SCALL, EXCP (дублируется t:clientID ?) мТаблицаКолонок = Новый ТаблицаЗначений; мТаблицаКолонок.Колонки.Добавить("ВнутреннееИмя", Новый ОписаниеТипов("Строка")); мТаблицаКолонок.Колонки.Добавить("ИмяВТаблице", Новый ОписаниеТипов("Строка")); мТаблицаКолонок.Индексы.Добавить("ВнутреннееИмя"); мТаблицаКолонок.Индексы.Добавить("ИмяВТаблице"); //мЧисловыеСвойства = Новый Структура; мСоответствиеКолонок = Новый Соответствие; МетаРеквизиты = Метаданные().ТабличныеЧасти.ТаблицаЖурнала.Реквизиты; Для Каждого ЭлементСписка Из мСписокКолонок Цикл мСоответствиеКолонок.Вставить(НРег(ЭлементСписка.Значение), ЭлементСписка.Представление); СтрокаСоответствия = мТаблицаКолонок.Добавить(); СтрокаСоответствия.ВнутреннееИмя = ЭлементСписка.Значение; СтрокаСоответствия.ИмяВТаблице = ЭлементСписка.Представление; //Если МетаРеквизиты[ЭлементСписка.Представление].Тип.СодержитТип(Тип("Число")) Тогда // мЧисловыеСвойства.Вставить(ЭлементСписка.Представление); //КонецЕсли; КонецЦикла; Для Каждого МетаРеквизит Из МетаРеквизиты Цикл Если мСоответствиеКолонок[МетаРеквизит.Имя] = Неопределено Тогда мСоответствиеКолонок.Вставить(НРег(МетаРеквизит.Имя), МетаРеквизит.Имя); КонецЕсли; КонецЦикла; мКартыФайлов = Новый ТаблицаЗначений; мКартыФайлов.Колонки.Добавить("ИмяКаталогаПроцесса", Новый ОписаниеТипов("Строка")); мКартыФайлов.Колонки.Добавить("ИмяТекущегоФайла", Новый ОписаниеТипов("Строка")); мКартыФайлов.Колонки.Добавить("СигнатураТекущегоФайла", Новый ОписаниеТипов("Строка")); мКартыФайлов.Колонки.Добавить("ОтборПоСеансу"); мКартыФайлов.Колонки.Добавить("ПозицияНачала", Новый ОписаниеТипов("Число")); мКартыФайлов.Колонки.Добавить("ПозицияКонца", Новый ОписаниеТипов("Число")); мКартыФайлов.Колонки.Добавить("НачалоПериода", Новый ОписаниеТипов("Дата")); мКартыФайлов.Колонки.Добавить("КонецПериода", Новый ОписаниеТипов("Дата")); мКартыФайлов.Колонки.Добавить("ДатаИзмененияФайла", Новый ОписаниеТипов("Дата")); мКартыФайлов.Индексы.Добавить("ИмяКаталогаПроцесса, ИмяТекущегоФайла, СигнатураТекущегоФайла, ОтборПоСеансу"); мСвойстваСИменамиБД = Новый Структура(); мСвойстваСИменамиБД.Вставить("ТекстSDBL", Ложь); мСвойстваСИменамиБД.Вставить("ТекстSDBLШаблон", Ложь); мСвойстваСИменамиБД.Вставить("ТекстСУБД", Истина); мСвойстваСИменамиБД.Вставить("ТекстСУБДШаблон", Ложь); мСвойстваСИменамиБД.Вставить("ПланСУБД", Истина); мСвойстваСИменамиБД.Вставить("Взаимоблокировка", Ложь); мСвойстваСИменамиБД.Вставить("Regions", Ложь); мСвойстваСИменамиБД.Вставить("Locks", Ложь); мСерверныеТипыПроцессов = Новый Структура; мСерверныеТипыПроцессов.Вставить("_adminprocess"); // ##AdminProcess## мСерверныеТипыПроцессов.Вставить("_rphost"); мСерверныеТипыПроцессов.Вставить("_rmngr"); мСерверныеТипыПроцессов.Вставить("_ragent"); мЛиТрассаПоПользователю = Ложь; МаксТысячСобытий = 100; мАдресЧужойСхемыБД = ""; шБуква = мПлатформа.шБуква; шГраничныйСимволИмени = "([^&" + шБуква + "\d]|^|$)"; мИменаВозвращаемыхСвойств = "мКартыФайлов, мНепустыеКолонкиЖурнала, мТипСУБД"; мТаблицаЖурнала = ТаблицаЖурнала; #Если Не Клиент Тогда мТаблицаЖурнала = мТаблицаЖурнала.ВыгрузитьКолонки(); #КонецЕсли