request-log-analyzer 1.3.7 → 1.4.0

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -1,5 +1,5 @@
1
1
  module RequestLogAnalyzer::FileFormat
2
-
2
+
3
3
  # The Merb file format parses the request header with the timestamp, the params line
4
4
  # with the most important request information and the durations line which contains
5
5
  # the different request durations that can be used for analysis.
@@ -11,14 +11,14 @@ module RequestLogAnalyzer::FileFormat
11
11
  line.teaser = /Started request handling\:/
12
12
  line.regexp = /Started request handling\:\ (.+)/
13
13
  line.captures << { :name => :timestamp, :type => :timestamp }
14
- end
15
-
14
+ end
15
+
16
16
  # ~ Params: {"action"=>"create", "controller"=>"session"}
17
17
  # ~ Params: {"_method"=>"delete", "authenticity_token"=>"[FILTERED]", "action"=>"d}
18
18
  line_definition :params do |line|
19
19
  line.teaser = /Params\:\ /
20
20
  line.regexp = /Params\:\ (\{.+\})/
21
- line.captures << { :name => :params, :type => :eval, :provides => {
21
+ line.captures << { :name => :params, :type => :eval, :provides => {
22
22
  :namespace => :string, :controller => :string, :action => :string, :format => :string, :method => :string } }
23
23
  end
24
24
 
@@ -31,32 +31,32 @@ module RequestLogAnalyzer::FileFormat
31
31
  :dispatch_time => :duration, :after_filters_time => :duration,
32
32
  :before_filters_time => :duration, :action_time => :duration } }
33
33
  end
34
-
35
- REQUEST_CATEGORIZER = Proc.new do |request|
34
+
35
+ REQUEST_CATEGORIZER = Proc.new do |request|
36
36
  category = "#{request[:controller]}##{request[:action]}"
37
37
  category = "#{request[:namespace]}::#{category}" if request[:namespace]
38
38
  category = "#{category}.#{request[:format]}" if request[:format]
39
39
  category
40
40
  end
41
-
41
+
42
42
  report do |analyze|
43
-
43
+
44
44
  analyze.timespan
45
45
  analyze.hourly_spread
46
46
 
47
- analyze.frequency :category => REQUEST_CATEGORIZER, :amount => 20, :title => "Top 20 by hits"
47
+ analyze.frequency :category => REQUEST_CATEGORIZER, :title => "Top 20 by hits"
48
48
  analyze.duration :dispatch_time, :category => REQUEST_CATEGORIZER, :title => 'Request dispatch duration'
49
-
49
+
50
50
  # analyze.duration :action_time, :category => REQUEST_CATEGORIZER, :title => 'Request action duration'
51
51
  # analyze.duration :after_filters_time, :category => REQUEST_CATEGORIZER, :title => 'Request after_filter duration'
52
52
  # analyze.duration :before_filters_time, :category => REQUEST_CATEGORIZER, :title => 'Request before_filter duration'
53
53
  end
54
54
 
55
55
  class Request < RequestLogAnalyzer::Request
56
-
56
+
57
57
  MONTHS = {'Jan' => '01', 'Feb' => '02', 'Mar' => '03', 'Apr' => '04', 'May' => '05', 'Jun' => '06',
58
58
  'Jul' => '07', 'Aug' => '08', 'Sep' => '09', 'Oct' => '10', 'Nov' => '11', 'Dec' => '12' }
59
-
59
+
60
60
  # Speed up timestamp conversion
61
61
  def convert_timestamp(value, definition)
62
62
  "#{value[26,4]}#{MONTHS[value[4,3]]}#{value[8,2]}#{value[11,2]}#{value[14,2]}#{value[17,2]}".to_i
@@ -1,11 +1,11 @@
1
1
  module RequestLogAnalyzer::FileFormat
2
-
2
+
3
3
  class Rack < Apache
4
-
4
+
5
5
  def self.create(*args)
6
6
  super(:rack, *args)
7
7
  end
8
-
8
+
9
9
  end
10
-
10
+
11
11
  end
@@ -1,98 +1,174 @@
1
1
  module RequestLogAnalyzer::FileFormat
2
-
2
+
3
+ # Default FileFormat class for Rails logs.
4
+ #
5
+ # Instances will be created dynamically based on the lines you want it to parse. You can
6
+ # specify what lines should be included in the parser by providing a list to the create
7
+ # method as first argument.
3
8
  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, :default => 'html' } \
13
- << { :name => :ip, :type => :string } \
14
- << { :name => :timestamp, :type => :timestamp } \
15
- << { :name => :method, :type => :string }
16
- end
17
9
 
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/
21
- end
22
-
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 }
10
+ # Creates a Rails FileFormat instance.
11
+ #
12
+ # The lines that will be parsed can be defined by the argument to this function,
13
+ # which should be an array of line names, or a list of line names as comma separated
14
+ # string. The resulting report depends on the lines that will be parsed. You can
15
+ # also provide s string that describes a common set of lines, like "production",
16
+ # "development" or "production".
17
+ def self.create(lines = 'production')
18
+ definitions_hash = line_definer.line_definitions.clone
19
+
20
+ lines = lines.to_s.split(',') if lines.kind_of?(String)
21
+ lines = [lines.to_s] if lines.kind_of?(Symbol)
22
+
23
+ lines.each do |line|
24
+ line = line.to_sym
25
+ if LINE_COLLECTIONS.has_key?(line)
26
+ LINE_COLLECTIONS[line].each { |l| definitions_hash[l] = LINE_DEFINITIONS[l] }
27
+ elsif LINE_DEFINITIONS.has_key?(line)
28
+ definitions_hash[line] = LINE_DEFINITIONS[line]
29
+ else
30
+ raise "Unrecognized Rails log line name: #{line.inspect}!"
31
+ end
32
+ end
33
+
34
+ return self.new(definitions_hash, report_trackers(definitions_hash))
32
35
  end
36
+
37
+ # Creates trackers based on the specified line definitions.
38
+ #
39
+ # The more lines that will be parsed, the more information will appear in the report.
40
+ def self.report_trackers(lines)
41
+ analyze = RequestLogAnalyzer::Aggregator::Summarizer::Definer.new
42
+
43
+ analyze.timespan
44
+ analyze.hourly_spread
45
+
46
+ analyze.frequency :category => REQUEST_CATEGORIZER, :title => 'Most requested'
47
+ analyze.frequency :method, :title => 'HTTP methods'
48
+ analyze.frequency :status, :title => 'HTTP statuses returned'
49
+
50
+ if lines.has_key?(:cache_hit)
51
+ analyze.frequency(:category => lambda { |request| request =~ :cache_hit ? 'Cache hit' : 'No hit' },
52
+ :title => 'Rails action cache hits')
53
+ end
54
+
55
+ analyze.duration :duration, :category => REQUEST_CATEGORIZER, :title => "Request duration", :line_type => :completed
56
+ analyze.duration :view, :category => REQUEST_CATEGORIZER, :title => "View rendering time", :line_type => :completed
57
+ analyze.duration :db, :category => REQUEST_CATEGORIZER, :title => "Database time", :line_type => :completed
58
+
59
+ analyze.frequency :category => REQUEST_CATEGORIZER, :title => 'Process blockers (> 1 sec duration)',
60
+ :if => lambda { |request| request[:duration] && request[:duration] > 1.0 }
61
+
62
+ if lines.has_key?(:failure)
63
+ analyze.frequency :error, :title => 'Failed requests', :line_type => :failure
64
+ end
33
65
 
66
+ if lines.has_key?(:rendered)
67
+ analyze.duration :render_duration, :category => :render_file, :multiple_per_request => true, :title => 'Partial rendering duration'
68
+ end
69
+
70
+ if lines.has_key?(:query_executed)
71
+ analyze.duration :query_duration, :category => :query_sql, :multiple_per_request => true, :title => 'Query duration'
72
+ end
73
+
74
+ return analyze.trackers + report_definer.trackers
75
+ end
34
76
 
35
77
  # Rails < 2.1 completed line example
36
78
  # Completed in 0.21665 (4 reqs/sec) | Rendering: 0.00926 (4%) | DB: 0.00000 (0%) | 200 OK [http://demo.nu/employees]
37
79
  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.+)\]/
38
80
 
39
81
  # Rails > 2.1 completed line example
40
- # Completed in 614ms (View: 120, DB: 31) | 200 OK [http://floorplanner.local/demo]
82
+ # Completed in 614ms (View: 120, DB: 31) | 200 OK [http://floorplanner.local/demo]
41
83
  RAILS_22_COMPLETED = /Completed in (\d+)ms \((?:View: (\d+), )?DB: (\d+)\) \| (\d\d\d).+\[(http.+)\]/
42
84
 
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|
47
-
48
- line.footer = true
49
- line.teaser = /Completed in /
50
- line.regexp = Regexp.new("(?:#{RAILS_21_COMPLETED}|#{RAILS_22_COMPLETED})")
51
-
52
- line.captures << { :name => :duration, :type => :duration, :unit => :sec } \
53
- << { :name => :view, :type => :duration, :unit => :sec } \
54
- << { :name => :db, :type => :duration, :unit => :sec } \
55
- << { :name => :status, :type => :integer } \
56
- << { :name => :url, :type => :string } # Old variant
57
-
58
- line.captures << { :name => :duration, :type => :duration, :unit => :msec } \
59
- << { :name => :view, :type => :duration, :unit => :msec } \
60
- << { :name => :db, :type => :duration, :unit => :msec } \
61
- << { :name => :status, :type => :integer } \
62
- << { :name => :url, :type => :string } # 2.2 variant
63
- end
85
+ # A hash of definitions for all common lines in Rails logs.
86
+ LINE_DEFINITIONS = {
87
+ :processing => RequestLogAnalyzer::LineDefinition.new(:processing, :header => true,
88
+ :teaser => /Processing /,
89
+ :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]+)\]/,
90
+ :captures => [{ :name => :controller, :type => :string },
91
+ { :name => :action, :type => :string },
92
+ { :name => :format, :type => :string, :default => 'html' },
93
+ { :name => :ip, :type => :string },
94
+ { :name => :timestamp, :type => :timestamp },
95
+ { :name => :method, :type => :string }]),
96
+
97
+ :completed => RequestLogAnalyzer::LineDefinition.new(:completed, :footer => true,
98
+ :teaser => /Completed in /,
99
+ :regexp => Regexp.union(RAILS_21_COMPLETED, RAILS_22_COMPLETED),
100
+ :captures => [{ :name => :duration, :type => :duration, :unit => :sec }, # First old variant capture
101
+ { :name => :view, :type => :duration, :unit => :sec },
102
+ { :name => :db, :type => :duration, :unit => :sec },
103
+ { :name => :status, :type => :integer },
104
+ { :name => :url, :type => :string }, # Last old variant capture
105
+ { :name => :duration, :type => :duration, :unit => :msec }, # First new variant capture
106
+ { :name => :view, :type => :duration, :unit => :msec },
107
+ { :name => :db, :type => :duration, :unit => :msec },
108
+ { :name => :status, :type => :integer },
109
+ { :name => :url, :type => :string }]), # Last new variant capture
64
110
 
111
+ :failure => RequestLogAnalyzer::LineDefinition.new(:failure, :footer => true,
112
+ :teaser => /((?:[A-Z]\w*[a-z]\w+\:\:)*[A-Z]\w*[a-z]\w+) \((.*)\)(?: on line #(\d+) of (.+))?\:/,
113
+ :regexp => /((?:[A-Z]\w*[a-z]\w+\:\:)*[A-Z]\w*[a-z]\w+) \((.*)\)(?: on line #(\d+) of (.+))?\:\s*$/,
114
+ :captures => [{ :name => :error, :type => :string },
115
+ { :name => :message, :type => :string },
116
+ { :name => :line, :type => :integer },
117
+ { :name => :file, :type => :string }]),
118
+
119
+ :cache_hit => RequestLogAnalyzer::LineDefinition.new(:cache_hit,
120
+ :regexp => /Filter chain halted as \[\#<ActionController::Caching::Actions::ActionCacheFilter/),
121
+
122
+ :parameters => RequestLogAnalyzer::LineDefinition.new(:parameters,
123
+ :teaser => / Parameters:/,
124
+ :regexp => / Parameters:\s+(\{.*\})/,
125
+ :captures => [{ :name => :params, :type => :eval }]),
126
+
127
+ :rendered => RequestLogAnalyzer::LineDefinition.new(:rendered,
128
+ :teaser => /Rendered /,
129
+ :regexp => /Rendered (\w+(?:\/\w+)+) \((\d+\.\d+)ms\)/,
130
+ :captures => [{ :name => :render_file, :type => :string },
131
+ { :name => :render_duration, :type => :duration, :unit => :msec }]),
132
+
133
+ :query_executed => RequestLogAnalyzer::LineDefinition.new(:query_executed,
134
+ :regexp => /\s+(?:\e\[4;36;1m)?((?:\w+::)*\w+) Load \((\d+\.\d+)ms\)(?:\e\[0m)?\s+(?:\e\[0;1m)?([^\e]+) ?(?:\e\[0m)?/,
135
+ :captures => [{ :name => :query_class, :type => :string },
136
+ { :name => :query_duration, :type => :duration, :unit => :msec },
137
+ { :name => :query_sql, :type => :sql }]),
138
+
139
+ :query_cached => RequestLogAnalyzer::LineDefinition.new(:query_cached,
140
+ :regexp => /\s+(?:\e\[4;35;1m)?CACHE \((\d+\.\d+)ms\)(?:\e\[0m)?\s+(?:\e\[0m)?([^\e]+) ?(?:\e\[0m)?/,
141
+ :captures => [{ :name => :cached_duration, :type => :duration, :unit => :msec },
142
+ { :name => :cached_sql, :type => :sql }])
143
+ }
144
+
145
+ # Definitions of common combinations of lines that can be parsed
146
+ LINE_COLLECTIONS = {
147
+ :minimal => [:processing, :completed],
148
+ :production => [:processing, :completed, :failure, :cache_hit],
149
+ :development => [:processing, :completed, :failure, :rendered, :query_executed, :query_cached],
150
+ :all => LINE_DEFINITIONS.keys
151
+ }
152
+
153
+
154
+ # Simple function to categorize Rails requests using controller/actions/format and method.
65
155
  REQUEST_CATEGORIZER = Proc.new do |request|
66
156
  "#{request[:controller]}##{request[:action]}.#{request[:format]} [#{request[:method]}]"
67
157
  end
68
158
 
69
- report do |analyze|
70
- analyze.timespan
71
- analyze.hourly_spread
72
-
73
- analyze.frequency :category => REQUEST_CATEGORIZER, :title => 'Top 20 hits', :amount => 20
74
- analyze.frequency :method, :title => 'HTTP methods'
75
- analyze.frequency :status, :title => 'HTTP statuses returned'
76
- analyze.frequency :category => lambda { |request| request =~ :cache_hit ? 'Cache hit' : 'No hit' }, :title => 'Rails action cache hits'
77
-
78
- analyze.duration :duration, :category => REQUEST_CATEGORIZER, :title => "Request duration", :line_type => :completed
79
- analyze.duration :view, :category => REQUEST_CATEGORIZER, :title => "View rendering time", :line_type => :completed
80
- analyze.duration :db, :category => REQUEST_CATEGORIZER, :title => "Database time", :line_type => :completed
81
-
82
- analyze.frequency :category => REQUEST_CATEGORIZER, :title => 'Process blockers (> 1 sec duration)',
83
- :if => lambda { |request| request[:duration] && request[:duration] > 1.0 }, :amount => 20
84
-
85
- analyze.frequency :error, :title => 'Failed requests', :line_type => :failed, :amount => 20
86
- end
87
-
88
159
  # Define a custom Request class for the Rails file format to speed up timestamp handling
89
160
  # and to ensure that a format is always set.
90
161
  class Request < RequestLogAnalyzer::Request
91
-
162
+
92
163
  # Do not use DateTime.parse
93
164
  def convert_timestamp(value, definition)
94
165
  value.gsub(/[^0-9]/, '')[0...14].to_i
95
166
  end
167
+
168
+ # Sanitizes SQL queries so that they can be grouped
169
+ def convert_sql(sql, definition)
170
+ sql.gsub(/\b\d+\b/, ':int').gsub(/`([^`]+)`/, '\1').gsub(/'[^']*'/, ':string').rstrip
171
+ end
96
172
  end
97
173
 
98
174
  end
@@ -1,57 +1,12 @@
1
1
  module RequestLogAnalyzer::FileFormat
2
-
2
+
3
3
  # The RailsDevelopment FileFormat is an extention to the default Rails file format. It includes
4
4
  # all lines of the normal Rails file format, but parses SQL queries and partial rendering lines
5
5
  # as well.
6
6
  class RailsDevelopment < Rails
7
-
8
- # Parameters: {"action"=>"demo", "controller"=>"page"}
9
- line_definition :parameters do |line|
10
- line.teaser = /Parameters/
11
- line.regexp = /\s+Parameters:\s+(\{.*\})/
12
- line.captures << { :name => :params, :type => :eval }
13
- end
14
-
15
- # Rendered layouts/_footer (2.9ms)
16
- line_definition :rendered do |line|
17
- line.regexp = /Rendered (\w+(?:\/\w+)+) \((\d+\.\d+)ms\)/
18
- line.captures << { :name => :render_file, :type => :string } \
19
- << { :name => :render_duration, :type => :duration, :unit => :msec }
20
- end
21
-
22
- # User Load (0.4ms) SELECT * FROM `users` WHERE (`users`.`id` = 18205844) 
23
- line_definition :query_executed do |line|
24
- line.regexp = /\s+(?:\e\[4;36;1m)?((?:\w+::)*\w+) Load \((\d+\.\d+)ms\)(?:\e\[0m)?\s+(?:\e\[0;1m)?([^\e]+) ?(?:\e\[0m)?/
25
- line.captures << { :name => :query_class, :type => :string } \
26
- << { :name => :query_duration, :type => :duration, :unit => :msec } \
27
- << { :name => :query_sql, :type => :sql }
28
- end
29
-
30
- # CACHE (0.0ms) SELECT * FROM `users` WHERE (`users`.`id` = 0) 
31
- line_definition :query_cached do |line|
32
- line.regexp = /\s+(?:\e\[4;35;1m)?CACHE \((\d+\.\d+)ms\)(?:\e\[0m)?\s+(?:\e\[0m)?([^\e]+) ?(?:\e\[0m)?/
33
- line.captures << { :name => :cached_duration, :type => :duration, :unit => :msec } \
34
- << { :name => :cached_sql, :type => :sql }
35
- end
36
-
37
- # Define the reporting for the additional parsed lines
38
- report(:append) do |analyze|
39
-
40
- analyze.duration :render_duration, :category => :render_file, :multiple_per_request => true,
41
- :amount => 20, :title => 'Partial rendering duration'
42
-
43
- analyze.duration :query_duration, :category => :query_sql, :multiple_per_request => true,
44
- :amount => 20, :title => 'Query duration'
45
-
46
- end
47
-
48
- # Add a converter method for the SQL fields the the Rails request class
49
- class Request < Rails::Request
50
-
51
- # Sanitizes SQL queries so that they can be grouped
52
- def convert_sql(sql, definition)
53
- sql.gsub(/\b\d+\b/, ':int').gsub(/`([^`]+)`/, '\1').gsub(/'[^']*'/, ':string').rstrip
54
- end
7
+ def self.create
8
+ puts 'DEPRECATED: use --rails-format development instead!'
9
+ super('development')
55
10
  end
56
11
  end
57
12
  end
@@ -1,17 +1,17 @@
1
1
  module RequestLogAnalyzer::Filter
2
-
2
+
3
3
  # Filter class loader using const_missing
4
4
  # This function will automatically load the class file based on the name of the class
5
5
  def self.const_missing(const)
6
6
  RequestLogAnalyzer::load_default_class_file(self, const)
7
7
  end
8
-
8
+
9
9
  # Base filter class used to filter input requests.
10
10
  # All filters should interit from this base.
11
11
  class Base
12
-
12
+
13
13
  attr_reader :file_format, :options
14
-
14
+
15
15
  # Initializer
16
16
  # <tt>format</tt> The file format
17
17
  # <tt>options</tt> Are passed to the filters.
@@ -19,12 +19,12 @@ module RequestLogAnalyzer::Filter
19
19
  @file_format = format
20
20
  @options = options
21
21
  end
22
-
22
+
23
23
  # Return the request if the request should be kept.
24
24
  # Return nil otherwise.
25
25
  def filter(request)
26
26
  request
27
27
  end
28
28
  end
29
-
29
+
30
30
  end
@@ -1,12 +1,12 @@
1
1
  module RequestLogAnalyzer::Filter
2
-
2
+
3
3
  # Filter to anonymize parsed values
4
4
  # Options
5
5
  # * <tt>:mode</tt> :reject or :accept.
6
6
  # * <tt>:field</tt> Specific field to accept or reject.
7
7
  # * <tt>:value</tt> Value that the field should match to be accepted or rejected.
8
8
  class Anonymize < Base
9
-
9
+
10
10
  def generate_random_ip
11
11
  "#{rand(256)}.#{rand(256)}.#{rand(256)}.#{rand(256)}"
12
12
  end
@@ -14,7 +14,7 @@ module RequestLogAnalyzer::Filter
14
14
  def anonymize_url(value)
15
15
  return value.sub(/^https?\:\/\/[A-Za-z0-9\.-]+\//, "http://example.com/")
16
16
  end
17
-
17
+
18
18
  def fuzz(value)
19
19
  value * ((75 + rand(50)) / 100.0)
20
20
  end
@@ -31,9 +31,9 @@ module RequestLogAnalyzer::Filter
31
31
  request.attributes[key] = fuzz(value)
32
32
  end
33
33
  end
34
-
34
+
35
35
  return request
36
- end
36
+ end
37
37
  end
38
-
38
+
39
39
  end