module RequestLogAnalyzer::Tracker # Determines the average hourly spread of the parsed requests. # This spread is shown in a graph form. # # Accepts the following options: # * :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). # * :output Direct output here (defaults to STDOUT) # * :unless Proc that has to return nil for a request to be passed to the tracker. # # Expects the following items in the update request hash # * :timestamp in YYYYMMDDHHMMSS format. # # Example output: # Requests graph - average per day per hour # -------------------------------------------------- # 7:00 - 330 hits : ======= # 8:00 - 704 hits : ================= # 9:00 - 830 hits : ==================== # 10:00 - 822 hits : =================== # 11:00 - 823 hits : =================== # 12:00 - 729 hits : ================= # 13:00 - 614 hits : ============== # 14:00 - 690 hits : ================ # 15:00 - 492 hits : =========== # 16:00 - 355 hits : ======== # 17:00 - 213 hits : ===== # 18:00 - 107 hits : == # ................ class HourlySpread < Base attr_reader :hour_frequencies, :first, :last # Check if timestamp field is set in the options and prepare the result time graph. def prepare options[:field] ||= :timestamp @hour_frequencies = (0...24).map { 0 } @first, @last = 99_999_999_999_999, 0 end # Check if the timestamp in the request and store it. # request The request. def update(request) timestamp = request.first(options[:field]) @hour_frequencies[timestamp.to_s[8..9].to_i] += 1 @first = timestamp if timestamp < @first @last = timestamp if timestamp > @last end # Total amount of requests tracked def total_requests @hour_frequencies.reduce(0) { |sum, value| sum + value } end # First timestamp encountered def first_timestamp DateTime.parse(@first.to_s, '%Y%m%d%H%M%S') rescue nil end # Last timestamp encountered def last_timestamp DateTime.parse(@last.to_s, '%Y%m%d%H%M%S') rescue nil end # Difference between last and first timestamp. def timespan last_timestamp - first_timestamp end # Generate an hourly spread 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(title) if total_requests == 0 output << "None found.\n" return end days = [1, timespan].max output.table({}, { align: :right }, { type: :ratio, width: :rest, treshold: 0.15 }) do |rows| @hour_frequencies.each_with_index do |requests, index| ratio = requests.to_f / total_requests.to_f requests_per_day = (requests / days).ceil rows << ["#{index.to_s.rjust(3)}:00", '%d hits/day' % requests_per_day, ratio] end end end # Returns the title of this tracker for reports def title options[:title] || 'Request distribution per hour' end # Returns the found frequencies per hour as a hash for YAML exporting def to_yaml_object yaml_object = {} @hour_frequencies.each_with_index do |freq, hour| yaml_object["#{hour}:00 - #{hour + 1}:00"] = freq end yaml_object end end end