Apacheアクセスログと私(エラーログを拾う)

アクセスログを眺めていて思ったんだが,ステータスコードでエラーを返している行を拾えば,便利なんじゃないだろうか.特に,404 Not Foundを拾うことができれば,サイト内のリンク切れをつぶすことができる.

そこで,スクリプトを改造,改造.

とりあえず,普通のログを吐くときとエラーログを吐くときに場合分けをするため,引数を取ることにした.ここで,CGIクラスとまた格闘してしまった(やっぱ,例文が欲しいよう).

begin
  cgi = CGI.new
  mode = cgi.params["mode"].to_s #モード取得
  file = lastlog() #最新ファイル取得
  logfile = open(file)
  case mode
    when "view"
      log_view(file) #生ログ表示
    when "error"
      errorlog_view(file) #エラーログ表示
    else
      print "Content-Type: text/plain; charset=EUC-JP\n\n"
      print "有効なモードを取得できません."
  end
rescue StandardError
    error_out()
rescue ScriptError
    error_out()
end

error_out()は,エラーを表示してデバッグしやすくするための物で,『Ruby de CGI―Rubyで作るインタラクティブWebサイト』のものをそのまま持ってきている.

と,場合分けするところは比較的すぐにできたのだが,肝心のエラー表示部でエラく苦労してしまった.そのまま出力しても分かりにくいだろうからとステータスコード順に並べようとしたら,はまったのである.変数にとりあえずエラーの行を保持しようとハッシュのハッシュをいじっていたら,何がどれを指すやら分からなくなった上,型の違いではまった!う~ん,Rubyは型を気にしなくていいのね~と思っていたのが間違いの元でした.なんとか完成させたのが以下のコード.

def errorlog_view(file)
  header_out("エラーログ")
  logfile = open(file)
  error = Hash.new
  error_count = Hash.new
  #エラー行を見つけてとりあえずハッシュに保持
  while logline = logfile.gets
    line = Accesslog.new(logline)
    status = line.status
    if /^[4|5]/ =~ status #ステータスコード400台と500台だけ処理
      unless error.key?(status)
        error[status] = Hash.new
        error_count[status] = 0
      end
      error_count[status] += 1 #ステータスエラーのカウンター
      #ステータスエラーの行を保持
      error[status][error_count[status]] = line
    end
  end
  error.sort.each{|status, value|
    print "<h3>" + status.to_s + " " + STATUS[status] +"</h3>\n"
    print "<ol>"
    error_line = error[status]
    error_line.sort.each{|count, line|
      print "<li><dl class=\"log\">\n"
      print "<dt>Access URI</dt><dd>#{line.requestURI}</dd>\n"
      print "<dt>Datetime</dt><dd>#{line.year}年#{line.month}月#{line.day}日"
      print "#{line.hour}時#{line.minute}分#{line.second}秒</dd>\n"
      print "<dt>IP Address</dt><dd>#{line.ip}</dd>\n"
      print "<dt>Referer</dt><dd>"
      case line.referer
        when "-"
          print "(ダイレクトアクセス)</dd>\n"
        else
          print "<a href=\"#{line.referer}\">#{line.referer_unencode}</a></dd>\n"
      end
      print "<dt>User Agent</dt><dd>#{line.user_agent}</dd>\n"
      print "</dl><hr>\n"
    }
    print "</ol>"
  }
  footer_out()
end

型違いではまったのは,「error[status] = Hash.new」のところ.ハッシュのハッシュを使っているので,ハッシュを入れとかなければいけないのに,""を入れていた.これだと文字列なんだよね…….

lineの保持さえうまくいけば,表示するところは簡単.並べ替えて全部表示する.STATUSという定数はハッシュで,ステータスコードをエラーメッセージにするための物.

#ステータスコードをメッセージにするためのハッシュ定数
STATUS = {"400" => "Bad Request",
          "401" => "Unauthorized",
          "402" => "Payment Required",
          "403" => "Forbidden",
          "404" => "Not Found",
          "405" => "Method Not Allowed",
          "406" => "Not Acceptable",
          "407" => "Proxy Authentication Required",
          "408" => "Request Timeout",
          "409" => "Conflict",
          "410" => "Gone",
          "411" => "Length Required",
          "412" => "Precondition Failed",
          "413" => "Request Entity Too Large",
          "414" => "Request-URI Too Long",
          "415" => "Unsupported Media Type",
          "416" => "Requested Range Not Satisfiable",
          "417" => "Expectation Failed",
          "500" => "Internal Server Error",
          "501" => "Not Implemented",
          "502" => "Bad Gateway",
          "503" => "Service Unavailable",
          "504" => "Gateway Timeout",
          "505" => "HTTP Version Not Supported"
}

400番台と500番台をここで拾うようにしたので,生ログ出力では拾わないことにした.

エラーログの出力結果はこんな感じ.

しまった,robots.txtとか/MSOffice/cltreq.asp~とか/favicon.icoは省いた方がよかったかなぁ.

ちなみに,robots.txtはロボット型検索エンジンのロボットさんが探しに来る物で,行儀のいいロボットならこのファイルの指示にしたがってくれる.MSOfficeなんたらかんたらは,IE+MS Office環境でWebディスカッション機能が有効になっていると探しに来るんだったと記憶する.で,favicon.icoはご存じ,IEなんかのお気に入りで表示されるアイコン.faviconのログは何か遊べそうだなあ.ちょっと調べてみるか.

日時: 2004年10月17日 | PC/Web > Ruby |

コメントを投稿

(空欄でもかまいません)

(メールアドレスは管理人に通知されますが,Web上には表示されません)

Powered by Movable Type