#!/usr/bin/env ruby # # Analyzes an Apache log file and shows IP addresses sorted on the # Y-axis, dates+hours on the X-axis and a symbol at (x,y) if the ip # address y accesses the site on date+hours, x # # INPUT : logfiles # OUTPUT : chart # EXAMPLE : accesses logfile-1 logfile-2 ... logfile-n # # Simple debugging def log(s) STDERR.puts s STDERR.flush end # @return creates and returns a new file dir+"/"+name def write_to(dir,name) filename = dir.path.to_s + "/" + name log "Writing to " + filename return File.new(filename,"w") end class Stats def initialize @times2ones = {} # maps hours, e.g. 2009/02/15@12 for Feb 15th, 2009 at noon @addrs2times2counts = {} # maps ip addresses to lists of times to counts end # returns sorted list of keys def times @times2ones.keys.sort end #returns sorted list of addresses def addrs @addrs2times2counts.keys.sort end def times2counts(addr) @addrs2times2counts[addr] end # converts a 3-letter month abbreviation to a 2-digit number def month2num(m) return '01' if m == 'Jan' return '02' if m == 'Feb' return '03' if m == 'Mar' return '04' if m == 'Apr' return '05' if m == 'May' return '06' if m == 'Jun' return '07' if m == 'Jul' return '08' if m == 'Aug' return '09' if m == 'Sep' return '10' if m == 'Oct' return '11' if m == 'Nov' return '12' if m == 'Dec' end # records one line def add_line(line) line.scan /(\d+\.\d+\.\d+\.\d+) - - \[(\d+)\/(\w{3})\/(\d{4})\:(\d{2})/ do |res| addr,date,month,year,hour = res time = year + '/' + month2num(month) + '/' + date + '@' + hour @times2ones[time] = 1 times2counts = @addrs2times2counts[addr] || {} times2counts[time] = (times2counts[time] || 0) + 1 @addrs2times2counts[addr] = times2counts end end def read_all(infiles) infiles.each do |infile| log "Reading from " << infile IO.foreach infile do |line| add_line line end end end def output puts '' puts '' puts '' puts '' puts '' puts '' ts = times addrs.each do |addr| print '' printf '' times2counts = times2counts addr ts.map { |time| print '' } printf '' print '' puts end (0..times[0].length-1).each do |i| print '' print '' times.map { |t| print '' } print '' puts end puts '
' + addr + ' ' + addr + '
' + t[i..i] + '
' puts '' puts '' end end def main(argv) stats = Stats.new stats.read_all argv stats.output end main ARGV