me44.org

Top> 管理人のメモ帳

000010: gawkで簡易Apacheログビューアを作成

§概要

余興で作ってみますた。ちなみにあっしはgawkのエキスパートではないので悪しからず。
gawk : 3.1.7, Apache : 2.2.15, CentOS : 6.3

§下準備(Apacheログのフォーマット変更)

デフォルトのApacheログフォーマット(combined)のままでは扱いにくいので変更します。
(combinedフォーマットのログを見やすくするのならgawkでなく別の手段にしたほうが
よいでしょー)httpd.confに新しいフォーマット(myset)を追加します。

LogFormat "\"%{%Y/%m/%d %H:%M:%S}t\"\t\"%h\"\t\"%l\"\t\"%u\"\t\"%r\"\t\"%>s\"\t\"%b\"\t\"%{Referer}i\"\t\"%{User-Agent}i\"" myset

現在有効になっているフォーマット設定をコメントにし、mysetを有効に設定します。
#CustomLog logs/access_log combined   # コメントにする
CustomLog logs/access_log myset     # 追加

ログフォーマットの設定については、他サイトを参照してください。
myset は「combinedの設定をベースとして、順番と日時のフォーマットを変え、ダブルクォートで
くくって、タブ(\t)で区切った」という設定です。
「タブ(\t)で区切る」という部分は必須です。他の「ダブルクォートでくくる」等は
お好みでやってください。
gawkの区切り文字にはどのような文字も指定可能ですが、カンマやスペースはApacheログのデータに
登場するのでダメです。
gawkでは組み込み変数 FS に設定された区切り文字で各データを分割し、フィールドに展開してくれます。

§仕様概略

詳細は割愛します(ソース見てください)。
 ・ページ本体へのアクセスのみを処理対象とする
 ・以下のタイプ分けを行い、カウントを取る
   SEARCH  検索サイトからのアクセス
   GNRL   検索サイト以外からのアクセス
   DIRECT  直接アクセス(厳密に言えばリファラーなし)
   INTMOV  自サイト内ページ遷移
   ROBOT   BOT、クローラー
   OTHER   上記以外

§ソース (最終更新:2012/11/29

001 : BEGIN {
002 :   # $1  datime
003 :   # $2  request host ip addr
004 :   # $5  request
005 :   # $6  response code
006 :   # $8  Referer
007 :   # $9  UserAgent
008 :   FS="\t";
009 :   FALSE = 0;
010 :   TRUE = 1;
011 :
012 :   #### Option Setting ####
013 :   #intShowBot = FALSE
014 :   intShowBot = FALSE;
015 :   intShowRef = FALSE;
016 :   intIgnore = 0;      # Normally, set 0
017 :
018 :   #### Counter Initialize ####
019 :   intCntSearch = 0;
020 :   intCntGnrl = 0;
021 :   intCntDirect = 0;
022 :   intCntIntmov = 0;
023 :   intCntBot    = 0;
024 :   intCntOther  = 0;
025 : }
026 : #### pattern 1 ####
027 : NR > intIgnore && ( \
028 :   $5 ~ / \/ / \
029 :   || $5 ~ /index\.html / \
030 :   || $5 ~ /memo/ \
031 : ) && $5 !~ / *HEAD / {
032 :   #### Variable initialize ####
033 :   intIsOther = FALSE;
034 :   intIsBot   = FALSE;
035 :   strType    = "";
036 :
037 :   #### Reduce request string length ####
038 :   strReq = $5;
039 :   # sub(/GET /, "", strReq);
040 :   # sub(/POST /, "", strReq);
041 :   sub(/ HTTP\/[0-9]\.[0-9]/, "", strReq);
042 :
043 :   #### Type decision ####
044 :   #### SEARCH ####
045 :   chkSearch();
046 :   if (length(strType) > 0) {
047 :     intCntSearch ++;
048 :     output();
049 :   }
050 :   #### GNRL   ####
051 :   chkGeneral();
052 :   if (length(strType) > 0) {
053 :     intCntGnrl ++;
054 :     output();
055 :   }
056 :   #### ROBOT  ####
057 :   chkRobot();
058 :   if (length(strType) > 0) {
059 :     intCntBot ++;
060 :     intIsBot = TRUE;
061 :     output();
062 :   }
063 :   #### INTMOV  ####
064 :   if ($8 ~ /^\"http\:\/\/me44\.org\// \
065 :       || $8 ~ /^\"http\:\/\/www\.me44\.org\// \
066 :       || $8 ~ /^\"http\:\/\/me44\.org/ \
067 :       || $8 ~ /^\"http\:\/\/www\.me44\.org/) {
068 :     strType = "INTMOV: -";
069 :     intCntIntmov ++;
070 :   }
071 :   #### DIRECT  ####
072 :   else if ($8 ~ /^\"-\"$/) {
073 :     strType = "DIRECT: -";
074 :     intCntDirect ++;
075 :   }
076 :   #### OTHER   ####
077 :   else {
078 :     strType = "OTHER : -";
079 :     intIsOther = TRUE;
080 :     intCntOther ++;
081 :   }
082 :   output();
083 : }
084 : END {
085 :   print "\n#### " \
086 :     "SEARCH: " intCntSearch ", " \
087 :     "GNRL  : " intCntGnrl   ", " \
088 :     "DIRECT: " intCntDirect ", " \
089 :     "INTMOV: " intCntIntmov ", " \
090 :     "ROBOT : " intCntBot    ", " \
091 :     "OTHER : " intCntOther " ####";
092 : }
093 : function chkSearch() {
094 :
095 :   if($8 ~ /www\.google\.co\.jp\/url/) { strType = "SEARCH: google.co.jp"; return; }
096 :   if($8 ~ /www\.google\.co\.jp\/search/) { strType = "SEARCH: google.co.jp"; return; }
097 :   if($8 ~ /www\.google\.com\/url/) { strType = "SEARCH: google.com"; return; }
098 :   if($8 ~ /www\.google\.com\/search/) { strType = "SEARCH: google.com"; return; }
099 :   if($8 ~ /www\.google\.com\/m\?q\=/) { strType = "SEARCH: google.com"; return; }
100 :   if($8 ~ /search\.yahoo\.co\.jp\//) { strType = "SEARCH: yahoo.co.jp"; return; }
101 :   if($8 ~ /www\.bing\.co\.jp\//) { strType = "SEARCH: bing.co.jp"; return; }
102 :   if($8 ~ /www\.bing\.com\//) { strType = "SEARCH: bing.com"; return; }
103 : }
104 : function chkGeneral() {
105 :   if($8 ~ /t\.co\//)        { strType = "GNRL  : Twitter"; return; }
106 :   if($8 ~ /twitter\.com\//) { strType = "GNRL  : Twitter"; return; }
107 :   if($8 ~ /getpocket\.com\/unread/) { strType = "GNRL  : getpocket.com"; return; }
108 : }
109 : function chkRobot() {
110 :   if($9 ~ /www\.google\.com\/bot\.html/) { strType = "ROBOT : google.com"; return; }
111 :   if($9 ~ /www\.bing\.com\/bingbot\.htm/) { strType = "ROBOT : bing.com"; return; }
112 :   if($9 ~ /www\.baidu\.com\/search\/spider\.html/) { strType = "ROBOT : baidu.com"; return; }
113 :   if($9 ~ /ezooms\.bot\@gmail\.com/)  { strType = "ROBOT : ezooms_bot"; return; }
114 :   if($9 ~ /SurveyBot.*DomainTools/)   { strType = "ROBOT : DomainTools"; return; }
115 :   if($9 ~ /LightspeedSystems/)        { strType = "ROBOT : LSS"; return; }
116 :   if($9 ~ /UnwindFetchor.*gnip\.com/) { strType = "ROBOT : Gnip"; return; }
117 :   if($9 ~ /Twitterbot/)               { strType = "ROBOT : TwitterBot"; return; }
118 :   if($9 ~ /TweetmemeBot/)             { strType = "ROBOT : TweetmemeBot"; return; }
119 :   if($9 ~ /Butterfly.*topsy\.com\/butterfly/) { strType = "ROBOT : Topsy"; return; }
120 :   if($9 ~ /Yahoo\! Slurp/)            { strType = "ROBOT : YahooSlurp"; return; }
121 :   if($9 ~ /MJ12bot/)                  { strType = "ROBOT : MJ12bot"; return; }
122 :   if($9 ~ /JS\-Kit URL Resolver/)     { strType = "ROBOT : JS-Kit"; return; }
123 :   if($9 ~ /YJApp-ANDROID jp.co.yahoo.android.yjtop/) { strType = "ROBOT : YJApp-ANDROID"; return; }
124 :   if($9 ~ /ips\-agent/)               { strType = "ROBOT : Verisign"; return; }
125 :   if($9 ~ /TurnitinBot/)              { strType = "ROBOT : Turnitin"; return; }
126 :   if($9 ~ /ia\_archiver/)             { strType = "ROBOT : Alexa"; return; }
127 :   if($9 ~ /NetcraftSurveyAgent/)      { strType = "ROBOT : Netcraft"; return; }
128 :   if($9 ~ /Eurovore\.com/)            { strType = "ROBOT : Eurovore"; return; }
129 :   if($9 ~ /stockmarketlive690\.com/)  { strType = "ROBOT : StockMarketLive"; return; }
130 :   if($9 ~ /wordpress\.com/)           { strType = "ROBOT : WordPress"; return; }
131 :   if($2 ~ /150\.70\.75\.162/ || \
132 :            $2 ~ /150\.70\.97\.42/  || \
133 :            $2 ~ /150\.70\.172\./ ) {
134 :     strType = "ROBOT : JPNIC"; return;
135 :   }
136 : }
137 : function output() {
138 :   #### Base ####
139 :   strDatime = $1;
140 :   gsub(/\"/, "", strDatime);
141 :   strResultRpad = $2;
142 :   gsub(/\"/, "", strResultRpad);
143 :   rpad(strResultRpad, " ", 15) ;
144 :   if (intIsBot == FALSE || intShowBot == TRUE) {
145 :     printf("[%s] %s %s \"%s\" %s\n", strDatime, strResultRpad, $6, strType, strReq);
146 :   }
147 :   #### UserAgent ####
148 :   if (intIsBot == FALSE) {
149 :     printf("--%s\n", $9);
150 :   }
151 :   #### Referer ####
152 :   if ( intIsOther == TRUE || (intShowRef == TRUE && intIsBot == FALSE) ) {
153 :     printf("--%s\n", $8);
154 :   }
155 :   next;
156 : }
157 : function rpad(strOrgStr, strPadChar, intLength,    intPadTurns) {
158 :   strResultRpad = strOrgStr;
159 :   intPadTurns = intLength - length(strOrgStr);
160 :   if(length(strPadChar) != 1) {
161 :     return;
162 :   }
163 :   while(intPadTurns > 0) {
164 :     strResultRpad = sprintf("%s%s", strResultRpad, strPadChar);
165 :     intPadTurns --;
166 :   }

§補足

・はじめに前処理(BEGIN)が行われ、次に入力1行ごとにパターン&アクション処理、最後に後処理(END)が行われます。
 本スクリプトではパターン&アクションを1つしか定義していませんが、複数個定義することもできます。
 26行目から31行目がパターン、32行目から83行目までがそれに対するアクションです。
・パターンで、requestから処理対象の行を判別(イメージファイル等へのrequestを除外してページ本体への
 requestのみを抽出)しています。本スクリプトは当サイト用ですので、貴サイトに用いる場合は貴サイト用の
 条件を定義します。また、64行目から67行目の自サイト内ページ遷移判別も同様です。
・関数「chkGeneral」にて、検索サイト以外からのアクセス判別を行っています。相互リンクの相手先ページ等を
 定義します。
・本スクリプトは、§下準備にて「タブルクォートでくくった」場合のものです。くくらない場合は、若干変更が必要です。
・gawkスクリプト内の変数は基本的にグローバル変数となります。
 157行目に4つの引数(っぽい)をもつrpadという関数が定義されています。
 3番目まではふつーに引数ですが、4番目の「intPadTurns」は引数ではなく「ローカル変数定義」です。
 つまり関数の外に「intPadTurns」という同名の変数が定義された場合、外と内の「intPadTurns」はそれぞれ
 別の変数として扱ってくれます。ローカル変数定義していないものは全てグローバル変数になります。

§ビューアの実行

  # gawk  -f  スクリプトファイル名  Apacheログファイル名

§実行結果(抜粋)

[2012/10/25 06:20:23] 66.249.66.103   200 "ROBOT : google.com" "GET /"
[2012/10/25 06:49:27] 126.165.26.183  200 "SEARCH: GoogleUS" "GET /memo/000009.html"
--"Mozilla/5.0 (Linux; Android 4.1.2; Nexus 7 Build/JZO54K) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166  Safari/535.19"
[2012/10/25 06:49:42] 126.165.26.183  304 "INTMOV: -" "GET /"
--"Mozilla/5.0 (Linux; Android 4.1.2; Nexus 7 Build/JZO54K) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.166  Safari/535.19"
[2012/10/29 10:31:29] 74.125.178.89   200 "SEARCH: GoogleJP" "GET /memo/000009.html"
--"Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 5.1; .NET CLR 2.0.50727; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729)"
[2012/10/29 11:13:41] 199.59.149.164  200 "ROBOT : TwitterBot" "GET /memo/000010.html"
[2012/10/29 11:13:42] 46.236.7.32     200 "ROBOT : TweetmemeBot" "GET /memo/000010.html"
[2012/10/29 11:13:43] 74.112.131.127  200 "ROBOT : Topsy" "GET /memo/000010.html"
[2012/10/29 11:13:43] 204.236.179.231 206 "ROBOT : JS-Kit" "GET /memo/000010.html"
[2012/10/29 11:13:54] 126.165.26.183  200 "GNRL  : Twitter" "GET /memo/000010.html"
--"Mozilla/5.0 (iPad; CPU OS 5_1_1 like Mac OS X) AppleWebKit/534.46 (KHTML, like Gecko) Mobile/9B206 Twitter for iPhone"
[2012/10/29 11:14:17] 65.52.0.51      200 "DIRECT: -" "GET /memo/000010.html"
--"Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0)"
[2012/10/29 13:48:13] 74.112.131.127  304 "ROBOT : Topsy" "GET /memo/000010.html"
[2012/10/29 17:32:09] 211.12.238.157  200 "SEARCH: GoogleJP" "GET /memo/000004.html"
--"Mozilla/5.0 (Windows NT 6.1; rv:16.0) Gecko/20100101 Firefox/16.0"
[2012/10/29 20:35:44] 76.72.166.150   200 "ROBOT : MJ12bot" "GET /"
[2012/10/29 23:28:36] 111.64.213.34   200 "SEARCH: GoogleJP" "GET /memo/000009.html"
--"Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; WOW64; Trident/5.0; MALC)"
[2012/10/30 00:42:31] 119.63.196.93   304 "ROBOT : baidu.com" "GET /memo.html"
[2012/10/30 01:16:40] 119.63.196.40   200 "ROBOT : baidu.com" "GET /"
[2012/10/30 03:20:00] 119.63.196.60   200 "ROBOT : baidu.com" "GET /memo/000003.html"
[2012/10/30 03:29:59] 66.249.69.105   304 "ROBOT : google.com" "GET /memo/000009.html"
[2012/10/30 06:41:24] 66.249.69.239   304 "ROBOT : google.com" "GET /memo/000004.html"

#### SEARCH: 33, GNRL  : 4, DIRECT: 39, INTMOV: 4, ROBOT : 72, OTHER : 0 ####

管理人のじぃやへメール


Copyright © me44.org All rights reserved