2010-01-22 106 views
5

我目前正在運行一個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

回答

11

@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

2

如果你真的需要它更快,你可以做我做的。我使用Ragel重寫了一個Apache日誌文件分析器。 Ragel允許您將正則表達式與C代碼混合使用。正則表達式轉換爲非常高效的C代碼,然後進行編譯。不幸的是,這要求你非常舒服用C編寫代碼。我不再有這個分析器。它在1或2秒內處理1 GB的Apache訪問日誌。

從awk語句中刪除不必要的printfs並用簡單的替換它們可能會有限的成功。

2

如果您使用的是gawk,則可以將日期和時間按摩到mktime(一個gawk函數)能夠理解的格式。它會給你現在使用的相同時間戳,併爲你節省重複撥打system()的費用。

2

這個小的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重寫

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