request-log-analyzer 1.3.7 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (84) hide show
  1. data/LICENSE +3 -3
  2. data/README.rdoc +1 -1
  3. data/bin/request-log-analyzer +17 -14
  4. data/lib/cli/command_line_arguments.rb +51 -51
  5. data/lib/cli/database_console.rb +3 -3
  6. data/lib/cli/database_console_init.rb +2 -2
  7. data/lib/cli/progressbar.rb +10 -10
  8. data/lib/cli/tools.rb +3 -3
  9. data/lib/request_log_analyzer.rb +4 -4
  10. data/lib/request_log_analyzer/aggregator.rb +10 -10
  11. data/lib/request_log_analyzer/aggregator/database_inserter.rb +9 -9
  12. data/lib/request_log_analyzer/aggregator/echo.rb +14 -9
  13. data/lib/request_log_analyzer/aggregator/summarizer.rb +26 -26
  14. data/lib/request_log_analyzer/controller.rb +153 -69
  15. data/lib/request_log_analyzer/database.rb +13 -13
  16. data/lib/request_log_analyzer/database/base.rb +17 -17
  17. data/lib/request_log_analyzer/database/connection.rb +3 -3
  18. data/lib/request_log_analyzer/database/request.rb +2 -2
  19. data/lib/request_log_analyzer/database/source.rb +1 -1
  20. data/lib/request_log_analyzer/file_format.rb +15 -15
  21. data/lib/request_log_analyzer/file_format/amazon_s3.rb +16 -16
  22. data/lib/request_log_analyzer/file_format/apache.rb +20 -19
  23. data/lib/request_log_analyzer/file_format/merb.rb +12 -12
  24. data/lib/request_log_analyzer/file_format/rack.rb +4 -4
  25. data/lib/request_log_analyzer/file_format/rails.rb +146 -70
  26. data/lib/request_log_analyzer/file_format/rails_development.rb +4 -49
  27. data/lib/request_log_analyzer/filter.rb +6 -6
  28. data/lib/request_log_analyzer/filter/anonymize.rb +6 -6
  29. data/lib/request_log_analyzer/filter/field.rb +9 -9
  30. data/lib/request_log_analyzer/filter/timespan.rb +12 -10
  31. data/lib/request_log_analyzer/line_definition.rb +15 -14
  32. data/lib/request_log_analyzer/log_processor.rb +22 -22
  33. data/lib/request_log_analyzer/mailer.rb +15 -9
  34. data/lib/request_log_analyzer/output.rb +53 -12
  35. data/lib/request_log_analyzer/output/fixed_width.rb +40 -41
  36. data/lib/request_log_analyzer/output/html.rb +20 -20
  37. data/lib/request_log_analyzer/request.rb +35 -36
  38. data/lib/request_log_analyzer/source.rb +7 -7
  39. data/lib/request_log_analyzer/source/database_loader.rb +7 -7
  40. data/lib/request_log_analyzer/source/log_parser.rb +48 -43
  41. data/lib/request_log_analyzer/tracker.rb +128 -14
  42. data/lib/request_log_analyzer/tracker/duration.rb +39 -132
  43. data/lib/request_log_analyzer/tracker/frequency.rb +31 -32
  44. data/lib/request_log_analyzer/tracker/hourly_spread.rb +20 -19
  45. data/lib/request_log_analyzer/tracker/timespan.rb +17 -17
  46. data/lib/request_log_analyzer/tracker/traffic.rb +36 -116
  47. data/request-log-analyzer.gemspec +19 -15
  48. data/spec/fixtures/rails_22.log +1 -1
  49. data/spec/integration/command_line_usage_spec.rb +1 -1
  50. data/spec/lib/helpers.rb +7 -7
  51. data/spec/lib/macros.rb +3 -3
  52. data/spec/lib/matchers.rb +41 -27
  53. data/spec/lib/mocks.rb +15 -14
  54. data/spec/lib/testing_format.rb +9 -9
  55. data/spec/spec_helper.rb +6 -6
  56. data/spec/unit/aggregator/database_inserter_spec.rb +13 -13
  57. data/spec/unit/aggregator/summarizer_spec.rb +4 -4
  58. data/spec/unit/controller/controller_spec.rb +2 -2
  59. data/spec/unit/controller/log_processor_spec.rb +1 -1
  60. data/spec/unit/database/base_class_spec.rb +19 -19
  61. data/spec/unit/database/connection_spec.rb +3 -3
  62. data/spec/unit/database/database_spec.rb +25 -25
  63. data/spec/unit/file_format/amazon_s3_format_spec.rb +5 -5
  64. data/spec/unit/file_format/apache_format_spec.rb +13 -13
  65. data/spec/unit/file_format/file_format_api_spec.rb +13 -13
  66. data/spec/unit/file_format/line_definition_spec.rb +24 -17
  67. data/spec/unit/file_format/merb_format_spec.rb +41 -45
  68. data/spec/unit/file_format/rails_format_spec.rb +157 -117
  69. data/spec/unit/filter/anonymize_filter_spec.rb +2 -2
  70. data/spec/unit/filter/field_filter_spec.rb +13 -13
  71. data/spec/unit/filter/filter_spec.rb +1 -1
  72. data/spec/unit/filter/timespan_filter_spec.rb +15 -15
  73. data/spec/unit/mailer_spec.rb +30 -0
  74. data/spec/unit/{source/request_spec.rb → request_spec.rb} +30 -30
  75. data/spec/unit/source/log_parser_spec.rb +27 -27
  76. data/spec/unit/tracker/duration_tracker_spec.rb +115 -78
  77. data/spec/unit/tracker/frequency_tracker_spec.rb +74 -63
  78. data/spec/unit/tracker/hourly_spread_spec.rb +28 -20
  79. data/spec/unit/tracker/timespan_tracker_spec.rb +25 -13
  80. data/spec/unit/tracker/tracker_api_spec.rb +13 -13
  81. data/spec/unit/tracker/traffic_tracker_spec.rb +81 -79
  82. data/tasks/github-gem.rake +125 -75
  83. data/tasks/request_log_analyzer.rake +2 -2
  84. metadata +8 -6
@@ -3,12 +3,11 @@ module RequestLogAnalyzer::Tracker
3
3
  # Analyze the duration of a specific attribute
4
4
  #
5
5
  # === Options
6
- # * <tt>:amount</tt> The amount of lines in the report
7
6
  # * <tt>:category</tt> Proc that handles request categorization for given fileformat (REQUEST_CATEGORIZER)
8
7
  # * <tt>:duration</tt> The field containing the duration in the request hash.
9
8
  # * <tt>:if</tt> Proc that has to return !nil for a request to be passed to the tracker.
10
9
  # * <tt>:line_type</tt> The line type that contains the duration field (determined by the category proc).
11
- # * <tt>:title</tt> Title do be displayed above the report
10
+ # * <tt>:title</tt> Title do be displayed above the report
12
11
  # * <tt>:unless</tt> Handle request if this proc is false for the handled request.
13
12
  #
14
13
  # The items in the update request hash are set during the creation of the Duration tracker.
@@ -21,141 +20,62 @@ module RequestLogAnalyzer::Tracker
21
20
  # EmployeeController#index.html [GET] | 5802 | 1477.32s | 0.25s
22
21
  # .............
23
22
  class Duration < Base
24
-
23
+
24
+ include RequestLogAnalyzer::Tracker::StatisticsTracking
25
+
25
26
  attr_reader :categories
26
27
 
27
28
  # Check if duration and catagory option have been received,
28
29
  def prepare
29
30
  raise "No duration field set up for category tracker #{self.inspect}" unless options[:duration]
30
- raise "No categorizer set up for duration tracker #{self.inspect}" unless options[:category]
31
+ raise "No categorizer set up for duration tracker #{self.inspect}" unless options[:category]
31
32
 
32
- @categorizer = options[:category].respond_to?(:call) ? options[:category] : lambda { |request| request[options[:category]] }
33
- @durationizer = options[:duration].respond_to?(:call) ? options[:duration] : lambda { |request| request[options[:duration]] }
34
- @categories = {}
33
+ unless options[:multiple]
34
+ @categorizer = create_lambda(options[:category])
35
+ @durationizer = create_lambda(options[:duration])
36
+ end
37
+
38
+ @categories = {}
35
39
  end
36
40
 
37
41
  # Get the duration information fron the request and store it in the different categories.
38
42
  # <tt>request</tt> The request.
39
43
  def update(request)
40
44
  if options[:multiple]
41
- categories = request.every(options[:category])
42
- durations = request.every(options[:duration])
43
-
44
- if categories.length == durations.length
45
- categories.each_with_index do |category, index|
46
- @categories[category] ||= {:hits => 0, :cumulative => 0.0}
47
- @categories[category][:hits] += 1
48
- @categories[category][:cumulative] += durations[index]
49
- end
50
- else
51
- raise "Capture mismatch for multiple values in a request"
52
- end
45
+ found_categories = request.every(options[:category])
46
+ found_durations = request.every(options[:duration])
47
+ raise "Capture mismatch for multiple values in a request" unless found_categories.length == found_durations.length
48
+ found_categories.each_with_index { |cat, index| update_statistics(cat, found_durations[index]) }
53
49
  else
54
50
  category = @categorizer.call(request)
55
51
  duration = @durationizer.call(request)
56
-
57
- if duration.kind_of?(Numeric) && !category.nil?
58
- @categories[category] ||= {:hits => 0, :cumulative => 0.0, :min => duration, :max => duration }
59
- @categories[category][:hits] += 1
60
- @categories[category][:cumulative] += duration
61
- @categories[category][:min] = duration if duration < @categories[category][:min]
62
- @categories[category][:max] = duration if duration > @categories[category][:max]
63
- end
52
+ update_statistics(category, duration) if duration.kind_of?(Numeric) && category
64
53
  end
65
54
  end
66
-
67
- # Get the number of hits of a specific category.
68
- # <tt>cat</tt> The category
69
- def hits(cat)
70
- categories[cat][:hits]
71
- end
72
-
73
- # Get the total duration of a specific category.
74
- # <tt>cat</tt> The category
75
- def cumulative_duration(cat)
76
- categories[cat][:cumulative]
77
- end
78
-
79
- # Get the minimal duration of a specific category.
80
- # <tt>cat</tt> The category
81
- def min_duration(cat)
82
- categories[cat][:min]
83
- end
84
-
85
- # Get the maximum duration of a specific category.
86
- # <tt>cat</tt> The category
87
- def max_duration(cat)
88
- categories[cat][:max]
89
- end
90
-
91
- # Get the average duration of a specific category.
92
- # <tt>cat</tt> The category
93
- def average_duration(cat)
94
- categories[cat][:cumulative] / categories[cat][:hits]
95
- end
96
-
97
- # Get the average duration of a all categories.
98
- def overall_average_duration
99
- overall_cumulative_duration / overall_hits
100
- end
101
-
102
- # Get the cumlative duration of a all categories.
103
- def overall_cumulative_duration
104
- categories.inject(0.0) { |sum, (name, cat)| sum + cat[:cumulative] }
105
- end
106
-
107
- # Get the total hits of a all categories.
108
- def overall_hits
109
- categories.inject(0) { |sum, (name, cat)| sum + cat[:hits] }
110
- end
111
55
 
112
- # Return categories sorted by hits.
113
- def sorted_by_hits
114
- sorted_by(:hits)
115
- end
116
-
117
- # Return categories sorted by cumulative duration.
118
- def sorted_by_cumulative
119
- sorted_by(:cumulative)
120
- end
121
-
122
- # Return categories sorted by cumulative duration.
123
- def sorted_by_average
124
- sorted_by { |cat| cat[:cumulative] / cat[:hits] }
125
- end
126
-
127
- # Return categories sorted by a given key.
128
- # <tt>by</tt> The key.
129
- def sorted_by(by = nil)
130
- if block_given?
131
- categories.sort { |a, b| yield(b[1]) <=> yield(a[1]) }
132
- else
133
- categories.sort { |a, b| b[1][by] <=> a[1][by] }
134
- end
135
- end
136
-
137
56
  # Block function to build a result table using a provided sorting function.
138
57
  # <tt>output</tt> The output object.
139
58
  # <tt>amount</tt> The number of rows in the report table (default 10).
140
59
  # === Options
141
60
  # * </tt>:title</tt> The title of the table
142
61
  # * </tt>:sort</tt> The key to sort on (:hits, :cumulative, :average, :min or :max)
143
- def report_table(output, amount = 10, options = {}, &block)
144
-
145
- output.title(options[:title])
146
-
147
- top_categories = @categories.sort { |a, b| yield(b[1]) <=> yield(a[1]) }.slice(0...amount)
148
- output.table({:title => 'Category', :width => :rest},
149
- {:title => 'Hits', :align => :right, :highlight => (options[:sort] == :hits), :min_width => 4},
150
- {:title => 'Cumulative', :align => :right, :highlight => (options[:sort] == :cumulative), :min_width => 10},
151
- {:title => 'Average', :align => :right, :highlight => (options[:sort] == :average), :min_width => 8},
152
- {:title => 'Min', :align => :right, :highlight => (options[:sort] == :min)},
153
- {:title => 'Max', :align => :right, :highlight => (options[:sort] == :max)}) do |rows|
154
-
155
- top_categories.each do |(cat, info)|
156
- rows << [cat, info[:hits], "%0.02fs" % info[:cumulative], "%0.02fs" % (info[:cumulative] / info[:hits]),
157
- "%0.02fs" % info[:min], "%0.02fs" % info[:max]]
158
- end
62
+ def report_table(output, sort, options = {}, &block)
63
+ output.puts
64
+ top_categories = output.slice_results(sorted_by(sort))
65
+ output.with_style(:top_line => true) do
66
+ output.table(*statistics_header(:title => options[:title], :highlight => sort)) do |rows|
67
+ top_categories.each { |(cat, info)| rows << statistics_row(cat) }
68
+ end
69
+ end
70
+ end
71
+
72
+ # Display a duration
73
+ def display_value(time)
74
+ case time
75
+ when nil then '-'
76
+ when 0...60 then "%0.02fs" % time
77
+ when 60...3600 then "%dm%02ds" % [time / 60, (time % 60).round]
78
+ else "%dh%02dm%02ds" % [time / 3600, (time % 3600) / 60, (time % 60).round]
159
79
  end
160
80
  end
161
81
 
@@ -164,33 +84,20 @@ module RequestLogAnalyzer::Tracker
164
84
  # Any options for the report should have been set during initialize.
165
85
  # <tt>output</tt> The output object
166
86
  def report(output)
167
-
168
- options[:title] ||= 'Request duration'
169
- options[:report] ||= [:cumulative, :average]
170
- options[:top] ||= 20
171
-
172
- options[:report].each do |report|
173
- case report
174
- when :average
175
- report_table(output, options[:top], :title => "#{options[:title]} - top #{options[:top]} by average time", :sort => :average) { |cat| cat[:cumulative] / cat[:hits] }
176
- when :cumulative
177
- report_table(output, options[:top], :title => "#{options[:title]} - top #{options[:top]} by cumulative time", :sort => :cumulative) { |cat| cat[:cumulative] }
178
- when :hits
179
- report_table(output, options[:top], :title => "#{options[:title]} - top #{options[:top]} by hits", :sort => :hits) { |cat| cat[:hits] }
180
- else
181
- raise "Unknown duration report specified: #{report}!"
182
- end
87
+ sortings = output.options[:sort] || [:sum, :mean]
88
+ sortings.each do |sorting|
89
+ report_table(output, sorting, :title => "#{title} - by #{sorting}")
183
90
  end
184
91
  end
185
-
92
+
186
93
  # Returns the title of this tracker for reports
187
94
  def title
188
95
  options[:title] || 'Request duration'
189
96
  end
190
-
97
+
191
98
  # Returns all the categories and the tracked duration as a hash than can be exported to YAML
192
99
  def to_yaml_object
193
- return nil if @categories.empty?
100
+ return nil if @categories.empty?
194
101
  @categories
195
102
  end
196
103
  end
@@ -1,10 +1,9 @@
1
1
  module RequestLogAnalyzer::Tracker
2
-
2
+
3
3
  # Catagorize requests by frequency.
4
- # Count and analyze requests for a specific attribute
4
+ # Count and analyze requests for a specific attribute
5
5
  #
6
6
  # === Options
7
- # * <tt>:amount</tt> The amount of lines in the report
8
7
  # * <tt>:category</tt> Proc that handles the request categorization.
9
8
  # * <tt>:if</tt> Proc that has to return !nil for a request to be passed to the tracker.
10
9
  # * <tt>:line_type</tt> The line type that contains the duration field (determined by the category proc).
@@ -23,41 +22,42 @@ module RequestLogAnalyzer::Tracker
23
22
  # DELETE | 512 hits (1.1%) |
24
23
  class Frequency < Base
25
24
 
26
- attr_reader :frequencies
25
+ attr_reader :categories
27
26
 
28
27
  # Check if categories are set up
29
28
  def prepare
30
29
  raise "No categorizer set up for category tracker #{self.inspect}" unless options[:category]
31
- @frequencies = {}
32
- if options[:all_categories].kind_of?(Enumerable)
33
- options[:all_categories].each { |cat| @frequencies[cat] = 0 }
34
- end
30
+ @categorizer = create_lambda(options[:category])
31
+
32
+ # Initialize the categories. Use the list of category names to
33
+ @categories = {}
34
+ options[:all_categories].each { |cat| @categories[cat] = 0 } if options[:all_categories].kind_of?(Enumerable)
35
35
  end
36
-
37
- # Check HTTP method of a request and store that in the frequencies hash.
36
+
37
+ # Check HTTP method of a request and store that in the categories hash.
38
38
  # <tt>request</tt> The request.
39
39
  def update(request)
40
- cat = options[:category].respond_to?(:call) ? options[:category].call(request) : request[options[:category]]
41
- if !cat.nil? || options[:nils]
42
- @frequencies[cat] ||= 0
43
- @frequencies[cat] += 1
40
+ cat = @categorizer.call(request)
41
+ if cat || options[:nils]
42
+ @categories[cat] ||= 0
43
+ @categories[cat] += 1
44
44
  end
45
45
  end
46
46
 
47
47
  # Return the amount of times a HTTP method has been encountered
48
48
  # <tt>cat</tt> The HTTP method (:get, :put, :post or :delete)
49
49
  def frequency(cat)
50
- frequencies[cat] || 0
50
+ categories[cat] || 0
51
51
  end
52
-
52
+
53
53
  # Return the overall frequency
54
54
  def overall_frequency
55
- frequencies.inject(0) { |carry, item| carry + item[1] }
55
+ categories.inject(0) { |carry, item| carry + item[1] }
56
56
  end
57
-
57
+
58
58
  # Return the methods sorted by frequency
59
59
  def sorted_by_frequency
60
- @frequencies.sort { |a, b| b[1] <=> a[1] }
60
+ @categories.sort { |a, b| b[1] <=> a[1] }
61
61
  end
62
62
 
63
63
  # Generate a HTTP method frequency report to the given output object.
@@ -65,29 +65,28 @@ module RequestLogAnalyzer::Tracker
65
65
  # <tt>output</tt> The output object
66
66
  def report(output)
67
67
  output.title(options[:title]) if options[:title]
68
-
69
- if @frequencies.empty?
70
- output << "None found.\n"
68
+
69
+ if @categories.empty?
70
+ output << "None found.\n"
71
71
  else
72
- sorted_frequencies = @frequencies.sort { |a, b| b[1] <=> a[1] }
73
- total_hits = sorted_frequencies.inject(0) { |carry, item| carry + item[1] }
74
- sorted_frequencies = sorted_frequencies.slice(0...options[:amount]) if options[:amount]
72
+ sorted_categories = output.slice_results(sorted_by_frequency)
73
+ total_hits = overall_frequency
75
74
 
76
- output.table({:align => :left}, {:align => :right }, {:align => :right}, {:type => :ratio, :width => :rest}) do |rows|
77
- sorted_frequencies.each do |(cat, count)|
75
+ output.table({:align => :left}, {:align => :right }, {:align => :right}, {:type => :ratio, :width => :rest}) do |rows|
76
+ sorted_categories.each do |(cat, count)|
78
77
  rows << [cat, "#{count} hits", '%0.1f%%' % ((count.to_f / total_hits.to_f) * 100.0), (count.to_f / total_hits.to_f)]
79
78
  end
80
79
  end
81
80
 
82
81
  end
83
82
  end
84
-
85
- # Returns a hash with the frequencies of every category that can be exported to YAML
83
+
84
+ # Returns a hash with the categories of every category that can be exported to YAML
86
85
  def to_yaml_object
87
- return nil if @frequencies.empty?
88
- @frequencies
86
+ return nil if @categories.empty?
87
+ @categories
89
88
  end
90
-
89
+
91
90
  # Returns the title of this tracker for reports
92
91
  def title
93
92
  options[:title] || 'Request frequency'
@@ -1,5 +1,5 @@
1
1
  module RequestLogAnalyzer::Tracker
2
-
2
+
3
3
  # Determines the average hourly spread of the parsed requests.
4
4
  # This spread is shown in a graph form.
5
5
  #
@@ -30,50 +30,51 @@ module RequestLogAnalyzer::Tracker
30
30
  # ................
31
31
  class HourlySpread < Base
32
32
 
33
- attr_reader :first, :last, :request_time_graph
33
+ attr_reader :hour_frequencies, :first, :last
34
34
 
35
35
  # Check if timestamp field is set in the options and prepare the result time graph.
36
36
  def prepare
37
37
  options[:field] ||= :timestamp
38
- @request_time_graph = [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
38
+ @hour_frequencies = (0...24).map { 0 }
39
+ @first, @last = 99999999999999, 0
39
40
  end
40
41
 
41
42
  # Check if the timestamp in the request and store it.
42
43
  # <tt>request</tt> The request.
43
44
  def update(request)
44
45
  timestamp = request.first(options[:field])
45
-
46
- @request_time_graph[timestamp.to_s[8..9].to_i] +=1
47
- @first = timestamp if @first.nil? || timestamp < @first
48
- @last = timestamp if @last.nil? || timestamp > @last
46
+ @hour_frequencies[timestamp.to_s[8..9].to_i] +=1
47
+ @first = timestamp if timestamp < @first
48
+ @last = timestamp if timestamp > @last
49
49
  end
50
50
 
51
51
  # Total amount of requests tracked
52
52
  def total_requests
53
- @request_time_graph.inject(0) { |sum, value| sum + value }
53
+ @hour_frequencies.inject(0) { |sum, value| sum + value }
54
54
  end
55
-
55
+
56
+
56
57
  # First timestamp encountered
57
58
  def first_timestamp
58
59
  DateTime.parse(@first.to_s, '%Y%m%d%H%M%S') rescue nil
59
60
  end
60
-
61
+
61
62
  # Last timestamp encountered
62
63
  def last_timestamp
63
64
  DateTime.parse(@last.to_s, '%Y%m%d%H%M%S') rescue nil
64
65
  end
65
-
66
+
66
67
  # Difference between last and first timestamp.
67
68
  def timespan
68
69
  last_timestamp - first_timestamp
69
70
  end
70
-
71
+
71
72
  # Generate an hourly spread report to the given output object.
72
73
  # Any options for the report should have been set during initialize.
73
74
  # <tt>output</tt> The output object
74
75
  def report(output)
75
76
  output.title(title)
76
-
77
+
77
78
  if total_requests == 0
78
79
  output << "None found.\n"
79
80
  return
@@ -81,23 +82,23 @@ module RequestLogAnalyzer::Tracker
81
82
 
82
83
  days = [1, timespan].max
83
84
  output.table({}, {:align => :right}, {:type => :ratio, :width => :rest, :treshold => 0.15}) do |rows|
84
- @request_time_graph.each_with_index do |requests, index|
85
- ratio = requests.to_f / total_requests.to_f
85
+ @hour_frequencies.each_with_index do |requests, index|
86
+ ratio = requests.to_f / total_requests.to_f
86
87
  requests_per_day = (requests / days).ceil
87
- rows << ["#{index.to_s.rjust(3)}:00", "%d hits" % requests_per_day, ratio]
88
+ rows << ["#{index.to_s.rjust(3)}:00", "%d hits/day" % requests_per_day, ratio]
88
89
  end
89
90
  end
90
91
  end
91
-
92
+
92
93
  # Returns the title of this tracker for reports
93
94
  def title
94
95
  options[:title] || "Request distribution per hour"
95
96
  end
96
-
97
+
97
98
  # Returns the found frequencies per hour as a hash for YAML exporting
98
99
  def to_yaml_object
99
100
  yaml_object = {}
100
- @request_time_graph.each_with_index do |freq, hour|
101
+ @hour_frequencies.each_with_index do |freq, hour|
101
102
  yaml_object["#{hour}:00 - #{hour+1}:00"] = freq
102
103
  end
103
104
  yaml_object
@@ -1,5 +1,5 @@
1
1
  module RequestLogAnalyzer::Tracker
2
-
2
+
3
3
  # Determines the datetime of the first request and the last request
4
4
  # Also determines the amount of days inbetween these.
5
5
  #
@@ -19,32 +19,32 @@ module RequestLogAnalyzer::Tracker
19
19
  # Total time analyzed: 7 days
20
20
  class Timespan < Base
21
21
 
22
- attr_reader :first, :last, :request_time_graph
22
+ attr_reader :first, :last
23
23
 
24
24
  # Check if timestamp field is set in the options.
25
25
  def prepare
26
26
  options[:field] ||= :timestamp
27
+ @first, @last = 99999999999999, 0
27
28
  end
28
-
29
+
29
30
  # Check if the timestamp in the request and store it.
30
31
  # <tt>request</tt> The request.
31
32
  def update(request)
32
33
  timestamp = request[options[:field]]
33
-
34
- @first = timestamp if @first.nil? || timestamp < @first
35
- @last = timestamp if @last.nil? || timestamp > @last
34
+ @first = timestamp if timestamp < @first
35
+ @last = timestamp if timestamp > @last
36
36
  end
37
37
 
38
38
  # First timestamp encountered
39
39
  def first_timestamp
40
40
  DateTime.parse(@first.to_s, '%Y%m%d%H%M%S') rescue nil
41
41
  end
42
-
42
+
43
43
  # Last timestamp encountered
44
44
  def last_timestamp
45
- DateTime.parse(@last.to_s, '%Y%m%d%H%M%S') rescue nil
45
+ DateTime.parse(@last.to_s, '%Y%m%d%H%M%S') rescue nil
46
46
  end
47
-
47
+
48
48
  # Difference between last and first timestamp.
49
49
  def timespan
50
50
  last_timestamp - first_timestamp
@@ -55,27 +55,27 @@ module RequestLogAnalyzer::Tracker
55
55
  # <tt>output</tt> The output object
56
56
  def report(output)
57
57
  output.title(options[:title]) if options[:title]
58
-
59
- if @last && @first
60
- output.with_style(:cell_separator => false) do
58
+
59
+ if @last > 0 && @first < 99999999999999
60
+ output.with_style(:cell_separator => false) do
61
61
  output.table({:width => 20}, {}) do |rows|
62
62
  rows << ['First request:', first_timestamp.strftime('%Y-%m-%d %H:%M:%I')]
63
- rows << ['Last request:', last_timestamp.strftime('%Y-%m-%d %H:%M:%I')]
64
- rows << ['Total time analyzed:', "#{timespan.ceil} days"]
63
+ rows << ['Last request:', last_timestamp.strftime('%Y-%m-%d %H:%M:%I')]
64
+ rows << ['Total time analyzed:', "#{timespan.ceil} days"]
65
65
  end
66
66
  end
67
67
  end
68
68
  end
69
-
69
+
70
70
  # Returns the title of this tracker for reports
71
71
  def title
72
72
  options[:title] || 'Request timespan'
73
73
  end
74
-
74
+
75
75
  # A hash that can be exported to YAML with the first and last timestamp encountered.
76
76
  def to_yaml_object
77
77
  { :first => first_timestamp, :last =>last_timestamp }
78
78
  end
79
-
79
+
80
80
  end
81
81
  end