2017-08-08 14 views
0

私は、cronジョブを介して毎時呼び出され、アスタリスクログを検索し、原因31で終わった呼び出しのユニークなIDを提供するシェルスクリプトを持っています。Grep巨大なログファイルのパターンが多い

while read ref 
do 
cat sample.log | grep "$ref" | grep 'got hangup request, cause 31' | grep -o 'C-[0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z]' >> cause_temp.log 
done < callref.log 

問題は、whileループが遅すぎることです。正確さのために、上記のようなループを4回追加してさまざまなチェックを実行しました。

callref.logファイルはコール識別子の値で構成され、約50〜90,000の値を持ち、スクリプトは実行を完了してレポートをメールで送信するのに約45〜50分かかります。

私はループの実行時間を短縮することができたら大いに役立つでしょう。 sample.logファイルのサイズは約20 GBなので、ループごとにファイルが開かれて検索が実行されるので、whileループがボトルネックになっていると思いました。

は、研究を行い、 Link 1Link 2

のようないくつかの有用なリンクを発見した。しかし解決策は、私は実装できないか、どのように知りませんが示唆されています。どんな提案も役に立ちます。ありがとう

sample.logは機密情報で構成されているため、ログを共有することはできませんが、インターネットから入手したサンプルログは以下のとおりです。また

C-001ec22d 
C-001ec23d 
C-001ec24d 
C-001ec31d 
C-001ec80d 

上記の所望の出力ループはまた、C-001ec80d

のように見えながら、私のメイン -

Dec 16 18:02:04 asterisk1 asterisk[31774]: NOTICE[31787]: chan_sip.c:11242 in handle_request_register: Registration from '"503"<sip:[email protected]>' failed for '192.168.1.137' - Wrong password 
Dec 16 18:03:13 asterisk1 asterisk[31774]: NOTICE[31787]: chan_sip.c:11242 in handle_request_register: Registration from '"502"<sip:[email protected]>' failed for '192.168.1.137' - Wrong password 
Dec 16 18:04:49 asterisk1 asterisk[31774]: NOTICE[31787]: chan_sip.c:11242 in handle_request_register: Registration from '"1737245082"<sip:[email protected]>' failed for '192.168.1.137' - Username/auth name mismatch 
Dec 16 18:04:49 asterisk1 asterisk[31774]: NOTICE[31787]: chan_sip.c:11242 in handle_request_register: Registration from '"100"<sip:[email protected]>' failed for '192.168.1.137' - Username/auth name mismatch 
Jun 27 18:09:47 host asterisk[31774]: ERROR[27910]: chan_zap.c:10314 setup_zap: Unable to register channel '1-2' 
Jun 27 18:09:47 host asterisk[31774]: WARNING[27910]: loader.c:414 __load_resource: chan_zap.so: load_module failed, returning -1 
Jun 27 18:09:47 host asterisk[31774]: WARNING[27910]: loader.c:554 load_modules: Loading module chan_zap.so failed! 

ファイルcallref.logは次のように見えるラインのリストから成りwhileループの実行を高速化することが重要です。配列内のcallref.logのすべての値をロードし、可能であればsample.logの単一パスですべての値を同時に検索するのと同様です。

+0

は次のようになります例えば価値があると考える価値がある。 grepの '-F'フラグは固定文字列を使用しているときに最初の2つのgrepのパフォーマンスを向上させる可能性があります(最後の文字列は使用しません)。役に立つはずのヒントがあります(https://stackoverflow.com/questions/13913014/grepping-a-huge-file-80gb-any-way-to-speed-it-up)。 – hnefatl

+0

あなたはawkを使うことができないのですか? –

+1

'sample.log'と' callref.log'と予想される出力を投稿してください。私はあなたに助けになるかもしれないと信じています。 –

答えて

0

私はテストフレームワークを構築し、さまざまなコマンドのバリエーションをテストしていましたが、私はあなたがすでに最も速いものを持っていると思います。

これは、より良いパフォーマンスを得るためには、ossec(ログサンプルがどこから来たか)のようなログダイジェストフレームワークを調べなければならないと思うかもしれません。それらはあなたの願いのためにあまりにも不器用かもしれません。あるいは、構文解析に適したjava/C/perl/awkでの設計と構築を検討するべきです。

既存のスクリプトをより頻繁に実行することも役立ちます。

幸運を祈る!あなたが好きなら、私がした仕事を箱に入れてここに掲示することができますが、私はその過労を考えています。

要求通りです。 CalFuncs.sh:私のスクリプト

#!/bin/bash 

LOGDIR="/tmp" 
LOG=$LOGDIR/CalFunc.log 
[ ! -d "$LOGDIR" ] && mkdir -p $(dirname $LOG) 

SSH_OPTIONS="-o StrictHostKeyChecking=no -q -o ConnectTimeout=15" 
SSH="ssh $SSH_OPTIONS -T" 
SCP="scp $SSH_OPTIONS" 
SI=$(basename $0) 

Log() { 
    echo "`date` [$SI] [email protected]" >> $LOG 
} 

Run() { 
    Log "Running '[email protected]' in '`pwd`'" 
    [email protected] 2>&1 | tee -a $LOG 
} 

RunHide() { 
    Log "Running '[email protected]' in '`pwd`'" 
    [email protected] >> $LOG 2>&1 
} 

PrintAndLog() { 
    Log "[email protected]" 
    echo "[email protected]" 
} 

ErrorAndLog() { 
    Log "[ERROR] [email protected] " 
    echo "[email protected]" >&2 
} 

showMilliseconds(){ 
    date +%s 
} 

runMethodForDuration(){ 
    local startT=$(showMilliseconds) 
    $1 
    local endT=$(showMilliseconds) 
    local totalT=$((endT-startT)) 
    PrintAndLog "that took $totalT seconds to run $1" 
    echo $totalT 
} 

genCallRefLog.shのほとんどのライブラリIソースは -

#!/bin/bash 
#Script to make 80000 sequential lines of callref.log this should suffice for a POC 
if [ -z "$1" ] ; then 
    echo "genCallRefLog.sh requires an integer of the number of lines to pump out of callref.log" 
    exit 1 
fi 
file="callref.log" 
[ -f "$file" ] && rm -f "$file" # del file if exists 
i=0 #put start num in here 
j="$1" #put end num in here 
echo "building $j lines of callref.log" 
for (( a=i ; a < j; a++ )) 
do 
    printf 'C-%08x\n' "$a" >> $file 
done 

genSampleLog.shは架空のサンプルを生成し、引数に応じて、架空のcallref.logサイズを生成します。引数に依存するログサイズ

#!/bin/bash 
#Script to make 80000 sequential lines of callref.log this should suffice for a POC 
if [ -z "$1" ] ; then 
    echo "genSampleLog.sh requires an integer of the number of lines to pump out of sample.log" 
    exit 1 
fi 
file="sample.log" 
[ -f "$file" ] && rm -f "$file" # del file if exists 
i=0 #put start num in here 
j="$1" #put end num in here 
echo "building $j lines of sample.log" 
for (( a=i ; a < j; a++ )) 
do 
    printf 'Dec 16 18:02:04 asterisk1 asterisk[31774]: NOTICE[31787]: C-%08x got hangup request, cause 31\n' "$a" >> $file 
done 

最後に私が使用した実際のテストスクリプト。多くの場合、ログサイズを変更するときに実行するだけでビルディングスクリプトをコメントアウトします。また、通常は一度に1つのテスト機能しか実行せず、結果を記録します。

test.sh

#!/bin/bash 
source "./CalFuncs.sh" 

targetLogFile="cause_temp.log" 
Log "Starting" 

checkTargetFileSize(){ 
    expectedS="$1" 
    hasS=$(cat $targetLogFile | wc -l) 
    if [ "$expectedS" != "$hasS" ] ; then 
    ErrorAndLog "Got $hasS but expected $expectedS, when inspecting $targetLogFile" 
    exit 244 
    fi 
} 

standard(){ 
    iter=0 
    while read ref 
    do 
    cat sample.log | grep "$ref" | grep 'got hangup request, cause 31' | grep -o 'C-[0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z][0-9a-z]' >> $targetLogFile 
    done < callref.log 
} 

subStandardVarient(){ 
    iter=0 
    while read ref 
    do 
    cat sample.log | grep 'got hangup request, cause 31' | grep -o "$ref" >> $targetLogFile 
    done < callref.log 
} 

newFunction(){ 
    grep -f callref.log sample.log | grep 'got hangup request, cause 31' >> $targetLogFile 
} 

newFunction4(){ 
    grep 'got hangup request, cause 31' sample.log | grep -of 'callref.log'>> $targetLogFile 
} 

newFunction5(){ 
    #splitting grep 
    grep 'got hangup request, cause 31' sample.log > /tmp/somefile 
    grep -of 'callref.log' /tmp/somefile >> $targetLogFile 
} 

newFunction2(){ 
    iter=0 

    while read ref 
    do 
    ((iter++)) 
    echo "$ref" | grep 'got hangup request, cause 31' | grep -of 'callref.log' >> $targetLogFile 
    done < sample.log 
} 

newFunction3(){ 
    iter=0 
    pat="" 
    while read ref 
    do 
    if [[ "$pat." != "." ]] ; then 
     pat="$pat|" 
    fi 
    pat="$pat$ref" 
    done < callref.log 
    # Log "Have pattern $pat" 
    while read ref 
    do 
    ((iter++)) 
    echo "$ref" | grep 'got hangup request, cause 31' | grep -oP "$pat" >> $targetLogFile 
    done < sample.log 
    #grep: regular expression is too large 
} 

[ -f "$targetLogFile" ] && rm -f "$targetLogFile" 

numLines="100000" 
Log "testing algorithms with $numLines in each log file." 

setupCallRef(){ 
    ./genCallRefLog.sh $numLines 
} 

setupSampleLog(){ 
    ./genSampleLog.sh $numLines 
} 

setupCallRef 
setupSampleLog 

runMethodForDuration standard > /dev/null 
checkTargetFileSize "$numLines" 
[ -f "$targetLogFile" ] && rm -f "$targetLogFile" 
runMethodForDuration subStandardVarient > /dev/null 
checkTargetFileSize "$numLines" 
[ -f "$targetLogFile" ] && rm -f "$targetLogFile" 
runMethodForDuration newFunction > /dev/null 
checkTargetFileSize "$numLines" 
# [ -f "$targetLogFile" ] && rm -f "$targetLogFile" 
# runMethodForDuration newFunction2 > /dev/null 
# checkTargetFileSize "$numLines" 
# [ -f "$targetLogFile" ] && rm -f "$targetLogFile" 
# runMethodForDuration newFunction3 > /dev/null 
# checkTargetFileSize "$numLines" 
# [ -f "$targetLogFile" ] && rm -f "$targetLogFile" 
# runMethodForDuration newFunction4 > /dev/null 
# checkTargetFileSize "$numLines" 
[ -f "$targetLogFile" ] && rm -f "$targetLogFile" 
runMethodForDuration newFunction5 > /dev/null 
checkTargetFileSize "$numLines" 

上記は、既存の方法では、常に私が思いついたものよりも高速であったことを示しています。私は誰かがそれを最適化するために気を配ったと思うawkの使い方

$ cat callref.log 
a 
b 
$ cat sample.log 
a 1 
b 2 
c 1 

+0

提案してくれてありがとうございますが、メインログファイルのタイムスタンプと一致させてsedを使用して処理する前に、メインログファイルから1時間以上のログを取得しています。 callref.logファイルはコール識別子の値で構成され、毎時約50-90,000の値を持ちます。また、私の主な関心事は、whileループをより速く実行させることです。配列内のcallref.logのすべての値をロードして、sample.logの1回のパスですべての値を同時に検索するようにします。 –

+0

検索は動的なので、 callref.logに値が変更されていますか? –

+0

はい、毎時callref.logの値が変化します –

0

あなたが要求した場合でもに対してテストするために十分なサンプルログを生成できなかったので、私は自分自身をいくつかのテスト材料を手早く

$ awk 'NR==FNR {    # hash callrefs 
    a[$1] 
    next 
} 
{       # check callrefs from sample records and output when match 
    for(l in a) 
     if($0 ~ l && $0 ~ 1) # 1 is the static string you look for along a callref 
      print l 
}' callref.log sample.log 
a 1 

HTHを

関連する問題