apachelog モジュール

以前までは、apache2のログを見るときは シェルスクリプトで適当にフェッチャやクローラらしき文字列を"grep -v"ではじいたりして 眺めてたのですが、もうちょっと便利にならないかなと思い Pythonの拡張モジュール apachelog を使ったスクリプトに変えてみました。

#!/bin/bash -x

grep -v robots.txt /var/log/apache2/access.log | \
grep -v \/static\/ | \
grep -v \/blog\/rss | \
grep -v robots.txt | \
grep -v ApacheBench | \
grep -v FeedFetcher | \
grep -v Baiduspider | \
grep -v BaiduImagespider | \
         :
grep -v "Yahoo! Slurp" | \
grep -v crawler

上記は以前までのシェルスクリプトです。ただ単に特定の文字をはじいているだけです。 以下はapachelogモジュールを使ったPythonスクリプトです。

#!/usr/bin/env python
import gzip
import sys
import urllib
import apachelog

default_log = "/var/log/apache2/access.log"
format = r"\"%{X-Forwarded-For}i\" %l %u %t \"%r\" " \
         r"%>s %b \"%{Referer}i\" \"%{User-Agent}i\""

ip_graylist = [
        "-",
        ]
access_ignorelist = [
        "HEAD",
        ]
useragent_graylist = [
        "localhost",
        "OPTIONS",
        ]

def check_ip_graylist(log):
    for g in ip_graylist:
        if g in log['%{X-Forwarded-For}i']:
            return False
    return True

def check_ua_graylist(log):
    for g in useragent_graylist:
        if g in log['%{User-Agent}i']:
            return False
    return True

def check_ignorelist(log):
    for g in access_ignorelist:
        if g in log['%r']:
            return False
    return True

def check_log(log):
    ret = None
    if False == check_ip_graylist(log):
        ret = True
    if False == check_ua_graylist(log):
        ret = True
    if False == check_ignorelist(log):
        ret = True
    return ret

def main(files):
    parser = apachelog.parser(format)
    for logfile in files:
        if logfile.endswith('.gz'):
            localopen = gzip.open
        else:
            localopen = open
        for line in localopen(logfile).readlines():
            log = parser.parse(line)
            if check_log(log):
                continue
            log['%{Referer}i'] = urllib.unquote(log['%{Referer}i'])
            print "%s %15s" % (log['%t'], log['%{X-Forwarded-For}i'])
            print "  request   :: %s" % (log['%r'])
            print "  user-agent:: %s" % (log['%{User-Agent}i'].split()[0])
            print "  referer   :: %s" % (log['%{Referer}i'])

if __name__ == '__main__':
    if 1 == len(sys.argv):
        main([default_log,])
    else:
        main(sys.argv[1:])

出力されるログは以下のようなものになります。 (ログの内容は若干いじってます。)

[17/Jul/2009:01:51:22 +0900]   127.0.0.1
  request   :: GET /blog/detail/30/ HTTP/1.1
  user-agent:: Mozilla/5.0
  referer   :: http://www.google.co.jp/search?q=ログ解析 Python&hl=ja&lr=&start=10&sa=N
[17/Jul/2009:23:26:26 +0900]   127.0.0.1
  request   :: GET /hgrepos/pyprof2html/ HTTP/1.1
  user-agent:: Mozilla/4.0
  referer   :: -
[18/Jul/2009:00:35:18 +0900]   127.0.0.1
  request   :: GET /ditz/pyprof2html/index.html HTTP/1.1
  user-agent:: Mozilla/4.0
  referer   :: -

なかなか便利です。