request-log-analyzer 1.9.10 → 1.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. data/.gitignore +4 -1
  2. data/.infinity_test +8 -0
  3. data/Gemfile +2 -0
  4. data/bin/request-log-analyzer +0 -1
  5. data/lib/request_log_analyzer/aggregator/database_inserter.rb +2 -1
  6. data/lib/request_log_analyzer/aggregator.rb +5 -5
  7. data/lib/request_log_analyzer/controller.rb +0 -3
  8. data/lib/request_log_analyzer/database.rb +6 -7
  9. data/lib/request_log_analyzer/file_format/apache.rb +19 -28
  10. data/lib/request_log_analyzer/file_format/delayed_job2.rb +2 -2
  11. data/lib/request_log_analyzer/file_format/delayed_job21.rb +2 -2
  12. data/lib/request_log_analyzer/file_format/haproxy.rb +232 -0
  13. data/lib/request_log_analyzer/file_format/mysql.rb +5 -5
  14. data/lib/request_log_analyzer/file_format/rails3.rb +9 -2
  15. data/lib/request_log_analyzer/file_format/w3c.rb +56 -0
  16. data/lib/request_log_analyzer/file_format.rb +46 -15
  17. data/lib/request_log_analyzer/filter.rb +4 -5
  18. data/lib/request_log_analyzer/line_definition.rb +6 -4
  19. data/lib/request_log_analyzer/output.rb +3 -5
  20. data/lib/request_log_analyzer/request.rb +7 -0
  21. data/lib/request_log_analyzer/source/log_parser.rb +56 -4
  22. data/lib/request_log_analyzer/source.rb +3 -4
  23. data/lib/request_log_analyzer/tracker.rb +8 -8
  24. data/lib/request_log_analyzer.rb +15 -29
  25. data/request-log-analyzer.gemspec +4 -4
  26. data/spec/fixtures/mysql_slow_query.log +0 -1
  27. data/spec/integration/command_line_usage_spec.rb +0 -5
  28. data/spec/lib/helpers.rb +2 -2
  29. data/spec/lib/matchers.rb +38 -7
  30. data/spec/lib/mocks.rb +1 -5
  31. data/spec/spec_helper.rb +3 -2
  32. data/spec/unit/database/base_class_spec.rb +1 -0
  33. data/spec/unit/file_format/amazon_s3_format_spec.rb +58 -55
  34. data/spec/unit/file_format/apache_format_spec.rb +90 -161
  35. data/spec/unit/file_format/common_regular_expressions_spec.rb +51 -26
  36. data/spec/unit/file_format/delayed_job21_format_spec.rb +22 -31
  37. data/spec/unit/file_format/delayed_job2_format_spec.rb +27 -32
  38. data/spec/unit/file_format/delayed_job_format_spec.rb +44 -63
  39. data/spec/unit/file_format/haproxy_format_spec.rb +82 -0
  40. data/spec/unit/file_format/line_definition_spec.rb +26 -33
  41. data/spec/unit/file_format/merb_format_spec.rb +22 -37
  42. data/spec/unit/file_format/mysql_format_spec.rb +80 -123
  43. data/spec/unit/file_format/oink_format_spec.rb +29 -61
  44. data/spec/unit/file_format/postgresql_format_spec.rb +10 -21
  45. data/spec/unit/file_format/rack_format_spec.rb +49 -44
  46. data/spec/unit/file_format/rails3_format_spec.rb +46 -38
  47. data/spec/unit/file_format/rails_format_spec.rb +52 -68
  48. data/spec/unit/file_format/w3c_format_spec.rb +47 -0
  49. data/spec/unit/source/log_parser_spec.rb +1 -1
  50. metadata +12 -7
  51. data/lib/mixins/gets_memory_protection.rb +0 -80
  52. data/lib/request_log_analyzer/output/fancy_html.rb +0 -44
  53. data/lib/request_log_analyzer/source/database_loader.rb +0 -87
@@ -13,6 +13,8 @@ module RequestLogAnalyzer::FileFormat
13
13
  autoload :DelayedJob21, 'request_log_analyzer/file_format/delayed_job21'
14
14
  autoload :Apache, 'request_log_analyzer/file_format/apache'
15
15
  autoload :AmazonS3, 'request_log_analyzer/file_format/amazon_s3'
16
+ autoload :W3c, 'request_log_analyzer/file_format/w3c'
17
+ autoload :Haproxy, 'request_log_analyzer/file_format/haproxy'
16
18
 
17
19
  # Loads a FileFormat::Base subclass instance.
18
20
  # You can provide:
@@ -32,7 +34,7 @@ module RequestLogAnalyzer::FileFormat
32
34
 
33
35
  elsif file_format.kind_of?(String) && File.exist?(file_format) && File.file?(file_format)
34
36
  # load a format from a ruby file
35
- require file_format
37
+ require File.expand_path(file_format)
36
38
 
37
39
  const = RequestLogAnalyzer.to_camelcase(File.basename(file_format, '.rb'))
38
40
  if RequestLogAnalyzer::FileFormat.const_defined?(const)
@@ -119,6 +121,18 @@ module RequestLogAnalyzer::FileFormat
119
121
  'Z' => '(?:[+-]\d{4}|[A-Z]{3,4})',
120
122
  '%' => '%'
121
123
  }
124
+
125
+ # Creates a regular expression to match a hostname
126
+ def hostname(blank = false)
127
+ regexp = /(?:(?:[a-zA-Z]|[a-zA-Z][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*(?:[A-Za-z]|[A-Za-z][A-Za-z0-9\-]*[A-Za-z0-9])/
128
+ add_blank_option(regexp, blank)
129
+ end
130
+
131
+ # Creates a regular expression to match a hostname or ip address
132
+ def hostname_or_ip_address(blank = false)
133
+ regexp = Regexp.union(hostname, ip_address)
134
+ add_blank_option(regexp, blank)
135
+ end
122
136
 
123
137
  # Create a regular expression for a timestamp, generated by a strftime call.
124
138
  # Provide the format string to construct a matching regular expression.
@@ -137,12 +151,7 @@ module RequestLogAnalyzer::FileFormat
137
151
  end
138
152
  end
139
153
 
140
- regexp = Regexp.new(regexp)
141
- return case blank
142
- when String then Regexp.union(regexp, Regexp.new(Regexp.quote(blank)))
143
- when true then Regexp.union(regexp, //)
144
- else regexp
145
- end
154
+ add_blank_option(Regexp.new(regexp), blank)
146
155
  end
147
156
 
148
157
  # Construct a regular expression to parse IPv4 and IPv6 addresses.
@@ -160,12 +169,22 @@ module RequestLogAnalyzer::FileFormat
160
169
  ipv6_regex_compressed_hex_4_dec = /(?:(?:[0-9A-Fa-f]{1,4}(?::[0-9A-Fa-f]{1,4})*)?)::(?:(?:[0-9A-Fa-f]{1,4}:)*)#{ipv4_regexp}/
161
170
  ipv6_regexp = Regexp.union(ipv6_regex_8_hex, ipv6_regex_compressed_hex, ipv6_regex_6_hex_4_dec, ipv6_regex_compressed_hex_4_dec)
162
171
 
163
- # Allow the field to be blank if this option is given. This can be true to
164
- # allow an empty string or a string alternative for the nil value.
165
- ip_regexp = case blank
166
- when String then Regexp.union(ipv4_regexp, ipv6_regexp, Regexp.new(Regexp.quote(blank)))
167
- when true then Regexp.union(ipv4_regexp, ipv6_regexp, //)
168
- else Regexp.union(ipv4_regexp, ipv6_regexp)
172
+ add_blank_option(Regexp.union(ipv4_regexp, ipv6_regexp), blank)
173
+ end
174
+
175
+ def anchored(regexp)
176
+ /^#{regexp}$/
177
+ end
178
+
179
+ protected
180
+
181
+ # Allow the field to be blank if this option is given. This can be true to
182
+ # allow an empty string or a string alternative for the nil value.
183
+ def add_blank_option(regexp, blank)
184
+ case blank
185
+ when String; Regexp.union(regexp, Regexp.new(Regexp.quote(blank)))
186
+ when true; Regexp.union(regexp, //)
187
+ else regexp
169
188
  end
170
189
  end
171
190
  end
@@ -258,9 +277,12 @@ module RequestLogAnalyzer::FileFormat
258
277
  end
259
278
 
260
279
  # Checks whether the file format is valid so it can be safely used with RLA.
261
- def valid?
280
+ def well_formed?
262
281
  valid_line_definitions? && valid_request_class?
263
282
  end
283
+
284
+ alias_method :valid?, :well_formed?
285
+
264
286
 
265
287
  # Checks whether the line definitions form a valid language.
266
288
  # A file format should have at least a header and a footer line type
@@ -292,5 +314,14 @@ module RequestLogAnalyzer::FileFormat
292
314
 
293
315
  return nil
294
316
  end
317
+
318
+ # Returns the max line length for this file format if any.
319
+ def max_line_length
320
+ self.class.const_get(MAX_LINE_LENGTH) if self.class.const_defined?(:MAX_LINE_LENGTH)
321
+ end
322
+
323
+ def line_divider
324
+ self.class.const_get(LINE_DIVIDER) if self.class.const_defined?(:LINE_DIVIDER)
325
+ end
295
326
  end
296
- end
327
+ end
@@ -1,9 +1,5 @@
1
1
  module RequestLogAnalyzer::Filter
2
2
 
3
- autoload :Field, 'request_log_analyzer/filter/field'
4
- autoload :Timespan, 'request_log_analyzer/filter/timespan'
5
- autoload :Anonymize, 'request_log_analyzer/filter/anonymize'
6
-
7
3
  # Base filter class used to filter input requests.
8
4
  # All filters should interit from this base.
9
5
  class Base
@@ -24,5 +20,8 @@ module RequestLogAnalyzer::Filter
24
20
  request
25
21
  end
26
22
  end
23
+ end
27
24
 
28
- end
25
+ require 'request_log_analyzer/filter/field'
26
+ require 'request_log_analyzer/filter/timespan'
27
+ require 'request_log_analyzer/filter/anonymize'
@@ -70,6 +70,10 @@ module RequestLogAnalyzer
70
70
  captures << new_capture_hash
71
71
  CaptureDefiner.new(new_capture_hash)
72
72
  end
73
+
74
+ def all_captured_variables
75
+ captures.map { |c| c[:name] } + captures.map { |c| c[:provides] }.compact.map { |pr| pr.keys }.flatten
76
+ end
73
77
 
74
78
  # Checks whether a given line matches this definition.
75
79
  # It will return false if a line does not match. If the line matches, a hash is returned
@@ -128,9 +132,7 @@ module RequestLogAnalyzer
128
132
 
129
133
  # Returns true if this line captures values of the given name
130
134
  def captures?(name)
131
- captures.any? { |c| c[:name] == name }
135
+ all_captured_variables.include?(name)
132
136
  end
133
-
134
137
  end
135
-
136
- end
138
+ end
@@ -1,10 +1,6 @@
1
1
  # Module for generating output
2
2
  module RequestLogAnalyzer::Output
3
3
 
4
- autoload :FixedWidth, 'request_log_analyzer/output/fixed_width'
5
- autoload :HTML, 'request_log_analyzer/output/html'
6
- autoload :FancyHTML, 'request_log_analyzer/output/fancy_html'
7
-
8
4
  # Loads a Output::Base subclass instance.
9
5
  def self.load(file_format, *args)
10
6
 
@@ -111,6 +107,8 @@ module RequestLogAnalyzer::Output
111
107
  def table_has_header?(columns)
112
108
  columns.any? { |column| !column[:title].nil? }
113
109
  end
114
-
115
110
  end
116
111
  end
112
+
113
+ require 'request_log_analyzer/output/fixed_width'
114
+ require 'request_log_analyzer/output/html'
@@ -27,6 +27,13 @@ module RequestLogAnalyzer
27
27
  def convert_integer(value, capture_definition); value.to_i; end
28
28
  def convert_sym(value, capture_definition); value.to_sym; end
29
29
  def convert_symbol(value, capture_definition); value.to_sym; end
30
+ def convert_nillable_string(value, definition); value == '-' ? nil : value ; end
31
+
32
+ # This function can be overridden to rewrite the path for better categorization in the
33
+ # reports.
34
+ def convert_path(value, definition)
35
+ value
36
+ end
30
37
 
31
38
  # Converts :eval field, which should evaluate to a hash.
32
39
  def convert_eval(value, capture_definition)
@@ -13,6 +13,11 @@ module RequestLogAnalyzer::Source
13
13
 
14
14
  include Enumerable
15
15
 
16
+ # The maximum number of bytes to read from a line.
17
+ DEFAULT_MAX_LINE_LENGTH = 8096
18
+
19
+ DEFAULT_LINE_DIVIDER = "\n"
20
+
16
21
  # The default parse strategy that will be used to parse the input.
17
22
  DEFAULT_PARSE_STRATEGY = 'assume-correct'
18
23
 
@@ -48,6 +53,14 @@ module RequestLogAnalyzer::Source
48
53
  end
49
54
  end
50
55
 
56
+ def max_line_length
57
+ file_format.max_line_length || DEFAULT_MAX_LINE_LENGTH
58
+ end
59
+
60
+ def line_divider
61
+ file_format.line_divider || DEFAULT_LINE_DIVIDER
62
+ end
63
+
51
64
  # Reads the input, which can either be a file, sequence of files or STDIN to parse
52
65
  # lines specified in the FileFormat. This lines will be combined into Request instances,
53
66
  # that will be yielded. The actual parsing occurs in the parse_io method.
@@ -132,6 +145,13 @@ module RequestLogAnalyzer::Source
132
145
  def parse_stream(stream, options = {}, &block)
133
146
  parse_io(stream, options, &block)
134
147
  end
148
+
149
+ # Parses a string. It will simply call parse_io. This function does not support progress updates.
150
+ # <tt>string</tt>:: The string that should be parsed.
151
+ # <tt>options</tt>:: A Hash of options that will be pased to parse_io.
152
+ def parse_string(string, options = {}, &block)
153
+ parse_io(StringIO.new(string), options, &block)
154
+ end
135
155
 
136
156
  # This method loops over each line of the input stream. It will try to parse this line as any of
137
157
  # the lines that are defined by the current file format (see RequestLogAnalyazer::FileFormat).
@@ -143,11 +163,15 @@ module RequestLogAnalyzer::Source
143
163
  # - The method will yield progress updates if a progress handler is installed using progress=
144
164
  # - The method will yield parse warnings if a warning handler is installed using warning=
145
165
  #
166
+ # This is a Ruby 1.9 specific version that offers memory protection.
167
+ #
146
168
  # <tt>io</tt>:: The IO instance to use as source
147
169
  # <tt>options</tt>:: A hash of options that can be used by the parser.
148
- def parse_io(io, options = {}, &block) # :yields: request
149
- @current_lineno = 0
150
- while line = io.gets
170
+ def parse_io_19(io, options = {}, &block) # :yields: request
171
+ @max_line_length = options[:max_line_length] || max_line_length
172
+ @line_divider = options[:line_divider] || line_divider
173
+ @current_lineno = 0
174
+ while line = io.gets(@line_divider, @max_line_length)
151
175
  @current_lineno += 1
152
176
  @progress_handler.call(:progress, io.pos) if @progress_handler && @current_lineno % 255 == 0
153
177
  parse_line(line, &block)
@@ -157,6 +181,35 @@ module RequestLogAnalyzer::Source
157
181
  @current_lineno = nil
158
182
  end
159
183
 
184
+ # This method loops over each line of the input stream. It will try to parse this line as any of
185
+ # the lines that are defined by the current file format (see RequestLogAnalyazer::FileFormat).
186
+ # It will then combine these parsed line into requests using heuristics. These requests (see
187
+ # RequestLogAnalyzer::Request) will then be yielded for further processing in the pipeline.
188
+ #
189
+ # - RequestLogAnalyzer::LineDefinition#matches is called to test if a line matches a line definition of the file format.
190
+ # - update_current_request is used to combine parsed lines into requests using heuristics.
191
+ # - The method will yield progress updates if a progress handler is installed using progress=
192
+ # - The method will yield parse warnings if a warning handler is installed using warning=
193
+ #
194
+ # This is a Ruby 1.8 specific version that doesn't offer memory protection.
195
+ #
196
+ # <tt>io</tt>:: The IO instance to use as source
197
+ # <tt>options</tt>:: A hash of options that can be used by the parser.
198
+ def parse_io_18(io, options = {}, &block) # :yields: request
199
+ @line_divider = options[:line_divider] || line_divider
200
+ @current_lineno = 0
201
+ while line = io.gets(@line_divider)
202
+ @current_lineno += 1
203
+ @progress_handler.call(:progress, io.pos) if @progress_handler && @current_lineno % 255 == 0
204
+ parse_line(line, &block)
205
+ end
206
+
207
+ warn(:unfinished_request_on_eof, "End of file reached, but last request was not completed!") unless @current_request.nil?
208
+ @current_lineno = nil
209
+ end
210
+
211
+ alias_method :parse_io, RUBY_VERSION.to_f < 1.9 ? :parse_io_18 : :parse_io_19
212
+
160
213
  # Parses a single line using the current file format. If successful, use the parsed
161
214
  # information to build a request
162
215
  # <tt>line</tt>:: The line to parse
@@ -295,5 +348,4 @@ module RequestLogAnalyzer::Source
295
348
  hash[:line_definition].footer
296
349
  end
297
350
  end
298
-
299
351
  end
@@ -8,9 +8,6 @@
8
8
  # - Currently, RequestLogAnalyzer::Source::LogParser is the only implemented source.
9
9
  module RequestLogAnalyzer::Source
10
10
 
11
- autoload :LogParser, 'request_log_analyzer/source/log_parser'
12
- autoload :DatabaseLoader, 'request_log_analyzer/source/database_loader'
13
-
14
11
  # The base Source class. All other sources should inherit from this class.
15
12
  #
16
13
  # A source implememtation should at least implement the each_request method, which should yield
@@ -65,4 +62,6 @@ module RequestLogAnalyzer::Source
65
62
  end
66
63
 
67
64
  end
68
- end
65
+ end
66
+
67
+ require 'request_log_analyzer/source/log_parser'
@@ -1,12 +1,5 @@
1
1
  module RequestLogAnalyzer::Tracker
2
2
 
3
- autoload :Duration, 'request_log_analyzer/tracker/duration'
4
- autoload :Frequency, 'request_log_analyzer/tracker/frequency'
5
- autoload :HourlySpread, 'request_log_analyzer/tracker/hourly_spread'
6
- autoload :NumericValue, 'request_log_analyzer/tracker/numeric_value'
7
- autoload :Timespan, 'request_log_analyzer/tracker/timespan'
8
- autoload :Traffic, 'request_log_analyzer/tracker/traffic'
9
-
10
3
  # Base Tracker class. All other trackers inherit from this class
11
4
  #
12
5
  # Accepts the following options:
@@ -99,4 +92,11 @@ module RequestLogAnalyzer::Tracker
99
92
  nil
100
93
  end
101
94
  end
102
- end
95
+ end
96
+
97
+ require 'request_log_analyzer/tracker/numeric_value'
98
+ require 'request_log_analyzer/tracker/duration'
99
+ require 'request_log_analyzer/tracker/frequency'
100
+ require 'request_log_analyzer/tracker/hourly_spread'
101
+ require 'request_log_analyzer/tracker/timespan'
102
+ require 'request_log_analyzer/tracker/traffic'
@@ -10,36 +10,10 @@ Encoding.default_external = 'binary' if defined? Encoding and Encoding.respond_t
10
10
  # The {RequestLogAnalyzer::VERSION} constant can be used to determine what version of request-log-analyzer
11
11
  # is running.
12
12
  module RequestLogAnalyzer
13
-
13
+
14
14
  # The current version of request-log-analyzer.
15
15
  # Do not change the value by hand; it will be updated automatically by the gem release script.
16
- VERSION = "1.9.10"
17
-
18
-
19
- autoload :Controller, 'request_log_analyzer/controller'
20
- autoload :Aggregator, 'request_log_analyzer/aggregator'
21
- autoload :Database, 'request_log_analyzer/database'
22
- autoload :FileFormat, 'request_log_analyzer/file_format'
23
- autoload :Filter, 'request_log_analyzer/filter'
24
- autoload :LineDefinition, 'request_log_analyzer/line_definition'
25
- autoload :LogProcessor, 'request_log_analyzer/log_processor'
26
- autoload :Mailer, 'request_log_analyzer/mailer'
27
- autoload :Output, 'request_log_analyzer/output'
28
- autoload :Request, 'request_log_analyzer/request'
29
- autoload :Source, 'request_log_analyzer/source'
30
- autoload :Tracker, 'request_log_analyzer/tracker'
31
-
32
- # Loads constants that reside in the RequestLogAnalyzer tree using the constant name and its base
33
- # constant to determine the filename.
34
- # @param [Module] base The base constant to load the constant from. This should be <tt>Foo</tt> when
35
- # the constant <tt>Foo::Bar</tt> is being loaded.
36
- # @param [Symbol] const The constant to load from the base constant as a string or symbol. This
37
- # should be <tt>"Bar"<tt> or <tt>:Bar</tt> when the constant <tt>Foo::Bar</tt> is being loaded.
38
- # @return [Module] The loaded module, nil if it was not found on the expected location.
39
- def self.load_default_class_file(base, const)
40
- require "#{to_underscore("#{base.name}::#{const}")}"
41
- base.const_get(const) if base.const_defined?(const)
42
- end
16
+ VERSION = "1.11.0"
43
17
 
44
18
  # Convert a string/symbol in camelcase ({RequestLogAnalyzer::Controller}) to underscores
45
19
  # (<tt>request_log_analyzer/controller</tt>). This function can be used to load the file (using
@@ -55,9 +29,21 @@ module RequestLogAnalyzer
55
29
  # ({RequestLogAnalyzer::Controller}). This can be used to find the class that is defined in a given
56
30
  # filename.
57
31
  #
58
- # @param [#to_s] str The string-like to convert in the following format: <tt>module_name/class_name</tt>.
32
+ # @param [#to_s] str The string-like to convert in the f`ollowing format: <tt>module_name/class_name</tt>.
59
33
  # @return [String] The input string converted to camelcase form.
60
34
  def self.to_camelcase(str)
61
35
  str.to_s.gsub(/\/(.?)/) { "::" + $1.upcase }.gsub(/(^|_)(.)/) { $2.upcase }
62
36
  end
63
37
  end
38
+
39
+ require 'request_log_analyzer/controller'
40
+ require 'request_log_analyzer/aggregator'
41
+ require 'request_log_analyzer/file_format'
42
+ require 'request_log_analyzer/filter'
43
+ require 'request_log_analyzer/line_definition'
44
+ require 'request_log_analyzer/log_processor'
45
+ require 'request_log_analyzer/mailer'
46
+ require 'request_log_analyzer/output'
47
+ require 'request_log_analyzer/request'
48
+ require 'request_log_analyzer/source'
49
+ require 'request_log_analyzer/tracker'
@@ -2,8 +2,8 @@ Gem::Specification.new do |s|
2
2
  s.name = "request-log-analyzer"
3
3
 
4
4
  # Do not set the version and date field manually, this is done by the release script
5
- s.version = "1.9.10"
6
- s.date = "2011-01-03"
5
+ s.version = "1.11.0"
6
+ s.date = "2011-04-27"
7
7
 
8
8
  s.rubyforge_project = 'r-l-a'
9
9
 
@@ -39,6 +39,6 @@ Gem::Specification.new do |s|
39
39
 
40
40
  # The files and test_files directives are set automatically by the release script.
41
41
  # Do not change them by hand, but make sure to add the files to the git repository.
42
- s.files = %w(.gitignore DESIGN.rdoc LICENSE README.rdoc Rakefile bin/request-log-analyzer lib/cli/command_line_arguments.rb lib/cli/database_console.rb lib/cli/database_console_init.rb lib/cli/progressbar.rb lib/cli/tools.rb lib/mixins/gets_memory_protection.rb lib/request_log_analyzer.rb lib/request_log_analyzer/aggregator.rb lib/request_log_analyzer/aggregator/database_inserter.rb lib/request_log_analyzer/aggregator/echo.rb lib/request_log_analyzer/aggregator/summarizer.rb lib/request_log_analyzer/controller.rb lib/request_log_analyzer/database.rb lib/request_log_analyzer/database/base.rb lib/request_log_analyzer/database/connection.rb lib/request_log_analyzer/database/request.rb lib/request_log_analyzer/database/source.rb lib/request_log_analyzer/database/warning.rb lib/request_log_analyzer/file_format.rb lib/request_log_analyzer/file_format/amazon_s3.rb lib/request_log_analyzer/file_format/apache.rb lib/request_log_analyzer/file_format/delayed_job.rb lib/request_log_analyzer/file_format/delayed_job2.rb lib/request_log_analyzer/file_format/delayed_job21.rb lib/request_log_analyzer/file_format/merb.rb lib/request_log_analyzer/file_format/mysql.rb lib/request_log_analyzer/file_format/oink.rb lib/request_log_analyzer/file_format/postgresql.rb lib/request_log_analyzer/file_format/rack.rb lib/request_log_analyzer/file_format/rails.rb lib/request_log_analyzer/file_format/rails3.rb lib/request_log_analyzer/file_format/rails_development.rb lib/request_log_analyzer/filter.rb lib/request_log_analyzer/filter/anonymize.rb lib/request_log_analyzer/filter/field.rb lib/request_log_analyzer/filter/timespan.rb lib/request_log_analyzer/line_definition.rb lib/request_log_analyzer/log_processor.rb lib/request_log_analyzer/mailer.rb lib/request_log_analyzer/output.rb lib/request_log_analyzer/output/fancy_html.rb lib/request_log_analyzer/output/fixed_width.rb lib/request_log_analyzer/output/html.rb lib/request_log_analyzer/request.rb lib/request_log_analyzer/source.rb lib/request_log_analyzer/source/database_loader.rb lib/request_log_analyzer/source/log_parser.rb lib/request_log_analyzer/tracker.rb lib/request_log_analyzer/tracker/duration.rb lib/request_log_analyzer/tracker/frequency.rb lib/request_log_analyzer/tracker/hourly_spread.rb lib/request_log_analyzer/tracker/numeric_value.rb lib/request_log_analyzer/tracker/timespan.rb lib/request_log_analyzer/tracker/traffic.rb request-log-analyzer.gemspec spec/database.yml spec/fixtures/apache_combined.log spec/fixtures/apache_common.log spec/fixtures/decompression.log spec/fixtures/decompression.log.bz2 spec/fixtures/decompression.log.gz spec/fixtures/decompression.log.zip spec/fixtures/decompression.tar.gz spec/fixtures/decompression.tgz spec/fixtures/header_and_footer.log spec/fixtures/merb.log spec/fixtures/merb_prefixed.log spec/fixtures/multiple_files_1.log spec/fixtures/multiple_files_2.log spec/fixtures/mysql_slow_query.log spec/fixtures/oink_22.log spec/fixtures/oink_22_failure.log spec/fixtures/postgresql.log spec/fixtures/rails.db spec/fixtures/rails_1x.log spec/fixtures/rails_22.log spec/fixtures/rails_22_cached.log spec/fixtures/rails_unordered.log spec/fixtures/sinatra.log spec/fixtures/syslog_1x.log spec/fixtures/test_file_format.log spec/fixtures/test_language_combined.log spec/fixtures/test_order.log spec/integration/command_line_usage_spec.rb spec/integration/mailer_spec.rb spec/integration/munin_plugins_rails_spec.rb spec/integration/scout_spec.rb spec/lib/helpers.rb spec/lib/macros.rb spec/lib/matchers.rb spec/lib/mocks.rb spec/lib/testing_format.rb spec/spec_helper.rb spec/unit/aggregator/database_inserter_spec.rb spec/unit/aggregator/summarizer_spec.rb spec/unit/controller/controller_spec.rb spec/unit/controller/log_processor_spec.rb spec/unit/database/base_class_spec.rb spec/unit/database/connection_spec.rb spec/unit/database/database_spec.rb spec/unit/file_format/amazon_s3_format_spec.rb spec/unit/file_format/apache_format_spec.rb spec/unit/file_format/common_regular_expressions_spec.rb spec/unit/file_format/delayed_job21_format_spec.rb spec/unit/file_format/delayed_job2_format_spec.rb spec/unit/file_format/delayed_job_format_spec.rb spec/unit/file_format/file_format_api_spec.rb spec/unit/file_format/format_autodetection_spec.rb spec/unit/file_format/line_definition_spec.rb spec/unit/file_format/merb_format_spec.rb spec/unit/file_format/mysql_format_spec.rb spec/unit/file_format/oink_format_spec.rb spec/unit/file_format/postgresql_format_spec.rb spec/unit/file_format/rack_format_spec.rb spec/unit/file_format/rails3_format_spec.rb spec/unit/file_format/rails_format_spec.rb spec/unit/filter/anonymize_filter_spec.rb spec/unit/filter/field_filter_spec.rb spec/unit/filter/filter_spec.rb spec/unit/filter/timespan_filter_spec.rb spec/unit/mailer_spec.rb spec/unit/request_spec.rb spec/unit/source/log_parser_spec.rb spec/unit/tracker/duration_tracker_spec.rb spec/unit/tracker/frequency_tracker_spec.rb spec/unit/tracker/hourly_spread_spec.rb spec/unit/tracker/numeric_value_tracker_spec.rb spec/unit/tracker/timespan_tracker_spec.rb spec/unit/tracker/tracker_api_spec.rb spec/unit/tracker/traffic_tracker_spec.rb tasks/github-gem.rake tasks/request_log_analyzer.rake)
43
- s.test_files = %w(spec/integration/command_line_usage_spec.rb spec/integration/mailer_spec.rb spec/integration/munin_plugins_rails_spec.rb spec/integration/scout_spec.rb spec/unit/aggregator/database_inserter_spec.rb spec/unit/aggregator/summarizer_spec.rb spec/unit/controller/controller_spec.rb spec/unit/controller/log_processor_spec.rb spec/unit/database/base_class_spec.rb spec/unit/database/connection_spec.rb spec/unit/database/database_spec.rb spec/unit/file_format/amazon_s3_format_spec.rb spec/unit/file_format/apache_format_spec.rb spec/unit/file_format/common_regular_expressions_spec.rb spec/unit/file_format/delayed_job21_format_spec.rb spec/unit/file_format/delayed_job2_format_spec.rb spec/unit/file_format/delayed_job_format_spec.rb spec/unit/file_format/file_format_api_spec.rb spec/unit/file_format/format_autodetection_spec.rb spec/unit/file_format/line_definition_spec.rb spec/unit/file_format/merb_format_spec.rb spec/unit/file_format/mysql_format_spec.rb spec/unit/file_format/oink_format_spec.rb spec/unit/file_format/postgresql_format_spec.rb spec/unit/file_format/rack_format_spec.rb spec/unit/file_format/rails3_format_spec.rb spec/unit/file_format/rails_format_spec.rb spec/unit/filter/anonymize_filter_spec.rb spec/unit/filter/field_filter_spec.rb spec/unit/filter/filter_spec.rb spec/unit/filter/timespan_filter_spec.rb spec/unit/mailer_spec.rb spec/unit/request_spec.rb spec/unit/source/log_parser_spec.rb spec/unit/tracker/duration_tracker_spec.rb spec/unit/tracker/frequency_tracker_spec.rb spec/unit/tracker/hourly_spread_spec.rb spec/unit/tracker/numeric_value_tracker_spec.rb spec/unit/tracker/timespan_tracker_spec.rb spec/unit/tracker/tracker_api_spec.rb spec/unit/tracker/traffic_tracker_spec.rb)
42
+ s.files = %w(.gitignore .infinity_test DESIGN.rdoc Gemfile LICENSE README.rdoc Rakefile bin/request-log-analyzer lib/cli/command_line_arguments.rb lib/cli/database_console.rb lib/cli/database_console_init.rb lib/cli/progressbar.rb lib/cli/tools.rb lib/request_log_analyzer.rb lib/request_log_analyzer/aggregator.rb lib/request_log_analyzer/aggregator/database_inserter.rb lib/request_log_analyzer/aggregator/echo.rb lib/request_log_analyzer/aggregator/summarizer.rb lib/request_log_analyzer/controller.rb lib/request_log_analyzer/database.rb lib/request_log_analyzer/database/base.rb lib/request_log_analyzer/database/connection.rb lib/request_log_analyzer/database/request.rb lib/request_log_analyzer/database/source.rb lib/request_log_analyzer/database/warning.rb lib/request_log_analyzer/file_format.rb lib/request_log_analyzer/file_format/amazon_s3.rb lib/request_log_analyzer/file_format/apache.rb lib/request_log_analyzer/file_format/delayed_job.rb lib/request_log_analyzer/file_format/delayed_job2.rb lib/request_log_analyzer/file_format/delayed_job21.rb lib/request_log_analyzer/file_format/haproxy.rb lib/request_log_analyzer/file_format/merb.rb lib/request_log_analyzer/file_format/mysql.rb lib/request_log_analyzer/file_format/oink.rb lib/request_log_analyzer/file_format/postgresql.rb lib/request_log_analyzer/file_format/rack.rb lib/request_log_analyzer/file_format/rails.rb lib/request_log_analyzer/file_format/rails3.rb lib/request_log_analyzer/file_format/rails_development.rb lib/request_log_analyzer/file_format/w3c.rb lib/request_log_analyzer/filter.rb lib/request_log_analyzer/filter/anonymize.rb lib/request_log_analyzer/filter/field.rb lib/request_log_analyzer/filter/timespan.rb lib/request_log_analyzer/line_definition.rb lib/request_log_analyzer/log_processor.rb lib/request_log_analyzer/mailer.rb lib/request_log_analyzer/output.rb lib/request_log_analyzer/output/fixed_width.rb lib/request_log_analyzer/output/html.rb lib/request_log_analyzer/request.rb lib/request_log_analyzer/source.rb lib/request_log_analyzer/source/log_parser.rb lib/request_log_analyzer/tracker.rb lib/request_log_analyzer/tracker/duration.rb lib/request_log_analyzer/tracker/frequency.rb lib/request_log_analyzer/tracker/hourly_spread.rb lib/request_log_analyzer/tracker/numeric_value.rb lib/request_log_analyzer/tracker/timespan.rb lib/request_log_analyzer/tracker/traffic.rb request-log-analyzer.gemspec spec/database.yml spec/fixtures/apache_combined.log spec/fixtures/apache_common.log spec/fixtures/decompression.log spec/fixtures/decompression.log.bz2 spec/fixtures/decompression.log.gz spec/fixtures/decompression.log.zip spec/fixtures/decompression.tar.gz spec/fixtures/decompression.tgz spec/fixtures/header_and_footer.log spec/fixtures/merb.log spec/fixtures/merb_prefixed.log spec/fixtures/multiple_files_1.log spec/fixtures/multiple_files_2.log spec/fixtures/mysql_slow_query.log spec/fixtures/oink_22.log spec/fixtures/oink_22_failure.log spec/fixtures/postgresql.log spec/fixtures/rails.db spec/fixtures/rails_1x.log spec/fixtures/rails_22.log spec/fixtures/rails_22_cached.log spec/fixtures/rails_unordered.log spec/fixtures/sinatra.log spec/fixtures/syslog_1x.log spec/fixtures/test_file_format.log spec/fixtures/test_language_combined.log spec/fixtures/test_order.log spec/integration/command_line_usage_spec.rb spec/integration/mailer_spec.rb spec/integration/munin_plugins_rails_spec.rb spec/integration/scout_spec.rb spec/lib/helpers.rb spec/lib/macros.rb spec/lib/matchers.rb spec/lib/mocks.rb spec/lib/testing_format.rb spec/spec_helper.rb spec/unit/aggregator/database_inserter_spec.rb spec/unit/aggregator/summarizer_spec.rb spec/unit/controller/controller_spec.rb spec/unit/controller/log_processor_spec.rb spec/unit/database/base_class_spec.rb spec/unit/database/connection_spec.rb spec/unit/database/database_spec.rb spec/unit/file_format/amazon_s3_format_spec.rb spec/unit/file_format/apache_format_spec.rb spec/unit/file_format/common_regular_expressions_spec.rb spec/unit/file_format/delayed_job21_format_spec.rb spec/unit/file_format/delayed_job2_format_spec.rb spec/unit/file_format/delayed_job_format_spec.rb spec/unit/file_format/file_format_api_spec.rb spec/unit/file_format/format_autodetection_spec.rb spec/unit/file_format/haproxy_format_spec.rb spec/unit/file_format/line_definition_spec.rb spec/unit/file_format/merb_format_spec.rb spec/unit/file_format/mysql_format_spec.rb spec/unit/file_format/oink_format_spec.rb spec/unit/file_format/postgresql_format_spec.rb spec/unit/file_format/rack_format_spec.rb spec/unit/file_format/rails3_format_spec.rb spec/unit/file_format/rails_format_spec.rb spec/unit/file_format/w3c_format_spec.rb spec/unit/filter/anonymize_filter_spec.rb spec/unit/filter/field_filter_spec.rb spec/unit/filter/filter_spec.rb spec/unit/filter/timespan_filter_spec.rb spec/unit/mailer_spec.rb spec/unit/request_spec.rb spec/unit/source/log_parser_spec.rb spec/unit/tracker/duration_tracker_spec.rb spec/unit/tracker/frequency_tracker_spec.rb spec/unit/tracker/hourly_spread_spec.rb spec/unit/tracker/numeric_value_tracker_spec.rb spec/unit/tracker/timespan_tracker_spec.rb spec/unit/tracker/tracker_api_spec.rb spec/unit/tracker/traffic_tracker_spec.rb tasks/github-gem.rake tasks/request_log_analyzer.rake)
43
+ s.test_files = %w(spec/integration/command_line_usage_spec.rb spec/integration/mailer_spec.rb spec/integration/munin_plugins_rails_spec.rb spec/integration/scout_spec.rb spec/unit/aggregator/database_inserter_spec.rb spec/unit/aggregator/summarizer_spec.rb spec/unit/controller/controller_spec.rb spec/unit/controller/log_processor_spec.rb spec/unit/database/base_class_spec.rb spec/unit/database/connection_spec.rb spec/unit/database/database_spec.rb spec/unit/file_format/amazon_s3_format_spec.rb spec/unit/file_format/apache_format_spec.rb spec/unit/file_format/common_regular_expressions_spec.rb spec/unit/file_format/delayed_job21_format_spec.rb spec/unit/file_format/delayed_job2_format_spec.rb spec/unit/file_format/delayed_job_format_spec.rb spec/unit/file_format/file_format_api_spec.rb spec/unit/file_format/format_autodetection_spec.rb spec/unit/file_format/haproxy_format_spec.rb spec/unit/file_format/line_definition_spec.rb spec/unit/file_format/merb_format_spec.rb spec/unit/file_format/mysql_format_spec.rb spec/unit/file_format/oink_format_spec.rb spec/unit/file_format/postgresql_format_spec.rb spec/unit/file_format/rack_format_spec.rb spec/unit/file_format/rails3_format_spec.rb spec/unit/file_format/rails_format_spec.rb spec/unit/file_format/w3c_format_spec.rb spec/unit/filter/anonymize_filter_spec.rb spec/unit/filter/field_filter_spec.rb spec/unit/filter/filter_spec.rb spec/unit/filter/timespan_filter_spec.rb spec/unit/mailer_spec.rb spec/unit/request_spec.rb spec/unit/source/log_parser_spec.rb spec/unit/tracker/duration_tracker_spec.rb spec/unit/tracker/frequency_tracker_spec.rb spec/unit/tracker/hourly_spread_spec.rb spec/unit/tracker/numeric_value_tracker_spec.rb spec/unit/tracker/timespan_tracker_spec.rb spec/unit/tracker/tracker_api_spec.rb spec/unit/tracker/traffic_tracker_spec.rb)
44
44
  end
@@ -1,4 +1,3 @@
1
- SELECT /*!40001 SQL_NO_CACHE */ * FROM `clients`;
2
1
  # Time: 091112 18:13:56
3
2
  # User@Host: admin[admin] @ db1 [10.0.0.1]
4
3
  # Query_time: 10 Lock_time: 0 Rows_sent: 1191307 Rows_examined: 1191307
@@ -14,11 +14,6 @@ describe RequestLogAnalyzer, 'running from command line' do
14
14
  output = run("#{log_fixture(:rails_1x)}")
15
15
  output.any? { |line| /^Parsed requests\:\s*4\s/ =~ line }.should be_true
16
16
  end
17
-
18
- it "should function correctly with the gets mixin" do
19
- output = run("#{log_fixture(:rails_1x)} --gets-memory-protection")
20
- output.any? { |line| /^Parsed requests\:\s*4\s/ =~ line }.should be_true
21
- end
22
17
 
23
18
  it "should find 2 requests when parsing a compressed file" do
24
19
  output = run("#{log_fixture(:decompression, :tgz)}")
data/spec/lib/helpers.rb CHANGED
@@ -11,8 +11,8 @@ module RequestLogAnalyzer::RSpec::Helpers
11
11
  end
12
12
 
13
13
  # Creates a log file given some lines
14
- def log_stream(*lines)
15
- StringIO.new(lines.join("\n") + "\n")
14
+ def log_snippet(*lines)
15
+ StringIO.new(lines.join("\n") << "\n")
16
16
  end
17
17
 
18
18
  # Request loopback
data/spec/lib/matchers.rb CHANGED
@@ -7,15 +7,23 @@ module RequestLogAnalyzer::RSpec::Matchers
7
7
  @captures = []
8
8
  end
9
9
 
10
- def capturing(*captures)
10
+ def and_capture(*captures)
11
11
  @captures += captures
12
12
  return self
13
13
  end
14
+
15
+ alias_method :capturing, :and_capture
16
+
17
+ def description
18
+ description = "have a #{@line_type.inspect} line definition"
19
+ description << " that captures #{@captures.join(', ')}" unless @captures.empty?
20
+ description
21
+ end
14
22
 
15
23
  def matches?(file_format)
16
24
  file_format = file_format.create if file_format.kind_of?(Class)
17
25
  if ld = file_format.line_definitions[@line_type]
18
- @captures.all? { |c| ld.captures.map { |cd| cd[:name] }.include?(c) }
26
+ @captures.all? { |c| ld.all_captured_variables.include?(c) }
19
27
  else
20
28
  false
21
29
  end
@@ -24,10 +32,25 @@ module RequestLogAnalyzer::RSpec::Matchers
24
32
 
25
33
  class ParseLine
26
34
 
27
- def initialize(line)
35
+ def initialize(line, line_description = nil)
28
36
  @line = line
29
37
  @captures = {}
30
38
  @line_type = nil
39
+ @line_description = line_description
40
+ end
41
+
42
+ def line_description
43
+ @full_line_description ||= if @line_description
44
+ if @line_type && @line_description =~ /^(?:with|without|having|using) /
45
+ "a #{@line_type.inspect} line #{@line_description}"
46
+ else
47
+ @line_description
48
+ end
49
+ elsif @line_type
50
+ "a #{@line_type.inspect} line"
51
+ else
52
+ "line #{@line.inspect}"
53
+ end
31
54
  end
32
55
 
33
56
  def failure_message
@@ -43,11 +66,20 @@ module RequestLogAnalyzer::RSpec::Matchers
43
66
  @captures = captures
44
67
  return self
45
68
  end
69
+
70
+ alias_method :capturing, :and_capture
46
71
 
47
72
  def fail(message)
48
73
  @failure_message = message
49
74
  return false
50
75
  end
76
+
77
+ def description
78
+ description = "parse #{line_description}"
79
+ description << " as line type #{@line_type.inspect}" if @line_type
80
+ description << " and capture #{@captures.keys.join(', ')} correctly" unless @captures.empty?
81
+ description
82
+ end
51
83
 
52
84
  def matches?(file_format)
53
85
  if @line_hash = file_format.parse_line(@line)
@@ -70,8 +102,7 @@ module RequestLogAnalyzer::RSpec::Matchers
70
102
  return HasLineDefinition.new(line_type)
71
103
  end
72
104
 
73
- def parse_line(line)
74
- ParseLine.new(line)
105
+ def parse_line(line, line_description = nil)
106
+ ParseLine.new(line, line_description)
75
107
  end
76
-
77
- end
108
+ end
data/spec/lib/mocks.rb CHANGED
@@ -70,8 +70,4 @@ module RequestLogAnalyzer::RSpec::Mocks
70
70
  connection.stub!(:table_creator).and_return(table_creator)
71
71
  return connection
72
72
  end
73
-
74
- def request_counter
75
- @request_counter ||= mock('aggregator to count request')
76
- end
77
- end
73
+ end
data/spec/spec_helper.rb CHANGED
@@ -1,8 +1,9 @@
1
- $LOAD_PATH << File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib'))
2
-
3
1
  require 'rubygems'
2
+ require 'bundler/setup'
3
+
4
4
  require 'rspec'
5
5
  require 'request_log_analyzer'
6
+ require 'stringio'
6
7
 
7
8
  module RequestLogAnalyzer::RSpec
8
9
  end
@@ -1,4 +1,5 @@
1
1
  require 'spec_helper'
2
+ require 'request_log_analyzer/database'
2
3
 
3
4
  describe RequestLogAnalyzer::Database::Base do
4
5