apache htttpdのログを可視化(グラフ?)してみることにした
テキストなログファイルをパースしてsqlへ取り込んでdhtmlxを駆使して簡易的なものを作ろうかと
思ったのだが、調べたらawstatsで足りるみたい。ちょうどepelリポジトリから入手可能だったのでこれを使ってみた
本家様 https://awstats.sourceforge.io/+
2017.07現在最新版は バージョン7.6 (epel版も同じく7.6)
インストール †
epelリポジトリが設定されていれば
[root@c ~]# yum --enablerepo=epel install awstats
で本体と関連する必須パッケージも同時にインストールされる
留意インストールの段階で自動的に設定ファイルが以下の場所に作成されてしまいます。
/etc/awstats/awstats.<FQDN>.conf
*FQDNが、c.sybyl.localなら「/etc/awstats/awstats.c.sybyl.local.conf」
httpd設定 †
セットアップ方法はhttps://awstats.sourceforge.io/docs/awstats_setup.html
に
記載されているが、rpmパッケージでインストールしたので、その状況をまず確認する
[root@c ~]# rpm -qali | less
:
Name : awstats
Version : 7.6
Release : 3.1.el7
Architecture: noarch
:
/etc/awstats
/etc/awstats/awstats.localhost.localdomain.conf
/etc/awstats/awstats.model.conf
/etc/cron.hourly/awstats
/etc/httpd/conf.d/awstats.conf
:
[root@c ~]#
とある。まずはhttpd向けの設定を修正します
[root@c ~]# cp -p /etc/httpd/conf.d/awstats.conf /etc/httpd/conf.d/awstats.conf.orig
[root@c ~]# vi /etc/httpd/conf.d/awstats.conf
[root@c ~]# diff -u /etc/httpd/conf.d/awstats.conf.orig /etc/httpd/conf.d/awstats.conf
--- /etc/httpd/conf.d/awstats.conf.orig 2017-05-31 23:01:21.000000000 +0900
+++ /etc/httpd/conf.d/awstats.conf 2017-07-30 19:38:36.665846738 +0900
@@ -26,7 +26,7 @@
AllowOverride None
<IfModule mod_authz_core.c>
# Apache 2.4
- Require local
+ Require ip 192.168.0.
</IfModule>
<IfModule !mod_authz_core.c>
# Apache 2.2
[root@c ~]#
[root@c ~]# systemctl reload httpd
awstats設定(追加) †
これで内部ネットワークからはアクセスできる状態になった. アクセス先は c.sybyl.local/awstats/awstats.pl である

と表示され内部アドレスベース(c.sybyl.local)での接続は問題ない。っが、この c.sybyl.local は
一方で外部向け web.chaperone.jp の担当なのだが、
web.chaperone.jpにアクセスすると下記のように表示されてしまう

*内輪ごとです
ローカル内は DNS で web.chaperone.jp を c.sybyl.local にアサインしているのだが、これだと面倒で
かつ外部からweb.chaperone.jpの awstats を閲覧できない。そのため、インストール時に作成されたawstats.c.sybyl.local.confを
awstats.web.chaperone.jp.confに変更する
上記説明文から
[root@c ~]# cp -p /etc/awstats/awstats.c.sybyl.local.conf /etc/awstats/awstats.web.chaperone.jp.conf
[root@c ~]# mv /etc/awstats/awstats.c.sybyl.local.conf /etc/awstats/awstats.c.sybyl.local.conf.old
[root@c ~]# vi /etc/awstats/awstats.web.chaperone.jp.conf
っでc.sybyl.localとの比較
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
| | [root@c ~]# diff -u /etc/awstats/awstats.c.sybyl.local.conf.old /etc/awstats/awstats.web.chaperone.jp.conf
--- /etc/awstats/awstats.c.sybyl.local.conf.old 2017-07-30 19:37:44.950616897 +0900
+++ /etc/awstats/awstats.web.chaperone.jp.conf 2017-07-30 20:10:20.145598451 +0900
@@ -153,7 +153,7 @@
# Example: "ftp.domain.com"
# Example: "domain.com"
#
-SiteDomain="c.sybyl.local"
+SiteDomain="web.chaperone.jp"
# Enter here all other possible domain names, addresses or virtual host
@@ -168,7 +168,7 @@
# Note: You can also use @/mypath/myfile if list of aliases are in a file.
# Example: "www.myserver.com localhost 127.0.0.1 REGEX[mydomain\.(net|org)$]"
#
-HostAliases="REGEX[^.*c\.sybyl\.local$]"
+HostAliases="localhost 127.0.0.1 REGEX[\.sybyl\.local$] REGEX[^192\.168\.0\.]"
# If you want to have hosts reported by name instead of ip address, AWStats
@@ -188,7 +188,7 @@
# 2 - DNS Lookup is made only from static DNS cache file (if it exists)
# Default: 2
#
-DNSLookup=2
+DNSLookup=1
# For very large sites, setting DNSLookup to 0 (or 2) might be the only
@@ -480,7 +480,7 @@
# Example: "localhost REGEX[^.*\.localdomain$]"
# Default: ""
#
-SkipHosts="127.0.0.1"
+SkipHosts="127.0.0.1 REGEX[^192\.168\.0\.]"
# Do not include access from clients with a user agent that match following
[root@c ~]#
|
また、既定のオリジナルとの比較は下記になる
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
| | [root@c ~]# diff -u /etc/awstats/awstats.model.conf /etc/awstats/awstats.web.chaperone.jp.conf
--- /etc/awstats/awstats.model.conf 2017-05-31 23:01:21.000000000 +0900
+++ /etc/awstats/awstats.web.chaperone.jp.conf 2017-07-30 20:10:20.145598451 +0900
@@ -153,7 +153,7 @@
# Example: "ftp.domain.com"
# Example: "domain.com"
#
-SiteDomain="localhost.localdomain"
+SiteDomain="web.chaperone.jp"
# Enter here all other possible domain names, addresses or virtual host
@@ -168,7 +168,7 @@
# Note: You can also use @/mypath/myfile if list of aliases are in a file.
# Example: "www.myserver.com localhost 127.0.0.1 REGEX[mydomain\.(net|org)$]"
#
-HostAliases="localhost 127.0.0.1"
+HostAliases="localhost 127.0.0.1 REGEX[\.sybyl\.local$] REGEX[^192\.168\.0\.]"
# If you want to have hosts reported by name instead of ip address, AWStats
@@ -188,7 +188,7 @@
# 2 - DNS Lookup is made only from static DNS cache file (if it exists)
# Default: 2
#
-DNSLookup=2
+DNSLookup=1
# For very large sites, setting DNSLookup to 0 (or 2) might be the only
@@ -480,7 +480,7 @@
# Example: "localhost REGEX[^.*\.localdomain$]"
# Default: ""
#
-SkipHosts="127.0.0.1"
+SkipHosts="127.0.0.1 REGEX[^192\.168\.0\.]"
# Do not include access from clients with a user agent that match following
[root@c ~]#
|
既存ログの吸い上げ †
/var/log/httpdフォルダに過去ログが残っている
それを吸い上げてデータベース化します。データベースの場所はawstats.web.chaperone.jp.confの「DirData」で定義され、既定は「/var/lib/awstats」です。
[root@c ~]# /usr/share/awstats/wwwroot/cgi-bin/awstats.pl -update -config=web.chaperone.jp \
-update -logfile=/var/log/httpd/access_log-20170716
[root@c ~]# /usr/share/awstats/wwwroot/cgi-bin/awstats.pl -update -config=web.chaperone.jp \
-update -logfile=/var/log/httpd/access_log
これで過去ログの収集は完了。次に日々のデータ収集であるが、cronを使うように用意されている
[root@c ~]# cat /etc/cron.hourly/awstats
#!/bin/bash
exec /usr/share/awstats/tools/awstats_updateall.pl now -configdir="/etc/awstats"
-awstatsprog="/usr/share/awstats/wwwroot/cgi-bin/awstats.pl" >/dev/null
exit 0
[root@c ~]#
とある。「-configdir」で「/etc/awstats」を示しているのでcronの毎時処理で/etc/awstatsのconfファイルが読み込まれることになる。
現在不要な設定ファイルが存在しているので、それらを無効化する
[root@c ~]# ls -l /etc/awstats/
合計 256
-rw-r--r-- 1 root root 63601 7月 30 19:37 awstats.c.sybyl.local.conf.old
-rw-r--r-- 1 root root 63602 5月 31 23:01 awstats.localhost.localdomain.conf
-rw-r--r-- 1 root root 63602 5月 31 23:01 awstats.model.conf
-rw-r--r-- 1 root root 63664 7月 30 20:10 awstats.web.chaperone.jp.conf
[root@c ~]#
[root@c ~]# mv /etc/awstats/awstats.model.conf /etc/awstats/awstats.model.conf.orig
[root@c ~]# mv /etc/awstats/awstats.localhost.localdomain.conf /etc/awstats/awstats.localhost.localdomain.conf.orig
[root@c ~]# ls -l /etc/awstats/*.conf
-rw-r--r-- 1 root root 63664 7月 30 20:10 /etc/awstats/awstats.web.chaperone.jp.conf
[root@c ~]#
ちょいと修正 †
「最後の訪問」欄が二段になっていて不味い。なので修正してみた
[root@c ~]# cp /usr/share/awstats/wwwroot/cgi-bin/awstats.pl /usr/share/awstats/wwwroot/cgi-bin/awstats.pl.orig
[root@c ~]# vi /usr/share/awstats/wwwroot/cgi-bin/awstats.pl
変更内容
1
2
3
4
5
6
7
8
9
10
11
12
| | [root@c ~]# diff -u /usr/share/awstats/wwwroot/cgi-bin/awstats.pl.orig /usr/share/awstats/wwwroot/cgi-bin/awstats.pl
--- /usr/share/awstats/wwwroot/cgi-bin/awstats.pl.orig 2016-12-03 21:58:28.000000000 +0900
+++ /usr/share/awstats/wwwroot/cgi-bin/awstats.pl 2017-07-30 20:52:55.746873132 +0900
@@ -12538,7 +12538,7 @@
"<th class=\"datasize\" bgcolor=\"#$color_k\" width=\"80\">$Message[75]</th>";
}
if ( $ShowHostsStats =~ /L/i ) {
- print "<th width=\"120\">$Message[9]</th>";
+ print "<th width=\"160\">$Message[9]</th>";
}
print "</tr>\n";
$total_p = $total_h = $total_k = 0;
[root@c ~]#
|
これで
から
となる
*ソースを変更せず、cssで修正すべきかも知れないが、即座に反映できる方法で行った
Plugins †
結構便利なPluginが公表されている
ここでは「AWStats Follow Me Plugin」を取り上げる
http://www.internetofficer.com/awstats/plugin-follow-me/
このサイトの「Free Download and Installation」リンクに行ってPluginファイル(follow_me_by_internetofficer.pm)を入手します。
次にそれを「/usr/share/awstats/plugins/」にコピーする.
AWStats config file(/etc/awstats/awstats.web.chaperone.jp.conf)に下記を追加すれば完了です。
LoadPlugin="follow_me_by_internetofficer"
注意 上記サイトでも指摘しているが、awstatsで「DNS lookup」機能を使っていると使えません。
なのでそれに対応するパッチが提示されている。
http://www.internetofficer.com/forum/awstats-plugins/follow-me-click-path-analysis-with-awstats/
だけど、上手く動かない。
「@fields = split('t', $_);」は「@fields = split('\t', $_);」と「タブ(\t)」だと思うのだが...
っで、どうしても変換できないホスト名もなぜかあるので、下記のようなpatchを作った
| [root@c ~]# diff -u /usr/share/awstats/plugins/follow_me_by_internetofficer.pm.orig /usr/share/awstats/plugins/follow_me_by_internetofficer.pm
--- /usr/share/awstats/plugins/follow_me_by_internetofficer.pm.orig 2017-08-30 21:30:47.256613048 +0900
+++ /usr/share/awstats/plugins/follow_me_by_internetofficer.pm 2017-08-30 21:44:48.229638389 +0900
@@ -109,9 +109,25 @@
if ($host eq '__title__') {
print '<th width="40">' . $plugin_message{'Follow Me'} . '</th>' ;
} elsif ($host) {
+my $ip="";
+$filename = '/var/lib/awstats/dnscachelastupdate.' . $SiteDomain . '.txt';
+if (open(FILE, $filename)) {
+ while(<FILE>)
+ {
+ chomp;
+ @fields = split('\t', $_);
+ if (lc($fields[2]) eq $host) {
+ $ip = $fields[1];
+ }
+ }
+ close FILE;
+}
print "<td>";
- print '<a href="' . $AWScript . '?config=' . $SiteConfig . '&pluginmode=follow_me_by_internetofficer&host=' . $host
+if ( $ip ne "" ){
+ print '<a href="' . $AWScript . '?config=' . $SiteConfig . '&pluginmode=follow_me_by_internetofficer&host=' . $ip
. ($Lang ? '&lang=' . $Lang : '') . '" target="_blank">' . $plugin_message{'Zoom'} . '</a>' ;
+}
+ print "</td>";
} else {
print "<td> </td>";
}
[root@c ~]#
|
っが、、、dnscachelastupdateファイルに存在しないものはNULLになります
ホスト名からIPを引っ張ってもいいような気がするけど...
結構な負荷になりますが、逐次名前からipを持ってくるなら
| [root@c ~]# diff -u /usr/share/awstats/plugins/follow_me_by_internetofficer.pm.orig [root@c ~]# diff -u /usr/share/awstats/plugins/follow_me_by_internetofficer.pm.orig /usr/share/awstats/plugins/follow_me_by_internetofficer.pm
--- /usr/share/awstats/plugins/follow_me_by_internetofficer.pm.orig 2017-08-30 21:30:47.256613048 +0900
+++ /usr/share/awstats/plugins/follow_me_by_internetofficer.pm 2017-08-30 22:34:10.426555690 +0900
@@ -110,8 +110,13 @@
print '<th width="40">' . $plugin_message{'Follow Me'} . '</th>' ;
} elsif ($host) {
print "<td>";
- print '<a href="' . $AWScript . '?config=' . $SiteConfig . '&pluginmode=follow_me_by_internetofficer&host=' . $host
+my $ip="";
+$ip = join('.', unpack('C4', gethostbyname($host)));
+if ( $ip ne "" ){
+ print '<a href="' . $AWScript . '?config=' . $SiteConfig . '&pluginmode=follow_me_by_internetofficer&host=' . $ip
. ($Lang ? '&lang=' . $Lang : '') . '" target="_blank">' . $plugin_message{'Zoom'} . '</a>' ;
+}
+ print "</td>";
} else {
print "<td> </td>";
}
[root@c ~]#
|
となる。