【问题标题】:Consolidated RegEx to parse syslog data合并 RegEx 以解析 syslog 数据
【发布时间】:2021-11-07 00:44:18
【问题描述】:

目标

我正在尝试制作一个 RegEx,它将从各种 syslog 条目中解析出特定数据,这些条目包含记录内容的细微差异。虽然我可以使用多个 RegEx 语句来实现我的目标,但如果可能的话,我想将这些语句组合成一个统一的 RegEx。


日志条目

我遇到的主要问题是一些日志条目有一个需要解析为命名组的 URL,而其他日志条目没有任何 URL。下面提供了这两个不同日志条目的示例。

使用 URL 输入

Nov  3 11:33:04 host1 postfix/smtpd[12812]: NOQUEUE: reject: RCPT from 178.red-83-59-180.dynamicip.rima-tde.net[83.59.180.178]: 554 5.7.1 Service unavailable; Client host [83.59.180.178] blocked using b.barracudacentral.org; http://www.barracudanetworks.com/reputation/?pr=1&ip=83.59.180.178; from=<lmclapp68@newmail.spamcop.net> to=<user1@example.com> proto=ESMTP helo=<178.red-83-59-180.dynamicip.rima-tde.net>

没有网址的条目

Nov  2 16:01:25 host1 postfix/smtpd[31667]: NOQUEUE: reject_warning: RCPT from mail1.sendersrv.com[185.3.229.125]: 554 5.7.1 Service unavailable; Client host [185.3.229.125] blocked using bl.spamcop.net; from=<bounces+rL59wUXq98_inBrG@sendersrv.com> to=<user1@example.com> proto=ESMTP helo=<mail1.sendersrv.com>

正则表达式

在随后的 RegEx 语句中,前两个是我目前用于前面每条日志消息的语句。第三个 RegEx 是我尝试将它们合并到一个 RegEx 中,该 RegEx 将解析来自任一日志消息的数据。我的尝试是使用一个条件语句,它基本上会检查http(s) 是否存在,如果找到,则将 URL 解析为命名组。如果没有找到http(s),那么它将解析出所有内容,直到下一个 RegEx 令牌。

问题是,当我针对具有 URL 的日志条目测试 RegEx 时,RegEx 似乎没有找到 http(s),尽管此标记被设置为可选(即使用 ? 量词)。但是,如果我删除 ? 量词,它确实会找到 http(s),然后根据需要解析 URL。但是,如果没有量词,RegEx 无法处理没有 URL 的日志条目。

使用 URL 解析条目

^(?P<datetime>.+) host1 postfix.+RCPT from (?P<srcDns>.+)\[(?P<srcIp>[0-9\.]+)\]:.+blocked using (?P<blkList>.+);.+https?:\/{2}(?P<entryUrl>.+);\s.+\sto=\<(?P<destEm>.+)>.+$

解析没有 URL 的条目

^(?P<datetime>.+) host1 postfix.+RCPT from (?P<srcDns>.+)\[(?P<srcIp>[0-9\.]+)\]:.+blocked using (?P<blkList>.+);\s.+\sto=\<(?P<destEm>.+)>.+$

尝试合并 RegEx

^(?P<datetime>.+) host1 postfix.+RCPT from (?P<srcDns>.+)\[(?P<srcIp>[0-9\.]+)\]:.+blocked using (?P<blkList>.+)(?<=[a-z]);.+(https?:\/{2})?(?(5)(?P<entryUrl>.+)|.+)to=\<(?P<destEm>.+)>.+$

我确定问题在于我对条件语句和 ? 量词如何工作的误解。

【问题讨论】:

    标签: regex regex-group


    【解决方案1】:

    查看您的模式,to: 的电子邮件地址介于标签 &lt;&gt; 之间,但由于问题中的格式,它们未显示。

    你的模式中的部分像.+首先匹配到字符串的末尾,然后会回溯并尝试匹配模式的其余部分。

    您可以使模式更高效,使您想要和了解的部分更具体。

    • 对于日期时间,您可以使用^(?P&lt;datetime&gt;[A-Z][a-z]{2}\s+\d{1,2}\s* \d{1,2}:\d{1,2}:\d{1,2}) 使模式匹配指定格式而不是.+

    • 对于(?P&lt;blkList&gt;[^;]+)(?P&lt;entryUrl&gt;[^;]+),您可以使用与除; 之外的任何字符匹配的否定字符类

    • 对于(?P&lt;destEm&gt;[^&lt;&gt;\s]+) 组,您可以排除匹配的标签。

    • 要匹配 url,而不是使用条件,您可以使用 ? 将组设为可选

    例如

    ^(?P<datetime>[A-Z][a-z]{2}\s+\d{1,2}\s* \d{1,2}:\d{1,2}:\d{1,2}) host1 postfix\b.*? RCPT from (?P<srcDns>.*?)\[(?P<srcIp>[0-9\.]+)\]:.*? blocked using (?P<blkList>[^;]+);(?:.+?https?:\/\/(?P<entryUrl>[^;]+);)?\s.*? to=[^<]*<(?P<destEm>[^<>\s]+)>
    

    查看regex demo

    【讨论】:

      【解决方案2】:

      您是否尝试在 regex101 之类的页面上测试您的正则表达式?
      to=\&lt;(?P&lt;destEm&gt;.+)&gt; 似乎与您的示例不匹配。您应该删除&lt;&gt; 或将to 替换为helo。小心在blkList 之后使你的量词变得懒惰,否则你可能会捕捉到太多的文字。
      然后,您可以使用 ? 将您的网址设为可选,并且它应该适用于两种情况:

      ^(?P<datetime>.+) host1 postfix.+RCPT from (?P<srcDns>.+)\[(?P<srcIp>[0-9\.]+)\]:.+blocked using (?P<blkList>.+?);(.+https?:\/{2}(?P<entryUrl>.+);\s)?.+\sto=(?P<destEm>.+?)\s.*$
      

      【讨论】:

        【解决方案3】:

        一种方法是将第一个正则表达式中的.+https?:\/{2}(?P&lt;entryUrl&gt;.+); 替换为(?:.+https?:\/{2}(?P&lt;entryUrl&gt;.+);)?,其中?: 表示它是非捕获组,而末尾的? 表示它是可选的。

        但是还是不行,因为.+是贪婪的,所以用懒惰的.+?代替。

        最终正则表达式:

        ^(?P<datetime>.+?) host1 postfix.+?RCPT from (?P<srcDns>.+?)\[(?P<srcIp>[0-9\.]+)\]:.+?blocked using (?P<blkList>.+?);(?:.+?https?:\/{2}(?P<entryUrl>.+?);)?\s.+?\sto=\<(?P<destEm>.+?)>.+?$
        

        https://regex101.com/r/QkmXWz(查看实际情况)

        【讨论】:

          猜你喜欢
          • 2015-02-13
          • 1970-01-01
          • 2010-10-03
          • 1970-01-01
          • 2022-01-22
          • 1970-01-01
          • 1970-01-01
          • 2020-10-30
          • 2014-01-13
          相关资源
          最近更新 更多