request-log-analyzer 1.3.5 → 1.3.6

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 (31) hide show
  1. data/lib/cli/database_console_init.rb +2 -1
  2. data/lib/request_log_analyzer.rb +1 -1
  3. data/lib/request_log_analyzer/aggregator.rb +1 -5
  4. data/lib/request_log_analyzer/aggregator/database_inserter.rb +4 -5
  5. data/lib/request_log_analyzer/controller.rb +10 -21
  6. data/lib/request_log_analyzer/database.rb +16 -91
  7. data/lib/request_log_analyzer/database/base.rb +4 -4
  8. data/lib/request_log_analyzer/database/request.rb +22 -0
  9. data/lib/request_log_analyzer/database/source.rb +13 -0
  10. data/lib/request_log_analyzer/database/warning.rb +14 -0
  11. data/lib/request_log_analyzer/file_format.rb +1 -13
  12. data/lib/request_log_analyzer/file_format/amazon_s3.rb +1 -2
  13. data/lib/request_log_analyzer/file_format/apache.rb +8 -10
  14. data/lib/request_log_analyzer/file_format/merb.rb +21 -5
  15. data/lib/request_log_analyzer/file_format/rails.rb +8 -14
  16. data/lib/request_log_analyzer/filter.rb +6 -10
  17. data/lib/request_log_analyzer/filter/anonymize.rb +2 -1
  18. data/lib/request_log_analyzer/log_processor.rb +6 -8
  19. data/lib/request_log_analyzer/request.rb +47 -35
  20. data/lib/request_log_analyzer/source.rb +4 -6
  21. data/lib/request_log_analyzer/source/database_loader.rb +3 -7
  22. data/lib/request_log_analyzer/source/log_parser.rb +3 -6
  23. data/lib/request_log_analyzer/tracker.rb +12 -19
  24. data/lib/request_log_analyzer/tracker/hourly_spread.rb +1 -2
  25. data/request-log-analyzer.gemspec +3 -3
  26. data/spec/database.yml +6 -0
  27. data/spec/unit/aggregator/database_inserter_spec.rb +3 -3
  28. data/spec/unit/database/base_class_spec.rb +9 -16
  29. data/spec/unit/database/database_spec.rb +9 -14
  30. data/spec/unit/tracker/tracker_api_spec.rb +111 -36
  31. metadata +7 -4
@@ -3,6 +3,7 @@ $:.unshift(File.dirname(__FILE__) + '/..')
3
3
 
4
4
  $database = RequestLogAnalyzer::Database.new(ENV['RLA_DBCONSOLE_DATABASE'])
5
5
  $database.load_database_schema!
6
+ $database.register_default_orm_classes!
6
7
 
7
8
  require 'cli/tools'
8
9
 
@@ -39,4 +40,4 @@ end
39
40
  puts "request-log-analyzer database console"
40
41
  puts "-------------------------------------"
41
42
  puts "The following ActiveRecord classes are available:"
42
- puts $database.orm_classes.join(", ")
43
+ puts $database.orm_classes.map { |k| k.name.split('::').last }.join(", ")
@@ -11,7 +11,7 @@ module RequestLogAnalyzer
11
11
 
12
12
  # The current version of request-log-analyzer.
13
13
  # This will be diplayed in output reports etc.
14
- VERSION = "1.3.5"
14
+ VERSION = "1.3.6"
15
15
 
16
16
  # Loads constants in the RequestLogAnalyzer namespace using self.load_default_class_file(base, const)
17
17
  # <tt>const</tt>:: The constant that is not yet loaded in the RequestLogAnalyzer namespace. This should be passed as a string or symbol.
@@ -8,16 +8,12 @@ module RequestLogAnalyzer::Aggregator
8
8
  # every aggregator should comply (by simply subclassing this class).
9
9
  class Base
10
10
 
11
- include RequestLogAnalyzer::FileFormat::Awareness
12
-
13
- attr_reader :options
14
- attr_reader :source
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
 
@@ -31,7 +31,7 @@ module RequestLogAnalyzer::Aggregator
31
31
  # This will create a record in the requests table and create a record for every line that has been parsed,
32
32
  # in which the captured values will be stored.
33
33
  def aggregate(request)
34
- @request_object = database.request_class.new(:first_lineno => request.first_lineno, :last_lineno => request.last_lineno)
34
+ @request_object = RequestLogAnalyzer::Database::Request.new(:first_lineno => request.first_lineno, :last_lineno => request.last_lineno)
35
35
  request.lines.each do |line|
36
36
  class_columns = database.get_class(line[:line_type]).column_names.reject { |column| ['id', 'source_id', 'request_id'].include?(column) }
37
37
  attributes = Hash[*line.select { |(k, v)| class_columns.include?(k.to_s) }.flatten]
@@ -45,14 +45,14 @@ module RequestLogAnalyzer::Aggregator
45
45
 
46
46
  # Finalizes the aggregator by closing the connection to the database
47
47
  def finalize
48
- @request_count = database.request_class.count
48
+ @request_count = RequestLogAnalyzer::Database::Request.count
49
49
  database.disconnect
50
50
  database.remove_orm_classes!
51
51
  end
52
52
 
53
53
  # Records w warining in the warnings table.
54
54
  def warning(type, message, lineno)
55
- database.warning_class.create!(:warning_type => type.to_s, :message => message, :lineno => lineno)
55
+ RequestLogAnalyzer::Database::Warning.create!(:warning_type => type.to_s, :message => message, :lineno => lineno)
56
56
  end
57
57
 
58
58
  # Records source changes in the sources table
@@ -60,8 +60,7 @@ module RequestLogAnalyzer::Aggregator
60
60
  if File.exist?(filename)
61
61
  case change
62
62
  when :started
63
- p database.source_class
64
- @sources[filename] = database.source_class.create!(:filename => filename)
63
+ @sources[filename] = RequestLogAnalyzer::Database::Source.create!(:filename => filename)
65
64
  when :finished
66
65
  @sources[filename].update_attributes!(:filesize => File.size(filename), :mtime => File.mtime(filename))
67
66
  end
@@ -17,14 +17,7 @@ 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.
@@ -35,8 +28,8 @@ module RequestLogAnalyzer
35
28
  # Database command line options
36
29
  options[:database] = arguments[:database] if arguments[:database]
37
30
  options[:reset_database] = arguments[:reset_database]
38
- options[:debug] = arguments[:debug]
39
- options[:dump] = arguments[:dump]
31
+ options[:debug] = arguments[:debug]
32
+ options[:dump] = arguments[:dump]
40
33
  options[:parse_strategy] = arguments[:parse_strategy]
41
34
  options[:no_progress] = arguments[:no_progress]
42
35
 
@@ -125,17 +118,13 @@ module RequestLogAnalyzer
125
118
  @filters = []
126
119
  @output = options[:output]
127
120
 
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
133
-
134
- # Handle progress messagess
135
- @source.progress = lambda { |message, value| handle_progress(message, value) } if @source && !options[:no_progress]
121
+ # Register the request format for this session after checking its validity
122
+ raise "Invalid file format!" unless @source.file_format.valid?
136
123
 
137
- # Handle source change messages
138
- @source.source_changes = lambda { |change, filename| handle_source_change(change, filename) } if @source
124
+ # Install event handlers for wrnings, progress updates and source changes
125
+ @source.warning = lambda { |type, message, lineno| @aggregators.each { |agg| agg.warning(type, message, lineno) } }
126
+ @source.progress = lambda { |message, value| handle_progress(message, value) } unless options[:no_progress]
127
+ @source.source_changes = lambda { |change, filename| handle_source_change(change, filename) }
139
128
  end
140
129
 
141
130
  # Progress function.
@@ -176,7 +165,7 @@ module RequestLogAnalyzer
176
165
  # Adds a request filter to the controller.
177
166
  def add_filter(filter, filter_options = {})
178
167
  filter = RequestLogAnalyzer::Filter.const_get(RequestLogAnalyzer::to_camelcase(filter)) if filter.kind_of?(Symbol)
179
- @filters << filter.new(file_format, @options.merge(filter_options))
168
+ @filters << filter.new(source.file_format, @options.merge(filter_options))
180
169
  end
181
170
 
182
171
  # Push a request through the entire filterchain (@filters).
@@ -10,7 +10,7 @@ class RequestLogAnalyzer::Database
10
10
  include RequestLogAnalyzer::Database::Connection
11
11
 
12
12
  attr_accessor :file_format
13
- attr_reader :request_class, :warning_class, :source_class, :line_classes
13
+ attr_reader :line_classes
14
14
 
15
15
  def initialize(connection_identifier = nil)
16
16
  @line_classes = []
@@ -24,97 +24,17 @@ class RequestLogAnalyzer::Database
24
24
  Object.const_get("#{line_type}_line".camelize)
25
25
  end
26
26
 
27
- # Returns the Request ORM class for the current database.
28
- #
29
- # It will create the class if not previously done so. The class will
30
- # include a create_table! method the migrate the database.
31
- def request_class
32
- @request_class ||= begin
33
- klass = Class.new(RequestLogAnalyzer::Database::Base) do
34
-
35
- def lines
36
- @lines ||= begin
37
- lines = []
38
- self.class.reflections.each { |r, d| lines += self.send(r).all }
39
- lines.sort
40
- end
41
- end
42
-
43
- # Creates the requests table
44
- def self.create_table!
45
- unless database.connection.table_exists?(:requests)
46
- database.connection.create_table(:requests) do |t|
47
- t.column :first_lineno, :integer
48
- t.column :last_lineno, :integer
49
- end
50
- end
51
- end
52
- end
53
-
54
- Object.const_set('Request', klass)
55
- Object.const_get('Request')
56
- end
57
- end
58
-
59
- # Returns the Source ORM class for the current database.
60
- #
61
- # It will create the class if not previously done so. The class will
62
- # include a create_table! method the migrate the database.
63
- def source_class
64
- @source_class ||= begin
65
- klass = Class.new(RequestLogAnalyzer::Database::Base) do
66
-
67
- # Creates the sources table
68
- def self.create_table!
69
- unless database.connection.table_exists?(:sources)
70
- database.connection.create_table(:sources) do |t|
71
- t.column :filename, :string
72
- t.column :mtime, :datetime
73
- t.column :filesize, :integer
74
- end
75
- end
76
- end
77
- end
78
-
79
- Object.const_set('Source', klass)
80
- Object.const_get('Source')
81
- end
82
- end
83
-
84
-
85
- # Returns the Warning ORM class for the current database.
86
- #
87
- # It will create the class if not previously done so. The class will
88
- # include a create_table! method the migrate the database.
89
- def warning_class
90
- @warning_class ||= begin
91
- klass = Class.new(RequestLogAnalyzer::Database::Base) do
92
-
93
- # Creates the warnings table
94
- def self.create_table!
95
- unless database.connection.table_exists?(:warnings)
96
- database.connection.create_table(:warnings) do |t|
97
- t.column :warning_type, :string, :limit => 30, :null => false
98
- t.column :message, :string
99
- t.column :source_id, :integer
100
- t.column :lineno, :integer
101
- end
102
- end
103
- end
104
- end
105
-
106
- Object.const_set('Warning', klass)
107
- Object.const_get('Warning')
108
- end
27
+ def default_classes
28
+ [RequestLogAnalyzer::Database::Request, RequestLogAnalyzer::Database::Source, RequestLogAnalyzer::Database::Warning]
109
29
  end
110
30
 
111
31
  # Loads the ORM classes by inspecting the tables in the current database
112
32
  def load_database_schema!
113
33
  connection.tables.map do |table|
114
34
  case table.to_sym
115
- when :warnings then warning_class
116
- when :sources then source_class
117
- when :requests then request_class
35
+ when :warnings then RequestLogAnalyzer::Database::Warning
36
+ when :sources then RequestLogAnalyzer::Database::Source
37
+ when :requests then RequestLogAnalyzer::Database::Request
118
38
  else load_activerecord_class(table)
119
39
  end
120
40
  end
@@ -122,7 +42,7 @@ class RequestLogAnalyzer::Database
122
42
 
123
43
  # Returns an array of all the ActiveRecord-bases ORM classes for this database
124
44
  def orm_classes
125
- [warning_class, request_class, source_class] + line_classes
45
+ default_classes + line_classes
126
46
  end
127
47
 
128
48
  # Loads an ActiveRecord-based class that correspond to the given parameter, which can either be
@@ -146,8 +66,6 @@ class RequestLogAnalyzer::Database
146
66
 
147
67
  def fileformat_classes
148
68
  raise "No file_format provided!" unless file_format
149
-
150
- default_classes = [request_class, source_class, warning_class]
151
69
  line_classes = file_format.line_definitions.map { |(name, definition)| load_activerecord_class(definition) }
152
70
  return default_classes + line_classes
153
71
  end
@@ -164,12 +82,19 @@ class RequestLogAnalyzer::Database
164
82
  remove_orm_classes!
165
83
  end
166
84
 
85
+ # Registers the default ORM classes in the default namespace
86
+ def register_default_orm_classes!
87
+ Object.const_set('Request', RequestLogAnalyzer::Database::Request)
88
+ Object.const_set('Source', RequestLogAnalyzer::Database::Source)
89
+ Object.const_set('Warning', RequestLogAnalyzer::Database::Warning)
90
+ end
91
+
167
92
  # Unregisters every ORM class constant
168
93
  def remove_orm_classes!
169
94
  orm_classes.each do |klass|
170
95
  if klass.respond_to?(:name) && !klass.name.blank?
171
- # klass_base_name = klass.name.split('::').last
172
- Object.send(:remove_const, klass.name) if Object.const_defined?(klass.name)
96
+ klass_name = klass.name.split('::').last
97
+ Object.send(:remove_const, klass_name) if Object.const_defined?(klass_name)
173
98
  end
174
99
  end
175
100
  end
@@ -32,8 +32,8 @@ class RequestLogAnalyzer::Database::Base < ActiveRecord::Base
32
32
  klass.send(:serialize, capture[:name], Hash)
33
33
  end
34
34
 
35
- database.request_class.has_many "#{definition.name}_lines".to_sym
36
- database.source_class.has_many "#{definition.name}_lines".to_sym
35
+ RequestLogAnalyzer::Database::Request.has_many "#{definition.name}_lines".to_sym
36
+ RequestLogAnalyzer::Database::Source.has_many "#{definition.name}_lines".to_sym
37
37
 
38
38
  return klass
39
39
  end
@@ -46,12 +46,12 @@ class RequestLogAnalyzer::Database::Base < ActiveRecord::Base
46
46
 
47
47
  if klass.column_names.include?('request_id')
48
48
  klass.belongs_to :request
49
- database.request_class.has_many table.to_sym
49
+ RequestLogAnalyzer::Database::Request.has_many table.to_sym
50
50
  end
51
51
 
52
52
  if klass.column_names.include?('source_id')
53
53
  klass.belongs_to :source
54
- database.source_class.has_many table.to_sym
54
+ RequestLogAnalyzer::Database::Source.has_many table.to_sym
55
55
  end
56
56
 
57
57
  return klass
@@ -0,0 +1,22 @@
1
+ class RequestLogAnalyzer::Database::Request < RequestLogAnalyzer::Database::Base
2
+
3
+ # Returns an array of all the Line objects of this request in the correct order.
4
+ def lines
5
+ @lines ||= begin
6
+ lines = []
7
+ self.class.reflections.each { |r, d| lines += self.send(r).all }
8
+ lines.sort
9
+ end
10
+ end
11
+
12
+ # Creates the table to store requests in.
13
+ def self.create_table!
14
+ unless database.connection.table_exists?(:requests)
15
+ database.connection.create_table(:requests) do |t|
16
+ t.column :first_lineno, :integer
17
+ t.column :last_lineno, :integer
18
+ end
19
+ end
20
+ end
21
+
22
+ end
@@ -0,0 +1,13 @@
1
+ class RequestLogAnalyzer::Database::Source < RequestLogAnalyzer::Database::Base
2
+
3
+ def self.create_table!
4
+ unless database.connection.table_exists?(:sources)
5
+ database.connection.create_table(:sources) do |t|
6
+ t.column :filename, :string
7
+ t.column :mtime, :datetime
8
+ t.column :filesize, :integer
9
+ end
10
+ end
11
+ end
12
+
13
+ end
@@ -0,0 +1,14 @@
1
+ class RequestLogAnalyzer::Database::Warning < RequestLogAnalyzer::Database::Base
2
+
3
+ def self.create_table!
4
+ unless database.connection.table_exists?(:warnings)
5
+ database.connection.create_table(:warnings) do |t|
6
+ t.column :warning_type, :string, :limit => 30, :null => false
7
+ t.column :message, :string
8
+ t.column :source_id, :integer
9
+ t.column :lineno, :integer
10
+ end
11
+ end
12
+ end
13
+
14
+ end
@@ -42,19 +42,7 @@ module RequestLogAnalyzer::FileFormat
42
42
  raise "Invalid FileFormat class" unless klass.kind_of?(Class) && klass.ancestors.include?(RequestLogAnalyzer::FileFormat::Base)
43
43
 
44
44
  @current_file_format = klass.create(*args) # return an instance of the class
45
- end
46
-
47
- # Makes classes aware of a file format by registering the file_format variable
48
- module Awareness
49
-
50
- def self.included(base)
51
- base.send(:attr_reader, :file_format)
52
- end
53
-
54
- def register_file_format(format)
55
- @file_format = format
56
- end
57
- end
45
+ end
58
46
 
59
47
  # Base class for all log file format definitions. This class provides functions for subclasses to
60
48
  # define their LineDefinitions and to define a summary report.
@@ -48,8 +48,7 @@ module RequestLogAnalyzer::FileFormat
48
48
  # Do not use DateTime.parse, but parse the timestamp ourselves to return a integer
49
49
  # to speed up parsing.
50
50
  def convert_timestamp(value, definition)
51
- d = /^(\d{2})\/([A-Za-z]{3})\/(\d{4}).(\d{2}):(\d{2}):(\d{2})/.match(value).captures
52
- "#{d[2]}#{MONTHS[d[1]]}#{d[0]}#{d[3]}#{d[4]}#{d[5]}".to_i
51
+ "#{value[7,4]}#{MONTHS[value[3,3]]}#{value[0,2]}#{value[12,2]}#{value[15,2]}#{value[18,2]}".to_i
53
52
  end
54
53
 
55
54
  # Make sure that the string '-' is parsed as a nil value.
@@ -92,18 +92,13 @@ module RequestLogAnalyzer::FileFormat
92
92
 
93
93
  analyze.frequency :category => :http_method, :amount => 20, :title => "HTTP methods" if line_definition.captures?(:http_method)
94
94
  analyze.frequency :category => :http_status, :amount => 20, :title => "HTTP statuses" if line_definition.captures?(:http_status)
95
- analyze.frequency :category => :path, :amount => 20, :title => "Most popular URIs" if line_definition.captures?(:path)
95
+ analyze.frequency :category => lambda { |r| r.category }, :amount => 20, :title => "Most popular URIs" if line_definition.captures?(:path)
96
96
 
97
97
  analyze.frequency :category => :user_agent, :amount => 20, :title => "User agents" if line_definition.captures?(:user_agent)
98
98
  analyze.frequency :category => :referer, :amount => 20, :title => "Referers" if line_definition.captures?(:referer)
99
99
 
100
- if line_definition.captures?(:path) && line_definition.captures?(:duration)
101
- analyze.duration :duration => :duration, :category => :path , :title => 'Request duration'
102
- end
103
-
104
- if line_definition.captures?(:path) && line_definition.captures?(:bytes_sent)
105
- analyze.traffic :traffic => :bytes_sent, :category => :path , :title => 'Traffic'
106
- end
100
+ analyze.duration :duration => :duration, :category => lambda { |r| r.category }, :title => 'Request duration' if line_definition.captures?(:duration)
101
+ analyze.traffic :traffic => :bytes_sent, :category => lambda { |r| r.category }, :title => 'Traffic' if line_definition.captures?(:bytes_sent)
107
102
 
108
103
  return analyze.trackers
109
104
  end
@@ -111,14 +106,17 @@ module RequestLogAnalyzer::FileFormat
111
106
  # Define a custom Request class for the Apache file format to speed up timestamp handling.
112
107
  class Request < RequestLogAnalyzer::Request
113
108
 
109
+ def category
110
+ first(:path)
111
+ end
112
+
114
113
  MONTHS = {'Jan' => '01', 'Feb' => '02', 'Mar' => '03', 'Apr' => '04', 'May' => '05', 'Jun' => '06',
115
114
  'Jul' => '07', 'Aug' => '08', 'Sep' => '09', 'Oct' => '10', 'Nov' => '11', 'Dec' => '12' }
116
115
 
117
116
  # Do not use DateTime.parse, but parse the timestamp ourselves to return a integer
118
117
  # to speed up parsing.
119
118
  def convert_timestamp(value, definition)
120
- d = /^(\d{2})\/([A-Za-z]{3})\/(\d{4}).(\d{2}):(\d{2}):(\d{2})/.match(value).captures
121
- "#{d[2]}#{MONTHS[d[1]]}#{d[0]}#{d[3]}#{d[4]}#{d[5]}".to_i
119
+ "#{value[7,4]}#{MONTHS[value[3,3]]}#{value[0,2]}#{value[12,2]}#{value[15,2]}#{value[18,2]}".to_i
122
120
  end
123
121
 
124
122
  # This function can be overridden to rewrite the path for better categorization in the
@@ -1,11 +1,14 @@
1
1
  module RequestLogAnalyzer::FileFormat
2
2
 
3
+ # The Merb file format parses the request header with the timestamp, the params line
4
+ # with the most important request information and the durations line which contains
5
+ # the different request durations that can be used for analysis.
3
6
  class Merb < Base
4
7
 
5
8
  # ~ Started request handling: Fri Aug 29 11:10:23 +0200 2008
6
9
  line_definition :started do |line|
7
10
  line.header = true
8
- line.teaser = /Started/
11
+ # line.teaser = /Started/
9
12
  line.regexp = /Started request handling\:\ (.+)/
10
13
  line.captures << { :name => :timestamp, :type => :timestamp }
11
14
  end
@@ -13,7 +16,7 @@ module RequestLogAnalyzer::FileFormat
13
16
  # ~ Params: {"action"=>"create", "controller"=>"session"}
14
17
  # ~ Params: {"_method"=>"delete", "authenticity_token"=>"[FILTERED]", "action"=>"d}
15
18
  line_definition :params do |line|
16
- line.teaser = /Params/
19
+ # line.teaser = /Params/
17
20
  line.regexp = /Params\:\ (\{.+\})/
18
21
  line.captures << { :name => :params, :type => :eval, :provides => {
19
22
  :namespace => :string, :controller => :string, :action => :string, :format => :string, :method => :string } }
@@ -36,15 +39,28 @@ module RequestLogAnalyzer::FileFormat
36
39
  end
37
40
 
38
41
  report do |analyze|
39
- analyze.timespan :line_type => :started
42
+
43
+ analyze.timespan
44
+ analyze.hourly_spread
45
+
40
46
  analyze.frequency :category => REQUEST_CATEGORIZER, :amount => 20, :title => "Top 20 by hits"
41
- analyze.hourly_spread :line_type => :started
42
47
  analyze.duration :dispatch_time, :category => REQUEST_CATEGORIZER, :title => 'Request dispatch duration'
48
+
43
49
  # analyze.duration :action_time, :category => REQUEST_CATEGORIZER, :title => 'Request action duration'
44
50
  # analyze.duration :after_filters_time, :category => REQUEST_CATEGORIZER, :title => 'Request after_filter duration'
45
51
  # analyze.duration :before_filters_time, :category => REQUEST_CATEGORIZER, :title => 'Request before_filter duration'
46
52
  end
47
-
53
+
54
+ class Request < RequestLogAnalyzer::Request
55
+
56
+ MONTHS = {'Jan' => '01', 'Feb' => '02', 'Mar' => '03', 'Apr' => '04', 'May' => '05', 'Jun' => '06',
57
+ 'Jul' => '07', 'Aug' => '08', 'Sep' => '09', 'Oct' => '10', 'Nov' => '11', 'Dec' => '12' }
58
+
59
+ # Speed up timestamp conversion
60
+ def convert_timestamp(value, definition)
61
+ "#{value[26,4]}#{MONTHS[value[4,3]]}#{value[8,2]}#{value[11,2]}#{value[14,2]}#{value[17,2]}".to_i
62
+ end
63
+ end
48
64
  end
49
65
 
50
66
  end