从日志中过滤多行

从日志中过滤多行

这个问题应该移到 stackoverflow 吗?

我经常需要使用 log4j 读取 java 应用程序生成的日志文件。通常,记录的消息(我们称之为日志条目)跨越多行。例子:

INFO  10:57:01.123 [Thread-1] [Logger1] This is a multi-line
text, two lines
DEBUG 10:57:01.234 [Thread-1] [Logger2] This entry takes 3 lines
line 2
line 3

请注意,每个日志条目都从新行开始,并且该行的第一个单词是 TRACE、DEBUG、INFO 或 ERROR 以及至少一个空格。这里有 2 个日志条目,第一个位于毫秒 123,另一个位于毫秒 234。

我想要一个快速命令(使用 sed/grep/awk/etc 的组合)来过滤日志条目(grep 仅过滤行),例如:删除包含文本“Logger2”的所有日志条目。

我考虑进行以下转换:

1) 使用特殊的字符序列连接属于相同日志条目的行(例如:##);这样,所有日志条目将恰好占据一行

INFO  10:57:01.123 [Thread-1] [Logger1] This is a multi-line##text, two lines
DEBUG 10:57:01.234 [Thread-1] [Logger2] This entry takes 3 lines##line 2##line 3

2) grep
3) 将行拆分回来(即:将 ## 替换为 \n)

我在第 1 步遇到了麻烦 - 我没有足够的 sed 经验。

也许上面的 3 个步骤不是必需的,也许 sed 可以完成所有工作。

答案1

无需混合多种乐器。任务sed只能通过

sed '/^INFO\|^DEBUG\|^TRACE\|^ERROR/{
         /Logger2/{
             :1
             N
             /\nINFO\|\nDEBUG\|\nTRACE\|\nERROR/!s/\n//
             $!t1
             D     }
                                    }' log.entry

答案2

perl 多行日志记录过滤器(记录开始标记)

使用以下 perl 脚本作为工作原型。
用法script_path regular_expression log_files
例如script_path "line \d" log_file_1 log_file_2

#!/usr/bin/perl
$pattern = qr/(?^s)$ARGV[0]/; shift; # process filtering expression
# (?^s) - treats matched string as single line
my $line = ''; # accumulates current log file record/paragraph
while(<>) {
 if( /^(TRACE|DEBUG|INFO|ERROR) /o ) { # start of new record
   &flush; # flush/print previous recors
 }
 $line.=$_;
}
&flush;
exit;

sub flush {
  local $_ = $line;
  if( length($_) and /$pattern/ ) {
    print;
  }
  $line = '';
}

答案3

基于一个答案https://stackoverflow.com/questions/9605232/merge-two-lines-into-one这似乎符合要求

#!/usr/local/bin/bash

PATTERN1='TRACE *';
PATTERN2='DEBUG *';
PATTERN3='INFO *';
PATTERN4='ERROR *';
LINEOUT=""
while read line; do
    case $line in
        $PATTERN1)
                echo $LINEOUT
                LINEOUT="$line"
                        ;;
        $PATTERN2)
                echo $LINEOUT
                LINEOUT="$line"
                        ;;
        $PATTERN3)
                echo $LINEOUT
                LINEOUT="$line"
                        ;;
        $PATTERN4)
                echo $LINEOUT
                LINEOUT="$line"
                        ;;
        "")
                LINEOUT=""
                ;;

        *)      LINEOUT="$LINEOUT ## $line"
                ;;
    esac        
done
echo $LINEOUT

注意:这将在输出的开头添加一个空格

相关内容