使用正则表达式解析日志文件

Posted

技术标签:

【中文标题】使用正则表达式解析日志文件【英文标题】:Parsing a log file with regular expressions 【发布时间】:2010-09-07 16:06:24 【问题描述】:

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

(?<date>\d2/\d2/\d2)\s(?<time>\d2):\d2:\d2),\d3)\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

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


@samjudson:

您需要将 RegexOptions.Singleline 标志传递给正则表达式,以便“.”匹配所有字符,而不仅仅是新行以外的所有字符(这是默认设置)。

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

问题在于消息的模式也与日期组匹配,因此当它没有在换行符上中断时,它只会继续下去。


我现在将这个正则表达式用于消息组。它可以工作,除非日志消息中的模式与日志消息的开头相同。

(?<message>(.(?!\d2/\d2/\d2\s\d2:\d2:\d2,\d3\s\[\d4\]))+)

【问题讨论】:

【参考方案1】:

这仅在日志消息的行首不包含日期时才有效,但您可以尝试在“消息”组中为日期添加否定的前瞻断言:

(?<date>\d2/\d2/\d2)\s(?<time>\d2:\d2:\d2,\d3)\s(?<message>(.(?!^\d2/\d2/
\d2))+)

请注意,这需要使用 RegexOptions.MultiLine 标志。

【讨论】:

【参考方案2】:

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

然而,就我个人而言,我不会使用正则表达式来解析整个日志条目。我更喜欢使用我自己的循环来遍历每一行,并使用一个简单的正则表达式来确定一行是否是新条目的开始。同样从可读性的角度来看,这将是我的偏好。

【讨论】:

【参考方案3】:

您遇到的问题是您需要终止 RegEx 模式,以便它知道一条消息何时结束,然后下一条消息开始。

当您在默认模式下运行时,换行符充当隐式终止符。

问题是,如果您进入多行模式,则没有终止符,因此该模式将吞噬整个文件。非贪婪匹配尽可能少的字符,这将只是一个。

现在,如果使用下一条消息的日期作为终止符,我认为您的解析器只会获取每隔一行。

文件中还有其他内容可以终止模式吗?

【讨论】:

【参考方案4】:

您可能会发现使用适当的解析器生成器解析文件要容易得多 - ANTLR 可以在 C# 中生成一个... 上下文无关的解析器只有在您“获得”它们之前看起来很困难 - 之后,它们变得更加简单并且比正则表达式更友好...

【讨论】:

【参考方案5】:

您需要传递RegexOptions。在正则表达式中加入单行标志,使“.”匹配所有字符,而不仅仅是除换行符以外的所有字符(这是默认设置)。

【讨论】:

以上是关于使用正则表达式解析日志文件的主要内容,如果未能解决你的问题,请参考以下文章

使用 c# 和正则表达式解析日志文件

如何在 Hive 中使用正则表达式来解析 Apache 日志时间戳?

使用正则表达式匹配日志文件行时的可选字段

Python 使用正则表达式解析日志

LogMX 正则表达式解析器的问题

C# |正则表达式 |如何提高我的正则表达式性能