request-log-analyzer 1.2.3 → 1.2.6
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +10 -0
- data/Rakefile +3 -1
- data/lib/request_log_analyzer.rb +1 -1
- data/lib/request_log_analyzer/aggregator/database.rb +29 -20
- data/lib/request_log_analyzer/file_format/merb.rb +5 -7
- data/lib/request_log_analyzer/request.rb +2 -2
- data/request-log-analyzer.gemspec +36 -0
- data/spec/fixtures/merb_prefixed.log +9 -0
- data/spec/lib/mocks.rb +12 -1
- data/spec/unit/aggregator/database_spec.rb +48 -22
- data/spec/unit/file_format/merb_format_spec.rb +20 -1
- data/spec/unit/source/request_spec.rb +90 -64
- data/tasks/github-gem.rake +199 -192
- metadata +117 -95
- data/RELEASE_NOTES.rdoc +0 -10
- data/tasks/rspec.rake +0 -19
data/.gitignore
ADDED
data/Rakefile
CHANGED
data/lib/request_log_analyzer.rb
CHANGED
@@ -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 =
|
14
|
+
VERSION = "1.2.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.
|
@@ -46,6 +46,7 @@ module RequestLogAnalyzer::Aggregator
|
|
46
46
|
def finalize
|
47
47
|
@request_count = orm_module::Request.count
|
48
48
|
remove_database_connection!
|
49
|
+
deinitialize_orm_module!
|
49
50
|
end
|
50
51
|
|
51
52
|
# Records w warining in the warnings table.
|
@@ -64,6 +65,11 @@ module RequestLogAnalyzer::Aggregator
|
|
64
65
|
output << "\n"
|
65
66
|
end
|
66
67
|
|
68
|
+
# Retreives the connection that is used for the database inserter
|
69
|
+
def connection
|
70
|
+
orm_module::Base.connection
|
71
|
+
end
|
72
|
+
|
67
73
|
protected
|
68
74
|
|
69
75
|
# Create a module and a default subclass of ActiveRecord::Base on which to establish the database connection
|
@@ -79,16 +85,22 @@ module RequestLogAnalyzer::Aggregator
|
|
79
85
|
orm_base_class.abstract_class = true
|
80
86
|
orm_module.const_set('Base', orm_base_class)
|
81
87
|
end
|
82
|
-
end
|
83
|
-
|
88
|
+
end
|
89
|
+
|
90
|
+
# Deinitializes the ORM module and the ActiveRecord::Base subclass.
|
91
|
+
def deinitialize_orm_module!
|
92
|
+
file_format.class.send(:remove_const, 'Database') if file_format.class.const_defined?('Database')
|
93
|
+
@orm_module = nil
|
94
|
+
end
|
95
|
+
|
84
96
|
# Established a connection with the database for this session
|
85
97
|
def establish_database_connection!
|
86
98
|
orm_module::Base.establish_connection(:adapter => 'sqlite3', :database => options[:database])
|
87
|
-
ActiveRecord::Migration.class_eval("def self.connection; #{@orm_module.to_s}::Base.connection; end ")
|
88
|
-
end
|
89
|
-
|
99
|
+
#ActiveRecord::Migration.class_eval("def self.connection; #{@orm_module.to_s}::Base.connection; end ")
|
100
|
+
end
|
101
|
+
|
90
102
|
def remove_database_connection!
|
91
|
-
ActiveRecord::Migration.class_eval("def self.connection; ActiveRecord::Base.connection; end ")
|
103
|
+
#ActiveRecord::Migration.class_eval("def self.connection; ActiveRecord::Base.connection; end ")
|
92
104
|
orm_module::Base.remove_connection
|
93
105
|
end
|
94
106
|
|
@@ -97,8 +109,7 @@ module RequestLogAnalyzer::Aggregator
|
|
97
109
|
# what line in the original file the line was found, and a request_id to link lines related
|
98
110
|
# to the same request. It will also create an index in the request_id field to speed up queries.
|
99
111
|
def create_database_table(definition)
|
100
|
-
|
101
|
-
ActiveRecord::Migration.create_table("#{definition.name}_lines") do |t|
|
112
|
+
connection.create_table("#{definition.name}_lines") do |t|
|
102
113
|
|
103
114
|
# Add default fields for every line type
|
104
115
|
t.column(:request_id, :integer)
|
@@ -114,7 +125,7 @@ module RequestLogAnalyzer::Aggregator
|
|
114
125
|
end
|
115
126
|
|
116
127
|
# Create an index on the request_id column to support faster querying
|
117
|
-
|
128
|
+
connection.add_index("#{definition.name}_lines", [:request_id])
|
118
129
|
end
|
119
130
|
|
120
131
|
# Creates an ActiveRecord class for a given line definition.
|
@@ -126,8 +137,8 @@ module RequestLogAnalyzer::Aggregator
|
|
126
137
|
klass = Class.new(orm_module::Base)
|
127
138
|
klass.send(:belongs_to, :request)
|
128
139
|
|
129
|
-
definition.captures.each do |capture|
|
130
|
-
klass.send(:serialize, capture[:name], Hash)
|
140
|
+
definition.captures.select { |c| c.has_key?(:provides) }.each do |capture|
|
141
|
+
klass.send(:serialize, capture[:name], Hash)
|
131
142
|
end
|
132
143
|
|
133
144
|
orm_module.const_set(class_name, klass) unless orm_module.const_defined?(class_name)
|
@@ -137,10 +148,9 @@ module RequestLogAnalyzer::Aggregator
|
|
137
148
|
# Creates a requests table, in which a record is created for every request. It also creates an
|
138
149
|
# ActiveRecord::Base class to communicate with this table.
|
139
150
|
def create_request_table_and_class
|
140
|
-
|
141
|
-
|
142
|
-
t.
|
143
|
-
t.integer :last_lineno
|
151
|
+
connection.create_table("requests") do |t|
|
152
|
+
t.column :first_lineno, :integer
|
153
|
+
t.column :last_lineno, :integer
|
144
154
|
end
|
145
155
|
|
146
156
|
orm_module.const_set('Request', Class.new(orm_module::Base)) unless orm_module.const_defined?('Request')
|
@@ -149,11 +159,10 @@ module RequestLogAnalyzer::Aggregator
|
|
149
159
|
|
150
160
|
# Creates a warnings table and a corresponding Warning class to communicate with this table using ActiveRecord.
|
151
161
|
def create_warning_table_and_class
|
152
|
-
|
153
|
-
|
154
|
-
t.
|
155
|
-
t.
|
156
|
-
t.integer :lineno
|
162
|
+
connection.create_table("warnings") do |t|
|
163
|
+
t.column :warning_type, :string, :limit => 30, :null => false
|
164
|
+
t.column :message, :string
|
165
|
+
t.column :lineno, :integer
|
157
166
|
end
|
158
167
|
|
159
168
|
orm_module.const_set('Warning', Class.new(orm_module::Base)) unless orm_module.const_defined?('Warning')
|
@@ -16,18 +16,16 @@ module RequestLogAnalyzer::FileFormat
|
|
16
16
|
line.teaser = /Params/
|
17
17
|
line.regexp = /Params\:\ (\{.+\})/
|
18
18
|
line.captures << { :name => :params, :type => :eval, :provides => {
|
19
|
-
:namespace => :string, :controller => :string, :action => :string, :format => :string } }
|
19
|
+
:namespace => :string, :controller => :string, :action => :string, :format => :string, :method => :string } }
|
20
20
|
end
|
21
21
|
|
22
22
|
# ~ {:dispatch_time=>0.006117, :after_filters_time=>6.1e-05, :before_filters_time=>0.000712, :action_time=>0.005833}
|
23
23
|
line_definition :completed do |line|
|
24
24
|
line.footer = true
|
25
|
-
line.
|
26
|
-
line.
|
27
|
-
|
28
|
-
|
29
|
-
<< { :name => :before_filters_time, :type => :duration } \
|
30
|
-
<< { :name => :action_time, :type => :duration }
|
25
|
+
line.regexp = /(\{.*\:dispatch_time\s*=>\s*\d+\.\d+.*\})/
|
26
|
+
line.captures << { :name => :times_hash, :type => :eval, :provides => {
|
27
|
+
:dispatch_time => :duration, :after_filters_time => :duration,
|
28
|
+
:before_filters_time => :duration, :action_time => :duration } }
|
31
29
|
end
|
32
30
|
|
33
31
|
REQUEST_CATEGORIZER = Proc.new do |request|
|
@@ -145,11 +145,11 @@ module RequestLogAnalyzer
|
|
145
145
|
end
|
146
146
|
|
147
147
|
def first_lineno
|
148
|
-
@lines.
|
148
|
+
@lines.map { |line| line[:lineno] }.reject { |v| v.nil? }.min
|
149
149
|
end
|
150
150
|
|
151
151
|
def last_lineno
|
152
|
-
@lines.
|
152
|
+
@lines.map { |line| line[:lineno] }.reject { |v| v.nil? }.max
|
153
153
|
end
|
154
154
|
end
|
155
155
|
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
s.name = 'request-log-analyzer'
|
3
|
+
s.version = "1.2.6"
|
4
|
+
s.date = "2009-09-02"
|
5
|
+
|
6
|
+
s.rubyforge_project = 'r-l-a'
|
7
|
+
|
8
|
+
s.bindir = 'bin'
|
9
|
+
s.executables = ['request-log-analyzer']
|
10
|
+
s.default_executable = 'request-log-analyzer'
|
11
|
+
|
12
|
+
s.summary = "A command line tool to analyze request logs for Rails, Merb and other application servers"
|
13
|
+
s.description = <<-eos
|
14
|
+
Request log analyzer's purpose is to find ot how your web application is being used and to focus your optimization efforts.
|
15
|
+
This tool will parse all requests in the application's log file and aggregate the information. Once it is finished parsing
|
16
|
+
the log file(s), it will show the requests that take op most server time using various metrics. It can also insert all
|
17
|
+
parsed request information into a database so you can roll your own analysis. It supports Rails- and Merb-based applications
|
18
|
+
out of the box, but file formats of other applications can easily be supported by supplying an easy to write log file format
|
19
|
+
definition.
|
20
|
+
eos
|
21
|
+
|
22
|
+
s.rdoc_options << '--title' << s.name << '--main' << 'README.rdoc' << '--line-numbers' << '--inline-source'
|
23
|
+
s.extra_rdoc_files = ['README.rdoc']
|
24
|
+
|
25
|
+
s.requirements << "To use the database inserter, ActiveRecord and an appropriate database adapter are required."
|
26
|
+
|
27
|
+
s.add_development_dependency('rspec', '>= 1.2.4')
|
28
|
+
s.add_development_dependency('git', '>= 1.1.0')
|
29
|
+
|
30
|
+
s.authors = ['Willem van Bergen', 'Bart ten Brinke']
|
31
|
+
s.email = ['willem@railsdoctors.com', 'bart@railsdoctors.com']
|
32
|
+
s.homepage = 'http://railsdoctors.com'
|
33
|
+
|
34
|
+
s.files = %w(spec/unit/filter/anonymize_filter_spec.rb lib/request_log_analyzer/line_definition.rb lib/request_log_analyzer/output/html.rb lib/request_log_analyzer/controller.rb spec/fixtures/rails_22_cached.log lib/request_log_analyzer/file_format/rails_development.rb spec/lib/macros.rb spec/fixtures/merb_prefixed.log tasks/request_log_analyzer.rake spec/unit/file_format/file_format_api_spec.rb spec/integration/command_line_usage_spec.rb spec/fixtures/decompression.log.bz2 lib/request_log_analyzer/log_processor.rb lib/request_log_analyzer/tracker.rb lib/request_log_analyzer/filter.rb spec/fixtures/rails_unordered.log bin/request-log-analyzer request-log-analyzer.gemspec DESIGN.rdoc spec/unit/filter/timespan_filter_spec.rb lib/request_log_analyzer/filter/field.rb lib/request_log_analyzer/tracker/frequency.rb spec/fixtures/decompression.log.gz spec/fixtures/decompression.log spec/lib/matchers.rb spec/fixtures/test_order.log lib/request_log_analyzer/output/fixed_width.rb lib/request_log_analyzer/filter/anonymize.rb spec/lib/testing_format.rb lib/request_log_analyzer/tracker/timespan.rb lib/request_log_analyzer/aggregator.rb lib/cli/progressbar.rb README.rdoc spec/fixtures/merb.log lib/request_log_analyzer/tracker/hourly_spread.rb .gitignore spec/unit/tracker/tracker_api_spec.rb spec/unit/tracker/duration_tracker_spec.rb lib/request_log_analyzer/aggregator/echo.rb spec/unit/controller/log_processor_spec.rb lib/request_log_analyzer.rb Rakefile spec/spec_helper.rb spec/unit/filter/filter_spec.rb lib/request_log_analyzer/aggregator/summarizer.rb lib/request_log_analyzer/file_format/rails.rb spec/fixtures/test_language_combined.log spec/fixtures/decompression.tar.gz spec/unit/filter/field_filter_spec.rb spec/spec.opts lib/request_log_analyzer/aggregator/database.rb lib/request_log_analyzer/filter/timespan.rb lib/request_log_analyzer/source/log_parser.rb spec/fixtures/decompression.tgz spec/unit/tracker/timespan_tracker_spec.rb spec/unit/tracker/hourly_spread_spec.rb spec/fixtures/header_and_footer.log lib/cli/tools.rb lib/request_log_analyzer/file_format/merb.rb spec/fixtures/multiple_files_1.log spec/unit/file_format/merb_format_spec.rb spec/unit/file_format/line_definition_spec.rb lib/request_log_analyzer/source.rb lib/request_log_analyzer/request.rb spec/unit/controller/controller_spec.rb lib/request_log_analyzer/output.rb spec/lib/helpers.rb spec/fixtures/rails_1x.log spec/lib/mocks.rb spec/fixtures/decompression.log.zip spec/unit/source/request_spec.rb spec/unit/source/log_parser_spec.rb spec/fixtures/test_file_format.log lib/request_log_analyzer/source/database.rb spec/unit/aggregator/database_spec.rb tasks/github-gem.rake lib/request_log_analyzer/tracker/duration.rb lib/request_log_analyzer/file_format.rb spec/unit/aggregator/summarizer_spec.rb spec/fixtures/rails_22.log spec/fixtures/multiple_files_2.log spec/fixtures/syslog_1x.log LICENSE spec/unit/tracker/frequency_tracker_spec.rb spec/unit/file_format/rails_format_spec.rb lib/cli/command_line_arguments.rb)
|
35
|
+
s.test_files = %w(spec/unit/filter/anonymize_filter_spec.rb spec/unit/file_format/file_format_api_spec.rb spec/integration/command_line_usage_spec.rb spec/unit/filter/timespan_filter_spec.rb spec/unit/tracker/tracker_api_spec.rb spec/unit/tracker/duration_tracker_spec.rb spec/unit/controller/log_processor_spec.rb spec/unit/filter/filter_spec.rb spec/unit/filter/field_filter_spec.rb spec/unit/tracker/timespan_tracker_spec.rb spec/unit/tracker/hourly_spread_spec.rb spec/unit/file_format/merb_format_spec.rb spec/unit/file_format/line_definition_spec.rb spec/unit/controller/controller_spec.rb spec/unit/source/request_spec.rb spec/unit/source/log_parser_spec.rb spec/unit/aggregator/database_spec.rb spec/unit/aggregator/summarizer_spec.rb spec/unit/tracker/frequency_tracker_spec.rb spec/unit/file_format/rails_format_spec.rb)
|
36
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
Aug 31 18:35:23 typekit-web001 merb: ~
|
2
|
+
Aug 31 18:35:23 typekit-web001 merb: cache: [GET /] miss
|
3
|
+
Aug 31 18:35:24 typekit-web001 merb: ~ Started request handling: Mon Aug 31 18:35:25 +0000 2009
|
4
|
+
Aug 31 18:35:24 typekit-web001 merb: ~ Routed to: {"action"=>"index", "controller"=>"home"}
|
5
|
+
Aug 31 18:35:24 typekit-web001 merb: ~ Params: {"action"=>"index", "controller"=>"home"}
|
6
|
+
Aug 31 18:35:24 typekit-web001 merb: ~ In repository block default
|
7
|
+
Aug 31 18:35:24 typekit-web001 merb: ~ (0.000000) SELECT `id`, `created_at`, `updated_at`, `braintree_vault_id`, `cancelled_at` FROM `accounts` WHERE (`id` IN (6214)) ORDER BY `id`
|
8
|
+
Aug 31 18:35:24 typekit-web001 merb: ~ Redirecting to: /plans (302)
|
9
|
+
Aug 31 18:35:24 typekit-web001 merb: ~ {:after_filters_time=>0.0, :before_filters_time=>0.0, :dispatch_time=>0.012001, :action_time=>0.012001}
|
data/spec/lib/mocks.rb
CHANGED
@@ -38,10 +38,21 @@ module RequestLogAnalyzer::Spec::Mocks
|
|
38
38
|
output.stub!(:title)
|
39
39
|
output.stub!(:line)
|
40
40
|
output.stub!(:with_style)
|
41
|
-
output.stub!(:table)
|
41
|
+
output.stub!(:table).and_yield([])
|
42
42
|
output.stub!(:io).and_return(mock_io)
|
43
43
|
return output
|
44
44
|
end
|
45
45
|
|
46
|
+
def mock_migrator
|
47
|
+
table_creator = mock('ActiveRecord table creator')
|
48
|
+
table_creator.stub!(:column)
|
49
|
+
|
50
|
+
migrator = mock('ActiveRecord::Base.connection for migrations')
|
51
|
+
migrator.stub!(:add_index)
|
52
|
+
migrator.stub!(:create_table).and_yield(table_creator).and_return(true)
|
53
|
+
migrator.stub!(:table_creator).and_return(table_creator)
|
54
|
+
return migrator
|
55
|
+
end
|
56
|
+
|
46
57
|
|
47
58
|
end
|
@@ -2,13 +2,13 @@ require File.dirname(__FILE__) + '/../../spec_helper'
|
|
2
2
|
|
3
3
|
describe RequestLogAnalyzer::Aggregator::Database do
|
4
4
|
|
5
|
-
before(:
|
5
|
+
before(:all) do
|
6
6
|
log_parser = RequestLogAnalyzer::Source::LogParser.new(testing_format)
|
7
7
|
@database_inserter = RequestLogAnalyzer::Aggregator::Database.new(log_parser, :database => ':memory:')
|
8
8
|
|
9
9
|
@line_definition = RequestLogAnalyzer::LineDefinition.new(:test, { :regexp => /Testing (\w+), tries\: (\d+)/,
|
10
10
|
:captures => [{ :name => :what, :type => :string }, { :name => :tries, :type => :integer },
|
11
|
-
{ :name => :evaluated, :type => :hash, :provides => {:evaluated_field => :duration} }]})
|
11
|
+
{ :name => :evaluated, :type => :hash, :provides => {:evaluated_field => :duration} }]})
|
12
12
|
end
|
13
13
|
|
14
14
|
# The prepare method is called before the parsing starts. It should establish a connection
|
@@ -16,12 +16,18 @@ describe RequestLogAnalyzer::Aggregator::Database do
|
|
16
16
|
describe '#prepare' do
|
17
17
|
|
18
18
|
before(:each) do
|
19
|
-
@database_inserter.stub!(:
|
19
|
+
@database_inserter.stub!(:initialize_orm_module!)
|
20
|
+
@database_inserter.stub!(:establish_database_connection!)
|
20
21
|
@database_inserter.stub!(:create_database_schema!)
|
21
22
|
end
|
22
23
|
|
24
|
+
it 'should create the ORM mdoule in which the classes can be created' do
|
25
|
+
@database_inserter.should_receive(:initialize_orm_module!)
|
26
|
+
@database_inserter.prepare
|
27
|
+
end
|
28
|
+
|
23
29
|
it 'should establish the database connection' do
|
24
|
-
@database_inserter.should_receive(:establish_database_connection!)
|
30
|
+
@database_inserter.should_receive(:establish_database_connection!)
|
25
31
|
@database_inserter.prepare
|
26
32
|
end
|
27
33
|
|
@@ -31,48 +37,70 @@ describe RequestLogAnalyzer::Aggregator::Database do
|
|
31
37
|
end
|
32
38
|
end
|
33
39
|
|
40
|
+
# The database inserter creates is own "Database" module within the file format
|
41
|
+
# class to create all the classes that are needed.
|
42
|
+
describe '#initialize_orm_module!' do
|
43
|
+
|
44
|
+
before(:all) { @database_inserter.send(:deinitialize_orm_module!) }
|
45
|
+
after(:all) { @database_inserter.send(:initialize_orm_module!) }
|
46
|
+
|
47
|
+
before(:each) { @database_inserter.send(:initialize_orm_module!) }
|
48
|
+
after(:each) { @database_inserter.send(:deinitialize_orm_module!) }
|
49
|
+
|
50
|
+
it "should create a Database module under the file format's class" do
|
51
|
+
testing_format.class.should be_const_defined('Database')
|
52
|
+
end
|
53
|
+
|
54
|
+
it "should define a Base class in the Database module" do
|
55
|
+
testing_format.class::Database.should be_const_defined('Base')
|
56
|
+
end
|
57
|
+
|
58
|
+
it "should create a ActiveRecord::Base class in the Database module" do
|
59
|
+
testing_format.class::Database::Base.ancestors.should include(ActiveRecord::Base)
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
63
|
+
|
34
64
|
# The create_database_table method should create a database table according to the line definition,
|
35
65
|
# so that parsed lines can be stored in it later on.
|
36
66
|
describe '#create_database_table' do
|
37
67
|
|
38
68
|
before(:each) do
|
39
|
-
@
|
40
|
-
@
|
41
|
-
ActiveRecord::Migration.stub!(:create_table).and_yield(@table_creator)
|
42
|
-
ActiveRecord::Migration.stub!(:add_index)
|
69
|
+
@connection = mock_migrator
|
70
|
+
@database_inserter.stub!(:connection).and_return(@connection)
|
43
71
|
end
|
44
72
|
|
45
73
|
it "should create a table based on the line type name" do
|
46
|
-
|
74
|
+
@connection.should_receive(:create_table).with('test_lines')
|
47
75
|
@database_inserter.send(:create_database_table, @line_definition)
|
48
76
|
end
|
49
77
|
|
50
78
|
it "should create an index on the request_id field" do
|
51
|
-
|
79
|
+
@connection.should_receive(:add_index).with('test_lines', [:request_id])
|
52
80
|
@database_inserter.send(:create_database_table, @line_definition)
|
53
81
|
end
|
54
82
|
|
55
83
|
it "should create a request_id field to link the requests together" do
|
56
|
-
@table_creator.should_receive(:column).with(:request_id, :integer)
|
84
|
+
@connection.table_creator.should_receive(:column).with(:request_id, :integer)
|
57
85
|
@database_inserter.send(:create_database_table, @line_definition)
|
58
86
|
end
|
59
87
|
|
60
88
|
it "should create a lineno field to save the location of the line in the original file" do
|
61
|
-
@table_creator.should_receive(:column).with(:lineno, :integer)
|
89
|
+
@connection.table_creator.should_receive(:column).with(:lineno, :integer)
|
62
90
|
@database_inserter.send(:create_database_table, @line_definition)
|
63
91
|
end
|
64
92
|
|
65
93
|
it "should create a field of the correct type for every defined field" do
|
66
|
-
@table_creator.should_receive(:column).with(:what, :string)
|
67
|
-
@table_creator.should_receive(:column).with(:tries, :integer)
|
94
|
+
@connection.table_creator.should_receive(:column).with(:what, :string)
|
95
|
+
@connection.table_creator.should_receive(:column).with(:tries, :integer)
|
68
96
|
# :hash capture type should map on a :text field type
|
69
|
-
@table_creator.should_receive(:column).with(:evaluated, :text)
|
97
|
+
@connection.table_creator.should_receive(:column).with(:evaluated, :text)
|
70
98
|
@database_inserter.send(:create_database_table, @line_definition)
|
71
99
|
end
|
72
100
|
|
73
101
|
it "should create a field of the correct type for every provided field" do
|
74
102
|
# :duration capture type should map on a :double field type
|
75
|
-
@table_creator.should_receive(:column).with(:evaluated_field, :double)
|
103
|
+
@connection.table_creator.should_receive(:column).with(:evaluated_field, :double)
|
76
104
|
@database_inserter.send(:create_database_table, @line_definition)
|
77
105
|
end
|
78
106
|
end
|
@@ -129,21 +157,19 @@ describe RequestLogAnalyzer::Aggregator::Database do
|
|
129
157
|
before(:each) do
|
130
158
|
@line_type_cnt = testing_format.line_definitions.length
|
131
159
|
|
132
|
-
|
133
|
-
|
134
|
-
ActiveRecord::Migration.stub!(:create_table)
|
160
|
+
@connection = mock_migrator
|
161
|
+
@database_inserter.stub!(:connection).and_return(@connection)
|
135
162
|
|
136
163
|
# Stub the expected method calls for the preparation
|
137
164
|
@database_inserter.stub!(:create_database_table)
|
138
165
|
@database_inserter.stub!(:create_activerecord_class)
|
139
166
|
|
140
|
-
|
141
167
|
# Make sure the ORM module exists
|
142
168
|
@database_inserter.send(:initialize_orm_module!)
|
143
169
|
end
|
144
170
|
|
145
171
|
it "should create a requests table to join request lines" do
|
146
|
-
|
172
|
+
@connection.should_receive(:create_table).with("requests")
|
147
173
|
@database_inserter.send :create_database_schema!
|
148
174
|
end
|
149
175
|
|
@@ -153,7 +179,7 @@ describe RequestLogAnalyzer::Aggregator::Database do
|
|
153
179
|
end
|
154
180
|
|
155
181
|
it "should create a warnings table for logging parse warnings" do
|
156
|
-
|
182
|
+
@connection.should_receive(:create_table).with("warnings")
|
157
183
|
@database_inserter.send :create_database_schema!
|
158
184
|
end
|
159
185
|
|
@@ -23,15 +23,34 @@ describe RequestLogAnalyzer::Source::LogParser, :merb do
|
|
23
23
|
@log_parser.parse_file(log_fixture(:merb))
|
24
24
|
end
|
25
25
|
|
26
|
-
it "should parse all details from
|
26
|
+
it "should parse all details from the first request correctly" do
|
27
27
|
request = nil
|
28
28
|
@log_parser.parse_file(log_fixture(:merb)) { |found_request| request ||= found_request }
|
29
29
|
|
30
30
|
request.should be_completed
|
31
|
+
request[:controller].should == 'session'
|
32
|
+
request[:action].should == 'destroy'
|
33
|
+
request[:method].should == 'delete'
|
34
|
+
request[:params].should be_kind_of(Hash)
|
31
35
|
request[:timestamp].should == 20080829111023 # 'Fri Aug 29 11:10:23 +0200 2008'
|
32
36
|
request[:dispatch_time].should == 0.243424
|
33
37
|
request[:after_filters_time].should == 6.9e-05
|
34
38
|
request[:before_filters_time].should == 0.213213
|
35
39
|
request[:action_time].should == 0.241652
|
40
|
+
|
41
|
+
end
|
42
|
+
|
43
|
+
it "should parse a prefixed Merb file correctly" do
|
44
|
+
request = nil
|
45
|
+
@log_parser.parse_file(log_fixture(:merb_prefixed)) { |found_request| request ||= found_request }
|
46
|
+
|
47
|
+
request.should be_completed
|
48
|
+
request[:timestamp].should == 20090831183525
|
49
|
+
request[:controller].should == 'home'
|
50
|
+
request[:action].should == 'index'
|
51
|
+
request[:dispatch_time].should == 0.012001
|
52
|
+
request[:after_filters_time].should == 0.0
|
53
|
+
request[:before_filters_time].should == 0.0
|
54
|
+
request[:action_time].should == 0.012001
|
36
55
|
end
|
37
56
|
end
|
@@ -1,85 +1,111 @@
|
|
1
1
|
require File.dirname(__FILE__) + '/../../spec_helper'
|
2
2
|
|
3
|
-
describe RequestLogAnalyzer::Request
|
3
|
+
describe RequestLogAnalyzer::Request do
|
4
4
|
|
5
5
|
before(:each) do
|
6
|
-
@
|
7
|
-
@incomplete_request << { :line_type => :test, :lineno => 1, :test_capture => 'awesome!' }
|
8
|
-
end
|
9
|
-
|
10
|
-
it "should be single if only one line has been added" do
|
11
|
-
@incomplete_request.should_not be_empty
|
12
|
-
end
|
13
|
-
|
14
|
-
it "should not be a completed request" do
|
15
|
-
@incomplete_request.should_not be_completed
|
6
|
+
@request = testing_format.request
|
16
7
|
end
|
17
8
|
|
18
|
-
it "should
|
19
|
-
@
|
20
|
-
@incomplete_request.should =~ :test
|
9
|
+
it "should be empty without any captured lines in it" do
|
10
|
+
@request.should be_empty
|
21
11
|
end
|
22
12
|
|
23
|
-
|
24
|
-
@incomplete_request[:test_capture].should == 'awesome!'
|
25
|
-
end
|
26
|
-
|
27
|
-
it "should return nil if no such field is present" do
|
28
|
-
@incomplete_request[:nonexisting].should be_nil
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
|
-
|
33
|
-
describe RequestLogAnalyzer::Request, :completed_request do
|
13
|
+
context :incomplete do
|
34
14
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
@completed_request << { :line_type => :test, :lineno => 4, :test_capture => 'testing' }
|
39
|
-
@completed_request << { :line_type => :test, :lineno => 7, :test_capture => 'testing some more' }
|
40
|
-
@completed_request << { :line_type => :last, :lineno => 10, :time => 0.03 }
|
41
|
-
end
|
15
|
+
before(:each) do
|
16
|
+
@request << { :line_type => :test, :lineno => 1, :test_capture => 'awesome!' }
|
17
|
+
end
|
42
18
|
|
43
|
-
|
44
|
-
|
45
|
-
|
19
|
+
it "should be single if only one line has been added" do
|
20
|
+
@request.should_not be_empty
|
21
|
+
end
|
46
22
|
|
47
|
-
|
48
|
-
|
49
|
-
|
23
|
+
it "should not be a completed request" do
|
24
|
+
@request.should_not be_completed
|
25
|
+
end
|
50
26
|
|
51
|
-
|
52
|
-
|
53
|
-
|
27
|
+
it "should take the line type of the first line as global line_type" do
|
28
|
+
@request.lines[0][:line_type].should == :test
|
29
|
+
@request.should =~ :test
|
30
|
+
end
|
54
31
|
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
end
|
32
|
+
it "should return the first field value" do
|
33
|
+
@request[:test_capture].should == 'awesome!'
|
34
|
+
end
|
59
35
|
|
60
|
-
|
61
|
-
|
36
|
+
it "should return nil if no such field is present" do
|
37
|
+
@request[:nonexisting].should be_nil
|
38
|
+
end
|
62
39
|
end
|
63
40
|
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
41
|
+
context :completed do
|
42
|
+
|
43
|
+
before(:each) do
|
44
|
+
@request << { :line_type => :first, :lineno => 1, :name => 'first line!' }
|
45
|
+
@request << { :line_type => :test, :lineno => 4, :test_capture => 'testing' }
|
46
|
+
@request << { :line_type => :test, :lineno => 7, :test_capture => 'testing some more' }
|
47
|
+
@request << { :line_type => :last, :lineno => 10, :time => 0.03 }
|
48
|
+
end
|
71
49
|
|
72
|
-
|
73
|
-
|
74
|
-
|
50
|
+
it "should not be empty when multiple liness are added" do
|
51
|
+
@request.should_not be_empty
|
52
|
+
end
|
75
53
|
|
76
|
-
|
77
|
-
|
78
|
-
|
54
|
+
it "should be a completed request" do
|
55
|
+
@request.should be_completed
|
56
|
+
end
|
57
|
+
|
58
|
+
it "should recognize all line types" do
|
59
|
+
[:first, :test, :last].each { |type| @request.should =~ type }
|
60
|
+
end
|
61
|
+
|
62
|
+
it "should detect the correct field value" do
|
63
|
+
@request[:name].should == 'first line!'
|
64
|
+
@request[:time].should == 0.03
|
65
|
+
end
|
66
|
+
|
67
|
+
it "should detect the first matching field value" do
|
68
|
+
@request.first(:test_capture).should == 'testing'
|
69
|
+
end
|
79
70
|
|
80
|
-
|
81
|
-
|
82
|
-
|
71
|
+
it "should detect the every matching field value" do
|
72
|
+
@request.every(:test_capture).should == ['testing', "testing some more"]
|
73
|
+
end
|
74
|
+
|
75
|
+
it "should set the first_lineno for a request to the lowest lineno encountered" do
|
76
|
+
@request.first_lineno.should eql(1)
|
77
|
+
end
|
78
|
+
|
79
|
+
it "should set the first_lineno for a request if a line with a lower lineno is added" do
|
80
|
+
@request << { :line_type => :test, :lineno => 0 }
|
81
|
+
@request.first_lineno.should eql(0)
|
82
|
+
end
|
83
|
+
|
84
|
+
it "should set the last_lineno for a request to the highest encountered lineno" do
|
85
|
+
@request.last_lineno.should eql(10)
|
86
|
+
end
|
87
|
+
|
88
|
+
it "should not set the last_lineno for a request if a line with a lower lineno is added" do
|
89
|
+
@request << { :line_type => :test, :lineno => 7 }
|
90
|
+
@request.last_lineno.should eql(10)
|
91
|
+
end
|
92
|
+
|
93
|
+
it "should not have a timestamp if no such field is captured" do
|
94
|
+
@request.timestamp.should be_nil
|
95
|
+
end
|
96
|
+
|
97
|
+
it "should set return a timestamp field if such a field is captured" do
|
98
|
+
@request << { :line_type => :first, :lineno => 1, :name => 'first line!', :timestamp => Time.now}
|
99
|
+
@request.timestamp.should_not be_nil
|
100
|
+
end
|
83
101
|
end
|
84
102
|
|
85
|
-
|
103
|
+
context 'single line' do
|
104
|
+
# combined is both a header and a footer line
|
105
|
+
before(:each) { @request << { :line_type => :combined, :lineno => 1 } }
|
106
|
+
|
107
|
+
it "should be a completed request if the line is both header and footer" do
|
108
|
+
@request.should be_completed
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|