request-log-analyzer 1.2.0 → 1.2.1

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 (36) hide show
  1. data/{DESIGN → DESIGN.rdoc} +13 -10
  2. data/README.rdoc +7 -5
  3. data/RELEASE_NOTES.rdoc +10 -0
  4. data/bin/request-log-analyzer +7 -3
  5. data/lib/cli/tools.rb +2 -2
  6. data/lib/request_log_analyzer/aggregator/summarizer.rb +51 -2
  7. data/lib/request_log_analyzer/controller.rb +4 -0
  8. data/lib/request_log_analyzer/output/fixed_width.rb +36 -1
  9. data/lib/request_log_analyzer/output/html.rb +20 -2
  10. data/lib/request_log_analyzer/output.rb +36 -1
  11. data/lib/request_log_analyzer/request.rb +2 -2
  12. data/lib/request_log_analyzer/source/database.rb +19 -4
  13. data/lib/request_log_analyzer/source/log_parser.rb +26 -3
  14. data/lib/request_log_analyzer/tracker/duration.rb +49 -8
  15. data/lib/request_log_analyzer/tracker/frequency.rb +30 -7
  16. data/lib/request_log_analyzer/tracker/hourly_spread.rb +41 -15
  17. data/lib/request_log_analyzer/tracker/timespan.rb +22 -2
  18. data/lib/request_log_analyzer/tracker.rb +38 -1
  19. data/lib/request_log_analyzer.rb +2 -4
  20. data/spec/fixtures/decompression.log +12 -0
  21. data/spec/fixtures/decompression.log.bz2 +0 -0
  22. data/spec/fixtures/decompression.log.gz +0 -0
  23. data/spec/fixtures/decompression.log.zip +0 -0
  24. data/spec/fixtures/decompression.tar.gz +0 -0
  25. data/spec/fixtures/decompression.tgz +0 -0
  26. data/spec/integration/command_line_usage_spec.rb +14 -14
  27. data/spec/lib/helper.rb +19 -3
  28. data/spec/lib/testing_format.rb +1 -0
  29. data/spec/spec_helper.rb +2 -0
  30. data/spec/unit/aggregator/summarizer_spec.rb +1 -1
  31. data/spec/unit/source/log_parser_spec.rb +39 -0
  32. data/spec/unit/tracker/{tracker_api_test.rb → tracker_api_spec.rb} +7 -1
  33. data/tasks/github-gem.rake +1 -2
  34. data/tasks/request_log_analyzer.rake +23 -7
  35. metadata +16 -29
  36. data/HACKING +0 -7
@@ -67,18 +67,41 @@ module RequestLogAnalyzer::Source
67
67
  def parse_files(files, options = {}, &block) # :yields: request
68
68
  files.each { |file| parse_file(file, options, &block) }
69
69
  end
70
+
71
+ # Check if a file has a compressed extention in the filename.
72
+ # If recognized, return the command string used to decompress the file
73
+ def decompress_file?(filename)
74
+ nice_command = "nice -n 5"
75
+
76
+ return "#{nice_command} gunzip -c -d #{filename}" if filename.match(/\.tar.gz$/) || filename.match(/\.tgz$/) || filename.match(/\.gz$/)
77
+ return "#{nice_command} bunzip2 -c -d #{filename}" if filename.match(/\.bz2$/)
78
+ return "#{nice_command} unzip -p #{filename}" if filename.match(/\.zip$/)
79
+
80
+ return ""
81
+ end
70
82
 
71
83
  # Parses a log file. Creates an IO stream for the provided file, and sends it to parse_io for
72
84
  # further handling. This method supports progress updates that can be used to display a progressbar
85
+ #
86
+ # If the logfile is compressed, it is uncompressed to stdout and read.
87
+ # TODO: Check if IO.popen encounters problems with the given command line.
88
+ # TODO: Fix progress bar that is broken for IO.popen, as it returns a single string.
89
+ #
73
90
  # <tt>file</tt>:: The file that should be parsed.
74
91
  # <tt>options</tt>:: A Hash of options that will be pased to parse_io.
75
92
  def parse_file(file, options = {}, &block)
93
+
76
94
  @progress_handler.call(:started, file) if @progress_handler
77
- File.open(file, 'r') { |f| parse_io(f, options, &block) }
95
+
96
+ if decompress_file?(file).empty?
97
+ File.open(file, 'r') { |f| parse_io(f, options, &block) }
98
+ else
99
+ IO.popen(decompress_file?(file), 'r') { |f| parse_io(f, options, &block) }
100
+ end
101
+
78
102
  @progress_handler.call(:finished, file) if @progress_handler
79
103
  end
80
104
 
81
-
82
105
  # Parses an IO stream. It will simply call parse_io. This function does not support progress updates
83
106
  # because the length of a stream is not known.
84
107
  # <tt>stream</tt>:: The IO stream that should be parsed.
@@ -103,7 +126,7 @@ module RequestLogAnalyzer::Source
103
126
 
104
127
  @current_io = io
105
128
  @current_io.each_line do |line|
106
-
129
+
107
130
  @progress_handler.call(:progress, @current_io.pos) if @progress_handler && @current_io.kind_of?(File)
108
131
 
109
132
  request_data = nil
@@ -2,13 +2,14 @@ module RequestLogAnalyzer::Tracker
2
2
 
3
3
  # Analyze the duration of a specific attribute
4
4
  #
5
- # Options:
6
- # * <tt>:line_type</tt> The line type that contains the duration field (determined by the category proc).
7
- # * <tt>:if</tt> Proc that has to return !nil for a request to be passed to the tracker.
8
- # * <tt>:title</tt> Title do be displayed above the report
5
+ # === Options
6
+ # * <tt>:amount</tt> The amount of lines in the report
9
7
  # * <tt>:category</tt> Proc that handles request categorization for given fileformat (REQUEST_CATEGORIZER)
10
8
  # * <tt>:duration</tt> The field containing the duration in the request hash.
11
- # * <tt>:amount</tt> The amount of lines in the report
9
+ # * <tt>:if</tt> Proc that has to return !nil for a request to be passed to the tracker.
10
+ # * <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
12
+ # * <tt>:unless</tt> Handle request if this proc is false for the handled request.
12
13
  #
13
14
  # The items in the update request hash are set during the creation of the Duration tracker.
14
15
  #
@@ -23,6 +24,7 @@ module RequestLogAnalyzer::Tracker
23
24
 
24
25
  attr_reader :categories
25
26
 
27
+ # Check if duration and catagory option have been received,
26
28
  def prepare
27
29
  raise "No duration field set up for category tracker #{self.inspect}" unless options[:duration]
28
30
  raise "No categorizer set up for duration tracker #{self.inspect}" unless options[:category]
@@ -30,6 +32,8 @@ module RequestLogAnalyzer::Tracker
30
32
  @categories = {}
31
33
  end
32
34
 
35
+ # Get the duration information fron the request and store it in the different categories.
36
+ # <tt>request</tt> The request.
33
37
  def update(request)
34
38
  if options[:multiple]
35
39
  categories = request.every(options[:category])
@@ -58,50 +62,68 @@ module RequestLogAnalyzer::Tracker
58
62
  end
59
63
  end
60
64
 
65
+ # Get the number of hits of a specific category.
66
+ # <tt>cat</tt> The category
61
67
  def hits(cat)
62
68
  categories[cat][:hits]
63
69
  end
64
70
 
71
+ # Get the total duration of a specific category.
72
+ # <tt>cat</tt> The category
65
73
  def cumulative_duration(cat)
66
74
  categories[cat][:cumulative]
67
75
  end
68
76
 
77
+ # Get the minimal duration of a specific category.
78
+ # <tt>cat</tt> The category
69
79
  def min_duration(cat)
70
80
  categories[cat][:min]
71
81
  end
72
82
 
83
+ # Get the maximum duration of a specific category.
84
+ # <tt>cat</tt> The category
73
85
  def max_duration(cat)
74
86
  categories[cat][:max]
75
87
  end
76
88
 
89
+ # Get the average duration of a specific category.
90
+ # <tt>cat</tt> The category
77
91
  def average_duration(cat)
78
92
  categories[cat][:cumulative] / categories[cat][:hits]
79
93
  end
80
94
 
95
+ # Get the average duration of a all categories.
81
96
  def overall_average_duration
82
97
  overall_cumulative_duration / overall_hits
83
98
  end
84
99
 
100
+ # Get the cumlative duration of a all categories.
85
101
  def overall_cumulative_duration
86
102
  categories.inject(0.0) { |sum, (name, cat)| sum + cat[:cumulative] }
87
103
  end
88
104
 
105
+ # Get the total hits of a all categories.
89
106
  def overall_hits
90
107
  categories.inject(0) { |sum, (name, cat)| sum + cat[:hits] }
91
108
  end
92
109
 
110
+ # Return categories sorted by hits.
93
111
  def sorted_by_hits
94
112
  sorted_by(:hits)
95
113
  end
96
114
 
115
+ # Return categories sorted by cumulative duration.
97
116
  def sorted_by_cumulative
98
117
  sorted_by(:cumulative)
99
118
  end
100
119
 
120
+ # Return categories sorted by cumulative duration.
101
121
  def sorted_by_average
102
122
  sorted_by { |cat| cat[:cumulative] / cat[:hits] }
103
123
  end
104
124
 
125
+ # Return categories sorted by a given key.
126
+ # <tt>by</tt> The key.
105
127
  def sorted_by(by = nil)
106
128
  if block_given?
107
129
  categories.sort { |a, b| yield(b[1]) <=> yield(a[1]) }
@@ -110,7 +132,12 @@ module RequestLogAnalyzer::Tracker
110
132
  end
111
133
  end
112
134
 
113
- # Builds a result table using a provided sorting function
135
+ # Block function to build a result table using a provided sorting function.
136
+ # <tt>output</tt> The output object.
137
+ # <tt>amount</tt> The number of rows in the report table (default 10).
138
+ # === Options
139
+ # * </tt>:title</tt> The title of the table
140
+ # * </tt>:sort</tt> The key to sort on (:hits, :cumulative, :average, :min or :max)
114
141
  def report_table(output, amount = 10, options = {}, &block)
115
142
 
116
143
  output.title(options[:title])
@@ -128,9 +155,12 @@ module RequestLogAnalyzer::Tracker
128
155
  "%0.02fs" % info[:min], "%0.02fs" % info[:max]]
129
156
  end
130
157
  end
131
-
132
158
  end
133
159
 
160
+ # Generate a request duration report to the given output object
161
+ # By default colulative and average duration are generated.
162
+ # Any options for the report should have been set during initialize.
163
+ # <tt>output</tt> The output object
134
164
  def report(output)
135
165
 
136
166
  options[:title] ||= 'Request duration'
@@ -149,6 +179,17 @@ module RequestLogAnalyzer::Tracker
149
179
  raise "Unknown duration report specified: #{report}!"
150
180
  end
151
181
  end
152
- end
182
+ end
183
+
184
+ # Returns the title of this tracker for reports
185
+ def title
186
+ options[:title] || 'Request duration'
187
+ end
188
+
189
+ # Returns all the categories and the tracked duration as a hash than can be exported to YAML
190
+ def to_yaml_object
191
+ return nil if @categories.empty?
192
+ @categories
193
+ end
153
194
  end
154
195
  end
@@ -3,26 +3,29 @@ module RequestLogAnalyzer::Tracker
3
3
  # Catagorize requests by frequency.
4
4
  # Count and analyze requests for a specific attribute
5
5
  #
6
- # Accepts the following options:
7
- # * <tt>:line_type</tt> The line type that contains the duration field (determined by the category proc).
6
+ # === Options
7
+ # * <tt>:amount</tt> The amount of lines in the report
8
+ # * <tt>:category</tt> Proc that handles the request categorization.
8
9
  # * <tt>:if</tt> Proc that has to return !nil for a request to be passed to the tracker.
10
+ # * <tt>:line_type</tt> The line type that contains the duration field (determined by the category proc).
11
+ # * <tt>:nils</tt> Track undetermined methods.
9
12
  # * <tt>:title</tt> Title do be displayed above the report.
10
- # * <tt>:category</tt> Proc that handles the request categorization.
11
- # * <tt>:amount</tt> The amount of lines in the report
13
+ # * <tt>:unless</tt> Proc that has to return nil for a request to be passed to the tracker.
12
14
  #
13
15
  # The items in the update request hash are set during the creation of the Duration tracker.
14
16
  #
15
17
  # Example output:
16
18
  # HTTP methods
17
19
  # ----------------------------------------------------------------------
18
- # GET | 22248 hits (46.2%) |░░░░░░░░░░░░░░░░░
19
- # PUT | 13685 hits (28.4%) |░░░░░░░░░░░
20
- # POST | 11662 hits (24.2%) |░░░░░░░░░
20
+ # GET | 22248 hits (46.2%) |=================
21
+ # PUT | 13685 hits (28.4%) |===========
22
+ # POST | 11662 hits (24.2%) |=========
21
23
  # DELETE | 512 hits (1.1%) |
22
24
  class Frequency < Base
23
25
 
24
26
  attr_reader :frequencies
25
27
 
28
+ # Check if categories are set up
26
29
  def prepare
27
30
  raise "No categorizer set up for category tracker #{self.inspect}" unless options[:category]
28
31
  @frequencies = {}
@@ -31,6 +34,8 @@ module RequestLogAnalyzer::Tracker
31
34
  end
32
35
  end
33
36
 
37
+ # Check HTTP method of a request and store that in the frequencies hash.
38
+ # <tt>request</tt> The request.
34
39
  def update(request)
35
40
  cat = options[:category].respond_to?(:call) ? options[:category].call(request) : request[options[:category]]
36
41
  if !cat.nil? || options[:nils]
@@ -39,18 +44,25 @@ module RequestLogAnalyzer::Tracker
39
44
  end
40
45
  end
41
46
 
47
+ # Return the amount of times a HTTP method has been encountered
48
+ # <tt>cat</tt> The HTTP method (:get, :put, :post or :delete)
42
49
  def frequency(cat)
43
50
  frequencies[cat] || 0
44
51
  end
45
52
 
53
+ # Return the overall frequency
46
54
  def overall_frequency
47
55
  frequencies.inject(0) { |carry, item| carry + item[1] }
48
56
  end
49
57
 
58
+ # Return the methods sorted by frequency
50
59
  def sorted_by_frequency
51
60
  @frequencies.sort { |a, b| b[1] <=> a[1] }
52
61
  end
53
62
 
63
+ # Generate a HTTP method frequency report to the given output object.
64
+ # Any options for the report should have been set during initialize.
65
+ # <tt>output</tt> The output object
54
66
  def report(output)
55
67
  output.title(options[:title]) if options[:title]
56
68
 
@@ -69,5 +81,16 @@ module RequestLogAnalyzer::Tracker
69
81
 
70
82
  end
71
83
  end
84
+
85
+ # Returns a hash with the frequencies of every category that can be exported to YAML
86
+ def to_yaml_object
87
+ return nil if @frequencies.empty?
88
+ @frequencies
89
+ end
90
+
91
+ # Returns the title of this tracker for reports
92
+ def title
93
+ options[:title] || 'Request frequency'
94
+ end
72
95
  end
73
96
  end
@@ -4,8 +4,10 @@ module RequestLogAnalyzer::Tracker
4
4
  # This spread is shown in a graph form.
5
5
  #
6
6
  # Accepts the following options:
7
- # * <tt>:line_type</tt> The line type that contains the duration field (determined by the category proc).
8
7
  # * <tt>:if</tt> Proc that has to return !nil for a request to be passed to the tracker.
8
+ # * <tt>:line_type</tt> The line type that contains the duration field (determined by the category proc).
9
+ # * <tt>:output</tt> Direct output here (defaults to STDOUT)
10
+ # * <tt>:unless</tt> Proc that has to return nil for a request to be passed to the tracker.
9
11
  #
10
12
  # Expects the following items in the update request hash
11
13
  # * <tt>:timestamp</tt> in YYYYMMDDHHMMSS format.
@@ -13,28 +15,31 @@ module RequestLogAnalyzer::Tracker
13
15
  # Example output:
14
16
  # Requests graph - average per day per hour
15
17
  # --------------------------------------------------
16
- # 7:00 - 330 hits : ░░░░░░░
17
- # 8:00 - 704 hits : ░░░░░░░░░░░░░░░░░
18
- # 9:00 - 830 hits : ░░░░░░░░░░░░░░░░░░░░
19
- # 10:00 - 822 hits : ░░░░░░░░░░░░░░░░░░░
20
- # 11:00 - 823 hits : ░░░░░░░░░░░░░░░░░░░
21
- # 12:00 - 729 hits : ░░░░░░░░░░░░░░░░░
22
- # 13:00 - 614 hits : ░░░░░░░░░░░░░░
23
- # 14:00 - 690 hits : ░░░░░░░░░░░░░░░░
24
- # 15:00 - 492 hits : ░░░░░░░░░░░
25
- # 16:00 - 355 hits : ░░░░░░░░
26
- # 17:00 - 213 hits : ░░░░░
27
- # 18:00 - 107 hits : ░░
18
+ # 7:00 - 330 hits : =======
19
+ # 8:00 - 704 hits : =================
20
+ # 9:00 - 830 hits : ====================
21
+ # 10:00 - 822 hits : ===================
22
+ # 11:00 - 823 hits : ===================
23
+ # 12:00 - 729 hits : =================
24
+ # 13:00 - 614 hits : ==============
25
+ # 14:00 - 690 hits : ================
26
+ # 15:00 - 492 hits : ===========
27
+ # 16:00 - 355 hits : ========
28
+ # 17:00 - 213 hits : =====
29
+ # 18:00 - 107 hits : ==
28
30
  # ................
29
31
  class HourlySpread < Base
30
32
 
31
33
  attr_reader :first, :last, :request_time_graph
32
34
 
35
+ # Check if timestamp field is set in the options and prepare the result time graph.
33
36
  def prepare
34
37
  options[:field] ||= :timestamp
35
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]
36
39
  end
37
-
40
+
41
+ # Check if the timestamp in the request and store it.
42
+ # <tt>request</tt> The request.
38
43
  def update(request)
39
44
  request = request.attributes
40
45
  timestamp = request[options[:field]]
@@ -44,24 +49,31 @@ module RequestLogAnalyzer::Tracker
44
49
  @last = timestamp if @last.nil? || timestamp > @last
45
50
  end
46
51
 
52
+ # Total amount of requests tracked
47
53
  def total_requests
48
54
  @request_time_graph.inject(0) { |sum, value| sum + value }
49
55
  end
50
56
 
57
+ # First timestamp encountered
51
58
  def first_timestamp
52
59
  DateTime.parse(@first.to_s, '%Y%m%d%H%M%S') rescue nil
53
60
  end
54
61
 
62
+ # Last timestamp encountered
55
63
  def last_timestamp
56
64
  DateTime.parse(@last.to_s, '%Y%m%d%H%M%S') rescue nil
57
65
  end
58
66
 
67
+ # Difference between last and first timestamp.
59
68
  def timespan
60
69
  last_timestamp - first_timestamp
61
70
  end
62
71
 
72
+ # Generate an hourly spread report to the given output object.
73
+ # Any options for the report should have been set during initialize.
74
+ # <tt>output</tt> The output object
63
75
  def report(output)
64
- output.title("Requests graph - average per day per hour")
76
+ output.title(title)
65
77
 
66
78
  if total_requests == 0
67
79
  output << "None found.\n"
@@ -77,5 +89,19 @@ module RequestLogAnalyzer::Tracker
77
89
  end
78
90
  end
79
91
  end
92
+
93
+ # Returns the title of this tracker for reports
94
+ def title
95
+ options[:title] || "Request distribution per hour"
96
+ end
97
+
98
+ # Returns the found frequencies per hour as a hash for YAML exporting
99
+ def to_yaml_object
100
+ yaml_object = {}
101
+ @request_time_graph.each_with_index do |freq, hour|
102
+ yaml_object["#{hour}:00 - #{hour+1}:00"] = freq
103
+ end
104
+ yaml_object
105
+ end
80
106
  end
81
107
  end
@@ -4,10 +4,11 @@ module RequestLogAnalyzer::Tracker
4
4
  # Also determines the amount of days inbetween these.
5
5
  #
6
6
  # Accepts the following options:
7
- # * <tt>:line_type</tt> The line type that contains the duration field (determined by the category proc).
8
- # * <tt>:if</tt> Proc that has to return !nil for a request to be passed to the tracker.
9
7
  # * <tt>:field</tt> The timestamp field that is looked at. Defaults to :timestamp.
8
+ # * <tt>:if</tt> Proc that has to return !nil for a request to be passed to the tracker.
9
+ # * <tt>:line_type</tt> The line type that contains the duration field (determined by the category proc).
10
10
  # * <tt>:title</tt> Title do be displayed above the report.
11
+ # * <tt>:unless</tt> Proc that has to return nil for a request to be passed to the tracker.
11
12
  #
12
13
  # Expects the following items in the update request hash
13
14
  # * <tt>:timestamp</tt> in YYYYMMDDHHMMSS format.
@@ -20,10 +21,13 @@ module RequestLogAnalyzer::Tracker
20
21
 
21
22
  attr_reader :first, :last, :request_time_graph
22
23
 
24
+ # Check if timestamp field is set in the options.
23
25
  def prepare
24
26
  options[:field] ||= :timestamp
25
27
  end
26
28
 
29
+ # Check if the timestamp in the request and store it.
30
+ # <tt>request</tt> The request.
27
31
  def update(request)
28
32
  timestamp = request[options[:field]]
29
33
 
@@ -31,18 +35,24 @@ module RequestLogAnalyzer::Tracker
31
35
  @last = timestamp if @last.nil? || timestamp > @last
32
36
  end
33
37
 
38
+ # First timestamp encountered
34
39
  def first_timestamp
35
40
  DateTime.parse(@first.to_s, '%Y%m%d%H%M%S') rescue nil
36
41
  end
37
42
 
43
+ # Last timestamp encountered
38
44
  def last_timestamp
39
45
  DateTime.parse(@last.to_s, '%Y%m%d%H%M%S') rescue nil
40
46
  end
41
47
 
48
+ # Difference between last and first timestamp.
42
49
  def timespan
43
50
  last_timestamp - first_timestamp
44
51
  end
45
52
 
53
+ # Generate an hourly spread report to the given output object.
54
+ # Any options for the report should have been set during initialize.
55
+ # <tt>output</tt> The output object
46
56
  def report(output)
47
57
  output.title(options[:title]) if options[:title]
48
58
 
@@ -55,7 +65,17 @@ module RequestLogAnalyzer::Tracker
55
65
  end
56
66
  end
57
67
  end
68
+ end
69
+
70
+ # Returns the title of this tracker for reports
71
+ def title
72
+ options[:title] || 'Request timespan'
73
+ end
58
74
 
75
+ # A hash that can be exported to YAML with the first and last timestamp encountered.
76
+ def to_yaml_object
77
+ { :first => first_timestamp, :last =>last_timestamp }
59
78
  end
79
+
60
80
  end
61
81
  end
@@ -9,28 +9,51 @@ module RequestLogAnalyzer::Tracker
9
9
  # Base Tracker class. All other trackers inherit from this class
10
10
  #
11
11
  # Accepts the following options:
12
- # * <tt>:line_type</tt> The line type that contains the duration field (determined by the category proc).
13
12
  # * <tt>:if</tt> Proc that has to return !nil for a request to be passed to the tracker.
13
+ # * <tt>:line_type</tt> The line type that contains the duration field (determined by the category proc).
14
14
  # * <tt>:output</tt> Direct output here (defaults to STDOUT)
15
+ # * <tt>:unless</tt> Proc that has to return nil for a request to be passed to the tracker.
15
16
  #
16
17
  # For example :if => lambda { |request| request[:duration] && request[:duration] > 1.0 }
17
18
  class Base
18
19
 
19
20
  attr_reader :options
20
21
 
22
+ # Initialize the class
23
+ # Note that the options are only applicable if should_update? is not overwritten
24
+ # by the inheriting class.
25
+ #
26
+ # === Options
27
+ # * <tt>:if</tt> Handle request if this proc is true for the handled request.
28
+ # * <tt>:unless</tt> Handle request if this proc is false for the handled request.
29
+ # * <tt>:line_type</tt> Line type this tracker will accept.
21
30
  def initialize(options ={})
22
31
  @options = options
23
32
  end
24
33
 
34
+ # Hook things that need to be done before running here.
25
35
  def prepare
26
36
  end
27
37
 
38
+ # Will be called with each request.
39
+ # <tt>request</tt> The request to track data in.
28
40
  def update(request)
29
41
  end
30
42
 
43
+ # Hook things that need to be done after running here.
31
44
  def finalize
32
45
  end
33
46
 
47
+ # Determine if we should run the update function at all.
48
+ # Usually the update function will be heavy, so a light check is done here
49
+ # determining if we need to call update at all.
50
+ #
51
+ # Default this checks if defined:
52
+ # * :line_type is also in the request hash.
53
+ # * :if is true for this request.
54
+ # * :unless if false for this request
55
+ #
56
+ # <tt>request</tt> The request object.
34
57
  def should_update?(request)
35
58
  return false if options[:line_type] && !request.has_line_type?(options[:line_type])
36
59
 
@@ -49,10 +72,24 @@ module RequestLogAnalyzer::Tracker
49
72
  return true
50
73
  end
51
74
 
75
+ # Hook report generation here.
76
+ # Defaults to self.inspect
77
+ # <tt>output</tt> The output object the report will be passed to.
52
78
  def report(output)
53
79
  output << self.inspect
54
80
  output << "\n"
55
81
  end
82
+
83
+ # The title of this tracker. Used for reporting.
84
+ def title
85
+ self.class.to_s
86
+ end
87
+
88
+ # This method is called by RequestLogAnalyzer::Aggregator:Summarizer to retrieve an
89
+ # object with all the results of this tracker, that can be dumped to YAML format.
90
+ def to_yaml_object
91
+ nil
92
+ end
56
93
 
57
94
  end
58
95
  end
@@ -1,9 +1,7 @@
1
1
  require 'date'
2
2
 
3
3
  # Satisfy ruby 1.9 sensitivity about encoding.
4
- if defined? Encoding and Encoding.respond_to? 'default_external='
5
- Encoding.default_external = 'binary'
6
- end
4
+ Encoding.default_external = 'binary' if defined? Encoding and Encoding.respond_to? 'default_external='
7
5
 
8
6
  # RequestLogAnalyzer is the base namespace in which all functionality of RequestLogAnalyzer is implemented.
9
7
  #
@@ -13,7 +11,7 @@ module RequestLogAnalyzer
13
11
 
14
12
  # The current version of request-log-analyzer.
15
13
  # This will be diplayed in output reports etc.
16
- VERSION = '1.1.7'
14
+ VERSION = '1.2.1'
17
15
 
18
16
  # Loads constants in the RequestLogAnalyzer namespace using self.load_default_class_file(base, const)
19
17
  # <tt>const</tt>:: The constant that is not yet loaded in the RequestLogAnalyzer namespace. This should be passed as a string or symbol.
@@ -0,0 +1,12 @@
1
+ Processing PageController#demo (for 127.0.0.1 at 2008-12-10 16:28:09) [GET]
2
+ Parameters: {"action"=>"demo", "controller"=>"page"}
3
+ Logging in from session data...
4
+ Logged in as test@example.com
5
+ Using locale: en-US, http-accept: ["en-US"], session: , det browser: en-US, det domain:
6
+ Rendering template within layouts/demo
7
+ Rendering page/demo
8
+ Rendered shared/_analytics (0.2ms)
9
+ Rendered layouts/_actions (0.6ms)
10
+ Rendered layouts/_menu (2.2ms)
11
+ Rendered layouts/_tabbar (0.5ms)
12
+ Completed in 614ms (View: 120, DB: 31) | 200 OK [http://www.example.coml/demo]
Binary file
Binary file
Binary file
Binary file
Binary file
@@ -3,19 +3,13 @@ require File.dirname(__FILE__) + '/../spec_helper.rb'
3
3
  describe RequestLogAnalyzer, 'running from command line' do
4
4
 
5
5
  include RequestLogAnalyzer::Spec::Helper
6
-
7
- TEMPORARY_DIRECTORY = "#{File.dirname(__FILE__)}/../fixtures"
8
- TEMP_DATABASE_FILE = TEMPORARY_DIRECTORY + "/output.db"
9
- TEMP_REPORT_FILE = TEMPORARY_DIRECTORY + "/report"
10
6
 
11
7
  before(:each) do
12
- File.unlink(TEMP_DATABASE_FILE) if File.exist?(TEMP_DATABASE_FILE)
13
- File.unlink(TEMP_REPORT_FILE) if File.exist?(TEMP_REPORT_FILE)
8
+ cleanup_temp_files!
14
9
  end
15
10
 
16
11
  after(:each) do
17
- File.unlink(TEMP_DATABASE_FILE) if File.exist?(TEMP_DATABASE_FILE)
18
- File.unlink(TEMP_REPORT_FILE) if File.exist?(TEMP_REPORT_FILE)
12
+ cleanup_temp_files!
19
13
  end
20
14
 
21
15
  it "should find 4 requests in default mode" do
@@ -34,13 +28,13 @@ describe RequestLogAnalyzer, 'running from command line' do
34
28
  end
35
29
 
36
30
  it "should write output to a file with the --file option" do
37
- run("#{log_fixture(:rails_1x)} --file #{TEMP_REPORT_FILE}")
38
- File.exist?(TEMP_REPORT_FILE).should be_true
31
+ run("#{log_fixture(:rails_1x)} --file #{temp_output_file(:report)}")
32
+ File.exist?(temp_output_file(:report)).should be_true
39
33
  end
40
34
 
41
35
  it "should write only ASCII characters to a file with the --file option" do
42
- run("#{log_fixture(:rails_1x)} --file #{TEMP_REPORT_FILE}")
43
- /^[\x00-\x7F]*$/.match(File.read(TEMP_REPORT_FILE)).should_not be_nil
36
+ run("#{log_fixture(:rails_1x)} --file #{temp_output_file(:report)}")
37
+ /^[\x00-\x7F]*$/.match(File.read(temp_output_file(:report))).should_not be_nil
44
38
  end
45
39
 
46
40
  it "should write HTML if --output HTML is provided" do
@@ -49,8 +43,8 @@ describe RequestLogAnalyzer, 'running from command line' do
49
43
  end
50
44
 
51
45
  it "should run with the --database option" do
52
- run("#{log_fixture(:rails_1x)} --database #{TEMP_DATABASE_FILE}")
53
- File.exist?(TEMP_DATABASE_FILE).should be_true
46
+ run("#{log_fixture(:rails_1x)} --database #{temp_output_file(:database)}")
47
+ File.exist?(temp_output_file(:database)).should be_true
54
48
  end
55
49
 
56
50
  it "should use no colors in the report with the --boring option" do
@@ -68,4 +62,10 @@ describe RequestLogAnalyzer, 'running from command line' do
68
62
  output.detect { |line| /Parsed requests\:\s*11/ =~ line }.should_not be_nil
69
63
  end
70
64
 
65
+ it "should dump the results to a YAML file" do
66
+ run("#{log_fixture(:rails_1x)} --dump #{temp_output_file(:dump)}")
67
+ File.exist?(temp_output_file(:dump)).should be_true
68
+ YAML::load(File.read(temp_output_file(:dump))).should have_at_least(1).item
69
+ end
70
+
71
71
  end