request-log-analyzer 1.2.9 → 1.3.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/bin/request-log-analyzer +33 -19
- data/lib/cli/database_console.rb +26 -0
- data/lib/cli/database_console_init.rb +42 -0
- data/lib/cli/tools.rb +1 -1
- data/lib/request_log_analyzer/aggregator/database_inserter.rb +81 -0
- data/lib/request_log_analyzer/aggregator/summarizer.rb +2 -2
- data/lib/request_log_analyzer/aggregator.rb +4 -0
- data/lib/request_log_analyzer/controller.rb +23 -7
- data/lib/request_log_analyzer/database/base.rb +114 -0
- data/lib/request_log_analyzer/database/connection.rb +38 -0
- data/lib/request_log_analyzer/database.rb +177 -0
- data/lib/request_log_analyzer/file_format.rb +6 -3
- data/lib/request_log_analyzer/mailer.rb +46 -0
- data/lib/request_log_analyzer/request.rb +2 -1
- data/lib/request_log_analyzer/source/{database.rb → database_loader.rb} +1 -1
- data/lib/request_log_analyzer/source/log_parser.rb +28 -15
- data/lib/request_log_analyzer/source.rb +7 -2
- data/lib/request_log_analyzer.rb +5 -8
- data/request-log-analyzer.gemspec +8 -8
- data/spec/database.yml +17 -0
- data/spec/fixtures/rails.db +0 -0
- data/spec/integration/command_line_usage_spec.rb +14 -9
- data/spec/lib/macros.rb +16 -0
- data/spec/lib/mocks.rb +18 -6
- data/spec/unit/aggregator/database_inserter_spec.rb +93 -0
- data/spec/unit/database/base_class_spec.rb +190 -0
- data/spec/unit/database/connection_spec.rb +34 -0
- data/spec/unit/database/database_spec.rb +138 -0
- data/spec/unit/source/log_parser_spec.rb +12 -0
- metadata +29 -16
- data/lib/request_log_analyzer/aggregator/database.rb +0 -220
- data/spec/spec.opts +0 -3
- data/spec/unit/aggregator/database_spec.rb +0 -245
data/bin/request-log-analyzer
CHANGED
@@ -1,8 +1,9 @@
|
|
1
1
|
#!/usr/bin/ruby
|
2
|
-
|
3
|
-
require
|
4
|
-
require
|
5
|
-
require
|
2
|
+
$:.unshift(File.dirname(__FILE__) + '/../lib')
|
3
|
+
require 'request_log_analyzer'
|
4
|
+
require 'cli/command_line_arguments'
|
5
|
+
require 'lib/cli/progressbar'
|
6
|
+
require 'lib/cli/tools'
|
6
7
|
|
7
8
|
# Parse the arguments given via commandline
|
8
9
|
begin
|
@@ -11,40 +12,49 @@ begin
|
|
11
12
|
command_line.command(:install) do |install|
|
12
13
|
install.parameters = 1
|
13
14
|
end
|
14
|
-
|
15
|
+
|
16
|
+
command_line.command(:console) do |cons|
|
17
|
+
cons.option(:database, :alias => :d, :required => true)
|
18
|
+
cons.option(:format, :alias => :f, :default => 'rails')
|
19
|
+
cons.option(:apache_format)
|
20
|
+
end
|
21
|
+
|
15
22
|
command_line.command(:strip) do |strip|
|
16
23
|
strip.minimum_parameters = 1
|
17
|
-
strip.option(:format, :alias => :f, :default => 'rails')
|
24
|
+
strip.option(:format, :alias => :f, :default => 'rails')
|
18
25
|
strip.option(:output, :alias => :o)
|
19
26
|
strip.switch(:discard_teaser_lines, :t)
|
20
27
|
strip.switch(:keep_junk_lines, :j)
|
21
28
|
end
|
22
|
-
|
29
|
+
|
23
30
|
command_line.option(:format, :alias => :f, :default => 'rails')
|
24
31
|
command_line.option(:apache_format)
|
25
|
-
|
32
|
+
|
26
33
|
command_line.option(:file, :alias => :e)
|
34
|
+
command_line.option(:mail, :alias => :m)
|
27
35
|
command_line.option(:parse_strategy, :default => 'assume-correct')
|
28
36
|
command_line.option(:dump)
|
29
|
-
|
37
|
+
|
30
38
|
command_line.option(:aggregator, :alias => :a, :multiple => true)
|
31
|
-
|
39
|
+
|
40
|
+
command_line.option(:database, :alias => :d)
|
41
|
+
command_line.switch(:reset_database)
|
32
42
|
|
33
43
|
# filtering options
|
34
44
|
command_line.option(:select, :multiple => true, :parameters => 2)
|
35
45
|
command_line.option(:reject, :multiple => true, :parameters => 2)
|
36
46
|
command_line.option(:after)
|
37
|
-
command_line.option(:before)
|
38
|
-
|
47
|
+
command_line.option(:before)
|
48
|
+
|
39
49
|
command_line.switch(:boring, :b)
|
40
|
-
command_line.option(:output, :alias => :o, :default => 'FixedWidth')
|
50
|
+
command_line.option(:output, :alias => :o, :default => 'FixedWidth')
|
41
51
|
command_line.option(:report_width, :default => terminal_width - 1)
|
42
|
-
|
52
|
+
|
43
53
|
command_line.switch(:debug)
|
44
|
-
|
45
|
-
command_line.minimum_parameters = 1
|
54
|
+
|
55
|
+
command_line.minimum_parameters = 1
|
46
56
|
end
|
47
|
-
|
57
|
+
|
48
58
|
rescue CommandLine::Error => e
|
49
59
|
puts "Request-log-analyzer, by Willem van Bergen and Bart ten Brinke - version #{RequestLogAnalyzer::VERSION}"
|
50
60
|
puts "Website: http://railsdoctors.com"
|
@@ -65,6 +75,7 @@ rescue CommandLine::Error => e
|
|
65
75
|
puts " --database <filename>, -d: Creates an SQLite3 database of all the parsed request information."
|
66
76
|
puts " --debug Print debug information while parsing."
|
67
77
|
puts " --file <filename> Output to file."
|
78
|
+
puts " --mail <emailaddress> Send report to an email address."
|
68
79
|
puts " --output <format> Output format. Supports 'HTML' and 'FixedWidth' (default)"
|
69
80
|
puts " --dump <filename> Dump the YAML formatted results in the given file"
|
70
81
|
puts
|
@@ -83,11 +94,14 @@ end
|
|
83
94
|
case arguments.command
|
84
95
|
when :install
|
85
96
|
install_rake_tasks(arguments.parameters[0])
|
97
|
+
when :console
|
98
|
+
require 'cli/database_console'
|
99
|
+
DatabaseConsole.new(arguments).run!
|
86
100
|
when :strip
|
87
|
-
require File.dirname(__FILE__) + '/../lib/request_log_analyzer/log_processor'
|
101
|
+
require File.dirname(__FILE__) + '/../lib/request_log_analyzer/log_processor'
|
88
102
|
RequestLogAnalyzer::LogProcessor.build(:strip, arguments).run!
|
89
103
|
else
|
90
|
-
puts "Request-log-analyzer, by Willem van Bergen and Bart ten Brinke - version #{RequestLogAnalyzer::VERSION}"
|
104
|
+
puts "Request-log-analyzer, by Willem van Bergen and Bart ten Brinke - version #{RequestLogAnalyzer::VERSION}"
|
91
105
|
puts "Website: http://railsdoctors.com"
|
92
106
|
puts
|
93
107
|
|
@@ -0,0 +1,26 @@
|
|
1
|
+
|
2
|
+
class DatabaseConsole
|
3
|
+
|
4
|
+
IRB = RUBY_PLATFORM =~ /(:?mswin|mingw)/ ? 'irb.bat' : 'irb'
|
5
|
+
|
6
|
+
def initialize(arguments)
|
7
|
+
@arguments = arguments
|
8
|
+
end
|
9
|
+
|
10
|
+
def run!
|
11
|
+
libraries = ['irb/completion', 'rubygems', './lib/request_log_analyzer', './lib/cli/database_console_init']
|
12
|
+
libaries_string = libraries.map { |l| "-r #{l}" }.join(' ')
|
13
|
+
|
14
|
+
ENV['RLA_DBCONSOLE_DATABASE'] = @arguments[:database]
|
15
|
+
if @arguments[:apache_format]
|
16
|
+
ENV['RLA_DBCONSOLE_FORMAT'] = 'apache'
|
17
|
+
ENV['RLA_DBCONSOLE_FORMAT_ARGUMENT'] = @arguments[:apache_format]
|
18
|
+
else
|
19
|
+
ENV['RLA_DBCONSOLE_FORMAT'] = @arguments[:format]
|
20
|
+
end
|
21
|
+
# ENV['RLA_DBCONSOLE_FORMAT_ARGS'] = arguments['database']
|
22
|
+
|
23
|
+
exec("#{IRB} #{libaries_string} --simple-prompt")
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# Setup the include path
|
2
|
+
$:.unshift(File.dirname(__FILE__) + '/..')
|
3
|
+
|
4
|
+
$database = RequestLogAnalyzer::Database.new(ENV['RLA_DBCONSOLE_DATABASE'])
|
5
|
+
$database.load_database_schema!
|
6
|
+
|
7
|
+
require 'cli/tools'
|
8
|
+
|
9
|
+
def wordwrap(string, max = 80, indent = "")
|
10
|
+
strings = [""]
|
11
|
+
string.split(", ").each do |item|
|
12
|
+
if strings.last.length == 0 || strings.last.length + item.length <= max
|
13
|
+
strings.last << item << ', '
|
14
|
+
else
|
15
|
+
strings << (item + ', ')
|
16
|
+
end
|
17
|
+
end
|
18
|
+
strings.map(&:strip).join("\n#{indent}").slice(0..-2)
|
19
|
+
end
|
20
|
+
|
21
|
+
class Request
|
22
|
+
def inspect
|
23
|
+
request_inspect = "Request[id: #{id}]"
|
24
|
+
request_inspect << " <#{lines.first.source.filename}>" if lines.first.source
|
25
|
+
|
26
|
+
inspected_lines = lines.map do |line|
|
27
|
+
inspect_line = " - #{line.line_type} (line #{line.lineno})"
|
28
|
+
if (inspect_attributes = line.attributes.reject { |(k, v)| [:id, :source_id, :request_id, :lineno].include?(k.to_sym) }).any?
|
29
|
+
inspect_attributes = inspect_attributes.map { |(k,v)| "#{k} = #{v.inspect}" }.join(', ')
|
30
|
+
inspect_line << "\n " + wordwrap(inspect_attributes, terminal_width - 6, " ")
|
31
|
+
end
|
32
|
+
inspect_line
|
33
|
+
end
|
34
|
+
|
35
|
+
request_inspect << "\n" << inspected_lines.join("\n") << "\n\n"
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
puts "request-log-analyzer database console"
|
40
|
+
puts "-------------------------------------"
|
41
|
+
puts "The following ActiveRecord classes are available:"
|
42
|
+
puts $database.orm_classes.join(", ")
|
data/lib/cli/tools.rb
CHANGED
@@ -0,0 +1,81 @@
|
|
1
|
+
|
2
|
+
module RequestLogAnalyzer::Aggregator
|
3
|
+
|
4
|
+
# The database aggregator will create an SQLite3 database with all parsed request information.
|
5
|
+
#
|
6
|
+
# The prepare method will create a database schema according to the file format definitions.
|
7
|
+
# It will also create ActiveRecord::Base subclasses to interact with the created tables.
|
8
|
+
# Then, the aggregate method will be called for every parsed request. The information of
|
9
|
+
# these requests is inserted into the tables using the ActiveRecord classes.
|
10
|
+
#
|
11
|
+
# A requests table will be created, in which a record is inserted for every parsed request.
|
12
|
+
# For every line type, a separate table will be created with a request_id field to point to
|
13
|
+
# the request record, and a field for every parsed value. Finally, a warnings table will be
|
14
|
+
# created to log all parse warnings.
|
15
|
+
class DatabaseInserter < Base
|
16
|
+
|
17
|
+
attr_reader :request_count, :sources, :database
|
18
|
+
|
19
|
+
# Establishes a connection to the database and creates the necessary database schema for the
|
20
|
+
# current file format
|
21
|
+
def prepare
|
22
|
+
@sources = {}
|
23
|
+
@database = RequestLogAnalyzer::Database.new(options[:database])
|
24
|
+
@database.file_format = source.file_format
|
25
|
+
|
26
|
+
database.drop_database_schema! if options[:reset_database]
|
27
|
+
database.create_database_schema!
|
28
|
+
end
|
29
|
+
|
30
|
+
# Aggregates a request into the database
|
31
|
+
# This will create a record in the requests table and create a record for every line that has been parsed,
|
32
|
+
# in which the captured values will be stored.
|
33
|
+
def aggregate(request)
|
34
|
+
@request_object = database.request_class.new(:first_lineno => request.first_lineno, :last_lineno => request.last_lineno)
|
35
|
+
request.lines.each do |line|
|
36
|
+
class_columns = database.get_class(line[:line_type]).column_names.reject { |column| ['id', 'source_id', 'request_id'].include?(column) }
|
37
|
+
attributes = Hash[*line.select { |(k, v)| class_columns.include?(k.to_s) }.flatten]
|
38
|
+
attributes[:source_id] = @sources[line[:source]].id if @sources[line[:source]]
|
39
|
+
@request_object.send("#{line[:line_type]}_lines").build(attributes)
|
40
|
+
end
|
41
|
+
@request_object.save!
|
42
|
+
rescue SQLite3::SQLException => e
|
43
|
+
raise Interrupt, e.message
|
44
|
+
end
|
45
|
+
|
46
|
+
# Finalizes the aggregator by closing the connection to the database
|
47
|
+
def finalize
|
48
|
+
@request_count = database.request_class.count
|
49
|
+
database.disconnect
|
50
|
+
database.remove_orm_classes!
|
51
|
+
end
|
52
|
+
|
53
|
+
# Records w warining in the warnings table.
|
54
|
+
def warning(type, message, lineno)
|
55
|
+
database.warning_class.create!(:warning_type => type.to_s, :message => message, :lineno => lineno)
|
56
|
+
end
|
57
|
+
|
58
|
+
# Records source changes in the sources table
|
59
|
+
def source_change(change, filename)
|
60
|
+
case change
|
61
|
+
when :started
|
62
|
+
@sources[filename] = database.source_class.create!(:filename => filename)
|
63
|
+
when :finished
|
64
|
+
@sources[filename].update_attributes!(:filesize => File.size(filename), :mtime => File.mtime(filename))
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
# Prints a short report of what has been inserted into the database
|
69
|
+
def report(output)
|
70
|
+
output.title('Request database created')
|
71
|
+
|
72
|
+
output << "A database file has been created with all parsed request information.\n"
|
73
|
+
output << "#{@request_count} requests have been added to the database.\n"
|
74
|
+
output << "\n"
|
75
|
+
output << "To open a Ruby console to inspect the database, run the following command.\n"
|
76
|
+
output << output.colorize(" $ request-log-analyzer console -d #{options[:database]}\n", :bold)
|
77
|
+
output << "\n"
|
78
|
+
end
|
79
|
+
|
80
|
+
end
|
81
|
+
end
|
@@ -130,9 +130,9 @@ module RequestLogAnalyzer::Aggregator
|
|
130
130
|
output.with_style(:cell_separator => false) do
|
131
131
|
output.table({:width => 20}, {:font => :bold}) do |rows|
|
132
132
|
rows << ['Parsed lines:', source.parsed_lines]
|
133
|
-
rows << ['Parsed requests:', source.parsed_requests]
|
134
133
|
rows << ['Skipped lines:', source.skipped_lines]
|
135
|
-
|
134
|
+
rows << ['Parsed requests:', source.parsed_requests]
|
135
|
+
rows << ['Skipped requests:', source.skipped_requests]
|
136
136
|
rows << ["Warnings:", @warnings_encountered.map { |(key, value)| "#{key}: #{value}" }.join(', ')] if has_warnings?
|
137
137
|
end
|
138
138
|
end
|
@@ -32,7 +32,10 @@ module RequestLogAnalyzer
|
|
32
32
|
def self.build(arguments)
|
33
33
|
options = { }
|
34
34
|
|
35
|
-
|
35
|
+
# Database command line options
|
36
|
+
options[:database] = arguments[:database] if arguments[:database]
|
37
|
+
options[:reset_database] = arguments[:reset_database]
|
38
|
+
|
36
39
|
options[:debug] = arguments[:debug]
|
37
40
|
options[:dump] = arguments[:dump]
|
38
41
|
|
@@ -40,6 +43,9 @@ module RequestLogAnalyzer
|
|
40
43
|
if arguments[:file]
|
41
44
|
output_file = File.new(arguments[:file], "w+")
|
42
45
|
options[:output] = output_class.new(output_file, :width => 80, :color => false, :characters => :ascii)
|
46
|
+
elsif arguments[:mail]
|
47
|
+
output_mail = RequestLogAnalyzer::Mailer.new(arguments[:mail])
|
48
|
+
options[:output] = output_class.new(output_mail, :width => 80, :color => false, :characters => :ascii)
|
43
49
|
else
|
44
50
|
options[:output] = output_class.new(STDOUT, :width => arguments[:report_width].to_i,
|
45
51
|
:color => !arguments[:boring], :characters => (arguments[:boring] ? :ascii : :utf))
|
@@ -68,7 +74,7 @@ module RequestLogAnalyzer
|
|
68
74
|
end
|
69
75
|
|
70
76
|
controller = Controller.new(RequestLogAnalyzer::Source::LogParser.new(file_format, options), options)
|
71
|
-
#controller = Controller.new(RequestLogAnalyzer::Source::
|
77
|
+
#controller = Controller.new(RequestLogAnalyzer::Source::DatabaseLoader.new(file_format, options), options)
|
72
78
|
|
73
79
|
options[:parse_strategy] = arguments[:parse_strategy]
|
74
80
|
|
@@ -92,9 +98,9 @@ module RequestLogAnalyzer
|
|
92
98
|
arguments[:aggregator].each { |agg| controller.add_aggregator(agg.to_sym) }
|
93
99
|
|
94
100
|
# register the database
|
95
|
-
controller.add_aggregator(:
|
96
|
-
controller.add_aggregator(:
|
97
|
-
|
101
|
+
controller.add_aggregator(:summarizer) if arguments[:aggregator].empty?
|
102
|
+
controller.add_aggregator(:database_inserter) if arguments[:database] && !arguments[:aggregator].include?('database')
|
103
|
+
|
98
104
|
# register the echo aggregator in debug mode
|
99
105
|
controller.add_aggregator(:echo) if arguments[:debug]
|
100
106
|
|
@@ -128,6 +134,8 @@ module RequestLogAnalyzer
|
|
128
134
|
|
129
135
|
# Handle progress messagess
|
130
136
|
@source.progress = lambda { |message, value| handle_progress(message, value) } if @source
|
137
|
+
|
138
|
+
@source.source_changes = lambda { |change, filename| handle_source_change(change, filename) } if @source
|
131
139
|
end
|
132
140
|
|
133
141
|
# Progress function.
|
@@ -151,6 +159,11 @@ module RequestLogAnalyzer
|
|
151
159
|
end
|
152
160
|
end
|
153
161
|
|
162
|
+
# Source change handler
|
163
|
+
def handle_source_change(change, filename)
|
164
|
+
@aggregators.each { |agg| agg.source_change(change, File.expand_path(filename, Dir.pwd)) }
|
165
|
+
end
|
166
|
+
|
154
167
|
# Adds an aggregator to the controller. The aggregator will be called for every request
|
155
168
|
# that is parsed from the provided sources (see add_source)
|
156
169
|
def add_aggregator(agg)
|
@@ -180,8 +193,9 @@ module RequestLogAnalyzer
|
|
180
193
|
# Push a request to all the aggregators (@aggregators).
|
181
194
|
# <tt>request</tt> The request to push to the aggregators.
|
182
195
|
def aggregate_request(request)
|
183
|
-
return unless request
|
196
|
+
return false unless request
|
184
197
|
@aggregators.each { |agg| agg.aggregate(request) }
|
198
|
+
return true
|
185
199
|
end
|
186
200
|
|
187
201
|
# Runs RequestLogAnalyzer
|
@@ -198,8 +212,8 @@ module RequestLogAnalyzer
|
|
198
212
|
install_signal_handlers
|
199
213
|
|
200
214
|
@source.each_request do |request|
|
201
|
-
aggregate_request(filter_request(request))
|
202
215
|
break if @interrupted
|
216
|
+
aggregate_request(filter_request(request))
|
203
217
|
end
|
204
218
|
|
205
219
|
@aggregators.each { |agg| agg.finalize }
|
@@ -217,6 +231,8 @@ module RequestLogAnalyzer
|
|
217
231
|
puts "Mail to contact@railsdoctors.com or visit us at http://railsdoctors.com"
|
218
232
|
puts "Thanks for using request-log-analyzer!"
|
219
233
|
@output.io.close
|
234
|
+
elsif @output.io.kind_of?(RequestLogAnalyzer::Mailer)
|
235
|
+
@output.io.mail
|
220
236
|
end
|
221
237
|
end
|
222
238
|
|
@@ -0,0 +1,114 @@
|
|
1
|
+
class RequestLogAnalyzer::Database::Base < ActiveRecord::Base
|
2
|
+
|
3
|
+
self.abstract_class = true
|
4
|
+
|
5
|
+
def <=>(other)
|
6
|
+
if (source_id.nil? && other.source_id.nil?) || (source_comparison = source_id <=> other.source_id) == 0
|
7
|
+
lineno <=> other.lineno
|
8
|
+
else
|
9
|
+
source_comparison
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def line_type
|
14
|
+
self.class.name.underscore.gsub(/_line$/, '').to_sym
|
15
|
+
end
|
16
|
+
|
17
|
+
cattr_accessor :database, :line_definition
|
18
|
+
|
19
|
+
def self.subclass_from_line_definition(definition)
|
20
|
+
klass = Class.new(RequestLogAnalyzer::Database::Base)
|
21
|
+
klass.set_table_name("#{definition.name}_lines")
|
22
|
+
|
23
|
+
klass.line_definition = definition
|
24
|
+
|
25
|
+
# Set relations with requests and sources table
|
26
|
+
klass.belongs_to :request
|
27
|
+
klass.belongs_to :source
|
28
|
+
|
29
|
+
# Serialize complex fields into the database
|
30
|
+
definition.captures.select { |c| c.has_key?(:provides) }.each do |capture|
|
31
|
+
klass.send(:serialize, capture[:name], Hash)
|
32
|
+
end
|
33
|
+
|
34
|
+
database.request_class.has_many "#{definition.name}_lines".to_sym
|
35
|
+
database.source_class.has_many "#{definition.name}_lines".to_sym
|
36
|
+
|
37
|
+
return klass
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.subclass_from_table(table)
|
41
|
+
raise "Table #{table} not found!" unless database.connection.table_exists?(table)
|
42
|
+
|
43
|
+
klass = Class.new(RequestLogAnalyzer::Database::Base)
|
44
|
+
klass.set_table_name(table)
|
45
|
+
|
46
|
+
if klass.column_names.include?('request_id')
|
47
|
+
klass.belongs_to :request
|
48
|
+
database.request_class.has_many table.to_sym
|
49
|
+
end
|
50
|
+
|
51
|
+
if klass.column_names.include?('source_id')
|
52
|
+
klass.belongs_to :source
|
53
|
+
database.source_class.has_many table.to_sym
|
54
|
+
end
|
55
|
+
|
56
|
+
return klass
|
57
|
+
end
|
58
|
+
|
59
|
+
def self.drop_table!
|
60
|
+
database.connection.remove_index(self.table_name, [:source_id]) rescue nil
|
61
|
+
database.connection.remove_index(self.table_name, [:request_id]) rescue nil
|
62
|
+
database.connection.drop_table(self.table_name) if database.connection.table_exists?(self.table_name)
|
63
|
+
end
|
64
|
+
|
65
|
+
def self.create_table!
|
66
|
+
raise "No line_definition available to base table schema on!" unless self.line_definition
|
67
|
+
|
68
|
+
unless table_exists?
|
69
|
+
database.connection.create_table(table_name.to_sym) do |t|
|
70
|
+
|
71
|
+
# Default fields
|
72
|
+
t.column :request_id, :integer
|
73
|
+
t.column :source_id, :integer
|
74
|
+
t.column :lineno, :integer
|
75
|
+
|
76
|
+
line_definition.captures.each do |capture|
|
77
|
+
# Add a field for every capture
|
78
|
+
t.column(capture[:name], column_type(capture[:type]))
|
79
|
+
|
80
|
+
# If the capture provides other field as well, create columns for them, too
|
81
|
+
capture[:provides].each { |field, field_type| t.column(field, column_type(field_type)) } if capture[:provides].kind_of?(Hash)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
# Add indices to table for more speedy querying
|
87
|
+
database.connection.add_index(self.table_name.to_sym, [:request_id]) # rescue
|
88
|
+
database.connection.add_index(self.table_name.to_sym, [:source_id]) # rescue
|
89
|
+
end
|
90
|
+
|
91
|
+
|
92
|
+
# Function to determine the column type for a field
|
93
|
+
# TODO: make more robust / include in file-format definition
|
94
|
+
def self.column_type(type_indicator)
|
95
|
+
case type_indicator
|
96
|
+
when :eval; :text
|
97
|
+
when :hash; :text
|
98
|
+
when :text; :text
|
99
|
+
when :string; :string
|
100
|
+
when :sec; :double
|
101
|
+
when :msec; :double
|
102
|
+
when :duration; :double
|
103
|
+
when :float; :double
|
104
|
+
when :double; :double
|
105
|
+
when :integer; :integer
|
106
|
+
when :int; :int
|
107
|
+
when :timestamp; :datetime
|
108
|
+
when :datetime; :datetime
|
109
|
+
when :date; :date
|
110
|
+
else :string
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module RequestLogAnalyzer::Database::Connection
|
2
|
+
|
3
|
+
def self.from_string(string)
|
4
|
+
hash = {}
|
5
|
+
if string =~ /^(?:\w+=(?:[^;])*;)*\w+=(?:[^;])*$/
|
6
|
+
string.scan(/(\w+)=([^;]*);?/) { |variable, value| hash[variable.to_sym] = value }
|
7
|
+
elsif string =~ /^(\w+)\:\/\/(?:(?:([^:]+)(?:\:([^:]+))?\@)?([\w\.-]+)\/)?([\w\:\-\.\/]+)$/
|
8
|
+
hash[:adapter], hash[:username], hash[:password], hash[:host], hash[:database] = $1, $2, $3, $4, $5
|
9
|
+
hash.delete_if { |k, v| v.nil? }
|
10
|
+
end
|
11
|
+
return hash.empty? ? nil : hash
|
12
|
+
end
|
13
|
+
|
14
|
+
def connect(connection_identifier)
|
15
|
+
if connection_identifier.kind_of?(Hash)
|
16
|
+
RequestLogAnalyzer::Database::Base.establish_connection(connection_identifier)
|
17
|
+
elsif connection_identifier == ':memory:'
|
18
|
+
RequestLogAnalyzer::Database::Base.establish_connection(:adapter => 'sqlite3', :database => ':memory:')
|
19
|
+
elsif connection_hash = RequestLogAnalyzer::Database::Connection.from_string(connection_identifier)
|
20
|
+
RequestLogAnalyzer::Database::Base.establish_connection(connection_hash)
|
21
|
+
elsif connection_identifier.kind_of?(String) # Normal SQLite 3 database file
|
22
|
+
RequestLogAnalyzer::Database::Base.establish_connection(:adapter => 'sqlite3', :database => connection_identifier)
|
23
|
+
elsif connection_identifier.nil?
|
24
|
+
nil
|
25
|
+
else
|
26
|
+
raise "Cannot connect with this connection_identifier: #{connection_identifier.inspect}"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def disconnect
|
31
|
+
RequestLogAnalyzer::Database::Base.remove_connection
|
32
|
+
end
|
33
|
+
|
34
|
+
def connection
|
35
|
+
RequestLogAnalyzer::Database::Base.connection
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|