快速过滤日志文件

时间:2016-01-31 20:30:08

标签: algorithm powershell full-text-search

我正在尝试编写PowerShell脚本来对生产日志文件进行一些分析。

我需要按大约50到100个值过滤大约250万行文本 - 如果O(nm),则需要250,000,000次迭代。

我已经尝试Get-Content | Select-String,但这似乎非常缓慢。

是否有任何方法来处理此问题,而不是为每个值迭代每一行一次?

修改

因此,日志文件看起来有点像这样(datetime:process_id:log_level:message)

2016-01-30 14:01:22.349 [ 27]  INFO XXX YYY XXXFX
2016-01-30 14:01:28.146 [ 16]  INFO XXXD YY Z YYY XXXX
2016-01-30 14:01:28.162 [ 16]  DEBUG YY XXXXX YY XX P YYY
2016-01-30 14:01:28.165 [ 16]  DEBUG YY XXXXX YY XX YYY
2016-01-30 14:01:28.167 [ 16]  DEBUG YY XXXXX YY XX YYY
2016-01-30 14:01:28.912 [ 27]  INFO XXX YY XXGXXX YYYYYY YY XX

我可能正在寻找值D,F,G和Z。

值可以是二进制数字的字符串,十六进制数字,两者的组合,常规文本和标点符号的字符串,或管道分隔的值。

2 个答案:

答案 0 :(得分:4)

经验法则:

  • StreamReader的速度比Get-Content快于Import-Csv
  • 字符串操作比通配符匹配快于正则表达式匹配。

如果它足以检查你的日志行是否包含任何给定的字符串,你可能想要这样的东西:

$reader  = [IO.StreamReader]'C:\path\to\your.log'
$filters = 'foo', 'bar', ...

while ($reader.Peek() -ge 0) {
  $line = $reader.ReadLine()
  if ($filters | Where-Object {$line.Contains($_)}) {
    $line
  }
}

$reader.Close()
$reader.Dispose()

如果您想使用StreamWriter而不是仅仅回显输出,只需调整代码如下:

$reader  = [IO.StreamReader]'C:\path\to\your.log'
$writer  = [IO.StreamWriter]'C:\path\to\output.txt'
$filters = 'foo', 'bar', ...

while ($reader.Peek() -ge 0) {
  $line = $reader.ReadLine()
  if ($filters | Where-Object {$line.Contains($_)}) {
    $writer.WriteLine($line)
  }
}

$reader.Close(); $reader.Dispose()
$writer.Close(); $writer.Dispose()

根据日志行的结构以及过滤器值以及如何应用它们,过滤器逻辑可能需要进行调整。但是,您需要实际显示日志格式并过滤示例。

答案 1 :(得分:3)

我会尝试使用StreamReader + StreamWriter来加快读/写速度,因为Get-Content对于大文件来说速度很慢。此外,我会尝试制作一个正则表达式(word OR word OR word等),以避免数百次迭代。例如:

$words = "foo","bar","donkey" 
#Create regex-pattern (usually faster to match)
$regex = ($words | % { [regex]::Escape($_) }) -join '|'

$reader = New-Object System.IO.StreamReader -ArgumentList "c:\myinputfile.txt"
$writer = New-Object System.IO.StreamWriter -ArgumentList "c:\myOUTputfile.txt"

while (($line = $reader.ReadLine()) -ne $null) {
    if($line -match $regex) { $writer.WriteLine($line) }
}


#Close writer
$writer.Close()
$writer.Dispose()

#Close reader
$reader.Close()
$reader.Dispose()