快速处理apache日志

时间:2010-01-22 04:28:08

标签: apache awk large-data-volumes

我目前正在运行一个awk脚本来处理一个大的(8.1GB)访问日志文件,它需要永远完成。在20分钟内,它写了14MB(1000 + - 500)MB我期望它写的,我想知道我是否可以更快地处理它。

这是awk脚本:

#!/bin/bash

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

编辑:

对于非awkers,脚本读取每一行,获取日期信息,将其修改为实用程序date识别的格式,并将其调用以将日期表示为自1970年以来的秒数,最后返回作为.csv文件的一行,以及IP。

示例输入: 189.5.56.113 - - [22 / Jan / 2010:05:54:55 +0100]“GET(...)”

退回产出: 189.5.56.113,124237889

5 个答案:

答案 0 :(得分:12)

@OP,你的脚本很慢,主要是因为系统日期命令过多地调用了文件中的每一行,而且它也是一个大文件(在GB中)。如果您有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

答案 1 :(得分:2)

如果你真的需要它更快,你可以做我做的。我使用Ragel重写了一个Apache日志文件分析器。 Ragel允许您将正则表达式与C代码混合使用。正则表达式转换为非常有效的C代码然后编译。不幸的是,这要求您非常舒服在C中编写代码。我不再拥有此分析器。它在1或2秒内处理了1 GB的Apache访问日志。

您可能在从awk语句中删除不必要的printfs并用更简单的东西替换它们的成功有限。

答案 2 :(得分:2)

如果您使用gawk,则可以按照mktimegawk功能)理解的格式按摩您的日期和时间。它会为您提供与您现在使用的时间戳相同的时间戳,并为您节省重复system()次呼叫的开销。

答案 3 :(得分:2)

这个小小的Python脚本在我的机器上大约3分钟处理大约400MB的示例行副本,产生~200MB的输出(请记住你的样本行很短,所以这是一个障碍):

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中重写一样容易。

答案 4 :(得分:1)

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