2010-01-22 5 views
5

Je suis en train de lancer un script awk pour traiter un gros fichier journal d'accès (8.1Go), et ça prend une éternité à finir. En 20 minutes, il a écrit 14 Mo du (1000 + - 500) Mo que je m'attendais à écrire, et je me demande si je peux le traiter beaucoup plus rapidement d'une manière ou d'une autre.Traitement rapide des journaux apache

Voici le script awk:

 
#!/bin/bash 

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

EDIT:

Pour les non-awkers, le script lit chaque ligne, reçoit les informations de date, modifie un format de la L'utilitaire date le reconnaît et l'appelle pour représenter la date en tant que nombre de secondes depuis 1970, pour finalement la renvoyer sous la forme d'une ligne d'un fichier .csv, avec l'adresse IP.

entrée Exemple: 189.5.56.113 - - [22/Jan/2010: 05: 54: 55 +0100] "GET (...)"

sortie Retourné: 189.5.56.113, 124237889

+2

Peut-être que vous pourriez décrire ce que le script ne nous donc non-awkers peut écrire un remplacement plus rapide dans une autre langue?D'un coup d'œil cependant, engendrer un nouveau processus via system() sur chaque enregistrement doit être assez lent. –

Répondre

11

@OP, votre script est lent principalement en raison de l'appel excessif de la commande date du système pour chaque ligne dans la fichier, et c'est un gros fichier ainsi (dans le GB). Si vous avez gawk, utilisez la commande mktime interne() pour la date à epoch seconde conversion

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 

sortie

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

La suppression de l'appel system() a rendu mon programme 10 fois plus rapide! – konr

2

Si vous avez vraiment besoin d'être plus rapide, vous pouvez faire ce que j'ai fait. J'ai réécrit un analyseur de fichier journal Apache en utilisant Ragel. Ragel vous permet de mélanger des expressions régulières avec du code C. Les expressions régulières sont transformées en code C très efficace puis compilées. Malheureusement, cela nécessite que vous soyez très confortable en code C. Je n'ai plus cet analyseur. Il a traité 1 Go de journaux d'accès Apache en 1 ou 2 secondes.

Vous avez peut-être un succès limité en supprimant des printfs inutiles de votre instruction awk et en les remplaçant par quelque chose de plus simple.

2

Si vous utilisez gawk, vous pouvez masquer votre date et heure dans un format que mktime (une fonction gawk) comprend. Il vous donnera le même horodatage que vous utilisez maintenant et vous économiserez le temps de répétition des appels system().

2

Ce petit script Python gère une valeur ~ 400 Mo de copies de votre ligne d'exemple à environ 3 minutes sur ma machine de production ~ 200Mo de sortie (gardez à l'esprit votre ligne de l'échantillon était assez courte, de sorte que c'est un handicap):

Un problème mineur est qu'il ne gère pas les fuseaux horaires (problème strptime()), mais vous pouvez le coder en dur ou en ajouter un peu pour en prendre soin.

Mais pour être honnête, quelque chose d'aussi simple que cela devrait être tout aussi facile de réécrire en C.

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