request-log-analyzer 1.1.0 → 1.1.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 (40) hide show
  1. data/README.rdoc +4 -3
  2. data/bin/request-log-analyzer +4 -5
  3. data/lib/cli/command_line_arguments.rb +2 -2
  4. data/lib/request_log_analyzer.rb +28 -6
  5. data/lib/request_log_analyzer/{aggregator/base.rb → aggregator.rb} +5 -1
  6. data/lib/request_log_analyzer/aggregator/summarizer.rb +2 -3
  7. data/lib/request_log_analyzer/controller.rb +11 -16
  8. data/lib/request_log_analyzer/file_format.rb +71 -38
  9. data/lib/request_log_analyzer/file_format/merb.rb +32 -26
  10. data/lib/request_log_analyzer/file_format/rails.rb +73 -71
  11. data/lib/request_log_analyzer/file_format/rails_development.rb +93 -95
  12. data/lib/request_log_analyzer/filter.rb +38 -0
  13. data/lib/request_log_analyzer/filter/anonimize.rb +1 -1
  14. data/lib/request_log_analyzer/line_definition.rb +1 -1
  15. data/lib/request_log_analyzer/output.rb +6 -8
  16. data/lib/request_log_analyzer/output/fixed_width.rb +133 -117
  17. data/lib/request_log_analyzer/output/html.rb +138 -60
  18. data/lib/request_log_analyzer/request.rb +3 -1
  19. data/lib/request_log_analyzer/{source/base.rb → source.rb} +5 -0
  20. data/lib/request_log_analyzer/source/{log_file.rb → log_parser.rb} +15 -6
  21. data/lib/request_log_analyzer/tracker.rb +58 -0
  22. data/lib/request_log_analyzer/tracker/category.rb +7 -8
  23. data/lib/request_log_analyzer/tracker/duration.rb +15 -12
  24. data/lib/request_log_analyzer/tracker/hourly_spread.rb +8 -8
  25. data/lib/request_log_analyzer/tracker/timespan.rb +10 -10
  26. data/spec/controller_spec.rb +5 -4
  27. data/spec/database_inserter_spec.rb +5 -8
  28. data/spec/file_format_spec.rb +2 -2
  29. data/spec/file_formats/spec_format.rb +2 -1
  30. data/spec/filter_spec.rb +0 -3
  31. data/spec/log_parser_spec.rb +6 -6
  32. data/spec/merb_format_spec.rb +38 -38
  33. data/spec/rails_format_spec.rb +2 -2
  34. data/spec/request_spec.rb +2 -2
  35. data/spec/spec_helper.rb +3 -37
  36. data/tasks/github-gem.rake +2 -1
  37. metadata +7 -8
  38. data/lib/request_log_analyzer/filter/base.rb +0 -32
  39. data/lib/request_log_analyzer/log_parser.rb +0 -173
  40. data/lib/request_log_analyzer/tracker/base.rb +0 -54
@@ -5,7 +5,7 @@ Merb to produce a performance report. Its purpose is to find what actions are be
5
5
 
6
6
  * Analyzes Rails log files (all versions)
7
7
  * Can combine multiple files (handy if you are using logrotate)
8
- * Uses several metrics, including cumulative request time, average request time, process blockers, database and rendering time, HTTP methods and states, Rails action cache statistics, etc.) (Sample output: http://wiki.github.com/wvanbergen/request-log-analyzer/sample-output)
8
+ * Uses several metrics, including cumulative request time, average request time, process blockers, database and rendering time, HTTP methods and statuses, Rails action cache statistics, etc.) (Sample output: http://wiki.github.com/wvanbergen/request-log-analyzer/sample-output)
9
9
  * Low memory footprint (server-safe)
10
10
  * Fast
11
11
  * MIT licensed
@@ -32,10 +32,11 @@ To analyze a log file and produce a performance report, run request-log-analyzer
32
32
 
33
33
  $ request-log-analyzer log/production.log
34
34
 
35
- For more details and available command line options, see the project's wiki:http://wiki.github.com/wvanbergen/request-log-analyzer/basic-usage
35
+ For more details and available command line options, see the project's wiki: http://wiki.github.com/wvanbergen/request-log-analyzer/basic-usage
36
36
 
37
37
  == Additional information
38
38
 
39
39
  * Project wiki at GitHub: http://wiki.github.com/wvanbergen/request-log-analyzer
40
+ * RDoc documentation: http://wvanbergen.github.com/request-log-analyzer
40
41
  * wvanbergen's blog posts: http://techblog.floorplanner.com/tag/request-log-analyzer
41
- * bart ten brinke's blog posts: http://movesonrails.com
42
+ * barttenbrinke's blog posts: http://movesonrails.com/articles/tag/analyzer
@@ -115,11 +115,10 @@ when :anonymize
115
115
  require File.dirname(__FILE__) + '/../lib/request_log_analyzer/log_processor'
116
116
  RequestLogAnalyzer::LogProcessor.build(:anonymize, arguments).run!
117
117
  else
118
- puts "Request log analyzer, by Willem van Bergen and Bart ten Brinke - Version 1.0\n\n"
119
-
118
+ puts "Request-log-analyzer, by Willem van Bergen and Bart ten Brinke - version #{RequestLogAnalyzer::VERSION}"
119
+ puts "Website: http://github.com/wvanbergen/request-log-analyzer"
120
+ puts
121
+
120
122
  # Run the request_log_analyzer!
121
123
  RequestLogAnalyzer::Controller.build(arguments).run!
122
-
123
- puts
124
- puts "Thanks for using request-log-analyzer"
125
124
  end
@@ -140,8 +140,8 @@ module CommandLine
140
140
  end
141
141
  end
142
142
 
143
- OPTION_REGEXP = /^\-\-([A-z0-9-]+)$/;
144
- ALIASES_REGEXP = /^\-([A-z0-9]+)$/
143
+ OPTION_REGEXP = /^\-\-([A-Za-z0-9-]+)$/;
144
+ ALIASES_REGEXP = /^\-([A-Aa-z0-9]+)$/
145
145
 
146
146
  attr_reader :definition
147
147
  attr_reader :tokens
@@ -1,14 +1,36 @@
1
1
  require 'date'
2
2
  require File.dirname(__FILE__) + '/cli/progressbar'
3
3
 
4
+ module RequestLogAnalyzer
5
+
6
+ VERSION = '1.1'
7
+
8
+ # Function to implement
9
+ def self.load_default_class_file(base, const)
10
+ path = to_underscore(base.to_s)
11
+ basename = to_underscore(const.to_s)
12
+ filename = "#{File.dirname(__FILE__)}/#{path}/#{basename}"
13
+ require filename
14
+ base.const_get(const)
15
+ end
16
+
17
+ # Convert a string/symbol in camelcase (RequestLogAnalyzer::Controller) to underscores (request_log_analyzer/controller)
18
+ def self.to_underscore(str)
19
+ str.to_s.gsub(/::/, '/').gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').gsub(/([a-z\d])([A-Z])/,'\1_\2').tr("-", "_").downcase
20
+ end
21
+
22
+ # Convert a string/symbol in underscores (request_log_analyzer/controller) to camelcase (RequestLogAnalyzer::Controller)
23
+ def self.to_camelcase(str)
24
+ str.to_s.to_s.gsub(/\/(.?)/) { "::" + $1.upcase }.gsub(/(^|_)(.)/) { $2.upcase }
25
+ end
26
+ end
27
+
4
28
  require File.dirname(__FILE__) + '/request_log_analyzer/file_format'
5
29
  require File.dirname(__FILE__) + '/request_log_analyzer/line_definition'
6
30
  require File.dirname(__FILE__) + '/request_log_analyzer/request'
7
- require File.dirname(__FILE__) + '/request_log_analyzer/log_parser'
8
- require File.dirname(__FILE__) + '/request_log_analyzer/aggregator/base'
9
- require File.dirname(__FILE__) + '/request_log_analyzer/aggregator/summarizer'
10
- require File.dirname(__FILE__) + '/request_log_analyzer/filter/base'
31
+ require File.dirname(__FILE__) + '/request_log_analyzer/aggregator'
32
+ require File.dirname(__FILE__) + '/request_log_analyzer/filter'
11
33
  require File.dirname(__FILE__) + '/request_log_analyzer/controller'
12
- require File.dirname(__FILE__) + '/request_log_analyzer/source/base'
13
- require File.dirname(__FILE__) + '/request_log_analyzer/source/log_file'
34
+ require File.dirname(__FILE__) + '/request_log_analyzer/source'
14
35
  require File.dirname(__FILE__) + '/request_log_analyzer/output'
36
+
@@ -1,5 +1,9 @@
1
1
  module RequestLogAnalyzer::Aggregator
2
-
2
+
3
+ def self.const_missing(const)
4
+ RequestLogAnalyzer::load_default_class_file(self, const)
5
+ end
6
+
3
7
  # The base class of an aggregator. This class provides the interface to which
4
8
  # every aggregator should comply (by simply subclassing this class).
5
9
  class Base
@@ -1,4 +1,4 @@
1
- require File.dirname(__FILE__) + '/../tracker/base'
1
+ require File.dirname(__FILE__) + '/../tracker'
2
2
 
3
3
  module RequestLogAnalyzer::Aggregator
4
4
 
@@ -33,8 +33,7 @@ module RequestLogAnalyzer::Aggregator
33
33
  end
34
34
 
35
35
  def track(tracker_klass, options = {})
36
- require "#{File.dirname(__FILE__)}/../tracker/#{tracker_klass}"
37
- tracker_klass = RequestLogAnalyzer::Tracker.const_get(tracker_klass.to_s.split(/[^a-z0-9]/i).map{ |w| w.capitalize }.join('')) if tracker_klass.kind_of?(Symbol)
36
+ tracker_klass = RequestLogAnalyzer::Tracker.const_get(RequestLogAnalyzer::to_camelcase(tracker_klass)) if tracker_klass.kind_of?(Symbol)
38
37
  @trackers << tracker_klass.new(options)
39
38
  end
40
39
  end
@@ -62,7 +62,7 @@ module RequestLogAnalyzer
62
62
  options.store(:source_files, arguments.parameters)
63
63
  end
64
64
 
65
- controller = Controller.new(RequestLogAnalyzer::Source::LogFile.new(file_format, options), options)
65
+ controller = Controller.new(RequestLogAnalyzer::Source::LogParser.new(file_format, options), options)
66
66
 
67
67
  options[:assume_correct_order] = arguments[:assume_correct_order]
68
68
 
@@ -147,12 +147,8 @@ module RequestLogAnalyzer
147
147
 
148
148
  # Adds an aggregator to the controller. The aggregator will be called for every request
149
149
  # that is parsed from the provided sources (see add_source)
150
- def add_aggregator(agg)
151
- if agg.kind_of?(Symbol)
152
- require File.dirname(__FILE__) + "/aggregator/#{agg}"
153
- agg = RequestLogAnalyzer::Aggregator.const_get(agg.to_s.split(/[^a-z0-9]/i).map{ |w| w.capitalize }.join(''))
154
- end
155
-
150
+ def add_aggregator(agg)
151
+ agg = RequestLogAnalyzer::Aggregator.const_get(RequestLogAnalyzer::to_camelcase(agg)) if agg.kind_of?(Symbol)
156
152
  @aggregators << agg.new(@source, @options)
157
153
  end
158
154
 
@@ -160,11 +156,7 @@ module RequestLogAnalyzer
160
156
 
161
157
  # Adds a request filter to the controller.
162
158
  def add_filter(filter, filter_options = {})
163
- if filter.kind_of?(Symbol)
164
- require File.dirname(__FILE__) + "/filter/#{filter}"
165
- filter = RequestLogAnalyzer::Filter.const_get(filter.to_s.split(/[^a-z0-9]/i).map{ |w| w.capitalize }.join(''))
166
- end
167
-
159
+ filter = RequestLogAnalyzer::Filter.const_get(RequestLogAnalyzer::to_camelcase(filter)) if filter.kind_of?(Symbol)
168
160
  @filters << filter.new(file_format, @options.merge(filter_options))
169
161
  end
170
162
 
@@ -178,13 +170,11 @@ module RequestLogAnalyzer
178
170
  # 6. Finalize Source
179
171
  def run!
180
172
 
181
-
182
-
183
173
  @filters.each { |filter| filter.prepare }
184
174
  @aggregators.each { |agg| agg.prepare }
185
175
 
186
176
  begin
187
- @source.requests do |request|
177
+ @source.each_request do |request|
188
178
  @filters.each { |filter| request = filter.filter(request) }
189
179
  @aggregators.each { |agg| agg.aggregate(request) } if request
190
180
  end
@@ -201,7 +191,12 @@ module RequestLogAnalyzer
201
191
 
202
192
  @source.finalize
203
193
 
204
-
194
+ if @output.io.kind_of?(File)
195
+ puts
196
+ puts "Report written to: " + File.expand_path(@output.io.path)
197
+ puts "Thanks for using request-log-analyzer!"
198
+ @output.io.close
199
+ end
205
200
  end
206
201
 
207
202
  end
@@ -1,29 +1,80 @@
1
- module RequestLogAnalyzer
1
+ module RequestLogAnalyzer::FileFormat
2
2
 
3
- class FileFormat
3
+
4
+ def self.const_missing(const)
5
+ RequestLogAnalyzer::load_default_class_file(self, const)
6
+ end
7
+
8
+ # Loads a FileFormat::Base subclass instance.
9
+ # You can provide:
10
+ # * A FileFormat instance (which will return itself)
11
+ # * A FileFormat class (of which an imstance will be returned)
12
+ # * A filename (from which the FileFormat class is loaded)
13
+ # * A symbol of a built-in file format (e.g. :rails)
14
+ def self.load(file_format)
15
+ klass = nil
16
+ if file_format.kind_of?(RequestLogAnalyzer::FileFormat::Base)
17
+ # this already is a file format! return itself
18
+ return @current_file_format = file_format
19
+
20
+ elsif file_format.kind_of?(Class) && file_format.ancestors.include?(RequestLogAnalyzer::FileFormat::Base)
21
+ # a usable class is provided. Use this format class.
22
+ klass = file_format
23
+
24
+ elsif file_format.kind_of?(String) && File.exist?(file_format)
25
+ # load a format from a ruby file
26
+ require file_format
27
+ klass = Object.const_get(RequestLogAnalyzer::to_camelcase(File.basename(file_format, '.rb')))
28
+
29
+ else
30
+ # load a provided file format
31
+ klass = RequestLogAnalyzer::FileFormat.const_get(RequestLogAnalyzer::to_camelcase(file_format))
32
+ end
4
33
 
5
- # Makes classes aware of a file format by registering the file_format variable
6
- module Awareness
7
-
8
- def self.included(base)
9
- base.send(:attr_reader, :file_format)
10
- end
11
-
12
- def register_file_format(format)
13
- @file_format = format
14
- end
34
+ raise if klass.nil?
35
+ @current_file_format = klass.new # return an instance of the class
36
+ end
37
+
38
+ # Makes classes aware of a file format by registering the file_format variable
39
+ module Awareness
40
+
41
+ def self.included(base)
42
+ base.send(:attr_reader, :file_format)
15
43
  end
44
+
45
+ def register_file_format(format)
46
+ @file_format = format
47
+ end
48
+ end
49
+
50
+ # Base class for all log file format definitions. This class provides functions for subclasses to
51
+ # define their LineDefinitions and to define a summary report.
52
+ #
53
+ # A subclass of this class is instantiated when request-log-analyzer is started and this instance
54
+ # is shared with all components of the application so they can act on the specifics of the format
55
+ class Base
16
56
 
57
+ # Registers the line definer instance for a subclass.
17
58
  def self.inherited(subclass)
18
59
  subclass.instance_variable_set(:@line_definer, RequestLogAnalyzer::LineDefinition::Definer.new)
19
60
  subclass.class_eval { class << self; attr_accessor :line_definer; end }
20
- subclass.class_eval { class << self; attr_accessor :report_definer; end }
61
+ subclass.class_eval { class << self; attr_accessor :report_definer; end }
62
+
63
+ unless subclass.const_defined?('Request')
64
+ subclass.const_set('Request', Class.new(RequestLogAnalyzer::Request))
65
+ end
21
66
  end
22
67
 
68
+ # Specifies a single line defintions.
23
69
  def self.line_definition(name, &block)
24
70
  @line_definer.send(name, &block)
25
71
  end
26
72
 
73
+ def create_request(*hashes)
74
+ self.class::Request.create(self, *hashes)
75
+ end
76
+
77
+ # Specifies multiple line definitions at once using a block
27
78
  def self.format_definition(&block)
28
79
  if block_given?
29
80
  yield(@line_definer)
@@ -32,48 +83,30 @@ module RequestLogAnalyzer
32
83
  end
33
84
  end
34
85
 
86
+ # Specifies the summary report using a block.
35
87
  def self.report(&block)
36
88
  @report_definer = RequestLogAnalyzer::Aggregator::Summarizer::Definer.new
37
89
  yield(@report_definer)
38
90
  end
39
91
 
40
- def self.load(file_format)
41
- if file_format.kind_of?(RequestLogAnalyzer::FileFormat)
42
- # this already is a file format! return itself
43
- return file_format
44
-
45
- elsif file_format.kind_of?(Class) && file_format.ancestors.include?(RequestLogAnalyzer::FileFormat)
46
- klass = file_format
47
-
48
- elsif file_format.kind_of?(String) && File.exist?(file_format)
49
- # load a format from a ruby file
50
- require file_format
51
- klass_name = File.basename(file_format, '.rb').split(/[^a-z0-9]/i).map{ |w| w.capitalize }.join('')
52
- klass = Object.const_get(klass_name)
53
-
54
- elsif File.exist?("#{File.dirname(__FILE__)}/file_format/#{file_format}.rb")
55
- # load a provided file format
56
- require "#{File.dirname(__FILE__)}/file_format/#{file_format}"
57
- klass_name = file_format.to_s.split(/[^a-z0-9]/i).map{ |w| w.capitalize }.join('')
58
- klass = RequestLogAnalyzer::FileFormat.const_get(klass_name)
59
-
60
- end
61
-
62
- klass.new # return an instance of the class
63
- end
64
-
92
+ # Returns all line definitions
65
93
  def line_definitions
66
94
  @line_definitions ||= self.class.line_definer.line_definitions
67
95
  end
68
96
 
97
+ # Returns all the defined trackers for the summary report.
69
98
  def report_trackers
70
99
  self.class.instance_variable_get(:@report_definer).trackers rescue []
71
100
  end
72
101
 
102
+ # Checks whether the line definitions form a valid language.
103
+ # A file format should have at least a header and a footer line type
73
104
  def valid?
74
105
  line_definitions.detect { |(name, ld)| ld.header } && line_definitions.detect { |(name, ld)| ld.footer }
75
106
  end
76
107
 
108
+ # Function that a file format con implement to monkey patch the environment.
109
+ # * <tt>controller</tt> The environment is provided as a controller instance
77
110
  def setup_environment(controller)
78
111
 
79
112
  end
@@ -1,33 +1,39 @@
1
- module RequestLogAnalyzer::FileFormat::Merb
1
+ module RequestLogAnalyzer::FileFormat
2
+
3
+ class Merb < Base
2
4
 
3
- LINE_DEFINITIONS = {
4
-
5
5
  # ~ Started request handling: Fri Aug 29 11:10:23 +0200 2008
6
- :started => {
7
- :header => true,
8
- :teaser => /Started/,
9
- :regexp => /Started request handling\:\ (.+)/,
10
- :captures => [{ :name => :timestamp, :type => :timestamp, :anonymize => :slightly }]
11
- },
6
+ line_definition :started do |line|
7
+ line.header = true
8
+ line.teaser = /Started/
9
+ line.regexp = /Started request handling\:\ (.+)/
10
+ line.captures << { :name => :timestamp, :type => :timestamp, :anonymize => :slightly }
11
+ end
12
12
 
13
13
  # ~ Params: {"action"=>"create", "controller"=>"session"}
14
14
  # ~ Params: {"_method"=>"delete", "authenticity_token"=>"[FILTERED]", "action"=>"d}
15
- :params => {
16
- :teaser => /Params/,
17
- :regexp => /Params\:\ \{(.+)\}/,
18
- :captures => [{ :name => :raw_hash, :type => :string}]
19
- },
20
-
15
+ line_definition :params do |line|
16
+ line.teaser = /Params/
17
+ line.regexp = /Params\:\ \{(.+)\}/
18
+ line.captures << { :name => :raw_hash, :type => :string}
19
+ end
20
+
21
21
  # ~ {:dispatch_time=>0.006117, :after_filters_time=>6.1e-05, :before_filters_time=>0.000712, :action_time=>0.005833}
22
- :completed => {
23
- :footer => true,
24
- :teaser => /\{:dispatch_time/,
25
- :regexp => /\{\:dispatch_time=>(\d+\.\d+(?:e-?\d+)?), (?:\:after_filters_time=>(\d+\.\d+(?:e-?\d+)?), )?(?:\:before_filters_time=>(\d+\.\d+(?:e-?\d+)?), )?\:action_time=>(\d+\.\d+(?:e-?\d+)?)\}/,
26
- :captures => [{ :name => :dispatch_time, :type => :sec, :anonymize => :slightly },
27
- { :name => :after_filters_time, :type => :sec, :anonymize => :slightly },
28
- { :name => :before_filters_time, :type => :sec, :anonymize => :slightly },
29
- { :name => :action_time, :type => :sec, :anonymize => :slightly }]
30
- }
31
- }
22
+ line_definition :completed do |line|
23
+ line.footer = true
24
+ line.teaser = /\{:dispatch_time/
25
+ line.regexp = /\{\:dispatch_time=>(\d+\.\d+(?:e-?\d+)?), (?:\:after_filters_time=>(\d+\.\d+(?:e-?\d+)?), )?(?:\:before_filters_time=>(\d+\.\d+(?:e-?\d+)?), )?\:action_time=>(\d+\.\d+(?:e-?\d+)?)\}/
26
+ line.captures << { :name => :dispatch_time, :type => :sec, :anonymize => :slightly } \
27
+ << { :name => :after_filters_time, :type => :sec, :anonymize => :slightly } \
28
+ << { :name => :before_filters_time, :type => :sec, :anonymize => :slightly } \
29
+ << { :name => :action_time, :type => :sec, :anonymize => :slightly }
30
+ end
32
31
 
33
- end
32
+
33
+ report do |analyze|
34
+ # FIX ME
35
+ end
36
+
37
+ end
38
+
39
+ end
@@ -1,90 +1,92 @@
1
- class RequestLogAnalyzer::FileFormat::Rails < RequestLogAnalyzer::FileFormat
1
+ module RequestLogAnalyzer::FileFormat
2
2
 
3
- # Processing EmployeeController#index (for 123.123.123.123 at 2008-07-13 06:00:00) [GET]
4
- line_definition :processing do |line|
5
- line.header = true # this line is the first log line for a request
6
- line.teaser = /Processing /
7
- line.regexp = /Processing ((?:\w+::)?\w+)#(\w+)(?: to (\w+))? \(for (\d+\.\d+\.\d+\.\d+) at (\d\d\d\d-\d\d-\d\d \d\d:\d\d:\d\d)\) \[([A-Z]+)\]/
8
- line.captures << { :name => :controller, :type => :string } \
9
- << { :name => :action, :type => :string } \
10
- << { :name => :format, :type => :string } \
11
- << { :name => :ip, :type => :string, :anonymize => :ip } \
12
- << { :name => :timestamp, :type => :timestamp, :anonymize => :slightly } \
13
- << { :name => :method, :type => :string }
14
- end
3
+ class Rails < Base
4
+
5
+ # Processing EmployeeController#index (for 123.123.123.123 at 2008-07-13 06:00:00) [GET]
6
+ line_definition :processing do |line|
7
+ line.header = true # this line is the first log line for a request
8
+ line.teaser = /Processing /
9
+ line.regexp = /Processing ((?:\w+::)?\w+)#(\w+)(?: to (\w+))? \(for (\d+\.\d+\.\d+\.\d+) at (\d\d\d\d-\d\d-\d\d \d\d:\d\d:\d\d)\) \[([A-Z]+)\]/
10
+ line.captures << { :name => :controller, :type => :string } \
11
+ << { :name => :action, :type => :string } \
12
+ << { :name => :format, :type => :string } \
13
+ << { :name => :ip, :type => :string, :anonymize => :ip } \
14
+ << { :name => :timestamp, :type => :timestamp, :anonymize => :slightly } \
15
+ << { :name => :method, :type => :string }
16
+ end
15
17
 
16
- # Filter chain halted as [#<ActionController::Caching::Actions::ActionCacheFilter:0x2a999ad620 @check=nil, @options={:store_options=>{}, :layout=>nil, :cache_path=>#<Proc:0x0000002a999b8890@/app/controllers/cached_controller.rb:8>}>] rendered_or_redirected.
17
- line_definition :cache_hit do |line|
18
- line.regexp = /Filter chain halted as \[\#<ActionController::Caching::Actions::ActionCacheFilter:.+>\] rendered_or_redirected/
19
- end
18
+ # Filter chain halted as [#<ActionController::Caching::Actions::ActionCacheFilter:0x2a999ad620 @check=nil, @options={:store_options=>{}, :layout=>nil, :cache_path=>#<Proc:0x0000002a999b8890@/app/controllers/cached_controller.rb:8>}>] rendered_or_redirected.
19
+ line_definition :cache_hit do |line|
20
+ line.regexp = /Filter chain halted as \[\#<ActionController::Caching::Actions::ActionCacheFilter:.+>\] rendered_or_redirected/
21
+ end
20
22
 
21
- # RuntimeError (Cannot destroy employee): /app/models/employee.rb:198:in `before_destroy'
22
- line_definition :failed do |line|
23
- line.footer = true
24
- line.regexp = /((?:[A-Z]\w+\:\:)*[A-Z]\w+) \((.*)\)(?: on line #(\d+) of .+)?\:(.*)/
25
- line.captures << { :name => :error, :type => :string } \
26
- << { :name => :message, :type => :string } \
27
- << { :name => :line, :type => :integer } \
28
- << { :name => :file, :type => :string } \
29
- << { :name => :stack_trace, :type => :string, :anonymize => true }
30
- end
23
+ # RuntimeError (Cannot destroy employee): /app/models/employee.rb:198:in `before_destroy'
24
+ line_definition :failed do |line|
25
+ line.footer = true
26
+ line.regexp = /((?:[A-Z]\w+\:\:)*[A-Z]\w+) \((.*)\)(?: on line #(\d+) of .+)?\:(.*)/
27
+ line.captures << { :name => :error, :type => :string } \
28
+ << { :name => :message, :type => :string } \
29
+ << { :name => :line, :type => :integer } \
30
+ << { :name => :file, :type => :string } \
31
+ << { :name => :stack_trace, :type => :string, :anonymize => true }
32
+ end
31
33
 
32
34
 
33
- # Rails < 2.1 completed line example
34
- # Completed in 0.21665 (4 reqs/sec) | Rendering: 0.00926 (4%) | DB: 0.00000 (0%) | 200 OK [http://demo.nu/employees]
35
- RAILS_21_COMPLETED = /Completed in (\d+\.\d{5}) \(\d+ reqs\/sec\) (?:\| Rendering: (\d+\.\d{5}) \(\d+\%\) )?(?:\| DB: (\d+\.\d{5}) \(\d+\%\) )?\| (\d\d\d).+\[(http.+)\]/
35
+ # Rails < 2.1 completed line example
36
+ # Completed in 0.21665 (4 reqs/sec) | Rendering: 0.00926 (4%) | DB: 0.00000 (0%) | 200 OK [http://demo.nu/employees]
37
+ RAILS_21_COMPLETED = /Completed in (\d+\.\d{5}) \(\d+ reqs\/sec\) (?:\| Rendering: (\d+\.\d{5}) \(\d+\%\) )?(?:\| DB: (\d+\.\d{5}) \(\d+\%\) )?\| (\d\d\d).+\[(http.+)\]/
36
38
 
37
- # Rails > 2.1 completed line example
38
- # Completed in 614ms (View: 120, DB: 31) | 200 OK [http://floorplanner.local/demo]
39
- RAILS_22_COMPLETED = /Completed in (\d+)ms \((?:View: (\d+), )?DB: (\d+)\) \| (\d\d\d).+\[(http.+)\]/
39
+ # Rails > 2.1 completed line example
40
+ # Completed in 614ms (View: 120, DB: 31) | 200 OK [http://floorplanner.local/demo]
41
+ RAILS_22_COMPLETED = /Completed in (\d+)ms \((?:View: (\d+), )?DB: (\d+)\) \| (\d\d\d).+\[(http.+)\]/
40
42
 
41
- # The completed line uses a kind of hack to ensure that both old style logs and new style logs
42
- # are both parsed by the same regular expression. The format in Rails 2.2 was slightly changed,
43
- # but the line contains exactly the same information.
44
- line_definition :completed do |line|
43
+ # The completed line uses a kind of hack to ensure that both old style logs and new style logs
44
+ # are both parsed by the same regular expression. The format in Rails 2.2 was slightly changed,
45
+ # but the line contains exactly the same information.
46
+ line_definition :completed do |line|
45
47
 
46
- line.footer = true
47
- line.teaser = /Completed in /
48
- line.regexp = Regexp.new("(?:#{RAILS_21_COMPLETED}|#{RAILS_22_COMPLETED})")
48
+ line.footer = true
49
+ line.teaser = /Completed in /
50
+ line.regexp = Regexp.new("(?:#{RAILS_21_COMPLETED}|#{RAILS_22_COMPLETED})")
49
51
 
50
- line.captures << { :name => :duration, :type => :sec, :anonymize => :slightly } \
51
- << { :name => :view, :type => :sec, :anonymize => :slightly } \
52
- << { :name => :db, :type => :sec, :anonymize => :slightly } \
53
- << { :name => :status, :type => :integer } \
54
- << { :name => :url, :type => :string, :anonymize => :url } # Old variant
52
+ line.captures << { :name => :duration, :type => :sec, :anonymize => :slightly } \
53
+ << { :name => :view, :type => :sec, :anonymize => :slightly } \
54
+ << { :name => :db, :type => :sec, :anonymize => :slightly } \
55
+ << { :name => :status, :type => :integer } \
56
+ << { :name => :url, :type => :string, :anonymize => :url } # Old variant
55
57
 
56
- line.captures << { :name => :duration, :type => :msec, :anonymize => :slightly } \
57
- << { :name => :view, :type => :msec, :anonymize => :slightly } \
58
- << { :name => :db, :type => :msec, :anonymize => :slightly } \
59
- << { :name => :status, :type => :integer} \
60
- << { :name => :url, :type => :string, :anonymize => :url } # 2.2 variant
61
- end
58
+ line.captures << { :name => :duration, :type => :msec, :anonymize => :slightly } \
59
+ << { :name => :view, :type => :msec, :anonymize => :slightly } \
60
+ << { :name => :db, :type => :msec, :anonymize => :slightly } \
61
+ << { :name => :status, :type => :integer} \
62
+ << { :name => :url, :type => :string, :anonymize => :url } # 2.2 variant
63
+ end
62
64
 
63
65
 
64
66
 
65
- REQUEST_CATEGORIZER = Proc.new do |request|
66
- format = request[:format] || 'html'
67
- "#{request[:controller]}##{request[:action]}.#{format} [#{request[:method]}]"
68
- end
67
+ REQUEST_CATEGORIZER = Proc.new do |request|
68
+ format = request[:format] || 'html'
69
+ "#{request[:controller]}##{request[:action]}.#{format} [#{request[:method]}]"
70
+ end
69
71
 
70
- report do |analyze|
71
- analyze.timespan :line_type => :processing
72
- analyze.category :category => REQUEST_CATEGORIZER, :title => 'Top 20 hits', :amount => 20, :line_type => :processing
73
- analyze.category :method, :title => 'HTTP methods'
74
- analyze.category :status, :title => 'HTTP statuses returned'
75
- analyze.category :category => lambda { |request| request =~ :cache_hit ? 'Cache hit' : 'No hit' }, :title => 'Rails action cache hits'
72
+ report do |analyze|
73
+ analyze.timespan :line_type => :processing
74
+ analyze.category :category => REQUEST_CATEGORIZER, :title => 'Top 20 hits', :amount => 20, :line_type => :processing
75
+ analyze.category :method, :title => 'HTTP methods'
76
+ analyze.category :status, :title => 'HTTP statuses returned'
77
+ analyze.category :category => lambda { |request| request =~ :cache_hit ? 'Cache hit' : 'No hit' }, :title => 'Rails action cache hits'
76
78
 
77
- analyze.duration :duration, :category => REQUEST_CATEGORIZER, :title => "Request duration", :line_type => :completed
78
- analyze.duration :view, :category => REQUEST_CATEGORIZER, :title => "Database time", :line_type => :completed
79
- analyze.duration :db, :category => REQUEST_CATEGORIZER, :title => "View rendering time", :line_type => :completed
79
+ analyze.duration :duration, :category => REQUEST_CATEGORIZER, :title => "Request duration", :line_type => :completed
80
+ analyze.duration :view, :category => REQUEST_CATEGORIZER, :title => "Database time", :line_type => :completed
81
+ analyze.duration :db, :category => REQUEST_CATEGORIZER, :title => "View rendering time", :line_type => :completed
80
82
 
81
- analyze.category :category => REQUEST_CATEGORIZER, :title => 'Process blockers (> 1 sec duration)',
82
- :if => lambda { |request| request[:duration] && request[:duration] > 1.0 }, :amount => 20
83
+ analyze.category :category => REQUEST_CATEGORIZER, :title => 'Process blockers (> 1 sec duration)',
84
+ :if => lambda { |request| request[:duration] && request[:duration] > 1.0 }, :amount => 20
83
85
 
84
- analyze.hourly_spread :line_type => :processing
85
- analyze.category :error, :title => 'Failed requests', :line_type => :failed, :amount => 20
86
- end
87
-
86
+ analyze.hourly_spread :line_type => :processing
87
+ analyze.category :error, :title => 'Failed requests', :line_type => :failed, :amount => 20
88
+ end
88
89
 
90
+ end
89
91
 
90
- end
92
+ end