使用perl正则表达式匹配单个日志条目

时间:2014-02-11 12:42:30

标签: regex perl

使用log4j语法考虑日志文件:

2014-02-10 08:44:53,295 ERROR com.comnany.some.class Message
message message message
2014-02-10 08:44:53,995 WARN com.comnany.some.class An irrelevant warn message...
2014-02-10 08:45:00,010 DEBUG com.comnany.some.class An irrelevant debug message...

我需要在perl中编写匹配器以匹配日志文件中的所有错误。匹配不仅必须包含其中包含ERROR的行,还必须包含所有行,直到(但不包括)下一个日志条目的开头。

任何人都可以提出正则表达式来执行此匹配(最好有解释)吗?

2 个答案:

答案 0 :(得分:2)

试试这个正则表达式:

/(?P<date>\d{4}-\d{2}-\d{2}\s+\d{2}:\d{2}:\d{2},\d{1,3}\s+)ERROR\s+
 (?P<class>.+?)\s+
 (?P<message>.+?)(?=(?1)|$)/gsx

调节剂

g: Search globally (don't return on first match).
s: Dot matches newline characters.
x: Spaces in the pattern are ignored.

演示

http://regex101.com/r/rD8dI7

参考

答案 1 :(得分:0)

加载整个文件以查找多行日志条目是一个非常糟糕的主意。考虑日志文件的大小,现在必须将其全部加载到内存中并一次处理。 Perl历史上不太善于释放记忆......

更合理的方法是整个或从特定点处理日志,在循环中设置一个标记,检查每一行并添加它是否是新条目。

首先请注意,请考虑使用qr()运算符预编译正则表达式。这将为您节省几个周期,特别是当您迭代多行或以其他方式多次使用相同的正则表达式时。

关于我下面的代码的另一个注意事项,我喜欢使用label和next()语句,因为显式地连接到循环的下一次迭代会澄清代码的流程。

整体流程将是:

  1. 标识作为日志条目开头的行;
  2. 如果是错误,请设置一个标志,以便将任何行追加到新的日志条目起始行;
  3. 在设置错误日志条目标志
  4. 时将行附加到当前错误消息
  5. 打印当前日志条目
  6. 它可能看起来像这样:

    my $log_entry_begin_regex = qr/(?P<date>\d{4}-\d{2}-\d{2}\s+\d{2}:\d{2}:\d{2},\d{1,3}\s+)(FATAL|WARN|ERROR|INFO|DEBUG|TRACE)/;
    
    my $found_error_flag;
    open my $file, "<", $path_to_file;
    LINE:
    while ( my $line = <$file> ) {
        # It's a new log entry line
        if (($line, $error_level) =~ $log_entry_begin_regex ) {
    
            if ( $error_level eq 'ERROR' ) {
                $found_error_flag = 1;
                print $line
                next LINE;
            } else {
                $found_error_flag = 0;
                next LINE;
            }
        } elsif ($found_error_flag ) {
            print $line;
        }
    }