wvanbergen-request-log-analyzer 1.0.1 → 1.0.2

Sign up to get free protection for your applications and to get access to all the features.
data/README.textile CHANGED
@@ -1,49 +1,36 @@
1
- h1. Request log analyzer
1
+ h1. Request-log-analyzer
2
2
 
3
3
  This is a simple command line tool to analyze request log files of both Rails and
4
- Merb. Its purpose is to find what actions are best candidates for optimization.
4
+ Merb to produce a performance report. Its purpose is to find what actions are best candidates for optimization.
5
5
 
6
6
  * Analyzes Rails log files (all versions)
7
7
  * Can combine multiple files (handy if you are using logrotate)
8
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)
9
9
  * Low memory footprint (server-safe)
10
- * MIT licensed
11
10
  * Fast
12
-
13
- h2. Additional information
14
-
15
- * "Project wiki at GitHub":http://wiki.github.com/wvanbergen/request-log-analyzer
16
- * "wvanbergen's blog posts":http://techblog.floorplanner.com/tag/request-log-analyzer/
11
+ * MIT licensed
17
12
 
18
13
  h2. Installation
19
14
 
20
- @sudo gem install wvanbergen-request-log-analyzer --source http://gems.github.com@
15
+ <pre>
16
+ $ sudo gem install wvanbergen-request-log-analyzer --source http://gems.github.com
17
+ </pre>
18
+
19
+ To get the best results out of request-log-analyzer, make sure to
20
+ "set up logging correctly":http://wiki.github.com/wvanbergen/request-log-analyzer/configure-logging
21
+ for your application.
21
22
 
22
23
  h2. Usage
23
24
 
25
+ To analyze a log file and produce a performance report, run request-log-analyzer like this:
26
+
24
27
  <pre>
25
- Usage: request-log-analyzer [LOGFILES*] <OPTIONS>
26
-
27
- Input options:
28
- --format <format>, -f: Uses the specified log file format. Defaults to rails.
29
- --after <date> Only consider requests from <date> or later.
30
- --before <date> Only consider requests before <date>.
31
- --select <field> <value> Only consider requests where <field> matches <value>.
32
- --reject <field> <value> Only consider requests where <field> does not match <value>.
33
-
34
- Output options:
35
- --boring, -b Output reports without ASCII colors.
36
- --database <filename>, -d: Creates an SQLite3 database of all the parsed request information.
37
- --debug Print debug information while parsing.
38
- --file <filename> Output to file.
39
-
40
- Examples:
41
- request-log-analyzer development.log
42
- request-log-analyzer mongrel.0.log mongrel.1.log mongrel.2.log
43
- request-log-analyzer --format merb -d requests.db production.log
44
-
45
- To install rake tasks in your Rails application,
46
- run the following command in your application's root directory:
47
-
48
- request-log-analyzer install rails
28
+ $ request-log-analyzer log/production.log
49
29
  </pre>
30
+
31
+ For more details and available command line options, see the "project's wiki":http://wiki.github.com/wvanbergen/request-log-analyzer/basic-usage
32
+
33
+ h2. Additional information
34
+
35
+ * "Project wiki at GitHub":http://wiki.github.com/wvanbergen/request-log-analyzer
36
+ * "wvanbergen's blog posts":http://techblog.floorplanner.com/tag/request-log-analyzer/
@@ -37,7 +37,6 @@ begin
37
37
 
38
38
  command_line.option(:format, :alias => :f, :default => 'rails')
39
39
  command_line.option(:file, :alias => :e)
40
- command_line.switch(:single_lines, :s)
41
40
  command_line.switch(:assume_correct_order)
42
41
 
43
42
  command_line.option(:aggregator, :alias => :a, :multiple => true)
@@ -2,12 +2,6 @@ module RequestLogAnalyzer::Aggregator
2
2
 
3
3
  # The base class of an aggregator. This class provides the interface to which
4
4
  # every aggregator should comply (by simply subclassing this class).
5
- #
6
- # When building an aggregator, do not forget that RequestLogAnalyzer can run in
7
- # single line mode or in combined requests mode. Make sure your aggregator can
8
- # handle both cases, or raise an exception if RLA is rnning in the wrong mode.
9
- # Calling options[:combined_requests] tells you if RLA is running in combined
10
- # requests mode, otherwise it is running in single line mode.
11
5
  class Base
12
6
 
13
7
  include RequestLogAnalyzer::FileFormat::Awareness
@@ -5,43 +5,45 @@ module RequestLogAnalyzer::Aggregator
5
5
 
6
6
  class Database < Base
7
7
 
8
- attr_reader :request_id
9
-
8
+ # Establishes a connection to the database and creates the necessary database schema for the
9
+ # current file format
10
10
  def prepare
11
11
  ActiveRecord::Base.establish_connection(:adapter => 'sqlite3', :database => options[:database])
12
-
13
- File.unlink(options[:database]) if File.exist?(options[:database])
12
+ File.unlink(options[:database]) if File.exist?(options[:database]) # TODO: keep old database?
14
13
  create_database_schema!
15
-
16
- @request_id = 0
17
14
  end
18
15
 
16
+ # Aggregates a request into the database
17
+ # This will create a record in the requests table and create a record for every line that has been parsed,
18
+ # in which the captured values will be stored.
19
19
  def aggregate(request)
20
- @request_id += 1
21
-
20
+ @request_object = @request_class.new(:first_lineno => request.first_lineno, :last_lineno => request.last_lineno)
22
21
  request.lines.each do |line|
23
- class_name = "#{line[:line_type]}_line".camelize #split(/[^a-z0-9]/i).map{ |w| w.capitalize }.join('')
24
-
25
22
  attributes = line.reject { |k, v| [:line_type].include?(k) }
26
- attributes[:request_id] = @request_id if options[:combined_requests]
27
- file_format.class.const_get(class_name).create!(attributes)
23
+ @request_object.send("#{line[:line_type]}_lines").build(attributes)
28
24
  end
25
+ @request_object.save!
29
26
  rescue SQLite3::SQLException => e
30
27
  raise Interrupt, e.message
31
28
  end
32
29
 
30
+ # Finalizes the aggregator by closing the connection to the database
33
31
  def finalize
32
+ @request_count = @orm_module::Request.count
34
33
  ActiveRecord::Base.remove_connection
35
34
  end
36
35
 
36
+ # Records w warining in the warnings table.
37
37
  def warning(type, message, lineno)
38
- file_format.class::Warning.create!(:warning_type => type.to_s, :message => message, :lineno => lineno)
38
+ @orm_module::Warning.create!(:warning_type => type.to_s, :message => message, :lineno => lineno)
39
39
  end
40
40
 
41
+ # Prints a short report of what has been inserted into the database
41
42
  def report(output = STDOUT, report_width = 80, color = false)
42
43
  output << "\n"
43
44
  output << green("━" * report_width, color) + "\n"
44
45
  output << "A database file has been created with all parsed request information.\n"
46
+ output << "#{@request_count} requests have been added to the database.\n"
45
47
  output << "To execute queries on this database, run the following command:\n"
46
48
  output << " $ sqlite3 #{options[:database]}\n"
47
49
  output << "\n"
@@ -49,17 +51,47 @@ module RequestLogAnalyzer::Aggregator
49
51
 
50
52
  protected
51
53
 
54
+ # This function creates a database table for a given line definition.
55
+ # It will create a field for every capture in the line, and adds a lineno field to indicate at
56
+ # what line in the original file the line was found, and a request_id to link lines related
57
+ # to the same request.
52
58
  def create_database_table(name, definition)
53
59
  ActiveRecord::Migration.verbose = options[:debug]
54
60
  ActiveRecord::Migration.create_table("#{name}_lines") do |t|
55
- t.column(:request_id, :integer) #if options[:combined_requests]
61
+ t.column(:request_id, :integer)
56
62
  t.column(:lineno, :integer)
57
63
  definition.captures.each do |capture|
58
64
  t.column(capture[:name], column_type(capture))
59
65
  end
60
66
  end
61
67
  end
68
+
69
+ # Creates an ActiveRecord class for a given line definition.
70
+ # A subclass of ActiveRecord::Base is created and an association with the Request class is
71
+ # created using belongs_to / has_many. This association will later be used to create records
72
+ # in the corresponding table. This table should already be created before this method is called.
73
+ def create_activerecord_class(name, definition)
74
+ class_name = "#{name}_line".camelize
75
+ klass = Class.new(ActiveRecord::Base)
76
+ klass.send(:belongs_to, :request)
77
+ @orm_module.const_set(class_name, klass) unless @orm_module.const_defined?(class_name)
78
+ @request_class.send(:has_many, "#{name}_lines".to_sym)
79
+ end
80
+
81
+ # Creates a requests table, in which a record is created for every request. It also creates an
82
+ # ActiveRecord::Base class to communicate with this table.
83
+ def create_request_table_and_class
84
+ ActiveRecord::Migration.verbose = options[:debug]
85
+ ActiveRecord::Migration.create_table("requests") do |t|
86
+ t.integer :first_lineno
87
+ t.integer :last_lineno
88
+ end
89
+
90
+ @orm_module.const_set('Request', Class.new(ActiveRecord::Base)) unless @orm_module.const_defined?('Request')
91
+ @request_class = @orm_module.const_get('Request')
92
+ end
62
93
 
94
+ # Creates a warnings table and a corresponding Warning class to communicate with this table using ActiveRecord.
63
95
  def create_warning_table_and_class
64
96
  ActiveRecord::Migration.verbose = options[:debug]
65
97
  ActiveRecord::Migration.create_table("warnings") do |t|
@@ -68,23 +100,30 @@ module RequestLogAnalyzer::Aggregator
68
100
  t.integer :lineno
69
101
  end
70
102
 
71
- file_format.class.const_set('Warning', Class.new(ActiveRecord::Base)) unless file_format.class.const_defined?('Warning')
103
+ @orm_module.const_set('Warning', Class.new(ActiveRecord::Base)) unless @orm_module.const_defined?('Warning')
72
104
  end
73
-
74
- def create_activerecord_class(name, definition)
75
- class_name = "#{name}_line".camelize
76
- file_format.class.const_set(class_name, Class.new(ActiveRecord::Base)) unless file_format.class.const_defined?(class_name)
77
- end
78
-
105
+
106
+ # Creates the database schema and related ActiveRecord::Base subclasses that correspond to the
107
+ # file format definition. These ORM classes will later be used to create records in the database.
79
108
  def create_database_schema!
109
+
110
+ if file_format.class.const_defined?('Database')
111
+ @orm_module = file_format.class.const_get('Database')
112
+ else
113
+ @orm_module = file_format.class.const_set('Database', Module.new)
114
+ end
115
+
116
+ create_request_table_and_class
117
+ create_warning_table_and_class
118
+
80
119
  file_format.line_definitions.each do |name, definition|
81
120
  create_database_table(name, definition)
82
121
  create_activerecord_class(name, definition)
83
122
  end
84
-
85
- create_warning_table_and_class
86
123
  end
87
124
 
125
+ # Function to determine the column type for a field
126
+ # TODO: make more robust / include in file-format definition
88
127
  def column_type(capture)
89
128
  case capture[:type]
90
129
  when :sec; :double
@@ -69,7 +69,7 @@ module RequestLogAnalyzer::Aggregator
69
69
 
70
70
  def report(output=STDOUT, report_width = 80, color = false)
71
71
  report_header(output, report_width, color)
72
- if source.parsed_requests - source.skipped_requests > 0
72
+ if source.parsed_requests > 0
73
73
  @trackers.each { |tracker| tracker.report(output, report_width, color) }
74
74
  else
75
75
  output << "\n"
@@ -82,8 +82,8 @@ module RequestLogAnalyzer::Aggregator
82
82
  output << "Request summary\n"
83
83
  output << green("━" * report_width, color) + "\n"
84
84
  output << "Parsed lines: #{green(source.parsed_lines, color)}\n"
85
- output << "Parsed requests: #{green(source.parsed_requests, color)}\n" if options[:combined_requests]
86
- output << "Skipped requests: #{green(source.skipped_requests, color)}\n" if source.skipped_requests > 0
85
+ output << "Parsed requests: #{green(source.parsed_requests, color)}\n"
86
+ output << "Skipped lines: #{green(source.skipped_lines, color)}\n" if source.skipped_lines > 0
87
87
  if has_warnings?
88
88
  output << "Warnings: " + @warnings_encountered.map { |(key, value)| "#{key.inspect}: #{blue(value, color)}" }.join(', ') + "\n"
89
89
  end
@@ -33,7 +33,6 @@ module RequestLogAnalyzer
33
33
 
34
34
  options = { :report_width => arguments[:report_width].to_i, :output => STDOUT}
35
35
 
36
- options[:combined_requests] = !arguments[:single_lines]
37
36
  options[:database] = arguments[:database] if arguments[:database]
38
37
  options[:debug] = arguments[:debug]
39
38
  options[:colorize] = !arguments[:boring]
@@ -45,7 +44,7 @@ module RequestLogAnalyzer
45
44
 
46
45
  # Create the controller with the correct file format
47
46
  file_format = RequestLogAnalyzer::FileFormat.load(arguments[:format])
48
- source_files = nil
47
+
49
48
  # register sources
50
49
  if arguments.parameters.length == 1
51
50
  file = arguments.parameters[0]
@@ -63,27 +62,22 @@ module RequestLogAnalyzer
63
62
 
64
63
  controller = Controller.new(RequestLogAnalyzer::Source::LogFile.new(file_format, options), options)
65
64
 
66
- # register filters
67
- # filters are only supported in combined requests mode
68
- if options[:combined_requests]
69
-
70
- options[:assume_correct_order] = arguments[:assume_correct_order]
71
-
72
- if arguments[:after] || arguments[:before]
73
- filter_options = {}
74
- filter_options[:after] = DateTime.parse(arguments[:after])
75
- filter_options[:before] = DateTime.parse(arguments[:before]) if arguments[:before]
76
- controller.add_filter(:timespan, filter_options)
77
- end
78
-
79
- arguments[:reject].each do |(field, value)|
80
- controller.add_filter(:field, :mode => :reject, :field => field, :value => value)
81
- end
82
-
83
- arguments[:select].each do |(field, value)|
84
- controller.add_filter(:field, :mode => :select, :field => field, :value => value)
85
- end
86
-
65
+ options[:assume_correct_order] = arguments[:assume_correct_order]
66
+
67
+ # register filters
68
+ if arguments[:after] || arguments[:before]
69
+ filter_options = {}
70
+ filter_options[:after] = DateTime.parse(arguments[:after])
71
+ filter_options[:before] = DateTime.parse(arguments[:before]) if arguments[:before]
72
+ controller.add_filter(:timespan, filter_options)
73
+ end
74
+
75
+ arguments[:reject].each do |(field, value)|
76
+ controller.add_filter(:field, :mode => :reject, :field => field, :value => value)
77
+ end
78
+
79
+ arguments[:select].each do |(field, value)|
80
+ controller.add_filter(:field, :mode => :select, :field => field, :value => value)
87
81
  end
88
82
 
89
83
  # register aggregators
@@ -95,7 +89,9 @@ module RequestLogAnalyzer
95
89
 
96
90
  # register the echo aggregator in debug mode
97
91
  controller.add_aggregator(:echo) if arguments[:debug]
98
-
92
+
93
+ file_format.setup_environment(controller)
94
+
99
95
  return controller
100
96
  end
101
97
 
@@ -103,7 +99,6 @@ module RequestLogAnalyzer
103
99
  # <tt>format</tt> Logfile format. Defaults to :rails
104
100
  # Options are passd on to the LogParser.
105
101
  # * <tt>:aggregator</tt> Aggregator array.
106
- # * <tt>:combined_requests</tt> Combine multiline requests into a single request.
107
102
  # * <tt>:database</tt> Database the controller should use.
108
103
  # * <tt>:echo</tt> Output debug information.
109
104
  # * <tt>:silent</tt> Do not output any warnings.
@@ -186,7 +181,7 @@ module RequestLogAnalyzer
186
181
 
187
182
  begin
188
183
  @source.requests do |request|
189
- @filters.each { |filter| request = filter.filter(request) }
184
+ #@filters.each { |filter| request = filter.filter(request) }
190
185
  @aggregators.each { |agg| agg.aggregate(request) } if request
191
186
  end
192
187
  rescue Interrupt => e
@@ -73,5 +73,9 @@ module RequestLogAnalyzer
73
73
  def valid?
74
74
  line_definitions.detect { |(name, ld)| ld.header } && line_definitions.detect { |(name, ld)| ld.footer }
75
75
  end
76
+
77
+ def setup_environment(controller)
78
+
79
+ end
76
80
  end
77
81
  end
@@ -22,11 +22,11 @@ class RequestLogAnalyzer::FileFormat::Rails < RequestLogAnalyzer::FileFormat
22
22
  line_definition :failed do |line|
23
23
  line.footer = true
24
24
  line.regexp = /((?:[A-Z]\w+\:\:)*[A-Z]\w+) \((.*)\)(?: on line #(\d+) of .+)?\:(.*)/
25
- line.captures << { :name => :error, :type => :string } \
26
- << { :name => :exception_string, :type => :string } \
27
- << { :name => :line, :type => :integer } \
28
- << { :name => :file, :type => :string } \
29
- << { :name => :stack_trace, :type => :string, :anonymize => true }
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
30
  end
31
31
 
32
32
 
@@ -63,37 +63,8 @@ class RequestLogAnalyzer::FileFormat::Rails < RequestLogAnalyzer::FileFormat
63
63
 
64
64
 
65
65
  REQUEST_CATEGORIZER = Proc.new do |request|
66
- if request.combined?
67
-
68
- if request =~ :failed
69
- format = request[:format] || 'html'
70
- "#{request[:error]} in #{request[:controller]}##{request[:action]}.#{format} [#{request[:method]}]"
71
- else
72
- format = request[:format] || 'html'
73
- "#{request[:controller]}##{request[:action]}.#{format} [#{request[:method]}]"
74
- end
75
-
76
- else
77
- case request.line_type
78
- when :processing
79
- format = request[:format] || 'html'
80
- "#{request[:controller]}##{request[:action]}.#{format} [#{request[:method]}]"
81
-
82
- when :completed
83
- url = request[:url].downcase.split(/^http[s]?:\/\/[A-z0-9\.-]+/).last.split('?').first # only the relevant URL part
84
- url << '/' if url[-1] != '/'[0] && url.length > 1 # pad a trailing slash for consistency
85
-
86
- url.gsub!(/\/\d+-\d+-\d+(\/|$)/, '/:date/') # Combine all (year-month-day) queries
87
- url.gsub!(/\/\d+-\d+(\/|$)/, '/:month/') # Combine all date (year-month) queries
88
- url.gsub!(/\/\d+[\w-]*/, '/:id') # replace identifiers in URLs request[:url] # TODO: improve me
89
- url
90
-
91
- when :failed
92
- request[:error]
93
- else
94
- raise "Cannot group this request: #{request.inspect}"
95
- end
96
- end
66
+ format = request[:format] || 'html'
67
+ "#{request[:controller]}##{request[:action]}.#{format} [#{request[:method]}]"
97
68
  end
98
69
 
99
70
  report do |analyze|
@@ -1,18 +1,14 @@
1
1
  module RequestLogAnalyzer
2
2
 
3
3
  # The LogParser class reads log data from a given source and uses a file format definition
4
- # to parse all relevent information about requests from the file.
4
+ # to parse all relevent information about requests from the file. A FileFormat module should
5
+ # be provided that contains the definitions of the lines that occur in the log data.
5
6
  #
6
- # A FileFormat module should be provided that contains the definitions of the lines that
7
- # occur in the log data. The log parser can run in two modes:
8
- # - In single line mode, it will emit every detected line as a separate request
9
- # - In combined requests mode, it will combine the different lines from the line defintions
10
- # into one request, that will then be emitted.
11
- #
12
- # The combined requests mode gives better information, but can be problematic if the log
13
- # file is unordered. This can be the case if data is written to the log file simultaneously
14
- # by different mongrel processes. This problem is detected by the parser, but the requests
15
- # that are mixed up cannot be parsed. It will emit warnings when this occurs.
7
+ # De order in which lines occur is used to combine lines to a single request. If these lines
8
+ # are mixed, requests cannot be combined properly. This can be the case if data is written to
9
+ # the log file simultaneously by different mongrel processes. This problem is detected by the
10
+ # parser, but the requests that are mixed up cannot be parsed. It will emit warnings when this
11
+ # occurs.
16
12
  class LogParser
17
13
 
18
14
  include RequestLogAnalyzer::FileFormat::Awareness
@@ -79,8 +75,6 @@ module RequestLogAnalyzer
79
75
  unknown = line_types.reject { |line_type| file_format.line_definitions.has_key?(line_type) }
80
76
  raise "Unknown line types: #{unknown.join(', ')}" unless unknown.empty?
81
77
 
82
- puts "Parsing mode: " + (options[:combined_requests] ? 'combined requests' : 'single lines') if options[:debug]
83
-
84
78
  @current_io = io
85
79
  @current_io.each_line do |line|
86
80
 
@@ -94,11 +88,7 @@ module RequestLogAnalyzer
94
88
 
95
89
  if request_data
96
90
  @parsed_lines += 1
97
- if @options[:combined_requests]
98
- update_current_request(request_data, &block)
99
- else
100
- handle_request(RequestLogAnalyzer::Request.create(@file_format, request_data), &block)
101
- end
91
+ update_current_request(request_data, &block)
102
92
  end
103
93
  end
104
94
 
@@ -126,9 +116,9 @@ module RequestLogAnalyzer
126
116
 
127
117
  protected
128
118
 
129
- # Combines the different lines of a request into a single Request object.
130
- # This function is only called in combined requests mode. It will start a new request when
131
- # a header line is encountered en will emit the request when a footer line is encountered.
119
+ # Combines the different lines of a request into a single Request object. It will start a
120
+ # new request when a header line is encountered en will emit the request when a footer line
121
+ # is encountered.
132
122
  #
133
123
  # - Every line that is parsed before a header line is ignored as it cannot be included in
134
124
  # any request. It will emit a :no_current_request warning.
@@ -4,12 +4,6 @@ module RequestLogAnalyzer
4
4
  # Instances are created by the LogParser and are passed to the different aggregators, so they
5
5
  # can do their aggregating work.
6
6
  #
7
- # Note that RequestLogAnalyzer can run in two modes:
8
- # - Single line mode: every parsed line is regarded as a request. Request::single_line? will
9
- # return true in this case
10
- # - Combined requests mode: lines that belong together are grouped into one request.
11
- # Request#combined? will return true in this case.
12
- #
13
7
  # This class provides several methods to access the data that was parsed from the log files.
14
8
  # Request#first(field_name) returns the first (only) value corresponding to the given field
15
9
  # Request#every(field_name) returns all values corresponding to the given field name as array.
@@ -54,7 +48,7 @@ module RequestLogAnalyzer
54
48
 
55
49
  # Returns the value that was captured for the "field" of this request.
56
50
  # This function will return the first value that was captured if the field
57
- # was captured in multiple lines for a combined request.
51
+ # was captured in multiple lines
58
52
  def first(field)
59
53
  @attributes[field]
60
54
  end
@@ -72,44 +66,30 @@ module RequestLogAnalyzer
72
66
  @lines.length == 0
73
67
  end
74
68
 
75
- # Checks whether this request contains exactly one line. This means that RequestLogAnalyzer
76
- # is running in single_line mode.
77
- def single_line?
78
- @lines.length == 1
79
- end
80
-
81
- # Checks whether this request contains more than one line. This means that RequestLogAnalyzer
82
- # is runring in combined requests mode.
83
- def combined?
84
- @lines.length > 1
85
- end
86
-
87
69
  # Checks whether this request is completed. A completed request contains both a parsed header
88
70
  # line and a parsed footer line. Not that calling this function in single line mode will always
89
71
  # return false.
90
72
  def completed?
91
- puts attributes[:method]
92
-
93
73
  header_found, footer_found = false, false
94
74
  @lines.each do |line|
95
75
  line_def = file_format.line_definitions[line[:line_type]]
96
76
  header_found = true if line_def.header
97
77
  footer_found = true if line_def.footer
98
78
  end
99
- header_found && footer_found
100
-
101
- end
102
-
103
- # Returns the line type of the parsed line of this request.
104
- # This function can only be called in single line mode.
105
- def line_type
106
- raise "Not a single line request!" unless single_line?
107
- lines.first[:line_type]
79
+ header_found && footer_found
108
80
  end
109
81
 
110
82
  # Returns the first timestamp encountered in a request.
111
83
  def timestamp
112
84
  first(:timestamp)
113
85
  end
86
+
87
+ def first_lineno
88
+ @lines.first[:lineno]
89
+ end
90
+
91
+ def last_lineno
92
+ @lines.last[:lineno]
93
+ end
114
94
  end
115
95
  end
@@ -15,8 +15,8 @@ module RequestLogAnalyzer::Source
15
15
  # The total number of parsed requests.
16
16
  attr_reader :parsed_requests
17
17
 
18
- # The number of skipped requests because of date constraints
19
- attr_reader :skipped_requests
18
+ # The number of skipped lines because of warnings
19
+ attr_reader :skipped_lines
20
20
 
21
21
  # Base source class used to filter input requests.
22
22
 
@@ -1,17 +1,14 @@
1
1
  module RequestLogAnalyzer::Source
2
+
2
3
  # The LogParser class reads log data from a given source and uses a file format definition
3
- # to parse all relevent information about requests from the file.
4
+ # to parse all relevent information about requests from the file. A FileFormat module should
5
+ # be provided that contains the definitions of the lines that occur in the log data.
4
6
  #
5
- # A FileFormat module should be provided that contains the definitions of the lines that
6
- # occur in the log data. The log parser can run in two modes:
7
- # - In single line mode, it will emit every detected line as a separate request
8
- # - In combined requests mode, it will combine the different lines from the line defintions
9
- # into one request, that will then be emitted.
10
- #
11
- # The combined requests mode gives better information, but can be problematic if the log
12
- # file is unordered. This can be the case if data is written to the log file simultaneously
13
- # by different mongrel processes. This problem is detected by the parser, but the requests
14
- # that are mixed up cannot be parsed. It will emit warnings when this occurs.
7
+ # De order in which lines occur is used to combine lines to a single request. If these lines
8
+ # are mixed, requests cannot be combined properly. This can be the case if data is written to
9
+ # the log file simultaneously by different mongrel processes. This problem is detected by the
10
+ # parser, but the requests that are mixed up cannot be parsed. It will emit warnings when this
11
+ # occurs.
15
12
  class LogFile < RequestLogAnalyzer::Source::Base
16
13
 
17
14
  attr_reader :source_files
@@ -24,8 +21,8 @@ module RequestLogAnalyzer::Source
24
21
  @options = options
25
22
  @parsed_lines = 0
26
23
  @parsed_requests = 0
27
- @skipped_requests = 0
28
- @current_io = nil
24
+ @skipped_lines = 0
25
+ @current_io = nil
29
26
  @source_files = options[:source_files]
30
27
 
31
28
  # install the file format module (see RequestLogAnalyzer::FileFormat)
@@ -78,8 +75,6 @@ module RequestLogAnalyzer::Source
78
75
  unknown = line_types.reject { |line_type| file_format.line_definitions.has_key?(line_type) }
79
76
  raise "Unknown line types: #{unknown.join(', ')}" unless unknown.empty?
80
77
 
81
- puts "Parsing mode: " + (options[:combined_requests] ? 'combined requests' : 'single lines') if options[:debug]
82
-
83
78
  @current_io = io
84
79
  @current_io.each_line do |line|
85
80
 
@@ -93,12 +88,7 @@ module RequestLogAnalyzer::Source
93
88
 
94
89
  if request_data
95
90
  @parsed_lines += 1
96
- if @options[:combined_requests]
97
- update_current_request(request_data, &block)
98
- else
99
- @parsed_requests +=1
100
- yield RequestLogAnalyzer::Request.create(@file_format, request_data)
101
- end
91
+ update_current_request(request_data, &block)
102
92
  end
103
93
  end
104
94
 
@@ -126,9 +116,9 @@ module RequestLogAnalyzer::Source
126
116
 
127
117
  protected
128
118
 
129
- # Combines the different lines of a request into a single Request object.
130
- # This function is only called in combined requests mode. It will start a new request when
131
- # a header line is encountered en will emit the request when a footer line is encountered.
119
+ # Combines the different lines of a request into a single Request object. It will start a
120
+ # new request when a header line is encountered en will emit the request when a footer line
121
+ # is encountered.
132
122
  #
133
123
  # - Every line that is parsed before a header line is ignored as it cannot be included in
134
124
  # any request. It will emit a :no_current_request warning.
@@ -144,7 +134,7 @@ module RequestLogAnalyzer::Source
144
134
  yield @current_request
145
135
  @current_request = RequestLogAnalyzer::Request.create(@file_format, request_data)
146
136
  else
147
- @skipped_requests += 1
137
+ @skipped_lines += 1
148
138
  warn(:unclosed_request, "Encountered header line, but previous request was not closed!")
149
139
  @current_request = nil # remove all data that was parsed, skip next request as well.
150
140
  end
@@ -160,7 +150,7 @@ module RequestLogAnalyzer::Source
160
150
  @current_request = nil
161
151
  end
162
152
  else
163
- @skipped_requests += 1
153
+ @skipped_lines += 1
164
154
  warn(:no_current_request, "Parsebale line found outside of a request!")
165
155
  end
166
156
  end
@@ -18,16 +18,31 @@ describe RequestLogAnalyzer::Aggregator::Database, "schema creation" do
18
18
 
19
19
  it "should create the correct tables" do
20
20
  ActiveRecord::Migration.should_receive(:create_table).with("warnings")
21
+ ActiveRecord::Migration.should_receive(:create_table).with("requests")
21
22
  ActiveRecord::Migration.should_receive(:create_table).with("first_lines")
22
23
  ActiveRecord::Migration.should_receive(:create_table).with("test_lines")
23
24
  ActiveRecord::Migration.should_receive(:create_table).with("last_lines")
24
25
  @database_inserter.prepare
25
26
  end
26
27
 
28
+ it "should create a default Request class" do
29
+ @database_inserter.prepare
30
+ SpecFormat::Database::Request.ancestors.should include(ActiveRecord::Base)
31
+ SpecFormat::Database::Request.column_names.should include('first_lineno')
32
+ SpecFormat::Database::Request.column_names.should include('last_lineno')
33
+ end
34
+
35
+ it "should create associations for the default Request class" do
36
+ @database_inserter.prepare
37
+ @request = SpecFormat::Database::Request.new
38
+ @request.should respond_to(:test_lines)
39
+ @request.test_lines.should
40
+ end
41
+
27
42
  it "should create the default table names" do
28
43
  @database_inserter.prepare
29
44
  @database_inserter.file_format.line_definitions.each do |name, definition|
30
- klass = SpecFormat.const_get("#{name}_line".camelize)
45
+ klass = SpecFormat::Database.const_get("#{name}_line".camelize)
31
46
  klass.column_names.should include('id')
32
47
  klass.column_names.should include('lineno')
33
48
  klass.column_names.should include('request_id')
@@ -37,9 +52,9 @@ describe RequestLogAnalyzer::Aggregator::Database, "schema creation" do
37
52
  it "should create the correct fields in the table" do
38
53
  @database_inserter.prepare
39
54
 
40
- SpecFormat::FirstLine.column_names.should include('request_no')
41
- SpecFormat::LastLine.column_names.should include('request_no')
42
- SpecFormat::TestLine.column_names.should include('test_capture')
55
+ SpecFormat::Database::FirstLine.column_names.should include('request_no')
56
+ SpecFormat::Database::LastLine.column_names.should include('request_no')
57
+ SpecFormat::Database::TestLine.column_names.should include('test_capture')
43
58
  end
44
59
 
45
60
  end
@@ -52,8 +67,8 @@ describe RequestLogAnalyzer::Aggregator::Database, "record insertion" do
52
67
  @database_inserter = RequestLogAnalyzer::Aggregator::Database.new(log_parser, :database => TEST_DATABASE_FILE)
53
68
  @database_inserter.prepare
54
69
 
55
- @single = RequestLogAnalyzer::Request.create(spec_format, {:line_type => :first, :request_no => 564})
56
- @combined = RequestLogAnalyzer::Request.create(spec_format,
70
+ @incomplete_request = RequestLogAnalyzer::Request.create(spec_format, {:line_type => :first, :request_no => 564})
71
+ @completed_request = RequestLogAnalyzer::Request.create(spec_format,
57
72
  {:line_type => :first, :request_no => 564},
58
73
  {:line_type => :test, :test_capture => "awesome"},
59
74
  {:line_type => :test, :test_capture => "indeed"},
@@ -64,20 +79,22 @@ describe RequestLogAnalyzer::Aggregator::Database, "record insertion" do
64
79
  File.unlink(TEST_DATABASE_FILE) if File.exist?(TEST_DATABASE_FILE)
65
80
  end
66
81
 
67
- it "should insert a record in the relevant table" do
68
- SpecFormat::FirstLine.should_receive(:create!).with(hash_including(:request_no => 564))
69
- @database_inserter.aggregate(@single)
82
+ it "should insert a record in the request table" do
83
+ SpecFormat::Database::Request.count.should == 0
84
+ @database_inserter.aggregate(@incomplete_request)
85
+ SpecFormat::Database::Request.count.should == 1
70
86
  end
71
87
 
72
- it "should insert records in all relevant tables" do
73
- SpecFormat::FirstLine.should_receive(:create!).with(hash_including(:request_no => 564)).once
74
- SpecFormat::TestLine.should_receive(:create!).twice
75
- SpecFormat::LastLine.should_receive(:create!).with(hash_including(:request_no => 564)).once
76
- @database_inserter.aggregate(@combined)
88
+ it "should insert records in all relevant line tables" do
89
+ @database_inserter.aggregate(@completed_request)
90
+ request = SpecFormat::Database::Request.first
91
+ request.should have(2).test_lines
92
+ request.should have(1).first_lines
93
+ request.should have(1).last_lines
77
94
  end
78
95
 
79
96
  it "should log a warning in the warnings table" do
80
- SpecFormat::Warning.should_receive(:create!).with(hash_including(:warning_type => 'test_warning'))
97
+ SpecFormat::Database::Warning.should_receive(:create!).with(hash_including(:warning_type => 'test_warning'))
81
98
  @database_inserter.warning(:test_warning, "Testing the warning system", 12)
82
99
  end
83
100
 
@@ -1,3 +1,4 @@
1
+ processing request 1
1
2
  testing
2
3
  testing methods
3
4
  testing is cool
@@ -8,4 +9,5 @@ testing
8
9
  nonsense
9
10
  testing is
10
11
 
11
- more nonsense
12
+ more nonsense
13
+ finishing request 1
@@ -1,46 +1,12 @@
1
1
  require File.dirname(__FILE__) + '/spec_helper'
2
2
 
3
- describe RequestLogAnalyzer::LogParser, :single_line_requests do
4
-
3
+ describe RequestLogAnalyzer::LogParser, :requests do
5
4
  include RequestLogAnalyzerSpecHelper
6
5
 
7
6
  before(:each) do
8
7
  @log_parser = RequestLogAnalyzer::LogParser.new(spec_format)
9
8
  end
10
9
 
11
- it "should have line definitions" do
12
- @log_parser.file_format.line_definitions.should_not be_empty
13
- end
14
-
15
- # it "should have include the language specific hooks in the instance, not in the class" do
16
- # metaclass = (class << @log_parser; self; end)
17
- # metaclass.ancestors.should include(TestFileFormat::LogParser)
18
- # @log_parser.class.ancestors.should_not include(TestFileFormat::LogParser)
19
- # end
20
-
21
- it "should parse a stream and find valid requests" do
22
- io = File.new(log_fixture(:test_file_format), 'r')
23
- @log_parser.parse_io(io, :line_types => [:test]) do |request|
24
- request.should be_kind_of(RequestLogAnalyzer::Request)
25
- request.should =~ :test
26
- request[:test_capture].should_not be_nil
27
- end
28
- io.close
29
- end
30
-
31
- it "should find as many lines as request" do
32
- @log_parser.parse_file(log_fixture(:test_file_format)) { |request| request.should be_single_line }
33
- @log_parser.parsed_lines.should eql(@log_parser.parsed_requests)
34
- end
35
- end
36
-
37
- describe RequestLogAnalyzer::LogParser, :combined_requests do
38
- include RequestLogAnalyzerSpecHelper
39
-
40
- before(:each) do
41
- @log_parser = RequestLogAnalyzer::LogParser.new(spec_format, :combined_requests => true)
42
- end
43
-
44
10
  it "should have multiple line definitions" do
45
11
  @log_parser.file_format.line_definitions.length.should >= 2
46
12
  end
@@ -51,7 +17,7 @@ describe RequestLogAnalyzer::LogParser, :combined_requests do
51
17
 
52
18
  it "should parse more lines than requests" do
53
19
  @log_parser.should_receive(:handle_request).with(an_instance_of(RequestLogAnalyzer::Request)).twice
54
- @log_parser.parse_file(log_fixture(:test_language_combined)) { |request| request.should be_combined }
20
+ @log_parser.parse_file(log_fixture(:test_language_combined))
55
21
  @log_parser.parsed_lines.should > 2
56
22
  end
57
23
 
@@ -68,20 +34,32 @@ describe RequestLogAnalyzer::LogParser, :combined_requests do
68
34
  request[:test_capture].should == "amazing"
69
35
  end
70
36
  end
37
+
38
+ it "should parse a stream and find valid requests" do
39
+ io = File.new(log_fixture(:test_file_format), 'r')
40
+ @log_parser.parse_io(io) do |request|
41
+ request.should be_kind_of(RequestLogAnalyzer::Request)
42
+ request.should =~ :test
43
+ request[:test_capture].should_not be_nil
44
+ end
45
+ io.close
46
+ end
47
+
71
48
  end
72
49
 
73
50
  describe RequestLogAnalyzer::LogParser, :warnings do
74
51
  include RequestLogAnalyzerSpecHelper
52
+
53
+ before(:each) do
54
+ @log_parser = RequestLogAnalyzer::LogParser.new(spec_format)
55
+ end
75
56
 
76
57
  it "should warn about teaser matching problems" do
77
- @log_parser = RequestLogAnalyzer::LogParser.new(spec_format)
78
58
  @log_parser.should_receive(:warn).with(:teaser_check_failed, anything).exactly(5).times
79
59
  @log_parser.parse_file(log_fixture(:test_file_format))
80
60
  end
81
61
 
82
62
  it "should warn about unmatching request headers and footers" do
83
- @log_parser = RequestLogAnalyzer::LogParser.new(spec_format, :combined_requests => true)
84
-
85
63
  @log_parser.should_receive(:warn).with(:unclosed_request, anything).at_least(1).times
86
64
  @log_parser.should_receive(:warn).with(:no_current_request, anything).at_least(1).times
87
65
  @log_parser.should_not_receive(:handle_request)
@@ -1,45 +1,25 @@
1
1
  # require File.dirname(__FILE__) + '/spec_helper'
2
2
  #
3
- # describe RequestLogAnalyzer::LogParser, "Merb without combined requests" do
3
+ # describe RequestLogAnalyzer::LogParser, "Merb" do
4
4
  # include RequestLogAnalyzerSpecHelper
5
5
  #
6
6
  # before(:each) do
7
- # @log_parser = RequestLogAnalyzer::LogParser.new(:merb, :combined_requests => false)
7
+ # @log_parser = RequestLogAnalyzer::LogParser.new(:merb)
8
+ # end
9
+ #
10
+ # it "should have a valid language definitions" do
11
+ # @log_parser.file_format.should be_valid
8
12
  # end
9
13
  #
10
14
  # it "should parse a stream and find valid requests" do
11
15
  # File.open(log_fixture(:merb), 'r') do |io|
12
16
  # @log_parser.parse_io(io) do |request|
13
17
  # request.should be_kind_of(RequestLogAnalyzer::Request)
14
- # request.should be_single_line
15
18
  # end
16
19
  # end
17
20
  # end
18
- #
19
- # it "should find 33 request lines when lines are not linked" do
20
- # @log_parser.should_receive(:handle_request).exactly(33).times
21
- # @log_parser.parse_file(log_fixture(:merb))
22
- # end
23
- #
24
- # it "should find 11 request start lines when lines are not linked" do
25
- # @log_parser.should_receive(:handle_request).exactly(11).times
26
- # @log_parser.parse_file(log_fixture(:merb), :line_types => [:started])
27
- # end
28
- # end
29
- #
30
- #
31
- # describe RequestLogAnalyzer::LogParser, "Merb with combined requests" do
32
- # include RequestLogAnalyzerSpecHelper
33
- #
34
- # before(:each) do
35
- # @log_parser = RequestLogAnalyzer::LogParser.new(:merb, :combined_requests => true)
36
- # end
37
- #
38
- # it "should have a valid language definitions" do
39
- # @log_parser.file_format.should be_valid
40
- # end
41
- #
42
- # it "should find 11 completed requests when lines are linked" do
21
+ #
22
+ # it "should find 11 completed requests" do
43
23
  # @log_parser.should_receive(:handle_request).exactly(11).times
44
24
  # @log_parser.parse_file(log_fixture(:merb))
45
25
  # end
@@ -55,4 +35,4 @@
55
35
  # request[:before_filters_time].should == 0.213213
56
36
  # request[:action_time].should == 0.241652
57
37
  # end
58
- # end
38
+ # end
@@ -1,10 +1,14 @@
1
1
  require File.dirname(__FILE__) + '/spec_helper'
2
2
 
3
- describe RequestLogAnalyzer::LogParser, "Rails without combined requests" do
3
+ describe RequestLogAnalyzer::LogParser, "Rails" do
4
4
  include RequestLogAnalyzerSpecHelper
5
5
 
6
6
  before(:each) do
7
- @log_parser = RequestLogAnalyzer::LogParser.new(RequestLogAnalyzer::FileFormat.load(:rails), :combined_requests => false)
7
+ @log_parser = RequestLogAnalyzer::LogParser.new(RequestLogAnalyzer::FileFormat.load(:rails))
8
+ end
9
+
10
+ it "should have a valid language definitions" do
11
+ @log_parser.file_format.should be_valid
8
12
  end
9
13
 
10
14
  it "should parse a stream and find valid requests" do
@@ -13,30 +17,9 @@ describe RequestLogAnalyzer::LogParser, "Rails without combined requests" do
13
17
  request.should be_kind_of(RequestLogAnalyzer::Request)
14
18
  end
15
19
  io.close
16
- end
17
-
18
- it "should find 8 requests when lines are not linked" do
19
- requests = []
20
- @log_parser.parse_file(log_fixture(:rails_1x)) { |request| requests << request }
21
- requests.length.should == 8
22
- requests.each { |r| r.should be_single_line }
23
- requests.select { |r| r.line_type == :processing }.should have(4).items
24
20
  end
25
- end
26
-
27
-
28
- describe RequestLogAnalyzer::LogParser, "Rails with combined requests" do
29
- include RequestLogAnalyzerSpecHelper
30
-
31
- before(:each) do
32
- @log_parser = RequestLogAnalyzer::LogParser.new(RequestLogAnalyzer::FileFormat.load(:rails), :combined_requests => true)
33
- end
34
-
35
- it "should have a valid language definitions" do
36
- @log_parser.file_format.should be_valid
37
- end
38
21
 
39
- it "should find 4 completed requests when lines are linked" do
22
+ it "should find 4 completed requests" do
40
23
  @log_parser.should_not_receive(:warn)
41
24
  @log_parser.should_receive(:handle_request).exactly(4).times
42
25
  @log_parser.parse_file(log_fixture(:rails_1x))
@@ -63,7 +46,6 @@ describe RequestLogAnalyzer::LogParser, "Rails with combined requests" do
63
46
  @log_parser.parse_file(log_fixture(:syslog_1x)) do |request|
64
47
 
65
48
  request.should be_completed
66
- request.should be_combined
67
49
 
68
50
  request[:controller].should == 'EmployeeController'
69
51
  request[:action].should == 'index'
@@ -79,7 +61,6 @@ describe RequestLogAnalyzer::LogParser, "Rails with combined requests" do
79
61
  @log_parser.should_not_receive(:warn)
80
62
  @log_parser.parse_file(log_fixture(:rails_22_cached)) do |request|
81
63
  request.should be_completed
82
- request.should be_combined
83
64
  request =~ :cache_hit
84
65
  end
85
66
  end
data/spec/request_spec.rb CHANGED
@@ -1,80 +1,72 @@
1
1
  require File.dirname(__FILE__) + '/spec_helper'
2
2
 
3
- describe RequestLogAnalyzer::Request, :single_line do
3
+ describe RequestLogAnalyzer::Request, :incomplete_request do
4
4
 
5
5
  include RequestLogAnalyzerSpecHelper
6
6
 
7
7
  before(:each) do
8
- @single_line_request = RequestLogAnalyzer::Request.new(spec_format)
9
- @single_line_request << { :line_type => :test, :lineno => 1, :test_capture => 'awesome!' }
8
+ @incomplete_request = RequestLogAnalyzer::Request.new(spec_format)
9
+ @incomplete_request << { :line_type => :test, :lineno => 1, :test_capture => 'awesome!' }
10
10
  end
11
11
 
12
- it "should include the file format module" do
13
- (class << @single_line_request; self; end).ancestors.include?(TestFileFormat)
14
- end
15
-
16
12
  it "should be single if only one line has been added" do
17
- @single_line_request.should be_single_line
18
- @single_line_request.should_not be_empty
19
- @single_line_request.should_not be_combined
13
+ @incomplete_request.should_not be_empty
20
14
  end
21
15
 
22
16
  it "should not be a completed request" do
23
- @single_line_request.should_not be_completed
17
+ @incomplete_request.should_not be_completed
24
18
  end
25
19
 
26
20
  it "should take the line type of the first line as global line_type" do
27
- @single_line_request.line_type.should == :test
28
- @single_line_request.should =~ :test
21
+ @incomplete_request.lines[0][:line_type].should == :test
22
+ @incomplete_request.should =~ :test
29
23
  end
30
24
 
31
25
  it "should return the first field value" do
32
- @single_line_request[:test_capture].should == 'awesome!'
26
+ @incomplete_request[:test_capture].should == 'awesome!'
33
27
  end
34
28
 
35
29
  it "should return nil if no such field is present" do
36
- @single_line_request[:nonexisting].should be_nil
30
+ @incomplete_request[:nonexisting].should be_nil
37
31
  end
38
32
  end
39
33
 
40
34
 
41
- describe RequestLogAnalyzer::Request, :combined do
35
+ describe RequestLogAnalyzer::Request, :completed_request do
42
36
 
43
37
  include RequestLogAnalyzerSpecHelper
44
38
 
45
39
  before(:each) do
46
- @combined_request = RequestLogAnalyzer::Request.new(spec_format)
47
- @combined_request << { :line_type => :first, :lineno => 1, :name => 'first line!' }
48
- @combined_request << { :line_type => :test, :lineno => 4, :test_capture => 'testing' }
49
- @combined_request << { :line_type => :test, :lineno => 7, :test_capture => 'testing some more' }
50
- @combined_request << { :line_type => :last, :lineno => 10, :time => 0.03 }
40
+ @completed_request = RequestLogAnalyzer::Request.new(spec_format)
41
+ @completed_request << { :line_type => :first, :lineno => 1, :name => 'first line!' }
42
+ @completed_request << { :line_type => :test, :lineno => 4, :test_capture => 'testing' }
43
+ @completed_request << { :line_type => :test, :lineno => 7, :test_capture => 'testing some more' }
44
+ @completed_request << { :line_type => :last, :lineno => 10, :time => 0.03 }
51
45
  end
52
46
 
53
- it "should be a combined request when more lines are added" do
54
- @combined_request.should be_combined
55
- @combined_request.should_not be_single_line
56
- @combined_request.should_not be_empty
47
+ it "should not be empty when multiple liness are added" do
48
+ @completed_request.should_not be_empty
57
49
  end
58
50
 
59
51
  it "should be a completed request" do
60
- @combined_request.should be_completed
52
+ @completed_request.should be_completed
61
53
  end
62
54
 
63
55
  it "should recognize all line types" do
64
- [:first, :test, :last].each { |type| @combined_request.should =~ type }
56
+ [:first, :test, :last].each { |type| @completed_request.should =~ type }
65
57
  end
66
58
 
67
59
  it "should detect the correct field value" do
68
- @combined_request[:name].should == 'first line!'
69
- @combined_request[:time].should == 0.03
60
+ @completed_request[:name].should == 'first line!'
61
+ @completed_request[:time].should == 0.03
70
62
  end
71
63
 
72
64
  it "should detect the first matching field value" do
73
- @combined_request.first(:test_capture).should == 'testing'
65
+ @completed_request.first(:test_capture).should == 'testing'
74
66
  end
75
67
 
76
68
  it "should detect the every matching field value" do
77
- @combined_request.every(:test_capture).should == ['testing', "testing some more"]
69
+ @completed_request.every(:test_capture).should == ['testing', "testing some more"]
78
70
  end
79
71
 
80
72
  end
@@ -1,13 +1,7 @@
1
1
  require File.dirname(__FILE__) + '/spec_helper'
2
2
  require 'request_log_analyzer/aggregator/summarizer'
3
3
 
4
- describe RequestLogAnalyzer::Aggregator::Summarizer, :single_line do
5
-
6
- before(:each) do
7
- end
8
- end
9
-
10
- describe RequestLogAnalyzer::Aggregator::Summarizer, :combined_requests do
4
+ describe RequestLogAnalyzer::Aggregator::Summarizer do
11
5
 
12
6
  before(:each) do
13
7
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: wvanbergen-request-log-analyzer
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.1
4
+ version: 1.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Willem van Bergen
@@ -10,7 +10,7 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
 
13
- date: 2009-01-12 00:00:00 -08:00
13
+ date: 2009-01-13 00:00:00 -08:00
14
14
  default_executable: request-log-analyzer
15
15
  dependencies: []
16
16