Быстрая обработка логов apache - PullRequest
6 голосов
/ 22 января 2010

В настоящее время я запускаю сценарий awk для обработки большого (8,1 ГБ) файла журнала доступа, и его завершение занимает вечность. Через 20 минут он записал 14 МБ из (1000 + - 500) МБ. Я ожидаю, что он напишет, и мне интересно, смогу ли я как-то обработать его намного быстрее.

Вот скрипт awk:

#!/bin/bash

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

РЕДАКТИРОВАТЬ:

Для неопытных сценарий читает каждую строку, получает информацию о дате, изменяет ее в формат, который утилита date распознает, и вызывает ее для представления даты в виде количества секунд с 1970 года, наконец возвращая ее строка файла .csv вместе с IP.

Пример ввода: 189.5.56.113 - - [22 / Jan / 2010: 05: 54: 55 +0100] "GET (...)"

Возвращаемый результат: 189.5.56.113,124237889

Ответы [ 5 ]

12 голосов
/ 22 января 2010

@ OP, ваш скрипт работает медленно, в основном из-за чрезмерного вызова команды системной даты для каждой строки в файле, а также для большого файла (в ГБ). Если у вас есть gawk, используйте его внутреннюю команду mktime () для преобразования даты в эпоху

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

выход

$ more file
189.5.56.113 - - [22/Jan/2010:05:54:55 +0100] "GET (...)"
$ ./shell.sh    
189.5.56.113 1264110895
2 голосов
/ 22 января 2010

Если вы используете gawk, вы можете преобразовать дату и время в формат, понятный mktime (функция gawk). Это даст вам ту же временную метку, которую вы используете сейчас, и избавит вас от накладных расходов при повторных system() вызовах.

2 голосов
/ 22 января 2010

Этот маленький скрипт на Python обрабатывает примерно 400 МБ копий вашей строки примера примерно за 3 минуты на моей машине с выходной мощностью ~ 200 МБ (имейте в виду, что ваша строка выборки была довольно короткой, так что это препятствие):

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()

Небольшая проблема заключается в том, что он не обрабатывает часовые пояса (проблема strptime ()), но вы можете либо жестко закодировать его, либо добавить немного больше, чтобы позаботиться об этом.

Но, честно говоря, что-то столь же простое, как это должно быть так же легко переписать в C.

2 голосов
/ 22 января 2010

Если вам действительно нужно, чтобы это было быстрее, вы можете сделать то, что я сделал. Я переписал анализатор лог-файлов Apache, используя Ragel. Ragel позволяет смешивать регулярные выражения с C-кодом. Регулярные выражения преобразуются в очень эффективный код C, а затем компилируются. К сожалению, это требует, чтобы вы очень удобно писали код на C. У меня больше нет этого анализатора. Он обработал 1 ГБ журналов доступа Apache за 1 или 2 секунды.

У вас может быть ограниченный успех, удаляя ненужные printfs из вашего оператора awk и заменяя их чем-то более простым.

1 голос
/ 07 июня 2013
gawk '{
    dt=substr($4,2,11); 
    gsub(/\//," ",dt); 
    "date -d \""dt"\" +%s"|getline ts; 
    print $1, ts
}' yourfile
...