Разбор PowerShell Advance для расчета времени установки компонентов на основе файла журнала

У меня есть приложение, которое создает файл журнала следующего формата:

2009-03-27 15:30:50 Start
2009-03-27 15:30:51 Starting Component 1 Installation
2009-03-27 15:30:52 blah
2009-03-27 15:30:53 blah
2009-03-27 15:30:54 blah
2009-03-27 15:30:55 ~~~ Finished Component 1 Installation ~~~
2009-03-27 15:30:56 Starting Component 2 Installation
2009-03-27 15:30:57 blah
2009-03-27 15:30:58 blah
2009-03-27 15:30:59 blah
2009-03-27 15:30:60 ~~~ Finished Component 2 Installation ~~~
2009-03-27 15:30:61 Starting Component 3 Installation
2009-03-27 15:30:62 blah
2009-03-27 15:30:63 blah
2009-03-27 15:30:64 blah
2009-03-27 15:30:65 ~~~ Finished Component 3 Installation ~~~
2009-03-27 15:30:66 Finished

Я думаю, вы поняли суть формата.

То, чего я хочу добиться, это иметь сценарий powershell, который вернет таблицу результатов, показывающую

  1. Название компонента
  2. Время начала
  3. Время окончания
  4. Затраченное время

Я называю это «продвинутым» скриптом, потому что он, вероятно, будет включать в себя: синтаксический анализ, форматирование, создание новых объектов и т. д.

  • Я новичок в powershell

person Ran Davidovitz    schedule 28.03.2009    source источник


Ответы (1)


Следующий сценарий может сделать это за вас... ЕСЛИ вы прибегаете к разумным значениям времени... более 60 секунд в минуту - это странно (и дал мне здесь несколько исключений, которые вызвали серьезные головные боли при разбор даты/времени, пока я не заметил, почему были выбраны исключения...)

$logfile = $args[0]

$log = get-content $logfile

$Components = @()

switch -regex ($log) {
    "(.*) Starting (.*) Installation" {
        $c = New-Object PSObject
        $st = [DateTime]::ParseExact($Matches[1], "yyyy'-'MM'-'dd HH':'mm':'ss", $null)
        $c | Add-Member -Type NoteProperty -Name Component -Value $Matches[2]
        $c | Add-Member -Type NoteProperty -Name StartTime -Value $st
    }
    "(.*) ~~~ Finished" {
        $et = [DateTime]::ParseExact($Matches[1], "yyyy'-'MM'-'dd HH':'mm':'ss", $null)
        $c | Add-Member -Type NoteProperty -Name EndTime -Value $et
        $c | Add-Member -Type NoteProperty -Name TimeTaken -Value ($c.EndTime - $c.StartTime)
        $Components += $c
    }
}

$Components

Я мог немного сократить время выполнения (примерно на 25 процентов) с помощью следующего кода:

$logfile = $args[0]

foreach ($l in Get-Content $logfile) {
    if ($l.Length -ge 30) {
        if ($l.Substring(20,8) -eq "Starting") {
            $c = New-Object PSObject
            $st = [DateTime]::ParseExact($l.Substring(0,19), "yyyy'-'MM'-'dd HH':'mm':'ss", $null)
            $c | Add-Member -Type NoteProperty -Name Component -Value $l.Substring(29, $l.Length - 42)
            $c | Add-Member -Type NoteProperty -Name StartTime -Value $st
        } elseif ($l.Substring(24,8) -eq "Finished") {
            $et = [DateTime]::ParseExact($l.Substring(0,19), "yyyy'-'MM'-'dd HH':'mm':'ss", $null)
            $c | Add-Member -Type NoteProperty -Name EndTime -Value $et
            $c | Add-Member -Type NoteProperty -Name TimeTaken -Value ($c.EndTime - $c.StartTime)
            $c
        }
    }
}

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

person Joey    schedule 28.03.2009
comment
Спасибо за скрипт (и извините за ошибку с секундами!). Скрипт отлично работает с функциональной точки зрения, но с точки зрения производительности он медленный, можете ли вы предложить, что может сделать его быстрее? - person Ran Davidovitz; 28.03.2009
comment
Что ж, в настоящее время скрипт считывает полный файл журнала, а затем выполняет обработку. Я только что попробовал это на файле журнала размером 800 КиБ, и разница между первым чтением, затем синтаксическим анализом и выполнением этого в конвейере не заметна (на самом деле конвейер еще медленнее). В настоящее время не знаю, как сделать это быстрее - person Joey; 28.03.2009
comment
Здесь на вызовы New-Object и Add-Member приходится примерно половина времени выполнения. Разбор с помощью регулярных выражений, по-видимому, является другой половиной (разбор даты/времени не заметен). Однако переписывание без регулярных выражений не будет очень увлекательным или читабельным. - person Joey; 28.03.2009
comment
Спасибо за быстрый ответ. изначально, когда я пытался сделать это, используя каналы, а не используя хэши для добавления соответствующего свойства к нужному объекту, ваше решение легче понять - person Ran Davidovitz; 28.03.2009
comment
Кроме того, .. как вы проверили его производительность? Есть ли возможность компилировать регулярное выражение? - person Ran Davidovitz; 28.03.2009
comment
Я использовал timethis (bit.ly/esXXA) и закомментировал некоторые части кода, чтобы измерить влияние. Время выполнения этого файла журнала размером 800 КиБ здесь составляло от 2,1 до 2,3 секунды, я добавил решение, которое сократило его до 1,6 секунды, но это, возможно, не стоит повышенного барьера для понимания. - person Joey; 28.03.2009
comment
Может быть возможность компилировать регулярные выражения, но я сомневаюсь, что это будет хорошо работать со встроенными функциями PS, такими как switch -regex, -match и $Matches. такого пока не смотрел - person Joey; 28.03.2009
comment
Хорошо, я проверил компиляцию - избыточно - person Ran Davidovitz; 28.03.2009
comment
Вы можете немного ускорить процесс, избегая New-Object/Add-Member и вместо этого используя Select-Object для добавления всего за один раз: $c = | Компонент Select-Object, StartTime, EndTime, TimeTaken; $c.Component = $l.Substring(29, $l.Length - 42) - person JasonMArcher; 03.04.2009
comment
Единственным недостатком является то, что вы получаете только динамически типизированные NoteProperties. Но в данном случае это все, что вы все равно добавляли. - person JasonMArcher; 03.04.2009