#! /usr/bin/env ruby # # refererplot - anylize a referer log and generate a flash-based chart. # # Copyright (C) 2004 Satoru Takabayashi # All rights reserved. # This is free software with ABSOLUTELY NO WARRANTY. # # You can redistribute it and/or modify it under the terms of # the GNU General Public License version 2. # require 'mingchart' require 'cgi' class RefererPlot def initialize (nreferers) @hourly_stat = Hash.new @referer_stat = Hash.new @nreferers = nreferers @top_referers = [] @plot_data = [] end def draw (filename) chart = MingChart.new(:flash_font => "EfontSerifB.fdb", :x_time_scale => true, :line_title_font_size => 16, :font_size => 24, :drawing_methods => [:draw_line], :x_time_scale_format => "%m/%d (%H:%M)", :line_titles => @top_referers ) @nreferers.times {|i| chart.add_data(@plot_data, i + 1) } chart.draw chart.save(filename) end # '11/Apr/2004:06:49:01 +0900' => Time def parse_apache_time (str) if m = %r!^(\d\d)/(\w+)/(\d\d\d\d):(\d\d):(\d\d):(\d\d) !.match(str) day = m[1].to_i mon = Time::RFC2822_MONTH_NAME.index(m[2]) + 1 year = m[3].to_i hour = m[4].to_i min = m[5].to_i sec = m[6].to_i Time.mktime(year, mon, day, hour, min, sec) else raise "unsupported time format #{str}" end end def analyze_log (pattern) while line = gets if m = line.match(%r!\[(.*?)\] "GET (.*?) HTTP/1\.[01]" 200 \d+ "(.*?)"!) time = parse_apache_time(m[1]) page = CGI.unescape(m[2]) referer = CGI.unescape(m[3]) if pattern.match(page) and referer != "-" and !referer.match(/#{page}$/) key = time.strftime("%Y-%m-%dT%H") @hourly_stat[key] ||= Hash.new @hourly_stat[key][referer] ||= 0 @hourly_stat[key][referer] += 1 @referer_stat[referer] ||= 0 @referer_stat[referer] += 1 end end end end def complete_stat @top_referers = @referer_stat.keys.sort {|a, b| @referer_stat[b] <=> @referer_stat[a] }[0, @nreferers] @top_referers.each {|referer| printf("%d\t%s\n", @referer_stat[referer], referer) } @hourly_stat.keys.sort.each {|timestr| time = Time.parse(timestr + ":00:00") data = [0] * @nreferers @hourly_stat[timestr].each {|referer, count| if n = @top_referers.index(referer) data[n] = count end } next unless data.find {|x| x > 0 } @plot_data.push([time.to_i] + data) } end end if ARGV.length != 2 puts "Usage: refererplot PATTERN NREFERERS" exit 0 end pattern = Regexp.new(ARGV.shift) nreferers = ARGV.shift.to_i plot = RefererPlot.new(nreferers) plot.analyze_log(pattern) plot.complete_stat plot.draw("refererplot.swf")