web-dev-qa-db-ja.com

ログからの複数行のフィルタリング

この質問は代わりにstackoverflowに移動する必要がありますか?

Javaアプリケーションがlog4jを使用して生成したログファイルを読み取る必要があることがよくあります。通常、ログに記録されたメッセージ(ログエントリと呼びましょう)は複数行にまたがっています。例:

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であり、少なくとも1つのスペースがあることに注意してください。ここでは、2つのログエントリがあります。1つ目はミリ秒123で、もう1つはミリ秒234です。

ログエントリをフィルタリングするための高速コマンド(sed/grep/awk/etcの組み合わせを使用)が必要です(grepは行のみをフィルタリングします)。例:テキスト「Logger2」を含むすべてのログエントリを削除します。

次の変換を行うことを検討しました。

1)同じログエントリに属する​​行を特別な文字シーケンス(例:##)で結合します。このように、すべてのログエントリは正確に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がすべての作業を実行できる可能性があります。

6
botismarius

多くの楽器を混ぜる必要はありません。タスクはsedのみで実行できます

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

複数行のログレコードの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 = '';
}
2
AnFi

https://stackoverflow.com/questions/9605232/merge-two-lines-into-one の1つの回答に基づくと、これは法案に適合しているようです

#!/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

注:これにより、出力の先頭に空白が追加されます

2
pmg