前回、「リンク元が同じものを1行にまとめるプログラム」というものを作ってみたのですが、一体どんな意味があるのかと思い考えてみたところ、あまり意味がないことに気づきました*1...(^_^;
そこで、refererをチェックするのではなく、requestをチェックして、「1アクセスを1行にまとめるプログラム」に改良しました。
#!/usr/bin/perl -w
use strict;
# ログファイルの整理プログラム log.pl [-dhqDHQ] ver.1.1
# オプション d:date, h:host, q:request を整形して出力
# D:date, H:host, Q:request を整形せずに出力
# 入力するログファイルのフォーマット
# host ident authuser date "request" status bytes "referer"
# "user-agent"\n
# date = [day/month/year:hour:minute:second zone]
# day 2桁, month 3文字, year 4桁, hour 2桁, minute 2桁, second 2桁
# zone (+|-)4桁
# request = command file-pass-name HTTP/*.*
# 出力するログファイルの標準フォーマット(-dhq)
# date host request
# date = day/month/year:hour:minute:second
# day 2桁, month 3文字, year 4桁, hour 2桁, minute 2桁, second 2桁 計20桁
# host 後半20文字
# request 前半37文字
my @delete = qw/ .jpg .gif .cgi .css .ico .sit .txt /; # 除外する拡張子名
my $option = '-dhq';
if (@ARGV) {
if ($ARGV[0] =~ /^-[dhqDHQ]/) {
$option = shift @ARGV;
}
}
foreach (<STDIN>) {
/(^\S+).+(\[\S+ \S+\]) "([^"]+)".+"[^"]+" "[^"]+"\n/;
my $host = $1;
my $date = $2;
my $request = $3;
# 除外する拡張子を持つファイルをリクエストしている行は出力しない
my $out = 1; # 初期値 = 出力する
foreach (@delete) {
if ($request =~ /$_/) {
$out = 0; # 出力しない
last;
}
}
# 出力
if ($out == 1) {
if ($option =~ /d/) { # 秒まで
print substr($date, 1, 20), ' ';
} elsif ($option =~ /D/) { # そのまま
print "$date ";
}
if ($option =~ /h/) { # 後半20文字
printf "%20.20s ", substr($host, -20, 20);
} elsif ($option =~ /H/) { # そのまま
print "$host ";
}
if ($option =~ /q/) { # 前半37文字
$request =~ /^\S+ (\S+) \S+/;
print substr($1, 0, 37);
} elsif ($option =~ /Q/) { # そのまま
print "\"", $request, "\"";
}
print "\n";
}
}
ただでさえPerlっぽい部分が少ないのに、さらに少なくなってしまいました。なお、@delete
に除外する拡張子名(例えば.xml
とか.rdf
等)を半角スペースで区切って追加すると、それらのファイルを要求している行が出力されなくなります。
前回と微妙に違いますな...w