grepによるhttpdログの解析。

httpd(Apache2)にて、httpdのアクセスログから上位のIP、国別表示をしたくなった。

IPの集計であれば、下記のようなコマンドで集計できるはず。

cat /var/log/httpd/access_log | grep "解析したいURL" | cut -d " " -f 1 | sort | uniq -c|sort -nr

実行すると、下記のようにIPアクセスの多い順に並びます。

    550 XXX.XXX.XXX.1
    543 XXX.XXX.XXX.2
    383 XXX.XXX.XXX.3
     97 XXX.XXX.XXX.4
     77 XXX.XXX.XXX.5
     76 XXX.XXX.XXX.6
     30 XXX.XXX.XXX.7
     11 XXX.XXX.XXX.8
     10 XXX.XXX.XXX.9
      8 XXX.XXX.XXX.10
          :

上位のアクセス者はなんでこんなに多い?あ、自分でした。

さらに、IPアドレスから国名を出すスクリプトを追加で入れたなら、こんな感じに。

$ cat /var/log/httpd/access_log  | grep "解析したいURL" | cut -d " " -f 1 | sort | perl ip2cc_stdin.pl |uniq -c|sort -nr|less
    550 XXX.XXX.XXX.1  JP
    543 XXX.XXX.XXX.2  JP
    383 XXX.XXX.XXX.3  JP
     97 XXX.XXX.XXX.4  JP
     77 XXX.XXX.XXX.5  US
     76 XXX.XXX.XXX.6  JP
     30 XXX.XXX.XXX.7  JP
     11 XXX.XXX.XXX.8  US
     10 XXX.XXX.XXX.9  US
      8 XXX.XXX.XXX.10 US

国別が出て良い感じです。ip2cc_stdin.plの元となるものは、こちらのサイトを参考させていただき、標準入力のIPから国別がでるようにしてみました。感謝!

$ cat ip2cc_stdin.pl

#!/usr/bin/perl

use strict;

my $file = 'ipv4.txt';
my @ipv4db = &file($file);
my @stdin = ;

foreach (@stdin) {
    my $ipad = $_;
    chomp($ipad);
    print $ipad ." ". &ip2cc(*ipv4db, $ipad) . "\n";
}


sub file {
    my $file = shift;

    open(FH, $file);
    my @lines = ;
    close(FH);
    chomp @lines;

    return @lines;
}

sub ip2cc {
    *ipv4db = shift;
    my $addr = shift;

    return if ($addr !~ /^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}$/);

    my $num;
    $num = ($num << 8) + $_ foreach (split(/\./, $addr));

    my ($l, $r, $m);
    $l = 0;
    $r = $#ipv4db;

    while ($l <= $r) {
        $m = int(($l + $r) / 2);
        my ($start, $end, $cc) = split(/\t/, $ipv4db[$m]);
        if ($start <= $num && $num < $end) {
            return $cc;
        } elsif ($end < $num) {
            $l = $m + 1;
        } elsif ($start >= $num) {
            $r = $m - 1;
        } else {
            return;
        }
    }
}