2013-03-30 22 views
0

我需要創建一個關於歷史唯一訪問者(由IP地址標識)的一次性報告,並按日期和操作系統從默認格式的Apache訪問日誌中組織。例如:Apache日誌分析:獨特訪客按日期按操作系統

Date OS Count 
3/1 iPhone 23 
3/1 Windows 402 
3/2 iPhone 32 
etc.. 

我曾與許多工具今日(Octupussy,AWStats的,goaccess,appachetop)實驗,並沒有發現任何東西,提供給打破記錄下這樣的能力。操作系統報告可以在所有這些中找到,但不是一天一天,只是整個日誌。任何人都知道該功能的任何東西?

另請參見: 我正在考慮編寫一個python程序,它將循環訪問日誌並使用正則表達式或系統grep/awk命令,但是如果有一個快速工具或者awk可以輕鬆地執行它,我將很感激輕輕一推。今天之前我從未使用awk,但它看起來很強大,如果我有更多的經驗,可以使它變得簡單。

+0

什麼是Apache Access日誌的「默認格式」?如果你在談論通用日誌格式,它不包含任何用戶代理信息... – FrankieTheKneeMan

+0

我的錯誤,格式實際上是:('127.0.0.1',' - ','frank','10/Oct/2000:13:55:36 -0700','GET /apache_pb.gif HTTP/1.0','http://www.example.com/start.html','Mozilla/4.08 [en](Win98; I ; Nav)') – tsspires

回答

1

您在示例輸出中沒有包含IP地址,我正在使用包含在輸出中的IP地址編寫答案。

我的Apache access.log文件的示例日誌行:

27.0.0.1 - - [28/Oct/2012:21:38:34 +0530] "GET /phpmyadmin HTTP/1.1" 301 559 "-" "Mozilla/5.0 (X11; Linux i686) AppleWebKit/537.4 (KHTML, like Gecko) Chrome/22.0.1229.94 Safari/537.4" 

要獲得基於OS每天的獨立訪客數,他們正在使用:

awk '$6 ~ /GET/ \ 
{ gsub("[[]", "", $4); \ 
gsub(":.*", "", $4); \ 
print $1,$4,$14}' access.log | \ 

sort -t ' ' -k 2 | \ 
uniq -c|awk '{print $3,$2}'|uniq -c|awk '{print $3, $2, $1}' 

以下的答案是基於日期的獨特用戶,每個操作系統的IP。

一個襯裏從上面得到所需要的輸出:

awk '$6 ~ /GET/ \ 
{ gsub("[[]", "", $4); \ 
gsub(":.*", "", $4); \ 
print $1,$4,$14}' access.log | \ 

sort -t ' ' -k 2 | \ 
uniq -c|awk '{print $3,$2,$4,$1}' 

說明

第一AWK線與GET請求來過濾行。

第二個awk行是刪除多餘的右方括號[

第三行將從apache日誌中的日期時間字段中刪除時間。

第四行輸出必填字段。

第五行根據日期排序輸出。

最後,再次使用uniqawk以您希望的格式打印輸出。

輸出:

28/Oct/2012 127.0.0.1 Linux 1 
+0

我想OP希望統計不同的訪問者,因此,當你有'uniq -c | awk'{print $ 3,$ 2,$ 4,$ 1}''時,我認爲'uniq | awk'{print $ 2,$ 3}'| uniq -c | awk'{print $ 2,$ 3,$ 1}''更符合OP的速度。知識產權故意遺漏。 – FrankieTheKneeMan

+0

我已經給出了一個簡約的答案。提供給uniq的輸出是: '127.0.0.1 03/Nov/2012 Linux' 我正在考慮將上述行作爲uniq訪問者。 –

+0

你的答案並不簡單,它是錯誤的。您正在計算每臺操作系統每天每個客戶端IP的訪問次數。 OP需要的是每個操作系統每天唯一的客戶端IP數量。你很接近,但只有一步。我的想法並不是放棄你的答案,而是寫自己的答案,我只是指出你的答案的相當小的修改,使其不同於OP的請求。 – FrankieTheKneeMan

0

對於組合的日誌格式,你可以掃描這樣的:

In [1]: import re 

In [2]: text = '127.0.0.1 - frank [10/Oct/2000:13:55:36 -0700] "GET /apache_pb.gif HTTP/1.0" 200 2326 "http://www.example.com/start.html" "Mozilla/4.08 [en] (Win98; I ;Nav)"' 

In [3]: logitems = re.compile('^(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}) ([^ ]*) ([^ ]*) \[([^\]]*)\] "([^"]*)" \d+ \d+ "([^"]*)" "([^"]*)"') 

In [4]: logitems.findall(text) 
Out[4]: [('127.0.0.1', '-', 'frank', '10/Oct/2000:13:55:36 -0700', 'GET /apache_pb.gif HTTP/1.0', 'http://www.example.com/start.html', 'Mozilla/4.08 [en] (Win98; I ;Nav)')] 

假設text包含日誌文件文本,使用re.findall會產生一個元組的列表包含您想要的信息。

假設你有元組的這份名單中,使用列表中理解和一組以獲得獨立IP(我用一個簡單的二元組用於演示目的在這裏):

In [4]: lst = [('127.0.0.1', 'foo'), ('192.168.0.1', 'bar'), ('123.022.200.023', 'baz'), ('127.0.0.1', 'double')] 

In [5]: [i[0] for i in lst] 
Out[5]: ['127.0.0.1', '192.168.0.1', '123.022.200.023', '127.0.0.1'] 

In [6]: list(set([i[0] for i in lst])) 
Out[6]: ['192.168.0.1', '123.022.200.023', '127.0.0.1'] 

對於所有IP地址,然後你可以得到所有的訪問:

In [8]: [i for i in lst if i[0] == '127.0.0.1'] 
Out[8]: [('127.0.0.1', 'foo'), ('127.0.0.1', 'double')] 

然後,您可以按日期進一步過濾(將其轉換爲datetime.datatime!)和操作系統。