wvanbergen-request-log-analyzer 1.2.0 → 1.2.1

Sign up to get free protection for your applications and to get access to all the features.
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 +12 -5
  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