はじめに
webサイトへのアクセスがどの時間帯にどのくらいあったのか?
⇒便利なツールが利用できない環境で手作業は時間かかるなぁ
⇒なのでスクリプトでやってみます
動作環境
Raspbian GNU/Linux 10
Apache/2.4.38
perl v5.28.1
Python 3.7.3
コード
- まず生ログをCSVに変換
alog.pl
#!/usr/bin/perl
# Format apache log by tab delimiter
#
# Output: IP timestamp request status byte time referer
#
# Usage:
# alog.pl logfile i.e. alog.pl access.log
# alog.pl < logfile > fmt.txt
# zcat logfile.gz | alog.pl
#
# LogFormat:
# pattern1:combined
# "%a %D %u %t \"%r\" %>s %b \"{Referer}i\" \"%{User-Agent}i\" \"-\J"" combined
#127.0.0.1 - - [12/Nov/2021:14:04:13 +0900] "GET /wp-content HTTP/1.0" 200 5021 "http://foo.com/home.htm" "Mozilla/5.0 (Windows NT 5.01; as-IN; rv:1.9.0.20) Gecko/2021-01-10 16:56:07 Firefox/14.0"
#
# pattern1:common
# "%h %l %u %t \"%r\" %>s %b" common
# 127.0.0.1 - - [10/Apr/2021:17:12:42 +0900] "GET /favicon.ico HTTP/1.1" 200 1150
#
use strict;
use warnings;
use Getopt::Long;
my $opt_fmt = "combined";
my $opt_help = 0;
GetOptions(
"format=s" => \$opt_fmt,
"help" => \$opt_help,
) or disp_usage();
disp_usage() if $opt_help;
sub disp_usage {
print "format apacke log by tab delimiter\n";
print "Usage: $0 [--format=common][--help] <filename> i.e. $0 --format=common access.log\n";
exit;
}
#print "$opt_fmt\n";
my $fmt = qr/^(\S+) (\S+) (\S+) \[(.*?)\] "(\S+)?(\s\S+)?(\s\S+)?" (\d+) (\d+|-)$/;
if ($opt_fmt eq "combined" ) {
$fmt = qr/^(\S+) (\S+) (\S+) \[(.*?)\] "(\S+)?(\s\S+)?(\s\S+)?" (\d+) (\d+|-) "([^"]*)" (.*)$/;
}
my ($ip,$ptime,$usr,$ts,$req,$url,$prt,$sts,$sz,$ref,$oth,$rlog);
my $tabstr;
while (<>) {
if ($_ =~ /$fmt/) {
if ($opt_fmt eq "combined" ) {
($ip,$ptime,$usr,$ts,$req,$url,$prt,$sts,$sz,$ref,$oth) = ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11);
if (defined $req){
$tabstr = join("\t",$ip,$ts,$req,$sts,$sz,$ptime,$ref);
} else {
$tabstr = join("\t",$ip,$ts,"",$sts,$sz,$ptime,$ref);
}
} else {
($ip,$rlog,$usr,$ts,$req,$url,$prt,$sts,$sz) = ($1,$2,$3,$4,$5,$6,$7,$8,$9);
$tabstr = join("\t",$ip,$ts,$req,$sts,$sz);
}
print "$tabstr\n";
} else {
print "Unmatch* $_";
}
}
注意:apacheのログフォーマットによるので必要に応じて修正すること
2.CSVファイルからグラフを作成して画像ファイルを出力
aplot.py
#!/usr/bin/env python3
# plot graph for appache log: number of access by hour
# input: access_log
# outout: aplot.png
# usage ./aplot.png
import pandas as pd
import matplotlib.pyplot as plt
from datetime import datetime
df = pd.read_csv('alog.tsv', sep='\t', header=None, names=['ip', 'datetime', 'method', 'status', 'size', 'referer', 'url'])
# convert date (12/Nov/2023:09:42:45 +0900)
df['datetime'] = df['datetime'].apply(lambda x: datetime.strptime(x.split()[0], "%d/%b/%Y:%H:%M:%S"))
# round time by 1h (2023-11-12 09:00:00)
df['hour'] = df['datetime'].dt.floor('H')
# group by time
access_counts = df.groupby('hour').size()
# plot graph
plt.figure(figsize=(12, 6))
access_counts.plot(kind='line', marker='o')
plt.bar(access_counts.index.astype(str), access_counts.values)
plt.title('Accesses per hour')
plt.xlabel('time')
plt.ylabel('number of access')
plt.grid(True)
plt.xticks(rotation=45)
plt.tight_layout()
plt.savefig('aplot.png')
# if you have GUI
#plt.show()
使い方
アパッチのアクセスログを整形してタブ区切りCSVを生成する
./alog.pl < access_log > alog.tsv
できたCSVからグラフを画像ファイルに出力する
python3 ./aplot.py
Xが使えるなら次のコマンドで画像ファイルを描画
xdg-open aplot.png
おわりに
便利なGUIツールが入れられない場合でもperlは入っていることが多いはず
CSVファイルをインポートしてエクセルの機能でグラフにしてもよい
毎分、IPアドレス毎などでグラフしたい場合は、pythonコードを改良したり、エクセルのテーブルで対応可能