request-log-analyzer 1.2.3 → 1.2.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|