Передача в LogParser

Я работаю над набором сценариев для управления некоторыми задачами анализа журналов, которые мне нужно выполнять с очень большими журналами IIS, сжатыми gzip. Работая над ним, я столкнулся с проблемой подключения к logparser. Я упростил свою проблему до следующего.

Если я запускаю это, он работает так, как ожидалось. Файл журнала не такой большой и возвращается довольно быстро.

$query = "Select s-computername, Count(*) as count FROM stdin GROUP by s-computername"
Get-Content .\01-01-16\ex160101.log |
  LogParser "$query" -i:IISW3C -o:CSV -headers:ON -fileMode:1 -q:ON

Однако, если я хочу поместить часть LogParser в функцию PowerShell, чтобы упростить ее выполнение. На самом деле, я действительно хотел бы передать запрос, но я пытаюсь работать в обратном направлении от самого простого, что я могу придумать.

Вот что у меня получилось.

Function Test-IISLog {
  Begin {
    $query = "Select s-computername, Count(*) as count FROM stdin GROUP by s-computername"
  }
  Process {
    $_ | LogParser "$query" -i:IISW3C -o:CSV -headers:ON -fileMode:1 -q:ON | Write-Output
  }
}
Get-Content .\01-01-16\ex160101.log | Test-IISLog

Когда я запускаю это, он просто крутит колеса в течение очень долгого времени. Я пробовал разные комбинации этой команды, одну без $_ и одну без Write-Output. Ни один из них не работает. Не знаю, почему так долго не возвращаются.

Может кто-нибудь помочь с этим? Должен ли я делать это по-другому?

Моя конечная цель состоит в том, чтобы иметь простой способ выполнить logparser запрос к набору журналов IIS, которые были заархивированы и сохранены на устройстве netapp. До сих пор часть разархивирования хорошо работала с конвейерами, и пока я передаю напрямую в LogParser, он работает. Когда я вызываю LogParser из другой функции PowerShell, у меня возникают проблемы.


person markdemich    schedule 30.01.2016    source источник
comment
Замените $_ на $input   -  person Mathias R. Jessen    schedule 30.01.2016
comment
$input дал те же результаты, что и $_   -  person markdemich    schedule 31.01.2016


Ответы (1)


Хотя правильно, что в контексте конвейера автоматическая переменная $_ представляет текущий объект, в вашем случае вам нужна другая автоматическая переменная ($input, как предложил Матиас), потому что вам нужно обрабатывать ввод функции, даже если он поступает из трубопровод:

function Test-IISLog {
  End {
    $query = "SELECT s-computername, Count(*) AS count FROM stdin GROUP BY s-computername"
    $input | LogParser "$query" -i:IISW3C -o:CSV -headers:ON -fileMode:1 -q:ON
  }
}

Цитата из документации:

$Input
Содержит перечислитель, который перечисляет все входные данные, передаваемые функции. Переменная $input доступна только для функций и блоков скриптов (которые являются безымянными функциями). В блоке Process функции переменная $input перечисляет объект, который в данный момент находится в конвейере. Когда блок Process завершится, в конвейере не останется объектов, поэтому переменная $input перечисляет пустую коллекцию. Если у функции нет блока Process, то в блоке End переменная $input перечисляет набор всех входных данных функции.

Вы также можете дать функции фактический параметр и использовать его вместо автоматической переменной, но тогда вам придется собирать строки в массив самостоятельно:

function Test-IISLog {
  [CmdletBinding()]
  Param(
    [Parameter(
      Mandatory=$true,
      Position=0,
      ValueFromPipeline=$true,
      ValueFromPipelineByPropertyName=$true
    )]
    [string[]]$LogLine
  )

  Begin {
    $query = "SELECT s-computername, Count(*) AS count FROM stdin GROUP BY s-computername"
    $lines = @()
  }
  Process {
    $lines += $LogLine
  }
  End {
    $lines | LogParser "$query" -i:IISW3C -o:CSV -headers:ON -fileMode:1 -q:ON
  }
}

Однако, зачем идти на все эти проблемы в первую очередь? logparser может читать файлы самостоятельно:

$filename = 'C:\path\to\ex160101.log'

$query = @"
SELECT s-computername, Count(*) AS count
FROM '$filename'
GROUP BY s-computername
"@

& logparser.exe $query -i:IISW3C -o:CSV -headers:ON -fileMode:1 -q:ON

Во всяком случае, я бы передал имя файла в функцию:

function Test-IISLog {
  [CmdletBinding()]
  Param(
    [Parameter(
      Mandatory=$true,
      Position=0,
      ValueFromPipeline=$true,
      ValueFromPipelineByPropertyName=$true
    )]
    [ValidateScript({Test-Path -LiteralPath $_})]
    [string]$Filename
  )

  Process {
    $query = @"
SELECT s-computername, Count(*) AS count
FROM '$filename'
GROUP BY s-computername
"@
    & logparser.exe $query -i:IISW3C -o:CSV -headers:ON -fileMode:1 -q:ON
  }
}
person Ansgar Wiechers    schedule 30.01.2016
comment
Я попробую ваш пример и дам вам знать, как это работает. Причина того, что анализатор журнала не читает файл, заключается в том, что в моем случае использования есть куча файлов, сжатых gzip, которые мне нужно передать парсеру журнала как один. Мой пример выше является упрощенной версией, потому что, несмотря на сжатую часть, я не смог заставить эту часть работать. - person markdemich; 31.01.2016
comment
Я пробовал оба примера. Один использует $input, а другой — @LogLine. Оба дали аналогичные результаты при использовании $_. - person markdemich; 31.01.2016
comment
Моя ошибка. Всего необходимо обработать $input в блоке End, иначе каждая строка журнала будет обрабатываться отдельно разными logparser процессами. Что, конечно, было бы совершенно бессмысленно. - person Ansgar Wiechers; 31.01.2016