2010-01-22 9 views
5

Attualmente sto eseguendo uno script awk per elaborare un file di accesso-log di grandi dimensioni (8,1 GB), e ci vorrà un'eternità per finire. In 20 minuti, ha scritto 14 MB di MB (1000 + - 500), mi aspetto che scriva, e mi chiedo se posso elaborarlo molto più velocemente in qualche modo.Elaborazione rapida dei log di apache

Ecco lo script awk:

 
#!/bin/bash 

awk '{t=$4" "$5; gsub("[\[\]\/]"," ",t); sub(":"," ",t);printf("%s,",$1);system("date -d \""t"\" +%s");}' $1 

EDIT:

Per i non awkers, lo script legge ogni riga, ottiene le informazioni sulla data, lo modifica in un formato del l'utility date riconosce e chiama per rappresentare la data come il numero di secondi dal 1970, restituendola infine come una riga di un file .csv, insieme all'IP. Ingresso

Esempio: 189.5.56.113 - - [22/Gen/2010: 05: 54: 55 0100] uscita "GET (...)"

restituiti: 189.5.56.113, 124237889

+2

Forse si potrebbe descrivere quello che lo script fa così noi non-awkers puoi scrivere una sostituzione più veloce in un'altra lingua?Da un colpo d'occhio però, la generazione di un nuovo processo tramite system() su ogni record deve essere piuttosto lenta. –

risposta

11

@OP, lo script è lenta dovuta principalmente alla chiamata eccessiva di comando data di sistema per ogni linea in file e anche un grande file (nel GB). Se si dispone di gawk, usare il suo comando mktime interna() per fare la data in epoca di conversione secondi

awk 'BEGIN{ 
    m=split("Jan|Feb|Mar|Apr|May|Jun|Jul|Aug|Sep|Oct|Nov|Dec",d,"|") 
    for(o=1;o<=m;o++){ 
     date[d[o]]=sprintf("%02d",o) 
    } 
} 
{ 
    gsub(/\[/,"",$4); gsub(":","/",$4); gsub(/\]/,"",$5) 
    n=split($4, DATE,"/") 
    day=DATE[1] 
    mth=DATE[2] 
    year=DATE[3] 
    hr=DATE[4] 
    min=DATE[5] 
    sec=DATE[6] 
    MKTIME= mktime(year" "date[mth]" "day" "hr" "min" "sec) 
    print $1,MKTIME 

}' file 

uscita

$ more file 
189.5.56.113 - - [22/Jan/2010:05:54:55 +0100] "GET (...)" 
$ ./shell.sh  
189.5.56.113 1264110895 
+0

La rimozione della chiamata di sistema() ha reso il mio programma 10 volte più veloce! – konr

2

Se davvero hai bisogno che sia più veloce, puoi fare quello che ho fatto. Ho riscritto un analizzatore di file di log Apache usando Ragel. Ragel ti consente di combinare espressioni regolari con il codice C. Le espressioni regolari vengono trasformate in codice C molto efficiente e quindi compilate. Sfortunatamente, questo richiede che tu sia molto comodo codice di scrittura in C. Non ho più questo analizzatore. Ha elaborato 1 GB di log di accesso Apache in 1 o 2 secondi.

Potresti avere un successo limitato rimuovendo stampe non necessarie dalla tua istruzione awk e sostituendole con qualcosa di più semplice.

2

Se si utilizza gawk, è possibile eseguire il massaggio della data e dell'ora in un formato compatibile con la funzione mktime (una funzione gawk). Ti darà lo stesso timestamp che stai usando ora e ti farà risparmiare l'overhead delle ripetute chiamate system().

2

Questo piccolo script Python gestisce un ~ 400MB vale la pena di copie della vostra linea di esempio in circa 3 minuti sulla mia macchina che produce ~ 200MB di uscita (tenere a mente la linea di campione è stato piuttosto breve, quindi questo è un handicap):

import time 

src = open('x.log', 'r') 
dest = open('x.csv', 'w') 

for line in src: 
    ip = line[:line.index(' ')] 
    date = line[line.index('[') + 1:line.index(']') - 6] 
    t = time.mktime(time.strptime(date, '%d/%b/%Y:%X')) 
    dest.write(ip) 
    dest.write(',') 
    dest.write(str(int(t))) 
    dest.write('\n') 

src.close() 
dest.close() 

un problema minore è che non gestisce fusi orari (strptime() problema), ma si potrebbe o hardcode che o aggiungere un po 'di più per prendersi cura di esso.

Ma ad essere onesti, qualcosa di semplice come che dovrebbe essere altrettanto facile di riscrivere in C.

1
gawk '{ 
    dt=substr($4,2,11); 
    gsub(/\//," ",dt); 
    "date -d \""dt"\" +%s"|getline ts; 
    print $1, ts 
}' yourfile