快速处理apache日志

快速处理apache日志

问题描述:

我目前正在运行一个awk脚本来处理一个大的(8.1GB)访问日志文件,并且它将永久完成。在20分钟内,它写了14MB(1000 + - 500)MB我期望它写,我不知道我能否以更快的速度处理它。快速处理apache日志

这里是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 /月/ 2010:05:54:55 0100] “GET(...)”

返回的输出: 189.5.56.113, 124237889

+2

也许你能描述一下脚本这样做我们不awkers可以用另一种语言编写更快的替代品?但从一眼看来,在每个记录上通过system()产生一个新进程都会非常缓慢。 – 2010-01-22 04:43:27

@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 
+0

删除system()调用使我的程序速度提高了10倍! – konr 2010-01-22 09:15:40

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

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

如果您使用的是gawk,则可以将日期和时间按摩到mktime(一个gawk函数)能够理解的格式。它会给你现在使用的相同时间戳,并为你节省重复拨打system()的费用。

这个小的Python脚本处理你的榜样行的拷贝的〜400MB值得在我的机器生产上约3分钟〜输出的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重写

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