module RequestLogAnalyzer::Tracker
# Catagorize requests by frequency.
# Count and analyze requests for a specific attribute
#
# === Options
# * :amount The amount of lines in the report
# * :category Proc that handles the request categorization.
# * :if Proc that has to return !nil for a request to be passed to the tracker.
# * :line_type The line type that contains the duration field (determined by the category proc).
# * :nils Track undetermined methods.
# * :title Title do be displayed above the report.
# * :unless Proc that has to return nil for a request to be passed to the tracker.
#
# The items in the update request hash are set during the creation of the Duration tracker.
#
# Example output:
# HTTP methods
# ----------------------------------------------------------------------
# GET | 22248 hits (46.2%) |=================
# PUT | 13685 hits (28.4%) |===========
# POST | 11662 hits (24.2%) |=========
# DELETE | 512 hits (1.1%) |
class Frequency < Base
attr_reader :frequencies
# Check if categories are set up
def prepare
raise "No categorizer set up for category tracker #{self.inspect}" unless options[:category]
@frequencies = {}
if options[:all_categories].kind_of?(Enumerable)
options[:all_categories].each { |cat| @frequencies[cat] = 0 }
end
end
# Check HTTP method of a request and store that in the frequencies hash.
# request The request.
def update(request)
cat = options[:category].respond_to?(:call) ? options[:category].call(request) : request[options[:category]]
if !cat.nil? || options[:nils]
@frequencies[cat] ||= 0
@frequencies[cat] += 1
end
end
# Return the amount of times a HTTP method has been encountered
# cat The HTTP method (:get, :put, :post or :delete)
def frequency(cat)
frequencies[cat] || 0
end
# Return the overall frequency
def overall_frequency
frequencies.inject(0) { |carry, item| carry + item[1] }
end
# Return the methods sorted by frequency
def sorted_by_frequency
@frequencies.sort { |a, b| b[1] <=> a[1] }
end
# Generate a HTTP method frequency report to the given output object.
# Any options for the report should have been set during initialize.
# output The output object
def report(output)
output.title(options[:title]) if options[:title]
if @frequencies.empty?
output << "None found.\n"
else
sorted_frequencies = @frequencies.sort { |a, b| b[1] <=> a[1] }
total_hits = sorted_frequencies.inject(0) { |carry, item| carry + item[1] }
sorted_frequencies = sorted_frequencies.slice(0...options[:amount]) if options[:amount]
output.table({:align => :left}, {:align => :right }, {:align => :right}, {:type => :ratio, :width => :rest}) do |rows|
sorted_frequencies.each do |(cat, count)|
rows << [cat, "#{count} hits", '%0.1f%%' % ((count.to_f / total_hits.to_f) * 100.0), (count.to_f / total_hits.to_f)]
end
end
end
end
# Returns a hash with the frequencies of every category that can be exported to YAML
def to_yaml_object
return nil if @frequencies.empty?
@frequencies
end
# Returns the title of this tracker for reports
def title
options[:title] || 'Request frequency'
end
end
end