request-log-analyzer 1.8.0 → 1.8.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (63) hide show
  1. data/.gitignore +1 -0
  2. data/bin/request-log-analyzer +2 -2
  3. data/lib/cli/database_console_init.rb +1 -1
  4. data/lib/cli/tools.rb +2 -1
  5. data/lib/mixins/gets_memory_protection.rb +1 -1
  6. data/lib/request_log_analyzer/aggregator/summarizer.rb +2 -2
  7. data/lib/request_log_analyzer/aggregator.rb +3 -3
  8. data/lib/request_log_analyzer/controller.rb +16 -12
  9. data/lib/request_log_analyzer/database.rb +5 -3
  10. data/lib/request_log_analyzer/file_format/oink.rb +1 -1
  11. data/lib/request_log_analyzer/file_format/rails3.rb +23 -9
  12. data/lib/request_log_analyzer/file_format.rb +27 -8
  13. data/lib/request_log_analyzer/filter.rb +3 -5
  14. data/lib/request_log_analyzer/output/fancy_html.rb +0 -5
  15. data/lib/request_log_analyzer/output.rb +6 -7
  16. data/lib/request_log_analyzer/source/log_parser.rb +3 -1
  17. data/lib/request_log_analyzer/source.rb +2 -6
  18. data/lib/request_log_analyzer/tracker.rb +6 -5
  19. data/lib/request_log_analyzer.rb +36 -17
  20. data/request-log-analyzer.gemspec +11 -4
  21. data/spec/integration/command_line_usage_spec.rb +3 -3
  22. data/spec/integration/mailer_spec.rb +1 -1
  23. data/spec/integration/munin_plugins_rails_spec.rb +1 -1
  24. data/spec/integration/scout_spec.rb +1 -1
  25. data/spec/lib/helpers.rb +1 -1
  26. data/spec/unit/aggregator/database_inserter_spec.rb +1 -1
  27. data/spec/unit/aggregator/summarizer_spec.rb +1 -1
  28. data/spec/unit/controller/controller_spec.rb +1 -1
  29. data/spec/unit/controller/log_processor_spec.rb +1 -1
  30. data/spec/unit/database/base_class_spec.rb +1 -1
  31. data/spec/unit/database/connection_spec.rb +1 -1
  32. data/spec/unit/database/database_spec.rb +1 -1
  33. data/spec/unit/file_format/amazon_s3_format_spec.rb +1 -1
  34. data/spec/unit/file_format/apache_format_spec.rb +1 -1
  35. data/spec/unit/file_format/common_regular_expressions_spec.rb +1 -1
  36. data/spec/unit/file_format/delayed_job_format_spec.rb +1 -1
  37. data/spec/unit/file_format/file_format_api_spec.rb +2 -2
  38. data/spec/unit/file_format/format_autodetection_spec.rb +1 -1
  39. data/spec/unit/file_format/line_definition_spec.rb +1 -1
  40. data/spec/unit/file_format/merb_format_spec.rb +1 -1
  41. data/spec/unit/file_format/mysql_format_spec.rb +1 -1
  42. data/spec/unit/file_format/oink_format_spec.rb +1 -1
  43. data/spec/unit/file_format/postgresql_format_spec.rb +1 -1
  44. data/spec/unit/file_format/rack_format_spec.rb +1 -1
  45. data/spec/unit/file_format/rails3_format_spec.rb +4 -4
  46. data/spec/unit/file_format/rails_format_spec.rb +1 -1
  47. data/spec/unit/filter/anonymize_filter_spec.rb +1 -1
  48. data/spec/unit/filter/field_filter_spec.rb +1 -1
  49. data/spec/unit/filter/filter_spec.rb +1 -1
  50. data/spec/unit/filter/timespan_filter_spec.rb +1 -1
  51. data/spec/unit/mailer_spec.rb +1 -1
  52. data/spec/unit/request_spec.rb +1 -1
  53. data/spec/unit/source/log_parser_spec.rb +1 -1
  54. data/spec/unit/tracker/duration_tracker_spec.rb +1 -1
  55. data/spec/unit/tracker/frequency_tracker_spec.rb +1 -1
  56. data/spec/unit/tracker/hourly_spread_spec.rb +1 -1
  57. data/spec/unit/tracker/numeric_value_tracker_spec.rb +1 -1
  58. data/spec/unit/tracker/timespan_tracker_spec.rb +1 -1
  59. data/spec/unit/tracker/tracker_api_spec.rb +1 -1
  60. data/spec/unit/tracker/traffic_tracker_spec.rb +1 -1
  61. data/tasks/github-gem.rake +5 -5
  62. data/tasks/request_log_analyzer.rake +102 -0
  63. metadata +56 -12
data/.gitignore CHANGED
@@ -4,6 +4,7 @@ request-log-analyzer-*.gem
4
4
  requests.db
5
5
  /pkg
6
6
  /doc
7
+ .yardoc/
7
8
  /tmp
8
9
  /classes
9
10
  /files
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env ruby
2
2
  # encoding: utf-8
3
3
 
4
- $:.unshift(File.dirname(__FILE__) + '/../lib')
4
+ $:.unshift(File.expand_path('../lib', File.dirname(__FILE__)))
5
5
  require 'request_log_analyzer'
6
6
  require 'cli/command_line_arguments'
7
7
  require 'cli/progressbar'
@@ -93,6 +93,7 @@ rescue CommandLine::Error => e
93
93
  puts " --report-amount <amount> Maximum numer of results per report."
94
94
  puts " --silent Skip the commercials (includes --no-progress)."
95
95
  puts " --yaml <filename> Dump the results in YAML format in the given file."
96
+ puts " --parse-strategy <strategy> Legal values are 'assume-correct' or 'cautious'."
96
97
  puts
97
98
  puts "Examples:"
98
99
  puts " request-log-analyzer production.log"
@@ -114,7 +115,6 @@ when :console
114
115
  require 'cli/database_console'
115
116
  DatabaseConsole.new(arguments).run!
116
117
  when :strip
117
- require File.dirname(__FILE__) + '/../lib/request_log_analyzer/log_processor'
118
118
  RequestLogAnalyzer::LogProcessor.build(:strip, arguments).run!
119
119
  else
120
120
  unless arguments[:silent]
@@ -1,5 +1,5 @@
1
1
  # Setup the include path
2
- $:.unshift(File.dirname(__FILE__) + '/..')
2
+ $:.unshift(File.expand_path('..', File.dirname(__FILE__))
3
3
 
4
4
  $database = RequestLogAnalyzer::Database.new(ENV['RLA_DBCONSOLE_DATABASE'])
5
5
  $database.load_database_schema!
data/lib/cli/tools.rb CHANGED
@@ -34,7 +34,8 @@ def install_rake_tasks(install_type = :rails)
34
34
  if install_type.to_sym == :rails
35
35
  require 'ftools'
36
36
  if File.directory?('./lib/tasks/')
37
- File.copy(File.dirname(__FILE__) + '/../../tasks/request_log_analyzer.rake', './lib/tasks/request_log_analyze.rake')
37
+ task_file = File.expand_path('../../tasks/request_log_analyzer.rake', File.dirname(__FILE__))
38
+ File.copy(task_file, './lib/tasks/request_log_analyze.rake')
38
39
  puts "Installed rake tasks."
39
40
  puts "To use, run: rake rla:report"
40
41
  else
@@ -29,7 +29,7 @@ class File
29
29
  if @last_pos.nil?
30
30
  seek(0, IO::SEEK_END)
31
31
  @last_pos = pos
32
- seek(0,0)
32
+ seek(@current_pos, IO::SEEK_SET)
33
33
  end
34
34
 
35
35
  #
@@ -32,7 +32,7 @@ module RequestLogAnalyzer::Aggregator
32
32
  # <tt>optiont</tt> The options to pass to the trackers.
33
33
  def track(tracker_klass, value_field = {}, other_options = {})
34
34
  options = value_field.kind_of?(Symbol) ? other_options.merge(:value => value_field) : value_field.merge(other_options)
35
- tracker_klass = RequestLogAnalyzer::Tracker.const_get(RequestLogAnalyzer::to_camelcase(tracker_klass)) if tracker_klass.kind_of?(Symbol)
35
+ tracker_klass = RequestLogAnalyzer::Tracker.const_get(RequestLogAnalyzer.to_camelcase(tracker_klass)) if tracker_klass.kind_of?(Symbol)
36
36
  @trackers << tracker_klass.new(options)
37
37
  end
38
38
  end
@@ -85,7 +85,7 @@ module RequestLogAnalyzer::Aggregator
85
85
  trackers_export = @trackers.inject({}) do |export, tracker|
86
86
  export[tracker.title] = tracker.to_yaml_object; export
87
87
  end
88
- YAML::dump(trackers_export)
88
+ YAML.dump(trackers_export)
89
89
  end
90
90
 
91
91
  # Call report on all trackers.
@@ -1,8 +1,8 @@
1
1
  module RequestLogAnalyzer::Aggregator
2
2
 
3
- def self.const_missing(const)
4
- RequestLogAnalyzer::load_default_class_file(self, const)
5
- end
3
+ autoload :Echo, 'request_log_analyzer/aggregator/echo'
4
+ autoload :Summarizer, 'request_log_analyzer/aggregator/summarizer'
5
+ autoload :DatabaseInserter, 'request_log_analyzer/aggregator/database_inserter'
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).
@@ -21,7 +21,7 @@ module RequestLogAnalyzer
21
21
  # <tt>arguments<tt> A CommandLine::Arguments hash containing parsed commandline parameters.
22
22
  def self.build_from_arguments(arguments)
23
23
 
24
- require File.dirname(__FILE__) + '/../mixins/gets_memory_protection' if arguments[:gets_memory_protection]
24
+ require 'mixins/gets_memory_protection' if arguments[:gets_memory_protection]
25
25
 
26
26
  options = {}
27
27
 
@@ -47,6 +47,7 @@ module RequestLogAnalyzer
47
47
  options[:mailhost] = arguments[:mailhost]
48
48
  options[:mailsubject] = arguments[:mailsubject]
49
49
  options[:silent] = arguments[:silent]
50
+ options[:parse_strategy] = arguments[:parse_strategy]
50
51
 
51
52
  # Apache format workaround
52
53
  if arguments[:rails_format]
@@ -155,7 +156,7 @@ module RequestLogAnalyzer
155
156
  if options[:output].is_a?(Class)
156
157
  output_class = options[:output]
157
158
  else
158
- output_class = RequestLogAnalyzer::Output::const_get(options[:output])
159
+ output_class = RequestLogAnalyzer::Output.const_get(options[:output])
159
160
  end
160
161
 
161
162
  output_sort = options[:report_sort].split(',').map { |s| s.to_sym }
@@ -183,14 +184,17 @@ module RequestLogAnalyzer
183
184
  end
184
185
 
185
186
  # Kickstart the controller
186
- controller = Controller.new( RequestLogAnalyzer::Source::LogParser.new(file_format, :source_files => options[:source_files]),
187
- { :output => output_instance,
188
- :database => options[:database], # FUGLY!
189
- :yaml => options[:yaml],
190
- :reset_database => options[:reset_database],
191
- :no_progress => options[:no_progress],
192
- :silent => options[:silent],
193
- })
187
+ controller =
188
+ Controller.new(RequestLogAnalyzer::Source::LogParser.new(file_format,
189
+ :source_files => options[:source_files],
190
+ :parse_strategy => options[:parse_strategy]),
191
+ { :output => output_instance,
192
+ :database => options[:database], # FUGLY!
193
+ :yaml => options[:yaml],
194
+ :reset_database => options[:reset_database],
195
+ :no_progress => options[:no_progress],
196
+ :silent => options[:silent]
197
+ })
194
198
 
195
199
  # register filters
196
200
  if options[:after] || options[:before]
@@ -283,7 +287,7 @@ module RequestLogAnalyzer
283
287
  # Adds an aggregator to the controller. The aggregator will be called for every request
284
288
  # that is parsed from the provided sources (see add_source)
285
289
  def add_aggregator(agg)
286
- agg = RequestLogAnalyzer::Aggregator.const_get(RequestLogAnalyzer::to_camelcase(agg)) if agg.kind_of?(Symbol)
290
+ agg = RequestLogAnalyzer::Aggregator.const_get(RequestLogAnalyzer.to_camelcase(agg)) if agg.kind_of?(Symbol)
287
291
  @aggregators << agg.new(@source, @options)
288
292
  end
289
293
 
@@ -291,7 +295,7 @@ module RequestLogAnalyzer
291
295
 
292
296
  # Adds a request filter to the controller.
293
297
  def add_filter(filter, filter_options = {})
294
- filter = RequestLogAnalyzer::Filter.const_get(RequestLogAnalyzer::to_camelcase(filter)) if filter.kind_of?(Symbol)
298
+ filter = RequestLogAnalyzer::Filter.const_get(RequestLogAnalyzer.to_camelcase(filter)) if filter.kind_of?(Symbol)
295
299
  @filters << filter.new(source.file_format, @options.merge(filter_options))
296
300
  end
297
301
 
@@ -3,9 +3,11 @@ require 'active_record'
3
3
 
4
4
  class RequestLogAnalyzer::Database
5
5
 
6
- def self.const_missing(const) # :nodoc:
7
- RequestLogAnalyzer::load_default_class_file(self, const)
8
- end
6
+ autoload :Connection, 'request_log_analyzer/database/connection'
7
+ autoload :Base, 'request_log_analyzer/database/base'
8
+ autoload :Request, 'request_log_analyzer/database/request'
9
+ autoload :Source, 'request_log_analyzer/database/source'
10
+ autoload :Warning, 'request_log_analyzer/database/warning'
9
11
 
10
12
  include RequestLogAnalyzer::Database::Connection
11
13
 
@@ -36,7 +36,7 @@ class RequestLogAnalyzer::FileFormat::Oink < RequestLogAnalyzer::FileFormat::Rai
36
36
  @pids ||= {}
37
37
  end
38
38
 
39
- class Request
39
+ class Request < RequestLogAnalyzer::FileFormat::Rails::Request
40
40
  # Overrides the #validate method to handle PID updating.
41
41
  def validate
42
42
  update_pids
@@ -8,11 +8,11 @@ module RequestLogAnalyzer::FileFormat
8
8
 
9
9
  extend CommonRegularExpressions
10
10
 
11
- # Started GET "/queries" for 127.0.0.1 at 2010-02-25 16:15:18
11
+ # beta4: Started GET "/" for 127.0.0.1 at Wed Jul 07 09:13:27 -0700 2010 (different time format)
12
12
  line_definition :started do |line|
13
13
  line.header = true
14
14
  line.teaser = /Started /
15
- line.regexp = /Started ([A-Z]+) "([^"]+)" for (#{ip_address}) at (#{timestamp('%Y-%m-%d %H:%M:%S')})/
15
+ line.regexp = /Started ([A-Z]+) "([^"]+)" for (#{ip_address}) at (#{timestamp('%a %b %d %H:%M:%S %z %Y')})/
16
16
 
17
17
  line.capture(:method)
18
18
  line.capture(:path)
@@ -30,14 +30,18 @@ module RequestLogAnalyzer::FileFormat
30
30
  line.capture(:format)
31
31
  end
32
32
 
33
- # Completed in 9ms (Views: 4.9ms | ActiveRecord: 0.5ms) with 200
33
+ # Completed 200 OK in 224ms (Views: 200.2ms | ActiveRecord: 3.4ms)
34
+ # Completed 302 Found in 23ms
35
+ # Completed in 189ms
34
36
  line_definition :completed do |line|
35
37
  line.footer = true
36
38
  line.teaser = /Completed /
37
- line.regexp = /Completed (\d+) .* in (\d+)ms \([^\)]*\)/
39
+ line.regexp = /Completed (\d+)? .*in (\d+)ms(?:[^(]*\(Views: ((?:\d|\.)+)ms .* ActiveRecord: ((?:\d|\.)+)ms\))?/
38
40
 
39
41
  line.capture(:status).as(:integer)
40
42
  line.capture(:duration).as(:duration, :unit => :msec)
43
+ line.capture(:view).as(:duration, :unit => :msec)
44
+ line.capture(:db).as(:duration, :unit => :msec)
41
45
  end
42
46
 
43
47
  # ActionView::Template::Error (undefined local variable or method `field' for #<Class>) on line #3 of /Users/willem/Code/warehouse/app/views/queries/execute.csv.erb:
@@ -69,18 +73,28 @@ module RequestLogAnalyzer::FileFormat
69
73
  analyze.frequency :status, :title => 'HTTP statuses returned'
70
74
 
71
75
  analyze.duration :duration, :category => REQUEST_CATEGORIZER, :title => "Request duration", :line_type => :completed
72
- # analyze.duration :view, :category => REQUEST_CATEGORIZER, :title => "View rendering time", :line_type => :completed
73
- # analyze.duration :db, :category => REQUEST_CATEGORIZER, :title => "Database time", :line_type => :completed
76
+ analyze.duration :view, :category => REQUEST_CATEGORIZER, :title => "View rendering time", :line_type => :completed
77
+ analyze.duration :db, :category => REQUEST_CATEGORIZER, :title => "Database time", :line_type => :completed
74
78
 
75
79
  analyze.frequency :category => REQUEST_CATEGORIZER, :title => 'Process blockers (> 1 sec duration)',
76
80
  :if => lambda { |request| request[:duration] && request[:duration] > 1.0 }
77
81
  end
78
82
 
79
83
  class Request < RequestLogAnalyzer::Request
80
- def convert_timestamp(value, defintion)
81
- value.gsub(/[^0-9]/, '')[0...14].to_i
84
+ # Used to handle conversion of abbrev. month name to a digit
85
+ MONTHS = %w(Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec)
86
+
87
+ def convert_timestamp(value, definition)
88
+ value.gsub!(/\W/,'')
89
+ time_as_str = value[-4..-1] # year
90
+ # convert the month to a 2-digit representation
91
+ month = MONTHS.index(value[3..5])+1
92
+ month < 10 ? time_as_str << "0#{month}" : time_as_str << month
93
+
94
+ time_as_str << value[6..13] # day of month + time
95
+ time_as_str.to_i
82
96
  end
83
97
  end
84
98
 
85
99
  end
86
- end
100
+ end
@@ -1,8 +1,17 @@
1
1
  module RequestLogAnalyzer::FileFormat
2
2
 
3
- def self.const_missing(const) # :nodoc:
4
- RequestLogAnalyzer::load_default_class_file(self, const)
5
- end
3
+ autoload :Rails, 'request_log_analyzer/file_format/rails'
4
+ autoload :Rails3, 'request_log_analyzer/file_format/rails3'
5
+ autoload :RailsDevelopment, 'request_log_analyzer/file_format/rails_development'
6
+ autoload :Oink, 'request_log_analyzer/file_format/oink'
7
+ autoload :Rack, 'request_log_analyzer/file_format/rack'
8
+ autoload :Merb, 'request_log_analyzer/file_format/merb'
9
+ autoload :Mysql, 'request_log_analyzer/file_format/mysql'
10
+ autoload :Postgresql, 'request_log_analyzer/file_format/postgresql'
11
+ autoload :DelayedJob, 'request_log_analyzer/file_format/delayed_job'
12
+ autoload :DelayedJob2, 'request_log_analyzer/file_format/delayed_job2'
13
+ autoload :Apache, 'request_log_analyzer/file_format/apache'
14
+ autoload :AmazonS3, 'request_log_analyzer/file_format/amazon_s3'
6
15
 
7
16
  # Loads a FileFormat::Base subclass instance.
8
17
  # You can provide:
@@ -24,7 +33,7 @@ module RequestLogAnalyzer::FileFormat
24
33
  # load a format from a ruby file
25
34
  require file_format
26
35
 
27
- const = RequestLogAnalyzer::to_camelcase(File.basename(file_format, '.rb'))
36
+ const = RequestLogAnalyzer.to_camelcase(File.basename(file_format, '.rb'))
28
37
  if RequestLogAnalyzer::FileFormat.const_defined?(const)
29
38
  klass = RequestLogAnalyzer::FileFormat.const_get(const)
30
39
  elsif Object.const_defined?(const)
@@ -35,7 +44,7 @@ module RequestLogAnalyzer::FileFormat
35
44
 
36
45
  else
37
46
  # load a provided file format
38
- klass = RequestLogAnalyzer::FileFormat.const_get(RequestLogAnalyzer::to_camelcase(file_format))
47
+ klass = RequestLogAnalyzer::FileFormat.const_get(RequestLogAnalyzer.to_camelcase(file_format))
39
48
  end
40
49
 
41
50
  # check the returned klass to see if it can be used
@@ -47,7 +56,7 @@ module RequestLogAnalyzer::FileFormat
47
56
 
48
57
  # Returns an array of all FileFormat instances that are shipped with request-log-analyzer by default.
49
58
  def self.all_formats
50
- @all_formats ||= Dir[File.dirname(__FILE__) + '/file_format/*.rb'].map do |file|
59
+ @all_formats ||= Dir[File.expand_path('file_format/*.rb', File.dirname(__FILE__))].map do |file|
51
60
  self.load(File.basename(file, '.rb'))
52
61
  end
53
62
  end
@@ -247,11 +256,21 @@ module RequestLogAnalyzer::FileFormat
247
256
  request_class.create(self, *hashes)
248
257
  end
249
258
 
250
- # Checks whether the line definitions form a valid language.
251
- # A file format should have at least a header and a footer line type
259
+ # Checks whether the file format is valid so it can be safely used with RLA.
252
260
  def valid?
261
+ valid_line_definitions? && valid_request_class?
262
+ end
263
+
264
+ # Checks whether the line definitions form a valid language.
265
+ # A file format should have at least a header and a footer line type
266
+ def valid_line_definitions?
253
267
  line_definitions.any? { |(name, ld)| ld.header } && line_definitions.any? { |(name, ld)| ld.footer }
254
268
  end
269
+
270
+ # Checks whether the request class inherits from the base Request class.
271
+ def valid_request_class?
272
+ request_class.ancestors.include?(RequestLogAnalyzer::Request)
273
+ end
255
274
 
256
275
  # Returns true if this language captures the given symbol in one of its line definitions
257
276
  def captures?(name)
@@ -1,10 +1,8 @@
1
1
  module RequestLogAnalyzer::Filter
2
2
 
3
- # Filter class loader using const_missing
4
- # This function will automatically load the class file based on the name of the class
5
- def self.const_missing(const)
6
- RequestLogAnalyzer::load_default_class_file(self, const)
7
- end
3
+ autoload :Field, 'request_log_analyzer/filter/field'
4
+ autoload :Timespan, 'request_log_analyzer/filter/timespan'
5
+ autoload :Anonymize, 'request_log_analyzer/filter/anonymize'
8
6
 
9
7
  # Base filter class used to filter input requests.
10
8
  # All filters should interit from this base.
@@ -10,11 +10,6 @@ module RequestLogAnalyzer::Output
10
10
 
11
11
  class FancyHTML < HTML
12
12
 
13
- # Load class files if needed
14
- def self.const_missing(const)
15
- RequestLogAnalyzer::load_default_class_file(self, const)
16
- end
17
-
18
13
  def report_tracker(tracker)
19
14
  case tracker
20
15
  when RequestLogAnalyzer::Tracker::HourlySpread then report_hourly_spread(tracker)
@@ -1,11 +1,10 @@
1
1
  # Module for generating output
2
2
  module RequestLogAnalyzer::Output
3
3
 
4
- # Load class files if needed
5
- def self.const_missing(const)
6
- RequestLogAnalyzer::load_default_class_file(self, const)
7
- end
8
-
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
+
9
8
  # Loads a Output::Base subclass instance.
10
9
  def self.load(file_format, *args)
11
10
 
@@ -21,7 +20,7 @@ module RequestLogAnalyzer::Output
21
20
  elsif file_format.kind_of?(String) && File.exist?(file_format)
22
21
  # load a format from a ruby file
23
22
  require file_format
24
- const = RequestLogAnalyzer::to_camelcase(File.basename(file_format, '.rb'))
23
+ const = RequestLogAnalyzer.to_camelcase(File.basename(file_format, '.rb'))
25
24
  if RequestLogAnalyzer::FileFormat.const_defined?(const)
26
25
  klass = RequestLogAnalyzer::Output.const_get(const)
27
26
  elsif Object.const_defined?(const)
@@ -32,7 +31,7 @@ module RequestLogAnalyzer::Output
32
31
 
33
32
  else
34
33
  # load a provided file format
35
- klass = RequestLogAnalyzer::Output.const_get(RequestLogAnalyzer::to_camelcase(file_format))
34
+ klass = RequestLogAnalyzer::Output.const_get(RequestLogAnalyzer.to_camelcase(file_format))
36
35
  end
37
36
 
38
37
  # check the returned klass to see if it can be used
@@ -43,7 +43,9 @@ module RequestLogAnalyzer::Source
43
43
  @progress_handler = nil
44
44
 
45
45
  @options[:parse_strategy] ||= DEFAULT_PARSE_STRATEGY
46
- raise "Unknown parse strategy" unless PARSE_STRATEGIES.include?(@options[:parse_strategy])
46
+ unless PARSE_STRATEGIES.include?(@options[:parse_strategy])
47
+ raise "Unknown parse strategy: #{@options[@parse_strategy]}"
48
+ end
47
49
  end
48
50
 
49
51
  # Reads the input, which can either be a file, sequence of files or STDIN to parse
@@ -8,12 +8,8 @@
8
8
  # - Currently, RequestLogAnalyzer::Source::LogParser is the only implemented source.
9
9
  module RequestLogAnalyzer::Source
10
10
 
11
- # Loads constants that reside in the RequestLogAnalyzer::Source namespace. This function uses
12
- # RequestLogAnalyzer::load_default_class_file to load the file in which the constant is declared.
13
- # <tt>const</tt>:: The constant to load in the RequestLogAnalyzer::Source namespace.
14
- def self.const_missing(const)
15
- RequestLogAnalyzer::load_default_class_file(self, const)
16
- end
11
+ autoload :LogParser, 'request_log_analyzer/source/log_parser'
12
+ autoload :DatabaseLoader, 'request_log_analyzer/source/database_loader'
17
13
 
18
14
  # The base Source class. All other sources should inherit from this class.
19
15
  #
@@ -1,10 +1,11 @@
1
1
  module RequestLogAnalyzer::Tracker
2
2
 
3
- # const_missing: this function is used to load subclasses in the RequestLogAnalyzer::Track namespace.
4
- # It will automatically load the required file based on the class name
5
- def self.const_missing(const)
6
- RequestLogAnalyzer::load_default_class_file(self, const)
7
- end
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'
8
9
 
9
10
  # Base Tracker class. All other trackers inherit from this class
10
11
  #
@@ -4,40 +4,59 @@ require 'date'
4
4
  Encoding.default_external = 'binary' if defined? Encoding and Encoding.respond_to? 'default_external='
5
5
 
6
6
  # RequestLogAnalyzer is the base namespace in which all functionality of RequestLogAnalyzer is implemented.
7
+ # This module itselfs contains some functions to help with class and source file loading. The actual
8
+ # application startup code resides in the {RequestLogAnalyzer::Controller} class.
7
9
  #
8
- # - This module itselfs contains some functions to help with class and source file loading.
9
- # - The actual application resides in the RequestLogAnalyzer::Controller class.
10
+ # The {RequestLogAnalyzer::VERSION} constant can be used to determine what version of request-log-analyzer
11
+ # is running.
10
12
  module RequestLogAnalyzer
11
13
 
12
14
  # The current version of request-log-analyzer.
13
15
  # Do not change the value by hand; it will be updated automatically by the gem release script.
14
- VERSION = "1.8.0"
16
+ VERSION = "1.8.1"
15
17
 
16
- # Loads constants in the RequestLogAnalyzer namespace using self.load_default_class_file(base, const)
17
- # <tt>const</tt>:: The constant that is not yet loaded in the RequestLogAnalyzer namespace. This should be passed as a string or symbol.
18
- def self.const_missing(const)
19
- load_default_class_file(RequestLogAnalyzer, const)
20
- end
21
18
 
22
- # Loads constants that reside in the RequestLogAnalyzer tree using the constant name
23
- # and its base constant to determine the filename.
24
- # <tt>base</tt>:: The base constant to load the constant from. This should be Foo when the constant Foo::Bar is being loaded.
25
- # <tt>const</tt>:: The constant to load from the base constant as a string or symbol. This should be 'Bar' or :Bar when the constant Foo::Bar is being loaded.
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.
26
39
  def self.load_default_class_file(base, const)
27
40
  require "#{to_underscore("#{base.name}::#{const}")}"
28
41
  base.const_get(const) if base.const_defined?(const)
29
42
  end
30
43
 
31
- # Convert a string/symbol in camelcase (RequestLogAnalyzer::Controller) to underscores (request_log_analyzer/controller)
32
- # This function can be used to load the file (using require) in which the given constant is defined.
33
- # <tt>str</tt>:: The string to convert in the following format: <tt>ModuleName::ClassName</tt>
44
+ # Convert a string/symbol in camelcase ({RequestLogAnalyzer::Controller}) to underscores
45
+ # (<tt>request_log_analyzer/controller</tt>). This function can be used to load the file (using
46
+ # <tt>require</tt>) in which the given constant is defined.
47
+ #
48
+ # @param [#to_s] str The string-like to convert in the following format: <tt>ModuleName::ClassName</tt>.
49
+ # @return [String] The input string converted to underscore form.
34
50
  def self.to_underscore(str)
35
51
  str.to_s.gsub(/::/, '/').gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').gsub(/([a-z\d])([A-Z])/,'\1_\2').tr("-", "_").downcase
36
52
  end
37
53
 
38
54
  # Convert a string/symbol in underscores (<tt>request_log_analyzer/controller</tt>) to camelcase
39
- # (<tt>RequestLogAnalyzer::Controller</tt>). This can be used to find the class that is defined in a given filename.
40
- # <tt>str</tt>:: The string to convert in the following format: <tt>module_name/class_name</tt>
55
+ # ({RequestLogAnalyzer::Controller}). This can be used to find the class that is defined in a given
56
+ # filename.
57
+ #
58
+ # @param [#to_s] str The string-like to convert in the following format: <tt>module_name/class_name</tt>.
59
+ # @return [String] The input string converted to camelcase form.
41
60
  def self.to_camelcase(str)
42
61
  str.to_s.gsub(/\/(.?)/) { "::" + $1.upcase }.gsub(/(^|_)(.)/) { $2.upcase }
43
62
  end
@@ -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.8.0"
6
- s.date = "2010-06-30"
5
+ s.version = "1.8.1"
6
+ s.date = "2010-08-31"
7
7
 
8
8
  s.rubyforge_project = 'r-l-a'
9
9
 
@@ -27,8 +27,15 @@ Gem::Specification.new do |s|
27
27
 
28
28
  s.requirements << "To use the database inserter, ActiveRecord and an appropriate database adapter are required."
29
29
 
30
- s.add_development_dependency('rspec', '>= 1.2.4')
31
- s.add_development_dependency('git', '>= 1.1.0')
30
+ s.add_development_dependency('rake')
31
+ s.add_development_dependency('rspec')
32
+
33
+ s.add_development_dependency('activerecord')
34
+ s.add_development_dependency('sqlite3-ruby')
35
+
36
+ s.add_development_dependency('git')
37
+ s.add_development_dependency('gemcutter')
38
+
32
39
 
33
40
  s.authors = ['Willem van Bergen', 'Bart ten Brinke']
34
41
  s.email = ['willem@railsdoctors.com', 'bart@railsdoctors.com']
@@ -1,4 +1,4 @@
1
- require File.dirname(__FILE__) + '/../spec_helper.rb'
1
+ require 'spec_helper'
2
2
 
3
3
  describe RequestLogAnalyzer, 'running from command line' do
4
4
 
@@ -38,7 +38,7 @@ describe RequestLogAnalyzer, 'running from command line' do
38
38
 
39
39
  it "should not write output with the --silent option" do
40
40
  output = run("#{log_fixture(:rails_1x)} --silent --file #{temp_output_file(:report)}")
41
- output.to_s.should eql("")
41
+ output.should be_empty
42
42
  File.exist?(temp_output_file(:report)).should be_true
43
43
  end
44
44
 
@@ -85,7 +85,7 @@ describe RequestLogAnalyzer, 'running from command line' do
85
85
  it "should dump the results to a YAML file" do
86
86
  run("#{log_fixture(:rails_1x)} --yaml #{temp_output_file(:yaml)}")
87
87
  File.exist?(temp_output_file(:yaml)).should be_true
88
- YAML::load(File.read(temp_output_file(:yaml))).should have_at_least(1).item
88
+ YAML.load(File.read(temp_output_file(:yaml))).should have_at_least(1).item
89
89
  end
90
90
 
91
91
  it "should parse 4 requests from the standard input" do
@@ -1,4 +1,4 @@
1
- require File.dirname(__FILE__) + '/../spec_helper.rb'
1
+ require 'spec_helper'
2
2
  require 'socket'
3
3
 
4
4
  describe RequestLogAnalyzer, 'running mailer integration' do
@@ -1,4 +1,4 @@
1
- require File.dirname(__FILE__) + '/../spec_helper.rb'
1
+ require 'spec_helper'
2
2
 
3
3
  describe RequestLogAnalyzer, 'when harvesting like munin-plugins-rails the YAML output' do
4
4
 
@@ -1,4 +1,4 @@
1
- require File.dirname(__FILE__) + '/../spec_helper.rb'
1
+ require 'spec_helper'
2
2
 
3
3
  def capture_stdout_and_stderr_with_warnings_on
4
4
  $stdout, $stderr, warnings, $VERBOSE =
data/spec/lib/helpers.rb CHANGED
@@ -53,7 +53,7 @@ module RequestLogAnalyzer::Spec::Helpers
53
53
  # Check if a given string can be found in the given file
54
54
  # Returns the line number if found, nil otherwise
55
55
  def find_string_in_file(string, file, options = {})
56
- return nil unless File::exists?(file)
56
+ return nil unless File.exists?(file)
57
57
 
58
58
  line_counter = 0
59
59
 
@@ -1,4 +1,4 @@
1
- require File.dirname(__FILE__) + '/../../spec_helper'
1
+ require 'spec_helper'
2
2
 
3
3
  describe RequestLogAnalyzer::Aggregator::DatabaseInserter do
4
4
 
@@ -1,4 +1,4 @@
1
- require File.dirname(__FILE__) + '/../../spec_helper'
1
+ require 'spec_helper'
2
2
 
3
3
  describe RequestLogAnalyzer::Aggregator::Summarizer do
4
4
 
@@ -1,4 +1,4 @@
1
- require File.dirname(__FILE__) + '/../../spec_helper'
1
+ require 'spec_helper'
2
2
 
3
3
  describe RequestLogAnalyzer::Controller do
4
4
 
@@ -1,4 +1,4 @@
1
- require File.dirname(__FILE__) + '/../../spec_helper'
1
+ require 'spec_helper'
2
2
 
3
3
  require 'request_log_analyzer/log_processor'
4
4
 
@@ -1,4 +1,4 @@
1
- require File.dirname(__FILE__) + '/../../spec_helper'
1
+ require 'spec_helper'
2
2
 
3
3
  describe RequestLogAnalyzer::Database::Base do
4
4
 
@@ -1,4 +1,4 @@
1
- require File.dirname(__FILE__) + '/../../spec_helper'
1
+ require 'spec_helper'
2
2
 
3
3
  describe RequestLogAnalyzer::Database::Connection do
4
4
  describe '.from_string' do
@@ -1,4 +1,4 @@
1
- require File.dirname(__FILE__) + '/../../spec_helper'
1
+ require 'spec_helper'
2
2
 
3
3
  describe RequestLogAnalyzer::Database do
4
4
 
@@ -1,4 +1,4 @@
1
- require File.dirname(__FILE__) + '/../../spec_helper'
1
+ require 'spec_helper'
2
2
 
3
3
  describe RequestLogAnalyzer::FileFormat::AmazonS3 do
4
4
 
@@ -1,4 +1,4 @@
1
- require File.dirname(__FILE__) + '/../../spec_helper'
1
+ require 'spec_helper'
2
2
 
3
3
  describe RequestLogAnalyzer::FileFormat::Apache do
4
4
 
@@ -1,4 +1,4 @@
1
- require File.dirname(__FILE__) + '/../../spec_helper'
1
+ require 'spec_helper'
2
2
 
3
3
  describe RequestLogAnalyzer::FileFormat::CommonRegularExpressions do
4
4
 
@@ -1,4 +1,4 @@
1
- require File.dirname(__FILE__) + '/../../spec_helper'
1
+ require 'spec_helper'
2
2
 
3
3
  describe RequestLogAnalyzer::FileFormat::DelayedJob do
4
4
 
@@ -1,4 +1,4 @@
1
- require File.dirname(__FILE__) + '/../../spec_helper'
1
+ require 'spec_helper'
2
2
 
3
3
  describe RequestLogAnalyzer::FileFormat do
4
4
 
@@ -60,7 +60,7 @@ describe RequestLogAnalyzer::FileFormat do
60
60
  end
61
61
 
62
62
  it "should load a provided format file" do
63
- format_filename = File.dirname(__FILE__) + '/../../lib/testing_format.rb'
63
+ format_filename = File.expand_path('../../lib/testing_format.rb', File.dirname(__FILE__))
64
64
  @file_format = RequestLogAnalyzer::FileFormat.load(format_filename)
65
65
  @file_format.should be_kind_of(TestingFormat)
66
66
  end
@@ -1,4 +1,4 @@
1
- require File.dirname(__FILE__) + '/../../spec_helper'
1
+ require 'spec_helper'
2
2
 
3
3
  describe RequestLogAnalyzer::FileFormat do
4
4
 
@@ -1,4 +1,4 @@
1
- require File.dirname(__FILE__) + '/../../spec_helper'
1
+ require 'spec_helper'
2
2
 
3
3
  describe RequestLogAnalyzer::LineDefinition do
4
4
 
@@ -1,4 +1,4 @@
1
- require File.dirname(__FILE__) + '/../../spec_helper'
1
+ require 'spec_helper'
2
2
 
3
3
  describe RequestLogAnalyzer::FileFormat::Merb do
4
4
 
@@ -1,4 +1,4 @@
1
- require File.dirname(__FILE__) + '/../../spec_helper'
1
+ require 'spec_helper'
2
2
 
3
3
  describe RequestLogAnalyzer::FileFormat::Mysql do
4
4
 
@@ -1,4 +1,4 @@
1
- require File.dirname(__FILE__) + '/../../spec_helper'
1
+ require 'spec_helper'
2
2
 
3
3
  describe RequestLogAnalyzer::FileFormat::Oink do
4
4
  describe '.create' do
@@ -1,4 +1,4 @@
1
- require File.dirname(__FILE__) + '/../../spec_helper'
1
+ require 'spec_helper'
2
2
 
3
3
  describe RequestLogAnalyzer::FileFormat::Postgresql do
4
4
 
@@ -1,4 +1,4 @@
1
- require File.dirname(__FILE__) + '/../../spec_helper'
1
+ require 'spec_helper'
2
2
 
3
3
  describe RequestLogAnalyzer::FileFormat::Rack do
4
4
 
@@ -10,7 +10,7 @@ describe RequestLogAnalyzer::FileFormat::Rails do
10
10
  before(:each) { @file_format = RequestLogAnalyzer::FileFormat.load(:rails3) }
11
11
 
12
12
  it "should parse :started lines correctly" do
13
- line = 'Started GET "/queries" for 127.0.0.1 at 2010-02-25 16:15:18'
13
+ line = 'Started GET "/queries" for 127.0.0.1 at Thu Feb 25 16:15:18 -0800 2010'
14
14
  @file_format.should parse_line(line).as(:started).and_capture(:method => 'GET',
15
15
  :path => '/queries', :ip => '127.0.0.1', :timestamp => 20100225161518)
16
16
  end
@@ -50,7 +50,7 @@ describe RequestLogAnalyzer::FileFormat::Rails do
50
50
 
51
51
  it "should parse a successful request correctly" do
52
52
  log = <<-EOLOG
53
- Started GET "/" for 127.0.0.1 at 2010-03-19 06:40:41
53
+ Started GET "/" for 127.0.0.1 at Fri Mar 19 06:40:41 -0700 2010
54
54
  Processing by QueriesController#index as HTML
55
55
  SQL (16.3ms) SHOW TABLES
56
56
  Query Load (32.0ms) SELECT `queries`.* FROM `queries`
@@ -68,7 +68,7 @@ describe RequestLogAnalyzer::FileFormat::Rails do
68
68
 
69
69
  it "should parse an unroutable request correctly" do
70
70
  log = <<-EOLOG
71
- Started GET "/404" for 127.0.0.1 at 2010-03-19 06:40:57
71
+ Started GET "/404" for 127.0.0.1 at Fri Mar 19 06:40:57 -0700 2010
72
72
 
73
73
  ActionController::RoutingError (No route matches "/404"):
74
74
 
@@ -87,7 +87,7 @@ describe RequestLogAnalyzer::FileFormat::Rails do
87
87
 
88
88
  it "should parse a failing request correctly" do
89
89
  log = <<-EOLOG
90
- Started POST "/queries/397638749/execute.csv" for 127.0.0.1 at 2010-03-01 18:44:33
90
+ Started POST "/queries/397638749/execute.csv" for 127.0.0.1 at Mon Mar 01 18:44:33 -0800 2010
91
91
  Processing by QueriesController#execute as CSV
92
92
  Parameters: {"commit"=>"Run query", "authenticity_token"=>"pz9WcxkcrlG/43eg6BgSAnJL7yIsaffuHbYxPHUsUzQ=", "id"=>"397638749"}
93
93
 
@@ -1,4 +1,4 @@
1
- require File.dirname(__FILE__) + '/../../spec_helper'
1
+ require 'spec_helper'
2
2
 
3
3
  describe RequestLogAnalyzer::FileFormat::Rails do
4
4
 
@@ -1,4 +1,4 @@
1
- require File.dirname(__FILE__) + '/../../spec_helper'
1
+ require 'spec_helper'
2
2
 
3
3
  describe RequestLogAnalyzer::Filter::Anonymize, 'anonymize request' do
4
4
 
@@ -1,4 +1,4 @@
1
- require File.dirname(__FILE__) + '/../../spec_helper'
1
+ require 'spec_helper'
2
2
 
3
3
  describe RequestLogAnalyzer::Filter::Field, 'string in accept mode' do
4
4
 
@@ -1,4 +1,4 @@
1
- require File.dirname(__FILE__) + '/../../spec_helper'
1
+ require 'spec_helper'
2
2
 
3
3
  describe RequestLogAnalyzer::Filter::Base, 'base filter' do
4
4
 
@@ -1,4 +1,4 @@
1
- require File.dirname(__FILE__) + '/../../spec_helper'
1
+ require 'spec_helper'
2
2
 
3
3
  describe RequestLogAnalyzer::Filter::Timespan, 'both before and after' do
4
4
 
@@ -1,4 +1,4 @@
1
- require File.dirname(__FILE__) + '/../spec_helper'
1
+ require 'spec_helper'
2
2
 
3
3
  describe RequestLogAnalyzer::Mailer, 'mailer' do
4
4
 
@@ -1,4 +1,4 @@
1
- require File.dirname(__FILE__) + '/../spec_helper'
1
+ require 'spec_helper'
2
2
 
3
3
  describe RequestLogAnalyzer::Request do
4
4
 
@@ -1,4 +1,4 @@
1
- require File.dirname(__FILE__) + '/../../spec_helper'
1
+ require 'spec_helper'
2
2
 
3
3
  describe RequestLogAnalyzer::Source::LogParser, :requests do
4
4
 
@@ -1,4 +1,4 @@
1
- require File.dirname(__FILE__) + '/../../spec_helper'
1
+ require 'spec_helper'
2
2
 
3
3
  describe RequestLogAnalyzer::Tracker::Duration do
4
4
 
@@ -1,4 +1,4 @@
1
- require File.dirname(__FILE__) + '/../../spec_helper'
1
+ require 'spec_helper'
2
2
 
3
3
  describe RequestLogAnalyzer::Tracker::Frequency do
4
4
 
@@ -1,4 +1,4 @@
1
- require File.dirname(__FILE__) + '/../../spec_helper'
1
+ require 'spec_helper'
2
2
 
3
3
  describe RequestLogAnalyzer::Tracker::HourlySpread do
4
4
 
@@ -1,4 +1,4 @@
1
- require File.dirname(__FILE__) + '/../../spec_helper'
1
+ require 'spec_helper'
2
2
 
3
3
  describe RequestLogAnalyzer::Tracker::NumericValue do
4
4
 
@@ -1,4 +1,4 @@
1
- require File.dirname(__FILE__) + '/../../spec_helper'
1
+ require 'spec_helper'
2
2
 
3
3
  describe RequestLogAnalyzer::Tracker::Timespan do
4
4
 
@@ -1,4 +1,4 @@
1
- require File.dirname(__FILE__) + '/../../spec_helper'
1
+ require 'spec_helper'
2
2
 
3
3
  describe RequestLogAnalyzer::Tracker::Base do
4
4
 
@@ -1,4 +1,4 @@
1
- require File.dirname(__FILE__) + '/../../spec_helper'
1
+ require 'spec_helper'
2
2
 
3
3
  describe RequestLogAnalyzer::Tracker::Traffic do
4
4
 
@@ -134,8 +134,8 @@ module GithubGem
134
134
  desc "Release the next version of the gem, by incrementing the last version segment by 1"
135
135
  task(:next => [:next_version] + release_tasks) { release_task }
136
136
 
137
- desc "Release the next version of the gem, using a bump increment (0.0.1)"
138
- task(:bump => [:next_bump_version] + release_tasks) { release_task }
137
+ desc "Release the next version of the gem, using a patch increment (0.0.1)"
138
+ task(:patch => [:next_patch_version] + release_tasks) { release_task }
139
139
 
140
140
  desc "Release the next version of the gem, using a minor increment (0.1.0)"
141
141
  task(:minor => [:next_minor_version] + release_tasks) { release_task }
@@ -152,7 +152,7 @@ module GithubGem
152
152
  task(:commit_modified_files) { commit_modified_files_task }
153
153
 
154
154
  task(:next_version) { next_version_task }
155
- task(:next_bump_version) { next_version_task(:bump) }
155
+ task(:next_patch_version) { next_version_task(:patch) }
156
156
  task(:next_minor_version) { next_version_task(:minor) }
157
157
  task(:next_major_version) { next_version_task(:major) }
158
158
 
@@ -187,7 +187,7 @@ module GithubGem
187
187
  next_version = newest_version.segments
188
188
  increment_index = case increment
189
189
  when :micro then 3
190
- when :bump then 2
190
+ when :patch then 2
191
191
  when :minor then 1
192
192
  when :major then 0
193
193
  else next_version.length - 1
@@ -217,7 +217,7 @@ module GithubGem
217
217
 
218
218
  def check_version_task
219
219
  raise "#{ENV['VERSION']} is not a valid version number!" if ENV['VERSION'] && !Gem::Version.correct?(ENV['VERSION'])
220
- proposed_version = Gem::Version.new(ENV['VERSION'] || gemspec.version)
220
+ proposed_version = Gem::Version.new(ENV['VERSION'].dup || gemspec.version)
221
221
  raise "This version (#{proposed_version}) is not higher than the highest tagged version (#{newest_version})" if newest_version >= proposed_version
222
222
  end
223
223
 
@@ -23,4 +23,106 @@ namespace :rla do
23
23
  end
24
24
  end
25
25
 
26
+ # Split a single logfile into multiple multiple logfiles based on PID information
27
+ # provided in the log lines.
28
+ #
29
+ # Usage:
30
+ # rake rla:split_log FILE=logfile
31
+ #
32
+ # Example:
33
+ # $> rake rla:split_log FILE=log/development.log
34
+ # Splitting the Rails log file by pid using the request-log-analyzer gem.
35
+ #
36
+ # Log file was split into the following files:
37
+ # split_log_development.catchall.log # <- log lines without a pid
38
+ # split_log_development.14634.log
39
+ # split_log_development.31277.log
40
+ # split_log_development.31279.log
41
+ #
42
+ # To analyze type:
43
+ # request-log-analyzer /log/split_log_development.*.log
44
+ desc "Split a logfile into seperate files by PID"
45
+ task :split do
46
+
47
+ if ENV['FILE']
48
+ logfile = ENV['FILE']
49
+ if logfile.nil?
50
+ puts "Please provide a logfile to split"
51
+ exit(0)
52
+ elsif !File.exist?(logfile)
53
+ puts "the logfile name you provided can not be found"
54
+ exit(0)
55
+ end
56
+
57
+ # Inline class def. Ugly, yet portable.
58
+ class LogSplitter
59
+ attr_reader :files_by_pid, :catchall, :filename, :rla_call_string
60
+
61
+ # All generated files should contain this prefix to allow for easy glob file matches
62
+ PREFIX = 'split_log_'
63
+ # The logfile pattern that captures the pid, this will be log format specific. Using Logging::Logger
64
+ # we define: Logging::Layouts::Pattern(:pattern => "%d pid:%p [%c:%l] %m [%F:%L]\n")
65
+ # PID_PATTERN = Regexp.union(/.*\[(\d+)\]\:/, /pid:(\d+)/)
66
+ PID_PATTERN = /(?-mix:.*\[(\d+)\]\:)|(?-mix:pid:(\d+))/ #
67
+
68
+ # Currently expects the filename to exist in the local directory for ease of implementation
69
+ def initialize(filename_to_split)
70
+ @filename = filename_to_split
71
+ directory = File.dirname(@filename) + '/'
72
+ directory = '' if @directory == './'
73
+ basename = @filename.split('/').last.gsub('.log', '')
74
+ @rla_call_string = "#{directory}#{PREFIX}#{basename}.*.log"
75
+
76
+ @files_by_pid =
77
+ Hash.new {|hash, pid_key| hash[pid_key] = File.open("#{directory}#{PREFIX}#{basename}.#{pid_key}.log", 'w') }
78
+ @catchall = File.open("#{directory}#{PREFIX}#{basename}.catchall.log", 'w')
79
+ end
80
+
81
+ def split
82
+ last_pid = nil
83
+ File.open(filename, 'r') do |f|
84
+ while(line = f.gets)
85
+ outfile =
86
+ if match_data = line.match(PID_PATTERN)
87
+ pid = match_data.captures[0]
88
+ last_pid = pid
89
+ files_by_pid[pid]
90
+ elsif last_pid
91
+ # handle cases where a single log call results in multiple lines of output.
92
+ files_by_pid[last_pid]
93
+ else
94
+ catchall
95
+ end
96
+ outfile.puts line
97
+ end
98
+ end
99
+ end
100
+
101
+ def close_files
102
+ @files_by_pid.values.map(&:close)
103
+ @catchall.close
104
+ end
105
+ end
106
+ # End inline class def
107
+
108
+ puts "Splitting the Rails log file by pid using the request-log-analyzer gem."
109
+
110
+ log_splitter = LogSplitter.new(logfile)
111
+ log_splitter.split
112
+ log_splitter.close_files
113
+
114
+ puts ''
115
+ puts ''
116
+ puts 'Log file was split into the following files:'
117
+ puts ' ' + log_splitter.catchall.path
118
+ log_splitter.files_by_pid.values.each {|f| puts ' ' + f.path }
119
+ puts ''
120
+ puts 'To analyze type:'
121
+ puts " request-log-analyzer #{log_splitter.rla_call_string}"
122
+ puts ''
123
+ puts ''
124
+ end
125
+
126
+ end
127
+
26
128
  end
metadata CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
5
5
  segments:
6
6
  - 1
7
7
  - 8
8
- - 0
9
- version: 1.8.0
8
+ - 1
9
+ version: 1.8.1
10
10
  platform: ruby
11
11
  authors:
12
12
  - Willem van Bergen
@@ -15,37 +15,81 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2010-06-30 00:00:00 +02:00
18
+ date: 2010-08-31 00:00:00 -07:00
19
19
  default_executable: request-log-analyzer
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
22
- name: rspec
22
+ name: rake
23
23
  prerelease: false
24
24
  requirement: &id001 !ruby/object:Gem::Requirement
25
25
  requirements:
26
26
  - - ">="
27
27
  - !ruby/object:Gem::Version
28
28
  segments:
29
- - 1
30
- - 2
31
- - 4
32
- version: 1.2.4
29
+ - 0
30
+ version: "0"
33
31
  type: :development
34
32
  version_requirements: *id001
35
33
  - !ruby/object:Gem::Dependency
36
- name: git
34
+ name: rspec
37
35
  prerelease: false
38
36
  requirement: &id002 !ruby/object:Gem::Requirement
39
37
  requirements:
40
38
  - - ">="
41
39
  - !ruby/object:Gem::Version
42
40
  segments:
43
- - 1
44
- - 1
45
41
  - 0
46
- version: 1.1.0
42
+ version: "0"
47
43
  type: :development
48
44
  version_requirements: *id002
45
+ - !ruby/object:Gem::Dependency
46
+ name: activerecord
47
+ prerelease: false
48
+ requirement: &id003 !ruby/object:Gem::Requirement
49
+ requirements:
50
+ - - ">="
51
+ - !ruby/object:Gem::Version
52
+ segments:
53
+ - 0
54
+ version: "0"
55
+ type: :development
56
+ version_requirements: *id003
57
+ - !ruby/object:Gem::Dependency
58
+ name: sqlite3-ruby
59
+ prerelease: false
60
+ requirement: &id004 !ruby/object:Gem::Requirement
61
+ requirements:
62
+ - - ">="
63
+ - !ruby/object:Gem::Version
64
+ segments:
65
+ - 0
66
+ version: "0"
67
+ type: :development
68
+ version_requirements: *id004
69
+ - !ruby/object:Gem::Dependency
70
+ name: git
71
+ prerelease: false
72
+ requirement: &id005 !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - ">="
75
+ - !ruby/object:Gem::Version
76
+ segments:
77
+ - 0
78
+ version: "0"
79
+ type: :development
80
+ version_requirements: *id005
81
+ - !ruby/object:Gem::Dependency
82
+ name: gemcutter
83
+ prerelease: false
84
+ requirement: &id006 !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - ">="
87
+ - !ruby/object:Gem::Version
88
+ segments:
89
+ - 0
90
+ version: "0"
91
+ type: :development
92
+ version_requirements: *id006
49
93
  description: " Request log analyzer's purpose is to find out how your web application is being used, how it performs and to\n focus your optimization efforts. This tool will parse all requests in the application's log file and aggregate the \n information. Once it is finished parsing the log file(s), it will show the requests that take op most server time \n using various metrics. It can also insert all parsed request information into a database so you can roll your own\n analysis. It supports Rails-, Merb- and Rack-based applications logs, Apache and Amazon S3 access logs and MySQL \n slow query logs out of the box, but file formats of other applications can easily be supported by supplying an \n easy to write log file format definition.\n"
50
94
  email:
51
95
  - willem@railsdoctors.com