request-log-analyzer 1.3.4 → 1.4.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 (86) 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 +4 -3
  7. data/lib/cli/progressbar.rb +10 -10
  8. data/lib/cli/tools.rb +3 -3
  9. data/lib/request_log_analyzer/aggregator/database_inserter.rb +19 -17
  10. data/lib/request_log_analyzer/aggregator/echo.rb +14 -9
  11. data/lib/request_log_analyzer/aggregator/summarizer.rb +26 -26
  12. data/lib/request_log_analyzer/aggregator.rb +11 -15
  13. data/lib/request_log_analyzer/controller.rb +162 -89
  14. data/lib/request_log_analyzer/database/base.rb +22 -21
  15. data/lib/request_log_analyzer/database/connection.rb +3 -3
  16. data/lib/request_log_analyzer/database/request.rb +22 -0
  17. data/lib/request_log_analyzer/database/source.rb +13 -0
  18. data/lib/request_log_analyzer/database/warning.rb +14 -0
  19. data/lib/request_log_analyzer/database.rb +28 -103
  20. data/lib/request_log_analyzer/file_format/amazon_s3.rb +20 -20
  21. data/lib/request_log_analyzer/file_format/apache.rb +37 -30
  22. data/lib/request_log_analyzer/file_format/merb.rb +30 -13
  23. data/lib/request_log_analyzer/file_format/rack.rb +11 -0
  24. data/lib/request_log_analyzer/file_format/rails.rb +143 -73
  25. data/lib/request_log_analyzer/file_format/rails_development.rb +4 -49
  26. data/lib/request_log_analyzer/file_format.rb +16 -28
  27. data/lib/request_log_analyzer/filter/anonymize.rb +8 -7
  28. data/lib/request_log_analyzer/filter/field.rb +9 -9
  29. data/lib/request_log_analyzer/filter/timespan.rb +12 -10
  30. data/lib/request_log_analyzer/filter.rb +12 -16
  31. data/lib/request_log_analyzer/line_definition.rb +15 -14
  32. data/lib/request_log_analyzer/log_processor.rb +27 -29
  33. data/lib/request_log_analyzer/mailer.rb +15 -9
  34. data/lib/request_log_analyzer/output/fixed_width.rb +48 -48
  35. data/lib/request_log_analyzer/output/html.rb +20 -20
  36. data/lib/request_log_analyzer/output.rb +53 -12
  37. data/lib/request_log_analyzer/request.rb +88 -69
  38. data/lib/request_log_analyzer/source/database_loader.rb +10 -14
  39. data/lib/request_log_analyzer/source/log_parser.rb +57 -50
  40. data/lib/request_log_analyzer/source.rb +10 -12
  41. data/lib/request_log_analyzer/tracker/duration.rb +41 -134
  42. data/lib/request_log_analyzer/tracker/frequency.rb +31 -32
  43. data/lib/request_log_analyzer/tracker/hourly_spread.rb +21 -21
  44. data/lib/request_log_analyzer/tracker/timespan.rb +17 -17
  45. data/lib/request_log_analyzer/tracker/traffic.rb +106 -0
  46. data/lib/request_log_analyzer/tracker.rb +139 -32
  47. data/lib/request_log_analyzer.rb +5 -5
  48. data/request-log-analyzer.gemspec +19 -15
  49. data/spec/database.yml +6 -0
  50. data/spec/fixtures/rails_22.log +1 -1
  51. data/spec/integration/command_line_usage_spec.rb +7 -1
  52. data/spec/lib/helpers.rb +7 -7
  53. data/spec/lib/macros.rb +3 -3
  54. data/spec/lib/matchers.rb +41 -27
  55. data/spec/lib/mocks.rb +19 -15
  56. data/spec/lib/testing_format.rb +9 -9
  57. data/spec/spec_helper.rb +6 -6
  58. data/spec/unit/aggregator/database_inserter_spec.rb +16 -16
  59. data/spec/unit/aggregator/summarizer_spec.rb +4 -4
  60. data/spec/unit/controller/controller_spec.rb +2 -2
  61. data/spec/unit/controller/log_processor_spec.rb +1 -1
  62. data/spec/unit/database/base_class_spec.rb +26 -33
  63. data/spec/unit/database/connection_spec.rb +3 -3
  64. data/spec/unit/database/database_spec.rb +33 -38
  65. data/spec/unit/file_format/amazon_s3_format_spec.rb +5 -5
  66. data/spec/unit/file_format/apache_format_spec.rb +48 -11
  67. data/spec/unit/file_format/file_format_api_spec.rb +13 -13
  68. data/spec/unit/file_format/line_definition_spec.rb +24 -17
  69. data/spec/unit/file_format/merb_format_spec.rb +41 -45
  70. data/spec/unit/file_format/rails_format_spec.rb +157 -117
  71. data/spec/unit/filter/anonymize_filter_spec.rb +2 -2
  72. data/spec/unit/filter/field_filter_spec.rb +13 -13
  73. data/spec/unit/filter/filter_spec.rb +1 -1
  74. data/spec/unit/filter/timespan_filter_spec.rb +15 -15
  75. data/spec/unit/mailer_spec.rb +30 -0
  76. data/spec/unit/{source/request_spec.rb → request_spec.rb} +30 -30
  77. data/spec/unit/source/log_parser_spec.rb +27 -27
  78. data/spec/unit/tracker/duration_tracker_spec.rb +115 -78
  79. data/spec/unit/tracker/frequency_tracker_spec.rb +74 -63
  80. data/spec/unit/tracker/hourly_spread_spec.rb +28 -20
  81. data/spec/unit/tracker/timespan_tracker_spec.rb +25 -13
  82. data/spec/unit/tracker/tracker_api_spec.rb +117 -42
  83. data/spec/unit/tracker/traffic_tracker_spec.rb +107 -0
  84. data/tasks/github-gem.rake +125 -75
  85. data/tasks/request_log_analyzer.rake +2 -2
  86. metadata +19 -10
@@ -1,9 +1,9 @@
1
1
  module RequestLogAnalyzer::Aggregator
2
2
 
3
3
  class Summarizer < Base
4
-
4
+
5
5
  class Definer
6
-
6
+
7
7
  attr_reader :trackers
8
8
 
9
9
  # Initialize tracker array
@@ -16,17 +16,17 @@ module RequestLogAnalyzer::Aggregator
16
16
  def initialize_copy(other)
17
17
  @trackers = other.trackers.dup
18
18
  end
19
-
19
+
20
20
  # Drop all trackers
21
21
  def reset!
22
22
  @trackers = []
23
23
  end
24
-
24
+
25
25
  # Include missing trackers through method missing.
26
26
  def method_missing(tracker_method, *args)
27
27
  track(tracker_method, *args)
28
28
  end
29
-
29
+
30
30
  # Track the frequency of a specific category
31
31
  # <tt>category_field</tt> Field to track
32
32
  # <tt>options</tt> options are passed to new frequency tracker
@@ -37,7 +37,7 @@ module RequestLogAnalyzer::Aggregator
37
37
  track(:frequency, category_field.merge(options))
38
38
  end
39
39
  end
40
-
40
+
41
41
  # Track the duration of a specific category
42
42
  # <tt>duration_field</tt> Field to track
43
43
  # <tt>options</tt> options are passed to new frequency tracker
@@ -45,10 +45,10 @@ module RequestLogAnalyzer::Aggregator
45
45
  if duration_field.kind_of?(Symbol)
46
46
  track(:duration, options.merge(:duration => duration_field))
47
47
  elsif duration_field.kind_of?(Hash)
48
- track(:duration, duration_field.merge(options))
48
+ track(:duration, duration_field.merge(options))
49
49
  end
50
- end
51
-
50
+ end
51
+
52
52
  # Helper function to initialize a tracker and add it to the tracker array.
53
53
  # <tt>tracker_class</tt> The class to include
54
54
  # <tt>optiont</tt> The options to pass to the trackers.
@@ -57,10 +57,10 @@ module RequestLogAnalyzer::Aggregator
57
57
  @trackers << tracker_klass.new(options)
58
58
  end
59
59
  end
60
-
60
+
61
61
  attr_reader :trackers
62
62
  attr_reader :warnings_encountered
63
-
63
+
64
64
  # Initialize summarizer.
65
65
  # Generate trackers from speciefied source.file_format.report_trackers and set them up
66
66
  def initialize(source, options = {})
@@ -69,16 +69,16 @@ module RequestLogAnalyzer::Aggregator
69
69
  @trackers = source.file_format.report_trackers
70
70
  setup
71
71
  end
72
-
72
+
73
73
  def setup
74
74
  end
75
-
75
+
76
76
  # Call prepare on all trackers.
77
77
  def prepare
78
78
  raise "No trackers set up in Summarizer!" if @trackers.nil? || @trackers.empty?
79
79
  @trackers.each { |tracker| tracker.prepare }
80
80
  end
81
-
81
+
82
82
  # Pass all requests to trackers and let them update if necessary.
83
83
  # <tt>request</tt> The request to pass.
84
84
  def aggregate(request)
@@ -86,19 +86,19 @@ module RequestLogAnalyzer::Aggregator
86
86
  tracker.update(request) if tracker.should_update?(request)
87
87
  end
88
88
  end
89
-
89
+
90
90
  # Call finalize on all trackers. Saves a YAML dump if this is set in the options.
91
91
  def finalize
92
92
  @trackers.each { |tracker| tracker.finalize }
93
93
  save_results_dump(options[:dump]) if options[:dump]
94
94
  end
95
-
95
+
96
96
  # Saves the results of all the trackers in YAML format to a file.
97
97
  # <tt>filename</tt> The file to store the YAML dump in.
98
98
  def save_results_dump(filename)
99
99
  File.open(filename, 'w') { |file| file.write(to_yaml) }
100
100
  end
101
-
101
+
102
102
  # Exports all the tracker results to YAML. It will call the to_yaml_object method
103
103
  # for every tracker and combines these into a single YAML export.
104
104
  def to_yaml
@@ -108,7 +108,7 @@ module RequestLogAnalyzer::Aggregator
108
108
  end
109
109
  YAML::dump(trackers_export)
110
110
  end
111
-
111
+
112
112
  # Call report on all trackers.
113
113
  # <tt>output</tt> RequestLogAnalyzer::Output object to output to
114
114
  def report(output)
@@ -121,13 +121,13 @@ module RequestLogAnalyzer::Aggregator
121
121
  end
122
122
  report_footer(output)
123
123
  end
124
-
124
+
125
125
  # Generate report header.
126
126
  # <tt>output</tt> RequestLogAnalyzer::Output object to output to
127
127
  def report_header(output)
128
128
  output.title("Request summary")
129
-
130
- output.with_style(:cell_separator => false) do
129
+
130
+ output.with_style(:cell_separator => false) do
131
131
  output.table({:width => 20}, {:font => :bold}) do |rows|
132
132
  rows << ['Parsed lines:', source.parsed_lines]
133
133
  rows << ['Skipped lines:', source.skipped_lines]
@@ -138,13 +138,13 @@ module RequestLogAnalyzer::Aggregator
138
138
  end
139
139
  output << "\n"
140
140
  end
141
-
141
+
142
142
  # Generate report footer.
143
143
  # <tt>output</tt> RequestLogAnalyzer::Output object to output to
144
144
  def report_footer(output)
145
145
  if has_log_ordering_warnings?
146
146
  output.title("Parse warnings")
147
-
147
+
148
148
  output.puts "Parseable lines were ancountered without a header line before it. It"
149
149
  output.puts "could be that logging is not setup correctly for your application."
150
150
  output.puts "Visit this website for logging configuration tips:"
@@ -152,17 +152,17 @@ module RequestLogAnalyzer::Aggregator
152
152
  output.puts
153
153
  end
154
154
  end
155
-
155
+
156
156
  # Returns true if there were any warnings generated by the trackers
157
157
  def has_warnings?
158
158
  @warnings_encountered.inject(0) { |result, (key, value)| result += value } > 0
159
159
  end
160
-
160
+
161
161
  # Returns true if there were any log ordering warnings
162
162
  def has_log_ordering_warnings?
163
163
  @warnings_encountered[:no_current_request] && @warnings_encountered[:no_current_request] > 0
164
164
  end
165
-
165
+
166
166
  # Store an encountered warning
167
167
  # <tt>type</tt> Type of warning
168
168
  # <tt>message</tt> Warning message
@@ -1,50 +1,46 @@
1
1
  module RequestLogAnalyzer::Aggregator
2
-
2
+
3
3
  def self.const_missing(const)
4
4
  RequestLogAnalyzer::load_default_class_file(self, const)
5
5
  end
6
-
6
+
7
7
  # The base class of an aggregator. This class provides the interface to which
8
8
  # every aggregator should comply (by simply subclassing this class).
9
9
  class Base
10
-
11
- include RequestLogAnalyzer::FileFormat::Awareness
12
-
13
- attr_reader :options
14
- attr_reader :source
10
+
11
+ attr_reader :options, :source
15
12
 
16
13
  # Intializes a new RequestLogAnalyzer::Aggregator::Base instance
17
14
  # It will include the specific file format module.
18
15
  def initialize(source, options = {})
19
16
  @source = source
20
- self.register_file_format(source.file_format)
21
17
  @options = options
22
18
  end
23
19
 
24
- # The prepare function is called just before parsing starts. This function
20
+ # The prepare function is called just before parsing starts. This function
25
21
  # can be used to initialie variables, etc.
26
22
  def prepare
27
23
  end
28
-
24
+
29
25
  # The aggregate function is called for every request.
30
26
  # Implement the aggregating functionality in this method
31
27
  def aggregate(request)
32
28
  end
33
-
29
+
34
30
  # The finalize function is called after all sources are parsed and no more
35
31
  # requests will be passed to the aggregator
36
32
  def finalize
37
33
  end
38
-
34
+
39
35
  # The warning method is called if the parser eits a warning.
40
36
  def warning(type, message, lineno)
41
- end
42
-
37
+ end
38
+
43
39
  # The report function is called at the end. Implement any result reporting
44
40
  # in this function.
45
41
  def report(output)
46
42
  end
47
-
43
+
48
44
  # The source_change function gets called when handling a source is started or finished.
49
45
  def source_change(change, filename)
50
46
  end
@@ -1,5 +1,5 @@
1
1
  module RequestLogAnalyzer
2
-
2
+
3
3
  # The RequestLogAnalyzer::Controller class creates a LogParser instance for the
4
4
  # requested file format, and connect it with sources and aggregators.
5
5
  #
@@ -17,49 +17,44 @@ module RequestLogAnalyzer
17
17
  # from several logrotated log files.
18
18
  class Controller
19
19
 
20
- include RequestLogAnalyzer::FileFormat::Awareness
21
-
22
- attr_reader :aggregators
23
- attr_reader :filters
24
- attr_reader :log_parser
25
- attr_reader :source
26
- attr_reader :output
27
- attr_reader :options
20
+ attr_reader :source, :filters, :aggregators, :output, :options
28
21
 
29
22
  # Builds a RequestLogAnalyzer::Controller given parsed command line arguments
30
23
  # <tt>arguments<tt> A CommandLine::Arguments hash containing parsed commandline parameters.
31
24
  # <rr>report_with</tt> Width of the report. Defaults to 80.
32
- def self.build(arguments)
33
- options = { }
34
-
35
- # Database command line options
36
- options[:database] = arguments[:database] if arguments[:database]
25
+ def self.build_from_arguments(arguments)
26
+
27
+ options = {}
28
+
29
+ # Copy fields
30
+ options[:database] = arguments[:database]
37
31
  options[:reset_database] = arguments[:reset_database]
38
- options[:debug] = arguments[:debug]
39
- options[:dump] = arguments[:dump]
32
+ options[:debug] = arguments[:debug]
33
+ options[:dump] = arguments[:dump]
40
34
  options[:parse_strategy] = arguments[:parse_strategy]
41
35
  options[:no_progress] = arguments[:no_progress]
36
+ options[:format] = arguments[:format]
37
+ options[:output] = arguments[:output]
38
+ options[:file] = arguments[:file]
39
+ options[:format] = arguments[:format]
40
+ options[:after] = arguments[:after]
41
+ options[:before] = arguments[:before]
42
+ options[:reject] = arguments[:reject]
43
+ options[:select] = arguments[:select]
44
+ options[:boring] = arguments[:boring]
45
+ options[:aggregator] = arguments[:aggregator]
46
+ options[:report_width] = arguments[:report_width]
47
+ options[:report_sort] = arguments[:report_sort]
48
+ options[:report_amount] = arguments[:report_amount]
42
49
 
43
- output_class = RequestLogAnalyzer::Output::const_get(arguments[:output])
44
- if arguments[:file]
45
- output_file = File.new(arguments[:file], "w+")
46
- options[:output] = output_class.new(output_file, :width => 80, :color => false, :characters => :ascii)
47
- elsif arguments[:mail]
48
- output_mail = RequestLogAnalyzer::Mailer.new(arguments[:mail])
49
- options[:output] = output_class.new(output_mail, :width => 80, :color => false, :characters => :ascii)
50
- else
51
- options[:output] = output_class.new(STDOUT, :width => arguments[:report_width].to_i,
52
- :color => !arguments[:boring], :characters => (arguments[:boring] ? :ascii : :utf))
50
+ # Apache format workaround
51
+ if arguments[:rails_format]
52
+ options[:format] = {:rails => arguments[:rails_format]}
53
+ elsif arguments[:apache_format]
54
+ options[:format] = {:apache => arguments[:apache_format]}
53
55
  end
54
-
55
- # Create the controller with the correct file format
56
- file_format = if arguments[:apache_format]
57
- RequestLogAnalyzer::FileFormat.load(:apache, arguments[:apache_format])
58
- else
59
- RequestLogAnalyzer::FileFormat.load(arguments[:format])
60
- end
61
-
62
- # register sources
56
+
57
+ # Register sources
63
58
  if arguments.parameters.length == 1
64
59
  file = arguments.parameters[0]
65
60
  if file == '-' || file == 'STDIN'
@@ -74,49 +69,128 @@ module RequestLogAnalyzer
74
69
  options.store(:source_files, arguments.parameters)
75
70
  end
76
71
 
77
- controller = Controller.new(RequestLogAnalyzer::Source::LogParser.new(file_format, options), options)
78
- #controller = Controller.new(RequestLogAnalyzer::Source::DatabaseLoader.new(file_format, options), options)
72
+ build(options)
73
+ end
74
+
75
+ # Build a new controller using parameters (Base for new API)
76
+ # <tt>source</tt> The source file
77
+ # Options are passd on to the LogParser.
78
+ #
79
+ # Options
80
+ # * <tt>:database</tt> Database file
81
+ # * <tt>:reset_database</tt>
82
+ # * <tt>:debug</tt> Enables echo aggregator.
83
+ # * <tt>:dump</tt>
84
+ # * <tt>:parse_strategy</tt>
85
+ # * <tt>:no_progress</tt>
86
+ # * <tt>:output</tt> :fixed_width, :html or Output class. Defaults to fixed width.
87
+ # * <tt>:file</tt> Filestring or File or StringIO
88
+ # * <tt>:format</tt> :rails, {:apache => 'FORMATSTRING'}, :merb, etcetera or Format Class. Defaults to :rails.
89
+ # * <tt>:source_files</tt> File or STDIN
90
+ # * <tt>:after</tt> Drop all requests after this date (Date, DateTime, Time, or a String in "YYYY-MM-DD hh:mm:ss" format)
91
+ # * <tt>:before</tt> Drop all requests before this date (Date, DateTime, Time, or a String in "YYYY-MM-DD hh:mm:ss" format)
92
+ # * <tt>:reject</tt> Reject specific {:field => :value} combination. Expects single hash.
93
+ # * <tt>:select</tt> Select specific {:field => :value} combination. Expects single hash.
94
+ # * <tt>:aggregator</tt> Array of aggregators (ATM: STRINGS OR SYMBOLS ONLY!). Defaults to [:summarizer
95
+ # * <tt>:boring</tt> Do not show color on STDOUT. Defaults to False.
96
+ # * <tt>:report_width</tt> Width or reports in characters. Defaults to 80.
97
+ #
98
+ # TODO:
99
+ # Check if defaults work (Aggregator defaults seem wrong).
100
+ # Refactor :database => options[:database], :dump => options[:dump] away from contoller intialization.
101
+ def self.build(options)
102
+ # Defaults
103
+ options[:output] ||= :fixed_width
104
+ options[:format] ||= :rails
105
+ options[:aggregator] ||= [:summarizer]
106
+ options[:report_width] ||= 80
107
+ options[:report_amount] ||= 20
108
+ options[:report_sort] ||= 'sum,mean'
109
+ options[:boring] ||= false
110
+
111
+ # Set the output class
112
+ output_args = {}
113
+ output_object = nil
114
+ if options[:output].is_a? Class
115
+ output_class = options[:output]
116
+ else
117
+ output_class = RequestLogAnalyzer::Output::const_get(options[:output])
118
+ end
119
+
120
+ output_sort = options[:report_sort].split(',').map { |s| s.to_sym }
121
+ output_amount = options[:report_amount] == 'all' ? :all : options[:report_amount].to_i
122
+
123
+ if options[:file]
124
+ output_object = %w[File StringIO].include?(options[:file].class.name) ? options[:file] : File.new(options[:file], "w+")
125
+ output_args = {:width => 80, :color => false, :characters => :ascii, :sort => output_sort, :amount => output_amount }
126
+ elsif options[:mail]
127
+ output_object = RequestLogAnalyzer::Mailer.new(arguments[:mail])
128
+ output_args = {:width => 80, :color => false, :characters => :ascii, :sort => output_sort, :amount => output_amount }
129
+ else
130
+ output_object = STDOUT
131
+ output_args = {:width => options[:report_width].to_i, :color => !options[:boring],
132
+ :characters => (options[:boring] ? :ascii : :utf), :sort => output_sort, :amount => output_amount }
133
+ end
134
+
135
+ output_instance = output_class.new(output_object, output_args)
136
+
137
+ # Create the controller with the correct file format
138
+ if options[:format].kind_of?(Hash)
139
+ file_format = RequestLogAnalyzer::FileFormat.load(options[:format].keys[0], options[:format].values[0])
140
+ else
141
+ file_format = RequestLogAnalyzer::FileFormat.load(options[:format])
142
+ end
79
143
 
144
+ # Kickstart the controller
145
+ controller = Controller.new( RequestLogAnalyzer::Source::LogParser.new(file_format, :source_files => options[:source_files]),
146
+ { :output => output_instance,
147
+ :database => options[:database], # FUGLY!
148
+ :dump => options[:dump],
149
+ :reset_database => options[:reset_database]})
150
+
80
151
  # register filters
81
- if arguments[:after] || arguments[:before]
152
+ if options[:after] || options[:before]
82
153
  filter_options = {}
83
- filter_options[:after] = DateTime.parse(arguments[:after])
84
- filter_options[:before] = DateTime.parse(arguments[:before]) if arguments[:before]
154
+ [:after, :before].each do |filter|
155
+ case options[filter]
156
+ when Date, DateTime, Time
157
+ filter_options[filter] = options[filter]
158
+ when String
159
+ filter_options[filter] = DateTime.parse(options[filter])
160
+ end
161
+ end
85
162
  controller.add_filter(:timespan, filter_options)
86
163
  end
87
-
88
- arguments[:reject].each do |(field, value)|
89
- controller.add_filter(:field, :mode => :reject, :field => field, :value => value)
164
+
165
+ if options[:reject]
166
+ options[:reject].each do |(field, value)|
167
+ controller.add_filter(:field, :mode => :reject, :field => field, :value => value)
168
+ end
90
169
  end
91
-
92
- arguments[:select].each do |(field, value)|
93
- controller.add_filter(:field, :mode => :select, :field => field, :value => value)
170
+
171
+ if options[:reject]
172
+ options[:select].each do |(field, value)|
173
+ controller.add_filter(:field, :mode => :select, :field => field, :value => value)
174
+ end
94
175
  end
95
176
 
96
177
  # register aggregators
97
- arguments[:aggregator].each { |agg| controller.add_aggregator(agg.to_sym) }
178
+ options[:aggregator].each { |agg| controller.add_aggregator(agg.to_sym) }
179
+ controller.add_aggregator(:summarizer) if options[:aggregator].empty?
180
+ controller.add_aggregator(:echo) if options[:debug]
181
+ controller.add_aggregator(:database_inserter) if options[:database] && !options[:aggregator].include?('database')
98
182
 
99
- # register the database
100
- controller.add_aggregator(:summarizer) if arguments[:aggregator].empty?
101
- controller.add_aggregator(:database_inserter) if arguments[:database] && !arguments[:aggregator].include?('database')
102
-
103
- # register the echo aggregator in debug mode
104
- controller.add_aggregator(:echo) if arguments[:debug]
105
-
106
183
  file_format.setup_environment(controller)
107
-
108
184
  return controller
109
- end
185
+ end
110
186
 
111
187
  # Builds a new Controller for the given log file format.
112
188
  # <tt>format</tt> Logfile format. Defaults to :rails
113
189
  # Options are passd on to the LogParser.
114
- # * <tt>:aggregator</tt> Aggregator array.
115
190
  # * <tt>:database</tt> Database the controller should use.
116
- # * <tt>:echo</tt> Output debug information.
117
- # * <tt>:silent</tt> Do not output any warnings.
118
- # * <tt>:colorize</tt> Colorize output
191
+ # * <tt>:dump</tt> Yaml Dump the contrller should use.
119
192
  # * <tt>:output</tt> All report outputs get << through this output.
193
+ # * <tt>:no_progress</tt> No progress bar
120
194
  def initialize(source, options = {})
121
195
 
122
196
  @source = source
@@ -124,20 +198,17 @@ module RequestLogAnalyzer
124
198
  @aggregators = []
125
199
  @filters = []
126
200
  @output = options[:output]
201
+ @interrupted = false
127
202
 
128
- # Requester format through RequestLogAnalyzer::FileFormat and construct the parser
129
- register_file_format(@source.file_format)
130
-
131
- # Pass all warnings to every aggregator so they can do something useful with them.
132
- @source.warning = lambda { |type, message, lineno| @aggregators.each { |agg| agg.warning(type, message, lineno) } } if @source
203
+ # Register the request format for this session after checking its validity
204
+ raise "Invalid file format!" unless @source.file_format.valid?
133
205
 
134
- # Handle progress messagess
135
- @source.progress = lambda { |message, value| handle_progress(message, value) } if @source && !options[:no_progress]
136
-
137
- # Handle source change messages
138
- @source.source_changes = lambda { |change, filename| handle_source_change(change, filename) } if @source
206
+ # Install event handlers for wrnings, progress updates and source changes
207
+ @source.warning = lambda { |type, message, lineno| @aggregators.each { |agg| agg.warning(type, message, lineno) } }
208
+ @source.progress = lambda { |message, value| handle_progress(message, value) } unless options[:no_progress]
209
+ @source.source_changes = lambda { |change, filename| handle_source_change(change, filename) }
139
210
  end
140
-
211
+
141
212
  # Progress function.
142
213
  # Expects :started with file, :progress with current line and :finished or :interrupted when done.
143
214
  # <tt>message</tt> Current state (:started, :finished, :interupted or :progress).
@@ -158,46 +229,46 @@ module RequestLogAnalyzer
158
229
  @progress_bar.set(value)
159
230
  end
160
231
  end
161
-
232
+
162
233
  # Source change handler
163
234
  def handle_source_change(change, filename)
164
235
  @aggregators.each { |agg| agg.source_change(change, File.expand_path(filename, Dir.pwd)) }
165
236
  end
166
-
167
- # Adds an aggregator to the controller. The aggregator will be called for every request
237
+
238
+ # Adds an aggregator to the controller. The aggregator will be called for every request
168
239
  # that is parsed from the provided sources (see add_source)
169
- def add_aggregator(agg)
240
+ def add_aggregator(agg)
170
241
  agg = RequestLogAnalyzer::Aggregator.const_get(RequestLogAnalyzer::to_camelcase(agg)) if agg.kind_of?(Symbol)
171
242
  @aggregators << agg.new(@source, @options)
172
243
  end
173
-
244
+
174
245
  alias :>> :add_aggregator
175
-
246
+
176
247
  # Adds a request filter to the controller.
177
248
  def add_filter(filter, filter_options = {})
178
249
  filter = RequestLogAnalyzer::Filter.const_get(RequestLogAnalyzer::to_camelcase(filter)) if filter.kind_of?(Symbol)
179
- @filters << filter.new(file_format, @options.merge(filter_options))
250
+ @filters << filter.new(source.file_format, @options.merge(filter_options))
180
251
  end
181
-
252
+
182
253
  # Push a request through the entire filterchain (@filters).
183
254
  # <tt>request</tt> The request to filter.
184
255
  # Returns the filtered request or nil.
185
256
  def filter_request(request)
186
- @filters.each do |filter|
257
+ @filters.each do |filter|
187
258
  request = filter.filter(request)
188
259
  return nil if request.nil?
189
260
  end
190
261
  return request
191
262
  end
192
-
263
+
193
264
  # Push a request to all the aggregators (@aggregators).
194
- # <tt>request</tt> The request to push to the aggregators.
265
+ # <tt>request</tt> The request to push to the aggregators.
195
266
  def aggregate_request(request)
196
267
  return false unless request
197
268
  @aggregators.each { |agg| agg.aggregate(request) }
198
269
  return true
199
270
  end
200
-
271
+
201
272
  # Runs RequestLogAnalyzer
202
273
  # 1. Call prepare on every aggregator
203
274
  # 2. Generate requests from source object
@@ -207,10 +278,12 @@ module RequestLogAnalyzer
207
278
  # 5. Call report on every aggregator
208
279
  # 6. Finalize Source
209
280
  def run!
210
-
281
+
282
+ # @aggregators.each{|agg| p agg}
283
+
211
284
  @aggregators.each { |agg| agg.prepare }
212
285
  install_signal_handlers
213
-
286
+
214
287
  @source.each_request do |request|
215
288
  break if @interrupted
216
289
  aggregate_request(filter_request(request))
@@ -221,9 +294,9 @@ module RequestLogAnalyzer
221
294
  @output.header
222
295
  @aggregators.each { |agg| agg.report(@output) }
223
296
  @output.footer
224
-
297
+
225
298
  @source.finalize
226
-
299
+
227
300
  if @output.io.kind_of?(File)
228
301
  puts
229
302
  puts "Report written to: " + File.expand_path(@output.io.path)
@@ -235,7 +308,7 @@ module RequestLogAnalyzer
235
308
  @output.io.mail
236
309
  end
237
310
  end
238
-
311
+
239
312
  def install_signal_handlers
240
313
  Signal.trap("INT") do
241
314
  handle_progress(:interrupted)
@@ -243,6 +316,6 @@ module RequestLogAnalyzer
243
316
  @interrupted = true
244
317
  end
245
318
  end
246
-
319
+
247
320
  end
248
321
  end