Понадобилось мне пропарсить технологический журнал, но во всех обучающих статьях используются утилиты и linux. В то же время большинство 1с серверов стоят на windows машинах, где есть powershell, возможностей у которого не меньше. В этой статье мой вариант скрипта top 25 call-вызовов используя инструмент от microsoft.
Тестирование скрипта проходило на платформе 8.3.17.
Сразу привожу полный код, подробное объяснение ниже. Внимание! Скрипт написал на Powershell 5.1:
$inputFile = "E:\exchange\logs_analyze\call\*\*.log"
$searchPattern = "^(?<time>\d\d:\d\d.\d+)-(?<dur>\d+),(?<eventName>CALL),.+Context=(?<context>.+),Interface.+Memory=(?<memory>-*\d+),.+CpuTime=(?<cputime>\d+)"
Select-String -Path $inputFile -Pattern $searchPattern |
ForEach-Object{
$dur,$eventName,$context,$memory,$cputime = $_.Matches[0].Groups[2..6].Value
[PSCustomObject] @{
Duration = [math]::Round($dur/1000000,2)
EventName = $eventName
Memory = $memory
Context = $context
CpuTime = $cputime
}
} | Group-Object Context |
ForEach-Object{
$measureDur, $measureCPU=$_.Group | Measure-Object Duration,CpuTime -Sum -Average -Maximum
[PSCustomObject] @{
DurSum = $measureDur.Sum
DurAvr = [math]::Round($measureDur.Average,2)
cpuSum = $measureCPU.Sum
cpuAvr = [math]::Round($measureCPU.Average,2)
cpuMax = $measureCPU.Maximum
Count = $measureDur.Count
Context = $_.Name
}
} |
Sort-Object -Property "cpuMax" -Descending | Select-Object -First 10 | Out-GridView
Подробное объяснение
Начинаем с объявления переменных и задаем регулярное выражение для разбора данных.
$inputFile = "E:\exchange\logs_analyze\call\*\*.log"
$searchPattern = "^(?<time>\d\d:\d\d.\d+)-(?<dur>\d+),(?<eventName>CALL),.+Context=(?<context>.+),Interface.+Memory=(?<memory>-*\d+),.+CpuTime=(?<cputime>\d+)"
Если с первой все понятно, она задает путь до каталога файлов, то вторая интереснее, она содержит регулярное выражение. В Powershell мы можем задать шаблон всей строки целиком, а нужные части выделить скобками и дать им названия для дальнейшего использования.
"^(?<time>\d\d:\d\d.\d+)-(?<dur>\d+),
/d - означает любую цифру, а /d+ - любое количество цифр. Поэтому когда мы пропарсим строку вида "00:09.509005-150", мы получим группу time содержащую "00:09.509005" и группу dur содержащую "150"
Context=(?<context>.+),
В группу context помещаем все, что между Context= и запятой. Аналогично с группой memory и cputime.
Читаем данные:
Select-String -Path $inputFile -Pattern $searchPattern
Вызываем команду Select-String, аналог grep, куда передаем наши переменные
Первый цикл и создание объектов:
ForEach-Object{
$dur,$eventName,$context,$memory,$cputime = $_.Matches[0].Groups[2..6].Value
[PSCustomObject] @{
Duration = [math]::Round($dur/1000000,2)
EventName = $eventName
Memory = $memory
Context = $context
CpuTime = $cputime
}
}
Pipeline в Powershell работает с объектами, поэтому нам надо вытащить полученные группы и превратить их в объекты, которые передадим дальше. Select-String возвращает объект MatchInfo из которого надо получить группы.
$dur,$eventName,$context,$memory,$cputime = $_.Matches[0].Groups[2..6].Value
В данной строке мы берем значения групп с 3 по 7 и присваиваем их переменным. Вторая группа(time) нам сейчас не интересна, а в первой группе(с индексом 0) содержится вся строка целиком, ее добавляет сам Powershell.
[PSCustomObject] @{
Duration = [math]::Round($dur/1000000,2)
EventName = $eventName
Memory = $memory
Context = $context
CpuTime = $cputime
}
Создаем свой объект, присваивая полученные на предыдущем шаге переменные, заодно переводим длительность в секунды.
Группировка:
Group-Object Context
объединяем наши созданные объекты по контексту
Второй цикл и новые объекты:
ForEach-Object{
$measureObj, $measureCPU=$_.Group | Measure-Object Duration,CpuTime -Sum -Average -Maximum
[PSCustomObject] @{
DurSum = $measureObj.Sum
DurAvr = [math]::Round($measureObj.Average,2)
cpuSum = $measureCPU.Sum
cpuAvr = [math]::Round($measureCPU.Average,2)
cpuMax = $measureCPU.Maximum
Count = $measureObj.Count
Context = $_.Name
}
}
Обходим полученный результат группировки, создавая новые объекты, с уже посчитанными данными.
Measure-Object Duration,CpuTime -Sum -Average -Maximum
На вход получает сгруппированные данные и считает сумму, среднее и максимум по реквизитам Duration и CpuTime, если нужно еще Memory, то именно сюда его нужно добавить.
Сортировка и выбор:
Sort-Object -Property "cpuMax" -Descending | Select-Object -First 25
Сортируем наши объекты по полю cpuMax и выбираем первые 25
Получаем результат:
Out-GridView
Наконец моя любимая функция, она выводит результат в отдельном окне в виде таблицы, по которой можно фильтровать данные, делать сортировку по колонкам, очень удобно.