#!/usr/bin/ruby
require File.dirname(__FILE__) + '/../lib/command_line/arguments'
require File.dirname(__FILE__) + '/../lib/rails_analyzer/log_parser'
require File.dirname(__FILE__) + '/../lib/rails_analyzer/summarizer'
require File.dirname(__FILE__) + '/../lib/bashcolorizer'
require File.dirname(__FILE__) + '/../lib/ruby-progressbar/progressbar.rb'
puts "Request log analyzer, by Willem van Bergen and Bart ten Brinke\n\n"
# Substitutes variable elements in a url (like the id field) with a fixed string (like ":id")
# This is used to aggregate simular requests.
# request The request to evaluate.
# Returns uniformed url string.
# Raises on mailformed request.
def request_hasher(request)
if request[:url]
url = request[:url].downcase.split(/^http[s]?:\/\/[A-z0-9\.-]+/).last.split('?').first # only the relevant URL part
url << '/' if url[-1] != '/'[0] && url.length > 1 # pad a trailing slash for consistency
url.gsub!(/\/\d+-\d+-\d+/, '/:date') # Combine all (year-month-day) queries
url.gsub!(/\/\d+-\d+/, '/:month') # Combine all date (year-month) queries
url.gsub!(/\/\d+/, '/:id') # replace identifiers in URLs
return url
elsif request[:controller] && request[:action]
return "#{request[:controller]}##{request[:action]}"
else
raise 'Cannot hash this request! ' + request.inspect
end
end
# Print results using a ASCII table.
# summarizer The summarizer containg information to draw the table.
# field The field containing the data to be printed
# amount The length of the table (defaults to 20)
def print_table(summarizer, field, amount = 20)
summarizer.sort_actions_by(field).reverse[0, amount.to_i].each do |a|
# As we show count by default, show totaltime if we sort by count
field = :total_time if field == :count
puts "#{a[0].ljust(50)}: %10.03fs [#{green("%d requests")}]" % [a[1][field], a[1][:count]]
end
end
# Parse the arguments given via commandline
begin
$arguments = CommandLine::Arguments.parse do |command_line|
command_line.switch(:guess_database_time, :g)
command_line.switch(:fast, :f)
command_line.switch(:colorize, :z)
command_line.flag(:output, :alias => :o)
command_line.flag(:amount, :alias => :c)
command_line.required_files = 1
end
rescue CommandLine::Error => e
puts "ARGUMENT ERROR: " + e.message
puts
load File.dirname(__FILE__) + "/../output/usage.rb"
exit(0)
end
$summarizer = RailsAnalyzer::Summarizer.new(:calculate_database => $arguments[:guess_database_time])
$summarizer.blocker_duration = 1.0
line_types = $arguments[:fast] ? [:completed] : [:started, :completed, :failed]
# Walk through al the files given via the arguments.
$arguments.files.each do |log_file|
puts "Processing #{line_types.join(', ')} log lines from #{log_file}..."
parser = RailsAnalyzer::LogParser.new(log_file)
# add progress bar
unless $arguments[:fast]
pbar = ProgressBar.new(green(log_file), File.size(log_file))
parser.progress { |pos, total| (pos == :finished) ? pbar.finish : pbar.set(pos) }
end
parser.each(*line_types) do |request|
$summarizer.group(request) { |r| request_hasher(r) }
end
end
# Select the reports to output and generate them.
output_reports = $arguments[:output].split(',') rescue [:timespan, :most_requested, :total_time, :mean_time, :total_db_time, :mean_db_time, :mean_rendering_time, :blockers, :hourly_spread, :errors]
output_reports.each do |report|
report_location = "#{File.dirname(__FILE__)}/../output/#{report}.rb"
if File.exist?(report_location)
load report_location
else
puts "\nERROR: Output report #{report} not found!"
end
end