request-log-analyzer 1.2.9 → 1.3.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|