【问题标题】:Powershell regex to extract data from log filePowershell正则表达式从日志文件中提取数据
【发布时间】:2016-08-19 15:11:49
【问题描述】:

使用脚本从日志文件中提取数据;搜索查询中的术语和执行时间。

来自日志文件的样本

19/08/2016 09:08:00 [100] ACTION%3DQuery%26MaxResults%3D9999%26abridged%3Dtrue%26abridgedmeta%3Ddatabase%26printfields%3DIM_DOCNUM,IM_VERSION%26combine%3Dfieldcheck%26databasematch%3DDATABASE_1,DATABASE-2%26Text%3D((pep21556)%3AIM_DOCNAME)%26fieldtext%3D(WILD%7BWORK%7D%3AIM_PRJ_SUBTYPE+AND+WILD%7BWEBDOC%7D%3AIM_CLASS)+AND+BIASDATE%7B1471612079e,2592000,20%7D%3Aautn_date+AND+BIASDATE%7B1471612079e,63072000,20%7D%3Aautn_date%26anyLanguage%3Dtrue%26TimeoutMS%3D60000
19/08/2016 09:08:00 [100] Request completed in 12 ms.
19/08/2016 09:08:28 [103] Request from 10.1.1.131

日志文件是 URL 编码的。

我正在进行的脚本加载日志文件

foreach ($line in [System.IO.File]::ReadLines($filename)) 

然后 URL 解码每一行并删除一个长的安全信息字符串

$VarURLDecoded = [System.Web.HttpUtility]::UrlDecode($line) -replace "SecurityInfo=.*"

现在我正在努力使用正则表达式来提取以下内容:Date +Time, MaxResault=xxxxxxx, Text=((??????????):???????) 和时间以毫秒为单位,以完成以下行中的请求。

$findText = $VarURLDecoded | select-string -Inputobject {$_} -pattern 

我有一些部分正则表达式。

'(\d{2}/\d{2}/\d{4} \d{2}:\d{2}:\d{2})'  will find 19/08/2016 09:08:00
'MaxResults=(\d*)' will find MaxResults=9999
'(?<Text>&Text=\(\([^()]*\)\:[^()]*\))' will find &Text=((campeau):IM_DOCNAME)
'(\d* ms)' will find the xx ms

但无法弄清楚将它们全部连接起来的 AND 语法,包括第二行上的持续时间记录。要么使用它遵循下面的行的事实,要么使用它具有适当时间戳的事实。

一旦我得到基本的正则表达式工作,我可以通过添加命名组并将结果导出到哈希表来增加复杂性。

【问题讨论】:

    标签: regex powershell


    【解决方案1】:

    从发布的日志来看,没有必要对其进行解码,因为没有%xx编码的字符。
    对于文本处理,不需要像[System.IO.File] 这样的低级内容。
    需要额外的一行,所以让我们使用-context before, after 参数。

    $report = select-string -path $filename -context 0,1 -pattern (
        '^(?<date>.+?) ' +
        '(?<time>.+?) .+?' +
        '&MaxResults=(?<results>\d+).+?' +
        '&Text=(?<text>[^&]+)') |
    %{
        $nextLine = $_.Context.PostContext[0]
        $g = $_.matches[0].groups
        @{
            date = $g['date'].value
            time = $g['time'].value
            results = $g['results'].value
            text = $g['text'].value
            duration = if ($nextLine -match 'completed in (\d+) ms') { $matches[1] }
        }
    }
    

    $report 现在是一个对象数组,每个对象如下:

    Name                           Value
    ----                           -----
    date                           19/08/2016
    time                           09:08:00
    duration                       12
    results                        9999
    text                           ((pep21556):IM_DOCNAME)
    

    或者,考虑到 select-string 的模式匹配在复杂模式下可能会很慢,让我们使用简单的字符串进行匹配,使用?Where-Object 的别名)进行过滤,然后处理结果:

    $report = select-string -path $filename -context 0,1 -pattern '&MaxResults=' -simpleMatch |
    ?{ $_.Line -match (
        '^(?<date>.+?) ' +
        '(?<time>.+?) .+?' +
        '&MaxResults=(?<results>\d+).+?' +
        '&Text=(?<text>[^&]+)')
    } | %{
        $nextLine = $_.Context.PostContext[0]
        $m = $matches # $matches is set by the above -match
        @{
            date = $m['date']
            time = $m['time']
            results = $m['results']
            text = $m['text']
            duration = if ($nextLine -match 'completed in (\d+) ms') { $matches[1] }
        }
    }
    

    【讨论】:

    • 感谢您回答我的第二个问题。有几点,我正在搜索的文件每个大小约为 100 兆,所以我认为使用 [System.IO.File] 会提供更好的性能。原始数据是 URL 编码的,(我把解码后的示例放在让我的问题更容易解释。我已经将你的代码改编为我的原始脚本,但持续时间字段是银行。我想知道这是否是因为它不起作用与 system.IO.File
    • 试过 ::readAllText 而不是 ::ReadLines 结果是脚本不再找到任何东西。那么在您的解决方案脚本中需要进行哪些更改来处理 URLEncode 行? (同样每个文件大约 100 兆,并且有接近 100 万行)
    • 管道:[IO.File]::ReadAllLines($filename) | select-string .....
    • 得到了那部分,但进来的数据仍然是 URL 编码的,不知道如何用你的管道示例解码每一行?
    • ?{ [Web.HttpUtility]::UrlDecode($_.Line) -match (
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-02-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-12-09
    相关资源
    最近更新 更多