代码之家  ›  专栏  ›  技术社区  ›  Erik van Brakel scottrakes

用正则表达式分析日志文件

  •  2
  • Erik van Brakel scottrakes  · 技术社区  · 16 年前

    我目前正在为我们的内部日志文件(由log4hp、log4net和log4j生成)开发一个解析器。到目前为止,我有一个很好的正则表达式来解析日志,除了一个恼人的地方:一些日志消息跨多行,我无法正确匹配。我现在得到的正则表达式是:

    (?<date>\d{2}/\d{2}/\d{2})\s(?<time>\d{2}):\d{2}:\d{2}),\d{3})\s(?<message>.+)
    

    日志格式(我用于测试解析器)如下:

    07/23/08 14:17:31,321 log 
    message
    spanning
    multiple
    lines
    07/23/08 14:17:31,321 log message on one line
    

    当我现在运行解析器时,只得到日志开始的行。如果将其更改为跨多行,则只会得到一个结果(整个日志文件)。


    萨姆森:

    需要将regexoptions.singleline标志传入正则表达式,以便“.”匹配所有字符,而不仅仅是除新行之外的所有字符(这是默认值)。

    我试过了,但它与整个文件相匹配。我还尝试将消息组设置为。+?(非贪婪),但它匹配一个字符(这也不是我要找的)。

    问题是消息的模式也在日期组中匹配,所以当它不在新行上中断时,它就会不断地中断。


    我现在使用这个regex作为消息组。除非日志消息中有与日志消息开头相同的模式,否则它可以工作。

    (?<message>(.(?!\d{2}/\d{2}/\d{2}\s\d{2}:\d{2}:\d{2},\d{3}\s\[\d{4}\]))+)
    
    5 回复  |  直到 7 年前
        1
  •  3
  •   Jeff Hillman    16 年前

    仅当日志消息不包含行首的日期时,此操作才有效,但您可以尝试在“消息”组中为日期添加否定的先行声明:

    (?<date>\d{2}/\d{2}/\d{2})\s(?<time>\d{2}:\d{2}:\d{2},\d{3})\s(?<message>(.(?!^\d{2}/\d{2}/
    \d{2}))+)
    

    请注意,这需要使用regexoptions.multiline标志。

        2
  •  2
  •   mweerden    16 年前

    显然,您需要将“消息行”与“日志行”区分开来;如果您允许消息部分在新行之后以日期/时间开始,那么就无法确定什么是消息的一部分,什么不是。因此,您不需要使用点,而是需要一个表达式,它允许任何不包括换行符、日期和时间的内容。

    但就个人而言,我不会使用正则表达式来解析整个日志条目。我更喜欢使用自己的循环对每行进行迭代,并使用一个简单的正则表达式来确定一行是否是新条目的开头。从可读性的角度来看,这也是我的偏好。

        3
  •  1
  •   David Webb    16 年前

    问题是您需要终止regex模式,这样它就知道一条消息何时结束,然后下一条消息何时开始。

    在默认模式下运行时,换行符作为隐式终止符工作。

    问题是,如果您进入多行模式,就没有终止符,因此模式将吞没整个文件。非贪心匹配几个字符,可能只有一个。

    现在,如果使用下一条消息的日期作为终止符,我认为您的解析器将只得到其他每一行。

    文件中是否还有其他东西可以终止模式?

        4
  •  0
  •   Daren Thomas    16 年前

    您可能会发现使用适当的解析器生成器来解析文件要容易得多-Antlr可以在C中生成一个。上下文无关的解析器只有在你“得到”它们之前才显得很难——之后,它们比正则表达式更简单、更友好…

        5
  •  0
  •   Alireza    7 年前

    你需要通过 RegexOptions . 在正则表达式中使用单行标志,以便“.”匹配所有字符,而不仅仅是除新行以外的所有字符(默认)。