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.
- data/LICENSE +3 -3
- data/README.rdoc +1 -1
- data/bin/request-log-analyzer +17 -14
- data/lib/cli/command_line_arguments.rb +51 -51
- data/lib/cli/database_console.rb +3 -3
- data/lib/cli/database_console_init.rb +4 -3
- data/lib/cli/progressbar.rb +10 -10
- data/lib/cli/tools.rb +3 -3
- data/lib/request_log_analyzer/aggregator/database_inserter.rb +19 -17
- data/lib/request_log_analyzer/aggregator/echo.rb +14 -9
- data/lib/request_log_analyzer/aggregator/summarizer.rb +26 -26
- data/lib/request_log_analyzer/aggregator.rb +11 -15
- data/lib/request_log_analyzer/controller.rb +162 -89
- data/lib/request_log_analyzer/database/base.rb +22 -21
- data/lib/request_log_analyzer/database/connection.rb +3 -3
- data/lib/request_log_analyzer/database/request.rb +22 -0
- data/lib/request_log_analyzer/database/source.rb +13 -0
- data/lib/request_log_analyzer/database/warning.rb +14 -0
- data/lib/request_log_analyzer/database.rb +28 -103
- data/lib/request_log_analyzer/file_format/amazon_s3.rb +20 -20
- data/lib/request_log_analyzer/file_format/apache.rb +37 -30
- data/lib/request_log_analyzer/file_format/merb.rb +30 -13
- data/lib/request_log_analyzer/file_format/rack.rb +11 -0
- data/lib/request_log_analyzer/file_format/rails.rb +143 -73
- data/lib/request_log_analyzer/file_format/rails_development.rb +4 -49
- data/lib/request_log_analyzer/file_format.rb +16 -28
- data/lib/request_log_analyzer/filter/anonymize.rb +8 -7
- data/lib/request_log_analyzer/filter/field.rb +9 -9
- data/lib/request_log_analyzer/filter/timespan.rb +12 -10
- data/lib/request_log_analyzer/filter.rb +12 -16
- data/lib/request_log_analyzer/line_definition.rb +15 -14
- data/lib/request_log_analyzer/log_processor.rb +27 -29
- data/lib/request_log_analyzer/mailer.rb +15 -9
- data/lib/request_log_analyzer/output/fixed_width.rb +48 -48
- data/lib/request_log_analyzer/output/html.rb +20 -20
- data/lib/request_log_analyzer/output.rb +53 -12
- data/lib/request_log_analyzer/request.rb +88 -69
- data/lib/request_log_analyzer/source/database_loader.rb +10 -14
- data/lib/request_log_analyzer/source/log_parser.rb +57 -50
- data/lib/request_log_analyzer/source.rb +10 -12
- data/lib/request_log_analyzer/tracker/duration.rb +41 -134
- data/lib/request_log_analyzer/tracker/frequency.rb +31 -32
- data/lib/request_log_analyzer/tracker/hourly_spread.rb +21 -21
- data/lib/request_log_analyzer/tracker/timespan.rb +17 -17
- data/lib/request_log_analyzer/tracker/traffic.rb +106 -0
- data/lib/request_log_analyzer/tracker.rb +139 -32
- data/lib/request_log_analyzer.rb +5 -5
- data/request-log-analyzer.gemspec +19 -15
- data/spec/database.yml +6 -0
- data/spec/fixtures/rails_22.log +1 -1
- data/spec/integration/command_line_usage_spec.rb +7 -1
- data/spec/lib/helpers.rb +7 -7
- data/spec/lib/macros.rb +3 -3
- data/spec/lib/matchers.rb +41 -27
- data/spec/lib/mocks.rb +19 -15
- data/spec/lib/testing_format.rb +9 -9
- data/spec/spec_helper.rb +6 -6
- data/spec/unit/aggregator/database_inserter_spec.rb +16 -16
- data/spec/unit/aggregator/summarizer_spec.rb +4 -4
- data/spec/unit/controller/controller_spec.rb +2 -2
- data/spec/unit/controller/log_processor_spec.rb +1 -1
- data/spec/unit/database/base_class_spec.rb +26 -33
- data/spec/unit/database/connection_spec.rb +3 -3
- data/spec/unit/database/database_spec.rb +33 -38
- data/spec/unit/file_format/amazon_s3_format_spec.rb +5 -5
- data/spec/unit/file_format/apache_format_spec.rb +48 -11
- data/spec/unit/file_format/file_format_api_spec.rb +13 -13
- data/spec/unit/file_format/line_definition_spec.rb +24 -17
- data/spec/unit/file_format/merb_format_spec.rb +41 -45
- data/spec/unit/file_format/rails_format_spec.rb +157 -117
- data/spec/unit/filter/anonymize_filter_spec.rb +2 -2
- data/spec/unit/filter/field_filter_spec.rb +13 -13
- data/spec/unit/filter/filter_spec.rb +1 -1
- data/spec/unit/filter/timespan_filter_spec.rb +15 -15
- data/spec/unit/mailer_spec.rb +30 -0
- data/spec/unit/{source/request_spec.rb → request_spec.rb} +30 -30
- data/spec/unit/source/log_parser_spec.rb +27 -27
- data/spec/unit/tracker/duration_tracker_spec.rb +115 -78
- data/spec/unit/tracker/frequency_tracker_spec.rb +74 -63
- data/spec/unit/tracker/hourly_spread_spec.rb +28 -20
- data/spec/unit/tracker/timespan_tracker_spec.rb +25 -13
- data/spec/unit/tracker/tracker_api_spec.rb +117 -42
- data/spec/unit/tracker/traffic_tracker_spec.rb +107 -0
- data/tasks/github-gem.rake +125 -75
- data/tasks/request_log_analyzer.rake +2 -2
- metadata +19 -10
|
@@ -5,13 +5,49 @@ module RequestLogAnalyzer::Output
|
|
|
5
5
|
def self.const_missing(const)
|
|
6
6
|
RequestLogAnalyzer::load_default_class_file(self, const)
|
|
7
7
|
end
|
|
8
|
+
|
|
9
|
+
# Loads a Output::Base subclass instance.
|
|
10
|
+
def self.load(file_format, *args)
|
|
11
|
+
|
|
12
|
+
klass = nil
|
|
13
|
+
if file_format.kind_of?(RequestLogAnalyzer::Output::Base)
|
|
14
|
+
# this already is a file format! return itself
|
|
15
|
+
return file_format
|
|
16
|
+
|
|
17
|
+
elsif file_format.kind_of?(Class) && file_format.ancestors.include?(RequestLogAnalyzer::Output::Base)
|
|
18
|
+
# a usable class is provided. Use this format class.
|
|
19
|
+
klass = file_format
|
|
20
|
+
|
|
21
|
+
elsif file_format.kind_of?(String) && File.exist?(file_format)
|
|
22
|
+
# load a format from a ruby file
|
|
23
|
+
require file_format
|
|
24
|
+
const = RequestLogAnalyzer::to_camelcase(File.basename(file_format, '.rb'))
|
|
25
|
+
if RequestLogAnalyzer::FileFormat.const_defined?(const)
|
|
26
|
+
klass = RequestLogAnalyzer::Output.const_get(const)
|
|
27
|
+
elsif Object.const_defined?(const)
|
|
28
|
+
klass = Object.const_get(const)
|
|
29
|
+
else
|
|
30
|
+
raise "Cannot load class #{const} from #{file_format}!"
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
else
|
|
34
|
+
# load a provided file format
|
|
35
|
+
klass = RequestLogAnalyzer::Output.const_get(RequestLogAnalyzer::to_camelcase(file_format))
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# check the returned klass to see if it can be used
|
|
39
|
+
raise "Could not load a file format from #{file_format.inspect}" if klass.nil?
|
|
40
|
+
raise "Invalid FileFormat class" unless klass.kind_of?(Class) && klass.ancestors.include?(RequestLogAnalyzer::Output::Base)
|
|
41
|
+
|
|
42
|
+
klass.create(*args) # return an instance of the class
|
|
43
|
+
end
|
|
8
44
|
|
|
9
45
|
# Base Class used for generating output for reports.
|
|
10
46
|
# All output should inherit fromt this class.
|
|
11
47
|
class Base
|
|
12
|
-
|
|
48
|
+
|
|
13
49
|
attr_accessor :io, :options, :style
|
|
14
|
-
|
|
50
|
+
|
|
15
51
|
# Initialize a report
|
|
16
52
|
# <tt>io</tt> iO Object (file, STDOUT, etc.)
|
|
17
53
|
# <tt>options</tt> Specific style options
|
|
@@ -27,32 +63,37 @@ module RequestLogAnalyzer::Output
|
|
|
27
63
|
@style = @style.merge(temp_style)
|
|
28
64
|
yield(self) if block_given?
|
|
29
65
|
@style = old_style
|
|
30
|
-
end
|
|
31
|
-
|
|
66
|
+
end
|
|
67
|
+
|
|
32
68
|
# Generate a header for a report
|
|
33
69
|
def header
|
|
34
70
|
end
|
|
35
|
-
|
|
36
|
-
# Generate the footer of a report
|
|
71
|
+
|
|
72
|
+
# Generate the footer of a report
|
|
37
73
|
def footer
|
|
38
74
|
end
|
|
39
75
|
|
|
76
|
+
def slice_results(array)
|
|
77
|
+
return array if options[:amount] == :all
|
|
78
|
+
return array.slice(0, options[:amount]) # otherwise
|
|
79
|
+
end
|
|
80
|
+
|
|
40
81
|
# Generate a report table and push it into the output object.
|
|
41
82
|
# Yeilds a rows array into which the rows can be pushed
|
|
42
83
|
# <tt>*colums<tt> Array of Column hashes (see Column options).
|
|
43
84
|
# <tt>&block</tt>: A block yeilding the rows.
|
|
44
|
-
#
|
|
85
|
+
#
|
|
45
86
|
# === Column options
|
|
46
87
|
# Columns is an array of hashes containing the column definitions.
|
|
47
88
|
# * <tt>:align</tt> Alignment :left or :right
|
|
48
89
|
# * <tt>:treshold</tt> Width in characters or :rest
|
|
49
90
|
# * <tt>:type</tt> :ratio or nil
|
|
50
91
|
# * <tt>:width</tt> Width in characters or :rest
|
|
51
|
-
#
|
|
92
|
+
#
|
|
52
93
|
# === Example
|
|
53
94
|
# The output object should support table definitions:
|
|
54
95
|
#
|
|
55
|
-
# output.table({:align => :left}, {:align => :right }, {:align => :right}, {:type => :ratio, :width => :rest}) do |rows|
|
|
96
|
+
# output.table({:align => :left}, {:align => :right }, {:align => :right}, {:type => :ratio, :width => :rest}) do |rows|
|
|
56
97
|
# sorted_frequencies.each do |(cat, count)|
|
|
57
98
|
# rows << [cat, "#{count} hits", '%0.1f%%' % ((count.to_f / total_hits.to_f) * 100.0), (count.to_f / total_hits.to_f)]
|
|
58
99
|
# end
|
|
@@ -60,13 +101,13 @@ module RequestLogAnalyzer::Output
|
|
|
60
101
|
#
|
|
61
102
|
def table(*columns, &block)
|
|
62
103
|
end
|
|
63
|
-
|
|
104
|
+
|
|
64
105
|
protected
|
|
65
106
|
# Check if a given table defination hash includes a header (title)
|
|
66
107
|
# <tt>columns</tt> The columns hash
|
|
67
108
|
def table_has_header?(columns)
|
|
68
|
-
columns.any? { |column| !column[:title].nil? }
|
|
109
|
+
columns.any? { |column| !column[:title].nil? }
|
|
69
110
|
end
|
|
70
|
-
|
|
111
|
+
|
|
71
112
|
end
|
|
72
113
|
end
|
|
@@ -1,71 +1,85 @@
|
|
|
1
1
|
module RequestLogAnalyzer
|
|
2
|
-
|
|
3
|
-
# The Request class represents a parsed request from the log file.
|
|
2
|
+
|
|
3
|
+
# The Request class represents a parsed request from the log file.
|
|
4
4
|
# Instances are created by the LogParser and are passed to the different aggregators, so they
|
|
5
|
-
# can do their aggregating work.
|
|
5
|
+
# can do their aggregating work.
|
|
6
6
|
#
|
|
7
7
|
# This class provides several methods to access the data that was parsed from the log files.
|
|
8
8
|
# Request#first(field_name) returns the first (only) value corresponding to the given field
|
|
9
9
|
# Request#every(field_name) returns all values corresponding to the given field name as array.
|
|
10
10
|
class Request
|
|
11
|
-
|
|
11
|
+
|
|
12
12
|
module Converters
|
|
13
|
-
|
|
13
|
+
|
|
14
|
+
# Default converter function, which converts the parsed strings to a native Ruby type
|
|
15
|
+
# using the type indication in the line definition. It will use a custom connverter
|
|
16
|
+
# method if one is available.
|
|
14
17
|
def convert_value(value, capture_definition)
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
elsif !value.nil?
|
|
19
|
-
case capture_definition[:type]
|
|
20
|
-
when :decimal; value.to_f
|
|
21
|
-
when :float; value.to_f
|
|
22
|
-
when :double; value.to_f
|
|
23
|
-
when :integer; value.to_i
|
|
24
|
-
when :int; value.to_i
|
|
25
|
-
when :symbol; value.to_sym
|
|
26
|
-
else; value.to_s
|
|
27
|
-
end
|
|
28
|
-
else
|
|
29
|
-
nil
|
|
30
|
-
end
|
|
18
|
+
return capture_definition[:default] if value.nil?
|
|
19
|
+
custom_converter_method = :"convert_#{capture_definition[:type]}"
|
|
20
|
+
send(custom_converter_method, value, capture_definition)
|
|
31
21
|
end
|
|
32
|
-
|
|
22
|
+
|
|
23
|
+
def convert_string(value, capture_definition); value; end
|
|
24
|
+
def convert_float(value, capture_definition); value.to_f; end
|
|
25
|
+
def convert_decimal(value, capture_definition); value.to_f; end
|
|
26
|
+
def convert_int(value, capture_definition); value.to_i; end
|
|
27
|
+
def convert_integer(value, capture_definition); value.to_i; end
|
|
28
|
+
def convert_sym(value, capture_definition); value.to_sym; end
|
|
29
|
+
def convert_symbol(value, capture_definition); value.to_sym; end
|
|
30
|
+
|
|
31
|
+
# Converts :eval field, which should evaluate to a hash.
|
|
33
32
|
def convert_eval(value, capture_definition)
|
|
34
|
-
eval(value).inject({}) { |h, (k, v)| h[k.to_sym] = v; h}
|
|
33
|
+
eval(value).inject({}) { |h, (k, v)| h[k.to_sym] = v; h}
|
|
35
34
|
rescue SyntaxError
|
|
36
35
|
nil
|
|
37
36
|
end
|
|
38
|
-
|
|
39
|
-
# Slow default method to parse timestamps
|
|
37
|
+
|
|
38
|
+
# Slow default method to parse timestamps.
|
|
39
|
+
# Reimplement this function in a file format specific Request class
|
|
40
|
+
# to improve the timestamp parsing speed.
|
|
40
41
|
def convert_timestamp(value, capture_definition)
|
|
41
|
-
DateTime.parse(value).strftime('%Y%m%d%H%M%S').to_i
|
|
42
|
+
DateTime.parse(value).strftime('%Y%m%d%H%M%S').to_i
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# Converts traffic fields to (whole) bytes based on the given unit.
|
|
46
|
+
def convert_traffic(value, capture_definition)
|
|
47
|
+
case capture_definition[:unit]
|
|
48
|
+
when nil, :b, :B, :byte then value.to_i
|
|
49
|
+
when :GB, :G, :gigabyte then (value.to_f * 1000_000_000).round
|
|
50
|
+
when :GiB, :gibibyte then (value.to_f * (2 ** 30)).round
|
|
51
|
+
when :MB, :M, :megabyte then (value.to_f * 1000_000).round
|
|
52
|
+
when :MiB, :mebibyte then (value.to_f * (2 ** 20)).round
|
|
53
|
+
when :KB, :K, :kilobyte, :kB then (value.to_f * 1000).round
|
|
54
|
+
when :KiB, :kibibyte then (value.to_f * (2 ** 10)).round
|
|
55
|
+
else raise "Unknown traffic unit"
|
|
56
|
+
end
|
|
42
57
|
end
|
|
43
|
-
|
|
58
|
+
|
|
59
|
+
# Convert duration fields to float, and make sure the values are in seconds.
|
|
44
60
|
def convert_duration(value, capture_definition)
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
else
|
|
50
|
-
value.to_f
|
|
61
|
+
case capture_definition[:unit]
|
|
62
|
+
when nil, :sec, :s then value.to_f
|
|
63
|
+
when :microsec, :musec then value.to_f / 1000000.0
|
|
64
|
+
when :msec, :millisec then value.to_f / 1000.0
|
|
65
|
+
else raise "Unknown duration unit"
|
|
51
66
|
end
|
|
52
67
|
end
|
|
53
68
|
end
|
|
54
|
-
|
|
55
|
-
|
|
69
|
+
|
|
70
|
+
# Install the default converter methods
|
|
56
71
|
include Converters
|
|
57
|
-
|
|
58
|
-
attr_reader :lines
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
# Initializes a new Request object.
|
|
72
|
+
|
|
73
|
+
attr_reader :lines, :attributes, :file_format
|
|
74
|
+
|
|
75
|
+
# Initializes a new Request object.
|
|
62
76
|
# It will apply the the provided FileFormat module to this instance.
|
|
63
77
|
def initialize(file_format, attributes = {})
|
|
64
|
-
@lines
|
|
65
|
-
@attributes
|
|
66
|
-
|
|
78
|
+
@lines = []
|
|
79
|
+
@attributes = attributes
|
|
80
|
+
@file_format = file_format
|
|
67
81
|
end
|
|
68
|
-
|
|
82
|
+
|
|
69
83
|
# Creates a new request that was parsed from the log with the given FileFormat. The hashes
|
|
70
84
|
# that are passed to this function are added as lines to this request.
|
|
71
85
|
def self.create(file_format, *hashes)
|
|
@@ -73,9 +87,11 @@ module RequestLogAnalyzer
|
|
|
73
87
|
hashes.flatten.each { |hash| request << hash }
|
|
74
88
|
return request
|
|
75
89
|
end
|
|
76
|
-
|
|
77
|
-
# Adds another line to the request.
|
|
78
|
-
#
|
|
90
|
+
|
|
91
|
+
# Adds another line to the request when it is parsed in the LogParser.
|
|
92
|
+
#
|
|
93
|
+
# The line should be provided as a hash with the attributes line_definition, :captures,
|
|
94
|
+
# :lineno and :source set. This function is called from LogParser.
|
|
79
95
|
def add_parsed_line (parsed_line)
|
|
80
96
|
value_hash = parsed_line[:line_definition].convert_captured_values(parsed_line[:captures], self)
|
|
81
97
|
value_hash[:line_type] = parsed_line[:line_definition].name
|
|
@@ -83,72 +99,75 @@ module RequestLogAnalyzer
|
|
|
83
99
|
value_hash[:source] = parsed_line[:source]
|
|
84
100
|
add_line_hash(value_hash)
|
|
85
101
|
end
|
|
86
|
-
|
|
102
|
+
|
|
103
|
+
# Adds another line to the request using a plain hash.
|
|
104
|
+
#
|
|
105
|
+
# The line should be provides as a hash of the fields parsed from the line.
|
|
87
106
|
def add_line_hash(value_hash)
|
|
88
107
|
@lines << value_hash
|
|
89
108
|
@attributes = value_hash.merge(@attributes)
|
|
90
109
|
end
|
|
91
|
-
|
|
92
|
-
|
|
110
|
+
|
|
111
|
+
# Adds another line to the request. This method switches automatically between
|
|
112
|
+
# the add_line_hash and add_parsed_line based on the keys of the provided hash.
|
|
93
113
|
def <<(hash)
|
|
94
114
|
hash[:line_definition] ? add_parsed_line(hash) : add_line_hash(hash)
|
|
95
115
|
end
|
|
96
|
-
|
|
116
|
+
|
|
97
117
|
# Checks whether the given line type was parsed from the log file for this request
|
|
98
118
|
def has_line_type?(line_type)
|
|
99
119
|
return true if @lines.length == 1 && @lines[0][:line_type] == line_type.to_sym
|
|
100
|
-
|
|
101
120
|
@lines.detect { |l| l[:line_type] == line_type.to_sym }
|
|
102
121
|
end
|
|
103
|
-
|
|
122
|
+
|
|
104
123
|
alias :=~ :has_line_type?
|
|
105
|
-
|
|
124
|
+
|
|
106
125
|
# Returns the value that was captured for the "field" of this request.
|
|
107
126
|
# This function will return the first value that was captured if the field
|
|
108
127
|
# was captured in multiple lines
|
|
109
128
|
def first(field)
|
|
110
129
|
@attributes[field]
|
|
111
130
|
end
|
|
112
|
-
|
|
131
|
+
|
|
113
132
|
alias :[] :first
|
|
114
|
-
|
|
133
|
+
|
|
115
134
|
# Returns an array of all the "field" values that were captured for this request
|
|
116
135
|
def every(field)
|
|
117
136
|
@lines.inject([]) { |result, fields| result << fields[field] if fields.has_key?(field); result }
|
|
118
|
-
end
|
|
119
|
-
|
|
120
|
-
# Returns true if this request does not yet contain any parsed lines. This should only occur
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
# Returns true if this request does not yet contain any parsed lines. This should only occur
|
|
121
140
|
# during parsing. An empty request should never be sent to the aggregators
|
|
122
141
|
def empty?
|
|
123
142
|
@lines.length == 0
|
|
124
143
|
end
|
|
125
|
-
|
|
144
|
+
|
|
126
145
|
# Checks whether this request is completed. A completed request contains both a parsed header
|
|
127
|
-
# line and a parsed footer line. Not that calling this function in single line mode will always
|
|
146
|
+
# line and a parsed footer line. Not that calling this function in single line mode will always
|
|
128
147
|
# return false.
|
|
129
148
|
def completed?
|
|
130
149
|
header_found, footer_found = false, false
|
|
131
|
-
@lines.each do |line|
|
|
150
|
+
@lines.each do |line|
|
|
132
151
|
line_def = file_format.line_definitions[line[:line_type]]
|
|
133
152
|
header_found = true if line_def.header
|
|
134
|
-
footer_found = true if line_def.footer
|
|
153
|
+
footer_found = true if line_def.footer
|
|
135
154
|
end
|
|
136
|
-
header_found && footer_found
|
|
155
|
+
header_found && footer_found
|
|
137
156
|
end
|
|
138
|
-
|
|
157
|
+
|
|
139
158
|
# This function is called before a Requests is yielded.
|
|
140
159
|
def validate
|
|
141
160
|
end
|
|
142
|
-
|
|
143
|
-
# Returns the first timestamp encountered in a request.
|
|
161
|
+
|
|
162
|
+
# Returns the first timestamp encountered in a request.
|
|
144
163
|
def timestamp
|
|
145
164
|
first(:timestamp)
|
|
146
165
|
end
|
|
147
|
-
|
|
166
|
+
|
|
148
167
|
def first_lineno
|
|
149
168
|
@lines.map { |line| line[:lineno] }.reject { |v| v.nil? }.min
|
|
150
169
|
end
|
|
151
|
-
|
|
170
|
+
|
|
152
171
|
def last_lineno
|
|
153
172
|
@lines.map { |line| line[:lineno] }.reject { |v| v.nil? }.max
|
|
154
173
|
end
|
|
@@ -2,7 +2,7 @@ require 'rubygems'
|
|
|
2
2
|
require 'activerecord'
|
|
3
3
|
|
|
4
4
|
module RequestLogAnalyzer::Source
|
|
5
|
-
|
|
5
|
+
|
|
6
6
|
# Active Resource hook
|
|
7
7
|
class Request < ActiveRecord::Base
|
|
8
8
|
has_many :completed_lines
|
|
@@ -26,8 +26,7 @@ module RequestLogAnalyzer::Source
|
|
|
26
26
|
# The Database class gets log data from the database.
|
|
27
27
|
class DatabaseLoader < Base
|
|
28
28
|
|
|
29
|
-
attr_reader :source_files
|
|
30
|
-
attr_reader :requests
|
|
29
|
+
attr_reader :source_files, :file_format, :requests
|
|
31
30
|
|
|
32
31
|
# Initializes the log file parser instance.
|
|
33
32
|
# It will apply the language specific FileFormat module to this instance. It will use the line
|
|
@@ -35,16 +34,13 @@ module RequestLogAnalyzer::Source
|
|
|
35
34
|
#
|
|
36
35
|
# <tt>format</tt>:: The current file format instance
|
|
37
36
|
# <tt>options</tt>:: A hash of options that are used by the parser
|
|
38
|
-
def initialize(format, options = {})
|
|
39
|
-
|
|
40
|
-
@options = options
|
|
37
|
+
def initialize(format, options = {})
|
|
38
|
+
super(format, options)
|
|
41
39
|
@source_files = options[:source_files]
|
|
42
40
|
@parsed_requests = 0
|
|
43
41
|
@requests = []
|
|
44
|
-
|
|
45
|
-
self.register_file_format(format)
|
|
46
42
|
end
|
|
47
|
-
|
|
43
|
+
|
|
48
44
|
# Reads the input, which can either be a file, sequence of files or STDIN to parse
|
|
49
45
|
# lines specified in the FileFormat. This lines will be combined into Request instances,
|
|
50
46
|
# that will be yielded. The actual parsing occurs in the parse_io method.
|
|
@@ -56,10 +52,10 @@ module RequestLogAnalyzer::Source
|
|
|
56
52
|
RequestLogAnalyzer::Source::Request.find(:all).each do |request|
|
|
57
53
|
@parsed_requests += 1
|
|
58
54
|
@progress_handler.call(:progress, @parsed_requests) if @progress_handler
|
|
59
|
-
|
|
55
|
+
|
|
60
56
|
yield request.convert(self.file_format)
|
|
61
57
|
end
|
|
62
|
-
|
|
58
|
+
|
|
63
59
|
@progress_handler.call(:finished, @source_files) if @progress_handler
|
|
64
60
|
end
|
|
65
61
|
|
|
@@ -70,15 +66,15 @@ module RequestLogAnalyzer::Source
|
|
|
70
66
|
end
|
|
71
67
|
|
|
72
68
|
# Add a block to this method to install a warning handler while parsing,
|
|
73
|
-
# <tt>proc</tt>:: The proc that will be called to handle parse warning messages
|
|
69
|
+
# <tt>proc</tt>:: The proc that will be called to handle parse warning messages
|
|
74
70
|
def warning=(proc)
|
|
75
71
|
@warning_handler = proc
|
|
76
72
|
end
|
|
77
73
|
|
|
78
74
|
# This method is called by the parser if it encounteres any parsing problems.
|
|
79
|
-
# It will call the installed warning handler if any.
|
|
75
|
+
# It will call the installed warning handler if any.
|
|
80
76
|
#
|
|
81
|
-
# By default, RequestLogAnalyzer::Controller will install a warning handler
|
|
77
|
+
# By default, RequestLogAnalyzer::Controller will install a warning handler
|
|
82
78
|
# that will pass the warnings to each aggregator so they can do something useful
|
|
83
79
|
# with it.
|
|
84
80
|
#
|