2017-08-08 3 views
0

Ich habe ein Shell-Skript, das jede Stunde über Cron-Job aufgerufen wird und durch die Stern-Logs durchsuchen und mir die eindeutigen IDs für einen Anruf, der mit Cause 31 endete.Grep große Anzahl von Mustern aus einer großen Protokolldatei

Das Problem ist, dass die While-Schleife zu langsam ist und für Genauigkeit habe ich 4 While-Schleifen wie oben erwähnt, um verschiedene Prüfungen durchzuführen.

callref.log-Datei besteht aus Call Identifier-Werten und jede Stunde wird es etwa 50-90 tausend Werte und das Skript dauert etwa 45-50 Minuten, um die Ausführung abzuschließen und mir den Bericht per E-Mail.

Es wäre sehr hilfreich, wenn ich die Ausführungszeit der Schleifen reduzieren könnte. Da die Größe der Datei sample.log ungefähr 20 GB beträgt und die Datei für jede Schleife geöffnet wird und die Suche ausgeführt wird, stellte ich fest, dass die while-Schleife hier der Flaschenhals ist.

Haben die Forschung und fand einige nützliche Links wie Link 1Link 2

Aber die Lösungen vorgeschlagen getan, was ich nicht umsetzen können oder nicht wissen, wie. Jeder Vorschlag wäre hilfreich. Danke

Da sample.log aus vertraulichen Informationen besteht, wäre ich nicht in der Lage, irgendwelche Protokolle zu teilen, aber unten sind einige Beispielprotokolle, die ich vom Internet bekommen habe.

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! 

die Datei callref.log besteht aus einer Liste von Zeilen, die wie folgt aussieht -

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

auch die gewünschte Ausgabe der obigen while-Schleife sieht wie C-001ec80d

Auch mein Haupt Sorge ist es, die While-Schleife schneller laufen zu lassen. Laden Sie alle Werte von callref.log in ein Array und suchen Sie nach allen Werten gleichzeitig in einem einzigen Durchlauf von sample.log, falls möglich.

+0

Könnte sein einen Blick wert, zB. das '-F'-Flag für Grep, das die Leistung der ersten beiden Greps verbessern kann, da Sie feste Strings verwenden (aber nicht für das letzte). Es gibt einige gute Tipps [https://stackoverflow.com/questions/13913014/grepping-a-huge-file-80gb-any-way-to-speed-it-up), die helfen sollten. – hnefatl

+0

Sie meinen Sie können nicht awk verwenden? –

+1

Wie wäre es mit der Veröffentlichung von 'sample.log' und' callref.log' und der erwarteten Ausgabe und ich denke, wir könnten Ihnen helfen. –

Antwort

0

Ich verbrachte einen Tag einen Test-Framework zu bauen und zu testen Variationen verschiedenen Befehle und ich denke, Sie bereits die schnellste haben.

Was mich zu denken, führt, dass wenn Sie eine bessere Leistung bekommen Sie in einem Protokoll zu verdauen Rahmen aussehen sollte, wie OSSEC (wo Ihre Log-Proben stammten aus) vielleicht splunk. Diese sind vielleicht zu ungeschickt für Ihre Wünsche. Alternativ sollten Sie etwas in java/C/perl/awk entwerfen und entwickeln, das besser zum Parsen geeignet ist.

Betrieb Ihres bestehenden Skript häufiger wird auch helfen.

Viel Glück! Wenn du magst, kann ich die Arbeit, die ich gemacht habe, einpacken und hier posten, aber ich denke, es ist übertrieben.

wie gewünscht; CalFuncs.sh: eine Bibliothek, die ich Quelle in den meisten meiner Skripte

#!/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 - erzeugt fiktive callref.log Größe je nach Argument

#!/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 fiktiven Probe erzeugt.Log-Größe je nach Argument

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

und schließlich das eigentliche Testskript ich verwendet. Häufig würde ich die Gebäudeskripte auskommentieren, da sie nur ausgeführt werden müssen, wenn die Protokollgröße geändert wird. Ich würde normalerweise auch nur eine Testfunktion gleichzeitig ausführen und die Ergebnisse aufzeichnen.

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" 

Die oben zeigt, dass die bestehende Methode war immer schneller als alles, was mit ich kam. Ich denke, jemand hat darauf geachtet, es zu optimieren.

+0

danke für den Vorschlag, aber ich nehme bereits 1 Stunde Protokolle aus der Hauptprotokolldatei vor der Verarbeitung mit sed durch Abgleich der Zeitstempel aus der Hauptprotokolldatei. Die Datei callref.log besteht aus Anrufbezeichnerwerten und jede Stunde werden etwa 50-90.000 Werte angezeigt. Mein Hauptanliegen ist es, die while-Schleife schneller laufen zu lassen. Wie laden Sie alle Werte von callref.log in einem Array und suchen Sie alle Werte gleichzeitig in einem einzigen Durchlauf von sample.log –

+0

Ihre Suche ist also dynamisch? zB hat Ihr callref.log wechselnde Werte? –

+0

Ja, die Werte in callref.log ändern sich jede Stunde –

0

Da Sie nicht ausreichende Probenprotokolle produzieren könnte sogar gegen testen, wenn gewünscht, ich einige Testmaterial selbst gepeitscht:

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

awk verwenden:

$ 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

Verwandte Themen