2010-01-22 16 views
5

Actualmente estoy ejecutando una secuencia de comandos awk para procesar un gran archivo de acceso-registro (8.1 GB), y está tardando mucho en terminar. En 20 minutos, escribió 14 MB del (1000 + - 500) MB que espero que escriba, y me pregunto si puedo procesarlo mucho más rápido de alguna manera.Procesando registros de apache rápidamente

Aquí es el script awk:

 
#!/bin/bash 

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

EDIT:

Para los no awkers, la secuencia de comandos lee cada línea, obtiene la información de fecha, lo modifica a un formato que el La utilidad date reconoce y lo llama para representar la fecha como la cantidad de segundos desde 1970, y finalmente la devuelve como una línea de un archivo .csv, junto con la IP.

Ejemplo de entrada: 189.5.56.113 - - [22/Ene/2010: 05: 54: 55 0100] salida de "Get (...)"

devuelto: 189.5.56.113, 124237889

+2

Tal vez podría describir lo que el guión lo hace nosotros no awkers puede escribir un reemplazo más rápido en otro idioma?Sin embargo, desde un vistazo, generar un nuevo proceso a través del sistema() en cada registro debe ser bastante lento. –

Respuesta

11

@OP, su guión es lento, debido principalmente a la llamada excesivo de comando fecha del sistema para cada línea en el archivo, y es un archivo grande también (en el GB). Si tiene gawk, utilice su comando mktime interno() que ver la fecha del cambio de época conversión segundos

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 

salida

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

Eliminar la llamada al sistema() hizo que mi programa 10 veces más rápido! – konr

2

Si realmente necesita que sea más rápido, puede hacer lo que hice. Reescribí un analizador de archivos de registro Apache usando Ragel. Ragel le permite mezclar expresiones regulares con código C. Las expresiones regulares se transforman en un código C muy eficiente y luego se compilan. Desafortunadamente, esto requiere que esté muy cómodo escribiendo el código en C. Ya no tengo este analizador. Procesó 1 GB de registros de acceso de Apache en 1 o 2 segundos.

Puede tener un éxito limitado eliminando printfs innecesarios de su declaración awk y reemplazándolos por algo más simple.

2

Si está utilizando gawk, puede dar masajes a su fecha y hora en un formato que mktime (una función gawk) entiende. Le dará la misma marca de tiempo que está usando ahora y le ahorrará la sobrecarga de llamadas repetidas system().

2

Este pequeño script Python maneja una 400MB pena ~ de copias de su línea de ejemplo en unos 3 minutos en mi máquina que produce ~ 200 MB de salida (tenga en cuenta que su línea de muestra era bastante corto, por lo que es una desventaja):

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 menor es que no maneja las zonas horarias (problema de strptime()), pero puede codificar eso o agregar un poco más para encargarse de ello.

Pero para ser honesto, algo tan simple como que debería ser tan fácil volver a escribir en C.

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