request-log-analyzer 1.3.7 → 1.4.0
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +3 -3
- data/README.rdoc +1 -1
- data/bin/request-log-analyzer +17 -14
- data/lib/cli/command_line_arguments.rb +51 -51
- data/lib/cli/database_console.rb +3 -3
- data/lib/cli/database_console_init.rb +2 -2
- data/lib/cli/progressbar.rb +10 -10
- data/lib/cli/tools.rb +3 -3
- data/lib/request_log_analyzer.rb +4 -4
- data/lib/request_log_analyzer/aggregator.rb +10 -10
- data/lib/request_log_analyzer/aggregator/database_inserter.rb +9 -9
- data/lib/request_log_analyzer/aggregator/echo.rb +14 -9
- data/lib/request_log_analyzer/aggregator/summarizer.rb +26 -26
- data/lib/request_log_analyzer/controller.rb +153 -69
- data/lib/request_log_analyzer/database.rb +13 -13
- data/lib/request_log_analyzer/database/base.rb +17 -17
- data/lib/request_log_analyzer/database/connection.rb +3 -3
- data/lib/request_log_analyzer/database/request.rb +2 -2
- data/lib/request_log_analyzer/database/source.rb +1 -1
- data/lib/request_log_analyzer/file_format.rb +15 -15
- data/lib/request_log_analyzer/file_format/amazon_s3.rb +16 -16
- data/lib/request_log_analyzer/file_format/apache.rb +20 -19
- data/lib/request_log_analyzer/file_format/merb.rb +12 -12
- data/lib/request_log_analyzer/file_format/rack.rb +4 -4
- data/lib/request_log_analyzer/file_format/rails.rb +146 -70
- data/lib/request_log_analyzer/file_format/rails_development.rb +4 -49
- data/lib/request_log_analyzer/filter.rb +6 -6
- data/lib/request_log_analyzer/filter/anonymize.rb +6 -6
- data/lib/request_log_analyzer/filter/field.rb +9 -9
- data/lib/request_log_analyzer/filter/timespan.rb +12 -10
- data/lib/request_log_analyzer/line_definition.rb +15 -14
- data/lib/request_log_analyzer/log_processor.rb +22 -22
- data/lib/request_log_analyzer/mailer.rb +15 -9
- data/lib/request_log_analyzer/output.rb +53 -12
- data/lib/request_log_analyzer/output/fixed_width.rb +40 -41
- data/lib/request_log_analyzer/output/html.rb +20 -20
- data/lib/request_log_analyzer/request.rb +35 -36
- data/lib/request_log_analyzer/source.rb +7 -7
- data/lib/request_log_analyzer/source/database_loader.rb +7 -7
- data/lib/request_log_analyzer/source/log_parser.rb +48 -43
- data/lib/request_log_analyzer/tracker.rb +128 -14
- data/lib/request_log_analyzer/tracker/duration.rb +39 -132
- data/lib/request_log_analyzer/tracker/frequency.rb +31 -32
- data/lib/request_log_analyzer/tracker/hourly_spread.rb +20 -19
- data/lib/request_log_analyzer/tracker/timespan.rb +17 -17
- data/lib/request_log_analyzer/tracker/traffic.rb +36 -116
- data/request-log-analyzer.gemspec +19 -15
- data/spec/fixtures/rails_22.log +1 -1
- data/spec/integration/command_line_usage_spec.rb +1 -1
- data/spec/lib/helpers.rb +7 -7
- data/spec/lib/macros.rb +3 -3
- data/spec/lib/matchers.rb +41 -27
- data/spec/lib/mocks.rb +15 -14
- data/spec/lib/testing_format.rb +9 -9
- data/spec/spec_helper.rb +6 -6
- data/spec/unit/aggregator/database_inserter_spec.rb +13 -13
- data/spec/unit/aggregator/summarizer_spec.rb +4 -4
- data/spec/unit/controller/controller_spec.rb +2 -2
- data/spec/unit/controller/log_processor_spec.rb +1 -1
- data/spec/unit/database/base_class_spec.rb +19 -19
- data/spec/unit/database/connection_spec.rb +3 -3
- data/spec/unit/database/database_spec.rb +25 -25
- data/spec/unit/file_format/amazon_s3_format_spec.rb +5 -5
- data/spec/unit/file_format/apache_format_spec.rb +13 -13
- data/spec/unit/file_format/file_format_api_spec.rb +13 -13
- data/spec/unit/file_format/line_definition_spec.rb +24 -17
- data/spec/unit/file_format/merb_format_spec.rb +41 -45
- data/spec/unit/file_format/rails_format_spec.rb +157 -117
- data/spec/unit/filter/anonymize_filter_spec.rb +2 -2
- data/spec/unit/filter/field_filter_spec.rb +13 -13
- data/spec/unit/filter/filter_spec.rb +1 -1
- data/spec/unit/filter/timespan_filter_spec.rb +15 -15
- data/spec/unit/mailer_spec.rb +30 -0
- data/spec/unit/{source/request_spec.rb → request_spec.rb} +30 -30
- data/spec/unit/source/log_parser_spec.rb +27 -27
- data/spec/unit/tracker/duration_tracker_spec.rb +115 -78
- data/spec/unit/tracker/frequency_tracker_spec.rb +74 -63
- data/spec/unit/tracker/hourly_spread_spec.rb +28 -20
- data/spec/unit/tracker/timespan_tracker_spec.rb +25 -13
- data/spec/unit/tracker/tracker_api_spec.rb +13 -13
- data/spec/unit/tracker/traffic_tracker_spec.rb +81 -79
- data/tasks/github-gem.rake +125 -75
- data/tasks/request_log_analyzer.rake +2 -2
- metadata +8 -6
@@ -7,24 +7,24 @@ describe RequestLogAnalyzer::FileFormat::AmazonS3 do
|
|
7
7
|
@log_parser = RequestLogAnalyzer::Source::LogParser.new(@file_format)
|
8
8
|
@sample = '2f88111968424e6306bf4d292c0188ccb94ff9374ea2836b50a1a79f7cd656e1 sample-bucket [06/Oct/2006:01:42:14 +0000] 207.171.172.6 65a011a29cdf8ec533ec3d1ccaae921c C980091AD89C936A REST.GET.OBJECT object.png "GET /sample-bucket/object.png HTTP/1.1" 200 - 1243 1243 988 987 "-" "aranhabot"'
|
9
9
|
end
|
10
|
-
|
10
|
+
|
11
11
|
it "should be a valid file format" do
|
12
12
|
@file_format.should be_valid
|
13
13
|
end
|
14
|
-
|
14
|
+
|
15
15
|
it "should parse access lines and capture all of its fields" do
|
16
16
|
@file_format.should have_line_definition(:access).capturing(:bucket_owner, :bucket, :timestamp, :remote_ip, :requester,
|
17
17
|
:key, :operation, :total_time, :turnaround_time, :bytes_sent, :object_size, :referer, :user_agent)
|
18
18
|
end
|
19
|
-
|
19
|
+
|
20
20
|
it "should match the sample line" do
|
21
21
|
@file_format.parse_line(@sample).should include(:line_definition, :captures)
|
22
22
|
end
|
23
|
-
|
23
|
+
|
24
24
|
it "should not match a nonsense line" do
|
25
25
|
@file_format.parse_line('dsadasdas dsaadsads dsaadsads').should be_nil
|
26
26
|
end
|
27
|
-
|
27
|
+
|
28
28
|
it "should parse and convert the sample fields correctly" do
|
29
29
|
@log_parser.parse_io(StringIO.new(@sample)) do |request|
|
30
30
|
request[:bucket_owner].should == '2f88111968424e6306bf4d292c0188ccb94ff9374ea2836b50a1a79f7cd656e1'
|
@@ -23,7 +23,7 @@ describe RequestLogAnalyzer::FileFormat::Apache do
|
|
23
23
|
it "should make it a footer line" do
|
24
24
|
@line_definition.should be_footer
|
25
25
|
end
|
26
|
-
|
26
|
+
|
27
27
|
it "should capture :duration" do
|
28
28
|
@line_definition.captures?(:duration).should be_true
|
29
29
|
end
|
@@ -43,7 +43,7 @@ describe RequestLogAnalyzer::FileFormat::Apache do
|
|
43
43
|
it "should be a valid file format" do
|
44
44
|
@format.should be_valid
|
45
45
|
end
|
46
|
-
|
46
|
+
|
47
47
|
it "should setup report trackers" do
|
48
48
|
@format.report_trackers.should_not be_empty
|
49
49
|
end
|
@@ -60,7 +60,7 @@ describe RequestLogAnalyzer::FileFormat::Apache do
|
|
60
60
|
it "should have a valid language definitions" do
|
61
61
|
@file_format.should be_valid
|
62
62
|
end
|
63
|
-
|
63
|
+
|
64
64
|
it "should parse a valid access log line" do
|
65
65
|
@file_format.line_definitions[:access].matches(@sample_1).should be_kind_of(Hash)
|
66
66
|
end
|
@@ -68,7 +68,7 @@ describe RequestLogAnalyzer::FileFormat::Apache do
|
|
68
68
|
it "should not parse a valid access log line" do
|
69
69
|
@file_format.line_definitions[:access].matches('addasdsasadadssadasd').should be_false
|
70
70
|
end
|
71
|
-
|
71
|
+
|
72
72
|
it "should read the correct values from a valid HTTP/1.0 access log line" do
|
73
73
|
@log_parser.parse_io(StringIO.new(@sample_1)) do |request|
|
74
74
|
request[:remote_host].should == '1.129.119.13'
|
@@ -80,7 +80,7 @@ describe RequestLogAnalyzer::FileFormat::Apache do
|
|
80
80
|
request[:user].should == nil
|
81
81
|
end
|
82
82
|
end
|
83
|
-
|
83
|
+
|
84
84
|
it "should read the correct values from a valid 200 access log line" do
|
85
85
|
@log_parser.parse_io(StringIO.new(@sample_2)) do |request|
|
86
86
|
request[:remote_host].should == '1.82.235.29'
|
@@ -91,7 +91,7 @@ describe RequestLogAnalyzer::FileFormat::Apache do
|
|
91
91
|
request[:bytes_sent].should == 23414
|
92
92
|
request[:user].should == nil
|
93
93
|
end
|
94
|
-
end
|
94
|
+
end
|
95
95
|
|
96
96
|
it "should parse 10 request from fixture access log" do
|
97
97
|
counter = mock('counter')
|
@@ -99,18 +99,18 @@ describe RequestLogAnalyzer::FileFormat::Apache do
|
|
99
99
|
@log_parser.parse_file(log_fixture(:apache_common)) { counter.hit! }
|
100
100
|
end
|
101
101
|
end
|
102
|
-
|
102
|
+
|
103
103
|
context '"Rack" access log parser' do
|
104
104
|
before(:each) do
|
105
105
|
@file_format = RequestLogAnalyzer::FileFormat.load(:rack)
|
106
106
|
@log_parser = RequestLogAnalyzer::Source::LogParser.new(@file_format)
|
107
107
|
@sample_1 = '127.0.0.1 - - [16/Sep/2009 06:40:08] "GET /favicon.ico HTTP/1.1" 500 63183 0.0453'
|
108
108
|
end
|
109
|
-
|
109
|
+
|
110
110
|
it "should create a kind of an Apache file format" do
|
111
111
|
@file_format.should be_kind_of(RequestLogAnalyzer::FileFormat::Apache)
|
112
112
|
end
|
113
|
-
|
113
|
+
|
114
114
|
it "should have a valid language definitions" do
|
115
115
|
@file_format.should be_valid
|
116
116
|
end
|
@@ -136,7 +136,7 @@ describe RequestLogAnalyzer::FileFormat::Apache do
|
|
136
136
|
end
|
137
137
|
end
|
138
138
|
end
|
139
|
-
|
139
|
+
|
140
140
|
context '"Combined" access log parsing' do
|
141
141
|
|
142
142
|
before(:all) do
|
@@ -171,7 +171,7 @@ describe RequestLogAnalyzer::FileFormat::Apache do
|
|
171
171
|
request[:user_agent].should == 'Mozilla/4.0 (compatible; MSIE 6.0; Windows 98)'
|
172
172
|
end
|
173
173
|
end
|
174
|
-
|
174
|
+
|
175
175
|
it "should read the correct values from a valid 200 access log line" do
|
176
176
|
@log_parser.parse_io(StringIO.new(@sample_2)) do |request|
|
177
177
|
request[:remote_host].should == '10.0.1.1'
|
@@ -184,8 +184,8 @@ describe RequestLogAnalyzer::FileFormat::Apache do
|
|
184
184
|
request[:user].should == nil
|
185
185
|
request[:user_agent].should == 'Mozilla/5.0 (Macintosh; U; Intel Mac OS X 10_5_8; en-us) AppleWebKit/531.9 (KHTML, like Gecko) Version/4.0.3 Safari/531.9'
|
186
186
|
end
|
187
|
-
end
|
188
|
-
|
187
|
+
end
|
188
|
+
|
189
189
|
it "should parse 5 request from fixture access log" do
|
190
190
|
counter = mock('counter')
|
191
191
|
counter.should_receive(:hit!).exactly(5).times
|
@@ -3,43 +3,43 @@ require File.dirname(__FILE__) + '/../../spec_helper'
|
|
3
3
|
describe RequestLogAnalyzer::FileFormat do
|
4
4
|
|
5
5
|
describe ".format_definition" do
|
6
|
-
|
6
|
+
|
7
7
|
before(:each) do
|
8
8
|
@first_file_format = Class.new(RequestLogAnalyzer::FileFormat::Base)
|
9
9
|
@second_file_format = Class.new(RequestLogAnalyzer::FileFormat::Base)
|
10
10
|
end
|
11
|
-
|
11
|
+
|
12
12
|
it "should specify line definitions directly within the file_format" do
|
13
13
|
@first_file_format.format_definition.direct_test :regexp => /test/
|
14
14
|
@first_file_format.should have_line_definition(:direct_test)
|
15
15
|
end
|
16
|
-
|
16
|
+
|
17
17
|
it "specify lines with a block for the format definition" do
|
18
18
|
@first_file_format.format_definition do |format|
|
19
19
|
format.block_test :regexp => /test (\w+)/, :captures => [{:name => :tester, :type => :string}]
|
20
|
-
end
|
21
|
-
|
20
|
+
end
|
21
|
+
|
22
22
|
@first_file_format.should have_line_definition(:block_test).capturing(:tester)
|
23
23
|
end
|
24
|
-
|
24
|
+
|
25
25
|
it "should specify a line with a block" do
|
26
26
|
@first_file_format.format_definition.hash_test do |line|
|
27
27
|
line.regexp = /test/
|
28
28
|
line.captures = []
|
29
29
|
end
|
30
|
-
|
30
|
+
|
31
31
|
@first_file_format.should have_line_definition(:hash_test)
|
32
32
|
end
|
33
|
-
|
33
|
+
|
34
34
|
it "should define lines only for its own language" do
|
35
35
|
@first_file_format.format_definition.first :regexp => /test 123/
|
36
36
|
@second_file_format.format_definition.second :regexp => /test 456/
|
37
|
-
|
37
|
+
|
38
38
|
@first_file_format.should have_line_definition(:first)
|
39
39
|
@first_file_format.should_not have_line_definition(:second)
|
40
|
-
@second_file_format.should_not have_line_definition(:first)
|
40
|
+
@second_file_format.should_not have_line_definition(:first)
|
41
41
|
@second_file_format.should have_line_definition(:second)
|
42
|
-
end
|
42
|
+
end
|
43
43
|
end
|
44
44
|
|
45
45
|
describe ".load" do
|
@@ -58,12 +58,12 @@ describe RequestLogAnalyzer::FileFormat do
|
|
58
58
|
@file_format = RequestLogAnalyzer::FileFormat.load(:rails)
|
59
59
|
@file_format.should be_kind_of(RequestLogAnalyzer::FileFormat::Rails)
|
60
60
|
end
|
61
|
-
|
61
|
+
|
62
62
|
it "should load a provided format file" do
|
63
63
|
format_filename = File.dirname(__FILE__) + '/../../lib/testing_format.rb'
|
64
64
|
@file_format = RequestLogAnalyzer::FileFormat.load(format_filename)
|
65
65
|
@file_format.should be_kind_of(TestingFormat)
|
66
66
|
end
|
67
|
-
|
67
|
+
|
68
68
|
end
|
69
69
|
end
|
@@ -9,20 +9,27 @@ describe RequestLogAnalyzer::LineDefinition do
|
|
9
9
|
:captures => [{ :name => :what, :type => :string }, { :name => :tries, :type => :integer }]
|
10
10
|
})
|
11
11
|
end
|
12
|
-
|
12
|
+
|
13
13
|
describe '#matches' do
|
14
|
-
|
14
|
+
|
15
15
|
it "should return false on an unmatching line" do
|
16
|
-
@line_definition.
|
16
|
+
@line_definition.matches("nonmatching").should be_false
|
17
17
|
end
|
18
|
-
|
18
|
+
|
19
19
|
it "should return false when only the teaser matches" do
|
20
|
-
@line_definition.
|
20
|
+
@line_definition.matches("Testing LineDefinition").should be_false
|
21
21
|
end
|
22
|
-
|
22
|
+
|
23
23
|
it "should parse a line and capture the expected values" do
|
24
|
-
@line_definition.
|
24
|
+
@line_definition.matches("Testing LineDefinition, tries: 123").should == {:line_definition => @line_definition, :captures => ['LineDefinition', '123'] }
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should know which names it can capture" do
|
28
|
+
@line_definition.captures?(:what).should be_true
|
29
|
+
@line_definition.captures?(:tries).should be_true
|
30
|
+
@line_definition.captures?(:bogus).should be_false
|
25
31
|
end
|
32
|
+
|
26
33
|
end
|
27
34
|
|
28
35
|
describe '#convert_captured_values' do
|
@@ -31,38 +38,38 @@ describe RequestLogAnalyzer::LineDefinition do
|
|
31
38
|
@request = mock('request')
|
32
39
|
@request.stub!(:convert_value).and_return('foo')
|
33
40
|
end
|
34
|
-
|
41
|
+
|
35
42
|
it "should call convert_value for every captured value" do
|
36
43
|
@request.should_receive(:convert_value).twice
|
37
44
|
@line_definition.convert_captured_values(['test', '123'], @request)
|
38
45
|
end
|
39
|
-
|
46
|
+
|
40
47
|
it "should set the converted values" do
|
41
48
|
@line_definition.convert_captured_values(['test', '123'], @request).should == {:what => 'foo', :tries => 'foo'}
|
42
49
|
end
|
43
|
-
|
50
|
+
|
44
51
|
context 'when using :provides option' do
|
45
52
|
before(:each) do
|
46
|
-
@ld = RequestLogAnalyzer::LineDefinition.new(:test, :regexp => /Hash\: (\{.+\})/,
|
53
|
+
@ld = RequestLogAnalyzer::LineDefinition.new(:test, :regexp => /Hash\: (\{.+\})/,
|
47
54
|
:captures => [{ :name => :hash, :type => :hash, :provides => {:bar => :string}}])
|
48
|
-
|
55
|
+
|
49
56
|
@request = mock('request')
|
50
57
|
|
51
58
|
@request.stub!(:convert_value).with("{:bar=>'baz'}", anything).and_return(:bar => 'baz')
|
52
59
|
@request.stub!(:convert_value).with('baz', anything).and_return('foo')
|
53
|
-
end
|
54
|
-
|
60
|
+
end
|
61
|
+
|
55
62
|
it "should call Request#convert_value for the initial hash and the value in the hash" do
|
56
63
|
@request.should_receive(:convert_value).with("{:bar=>'baz'}", anything).and_return(:bar => 'baz')
|
57
64
|
@request.should_receive(:convert_value).with("baz", anything)
|
58
65
|
@ld.convert_captured_values(["{:bar=>'baz'}"], @request)
|
59
66
|
end
|
60
|
-
|
67
|
+
|
61
68
|
it "should set the provides fields" do
|
62
69
|
# The captures field must be set and converted as well
|
63
70
|
@ld.convert_captured_values(["{:bar=>'baz'}"], @request)[:bar].should eql('foo')
|
64
|
-
end
|
71
|
+
end
|
65
72
|
end
|
66
|
-
|
73
|
+
|
67
74
|
end
|
68
75
|
end
|
@@ -1,56 +1,52 @@
|
|
1
1
|
require File.dirname(__FILE__) + '/../../spec_helper'
|
2
2
|
|
3
3
|
describe RequestLogAnalyzer::FileFormat::Merb do
|
4
|
-
|
5
|
-
before(:each) do
|
6
|
-
@log_parser = RequestLogAnalyzer::Source::LogParser.new(RequestLogAnalyzer::FileFormat.load(:merb))
|
7
|
-
end
|
8
|
-
|
9
|
-
it "should have a valid language definitions" do
|
10
|
-
@log_parser.file_format.should be_valid
|
11
|
-
end
|
12
|
-
|
13
|
-
it "should parse a stream and find valid requests" do
|
14
|
-
File.open(log_fixture(:merb), 'r') do |io|
|
15
|
-
@log_parser.parse_io(io) do |request|
|
16
|
-
request.should be_kind_of(RequestLogAnalyzer::Request)
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
20
4
|
|
21
|
-
it "should
|
22
|
-
|
23
|
-
@log_parser.parse_file(log_fixture(:merb))
|
5
|
+
it "should be a valid file format" do
|
6
|
+
RequestLogAnalyzer::FileFormat.load(:merb).should be_valid
|
24
7
|
end
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
8
|
+
|
9
|
+
describe '#parse_line' do
|
10
|
+
before(:each) do
|
11
|
+
@file_format = RequestLogAnalyzer::FileFormat.load(:merb)
|
12
|
+
end
|
29
13
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
request[:params].should be_kind_of(Hash)
|
35
|
-
request[:timestamp].should == 20080829111023 # 'Fri Aug 29 11:10:23 +0200 2008'
|
36
|
-
request[:dispatch_time].should == 0.243424
|
37
|
-
request[:after_filters_time].should == 6.9e-05
|
38
|
-
request[:before_filters_time].should == 0.213213
|
39
|
-
request[:action_time].should == 0.241652
|
14
|
+
it "should parse a :started line correctly" do
|
15
|
+
line = '~ Started request handling: Fri Aug 29 11:10:23 +0200 2008'
|
16
|
+
@file_format.should parse_line(line).as(:started).and_capture(:timestamp => 20080829111023)
|
17
|
+
end
|
40
18
|
|
19
|
+
it "should parse a prefixed :started line correctly" do
|
20
|
+
line = '~ Aug 31 18:35:24 typekit-web001 merb: ~ Started request handling: Mon Aug 31 18:35:25 +0000 2009'
|
21
|
+
@file_format.should parse_line(line).as(:started).and_capture(:timestamp => 20090831183525)
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should parse a :params line correctly" do
|
25
|
+
line = '~ Params: {"_method"=>"delete", "authenticity_token"=>"[FILTERED]", "action"=>"delete", "controller"=>"session"}'
|
26
|
+
@file_format.should parse_line(line).as(:params).and_capture(:controller => 'session', :action => 'delete', :namespace => nil)
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should parse a :completed line correctly" do
|
30
|
+
line = '~ {:dispatch_time=>0.006117, :after_filters_time=>6.1e-05, :before_filters_time=>0.000712, :action_time=>0.005833}'
|
31
|
+
@file_format.should parse_line(line).as(:completed).and_capture(:dispatch_time => 0.006117,
|
32
|
+
:before_filters_time => 0.000712, :action_time => 0.005833, :after_filters_time => 6.1e-05)
|
33
|
+
end
|
41
34
|
end
|
35
|
+
|
36
|
+
describe '#parse_io' do
|
37
|
+
before(:each) do
|
38
|
+
@log_parser = RequestLogAnalyzer::Source::LogParser.new(RequestLogAnalyzer::FileFormat.load(:merb))
|
39
|
+
end
|
40
|
+
|
41
|
+
it "should parse a stream and find valid Merb requests" do
|
42
|
+
@log_parser.parse_file(log_fixture(:merb)) do |request|
|
43
|
+
request.should be_kind_of(RequestLogAnalyzer::FileFormat::Merb::Request)
|
44
|
+
end
|
45
|
+
end
|
42
46
|
|
43
|
-
|
44
|
-
|
45
|
-
|
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
|
47
|
+
it "should find 11 completed requests" do
|
48
|
+
@log_parser.should_receive(:handle_request).exactly(11).times
|
49
|
+
@log_parser.parse_file(log_fixture(:merb))
|
50
|
+
end
|
55
51
|
end
|
56
52
|
end
|
@@ -1,127 +1,167 @@
|
|
1
1
|
require File.dirname(__FILE__) + '/../../spec_helper'
|
2
2
|
|
3
3
|
describe RequestLogAnalyzer::FileFormat::Rails do
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
end
|
19
|
-
io.close
|
20
|
-
end
|
21
|
-
|
22
|
-
it "should find 4 completed requests" do
|
23
|
-
@log_parser.should_not_receive(:warn)
|
24
|
-
@log_parser.should_receive(:handle_request).exactly(4).times
|
25
|
-
@log_parser.parse_file(log_fixture(:rails_1x))
|
26
|
-
end
|
27
|
-
|
28
|
-
it "should parse a Rails 2.2 request properly" do
|
29
|
-
@log_parser.should_not_receive(:warn)
|
30
|
-
@log_parser.parse_file(log_fixture(:rails_22)) do |request|
|
31
|
-
request.should =~ :processing
|
32
|
-
request.should =~ :completed
|
33
|
-
|
34
|
-
request[:controller].should == 'PageController'
|
35
|
-
request[:action].should == 'demo'
|
36
|
-
request[:url].should == 'http://www.example.coml/demo'
|
37
|
-
request[:status].should == 200
|
38
|
-
request[:duration].should == 0.614
|
39
|
-
request[:db].should == 0.031
|
40
|
-
request[:view].should == 0.120
|
4
|
+
|
5
|
+
describe '.create' do
|
6
|
+
|
7
|
+
context 'without providing a lines argument' do
|
8
|
+
before(:each) { @rails = RequestLogAnalyzer::FileFormat.load(:rails) }
|
9
|
+
|
10
|
+
it "should create a valid file format" do
|
11
|
+
@rails.should be_valid
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should parse the production lines" do
|
15
|
+
production_rails = RequestLogAnalyzer::FileFormat.load(:rails, 'production')
|
16
|
+
@rails.line_definitions.should == production_rails.line_definitions
|
17
|
+
end
|
41
18
|
end
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
19
|
+
|
20
|
+
context 'using a comma separated list of lines as argument' do
|
21
|
+
before(:each) { @rails = RequestLogAnalyzer::FileFormat.load(:rails, 'minimal,failure') }
|
22
|
+
|
23
|
+
it "should return a valid language" do
|
24
|
+
@rails.should be_valid
|
25
|
+
end
|
49
26
|
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
request[:status].should == 200
|
54
|
-
request[:duration].should == 0.21665
|
55
|
-
request[:db].should == 0.0
|
56
|
-
request[:view].should == 0.00926
|
27
|
+
it "should at least parse :processing and :completed lines" do
|
28
|
+
@rails.line_definitions.should include(:processing, :completed, :failure)
|
29
|
+
end
|
57
30
|
end
|
58
|
-
end
|
59
|
-
|
60
|
-
it "should parse cached requests" do
|
61
|
-
@log_parser.should_not_receive(:warn)
|
62
|
-
@log_parser.parse_file(log_fixture(:rails_22_cached)) do |request|
|
63
|
-
request.should be_completed
|
64
|
-
request =~ :cache_hit
|
65
|
-
end
|
66
|
-
end
|
67
|
-
|
68
|
-
it "should detect unordered requests in the logs" do
|
69
|
-
# No valid request should be found in cautious mode
|
70
|
-
@log_parser.should_not_receive(:handle_request)
|
71
|
-
# the first Processing-line will not give a warning, but the next one will
|
72
|
-
@log_parser.should_receive(:warn).with(:unclosed_request, anything).once
|
73
|
-
# Both Completed lines will give a warning
|
74
|
-
@log_parser.should_receive(:warn).with(:no_current_request, anything).twice
|
75
|
-
|
76
|
-
@log_parser.parse_file(log_fixture(:rails_unordered))
|
77
|
-
end
|
78
|
-
end
|
79
31
|
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
32
|
+
RequestLogAnalyzer::FileFormat::Rails::LINE_COLLECTIONS.keys.each do |constant|
|
33
|
+
|
34
|
+
context "using the '#{constant}' line collection constant" do
|
35
|
+
before(:each) { @rails = RequestLogAnalyzer::FileFormat.load(:rails, constant) }
|
36
|
+
|
37
|
+
it "should return a valid language" do
|
38
|
+
@rails.should be_valid
|
39
|
+
end
|
40
|
+
|
41
|
+
it "should at least parse :processing and :completed lines" do
|
42
|
+
@rails.line_definitions.should include(:processing, :completed)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
94
46
|
end
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
47
|
+
|
48
|
+
describe '#parse_line' do
|
49
|
+
before(:each) { @rails = RequestLogAnalyzer::FileFormat.load(:rails, :all) }
|
50
|
+
|
51
|
+
{'with prefix' => 'LINE PREFIX: ', 'without prefix' => '' }.each do |context, prefix|
|
52
|
+
context context do
|
53
|
+
it "should parse a :processing line correctly" do
|
54
|
+
line = prefix + 'Processing PeopleController#index (for 1.1.1.1 at 2008-08-14 21:16:30) [GET]'
|
55
|
+
@rails.should parse_line(line).as(:processing).and_capture(:controller => 'PeopleController', :action => 'index', :timestamp => 20080814211630, :method => 'GET')
|
56
|
+
end
|
57
|
+
|
58
|
+
it "should parse a Rails 2.1 style :completed line correctly" do
|
59
|
+
line = prefix + 'Completed in 0.21665 (4 reqs/sec) | Rendering: 0.00926 (4%) | DB: 0.00000 (0%) | 200 OK [http://demo.nu/employees]'
|
60
|
+
@rails.should parse_line(line).as(:completed).and_capture(:duration => 0.21665, :db => 0.0, :view => 0.00926, :status => 200, :url => 'http://demo.nu/employees')
|
61
|
+
end
|
62
|
+
|
63
|
+
it "should parse a Rails 2.2 style :completed line correctly" do
|
64
|
+
line = prefix + 'Completed in 614ms (View: 120, DB: 31) | 200 OK [http://floorplanner.local/demo]'
|
65
|
+
@rails.should parse_line(line).as(:completed).and_capture(:duration => 0.614, :db => 0.031, :view => 0.120, :status => 200, :url => 'http://floorplanner.local/demo')
|
66
|
+
end
|
67
|
+
|
68
|
+
it "should parse a :failure line with exception correctly" do
|
69
|
+
line = prefix + "NoMethodError (undefined method `update_domain_account' for nil:NilClass):"
|
70
|
+
@rails.should parse_line(line).as(:failure).and_capture(:error => 'NoMethodError', :message => "undefined method `update_domain_account' for nil:NilClass")
|
71
|
+
end
|
72
|
+
|
73
|
+
it "should parse a :cache_hit line correctly" do
|
74
|
+
line = prefix + 'Filter chain halted as [#<ActionController::Caching::Actions::ActionCacheFilter:0x2a999ad620 @check=nil, @options={:store_options=>{}, :layout=>nil, :cache_path=>#<Proc:0x0000002a999b8890@/app/controllers/cached_controller.rb:8>}>] rendered_or_redirected.'
|
75
|
+
@rails.should parse_line(line).as(:cache_hit)
|
76
|
+
end
|
77
|
+
|
78
|
+
it "should parse a :parameters line correctly" do
|
79
|
+
line = prefix + ' Parameters: {"action"=>"cached", "controller"=>"cached"}'
|
80
|
+
@rails.should parse_line(line).as(:parameters).and_capture(:params => {:action => 'cached', :controller => 'cached'})
|
81
|
+
end
|
82
|
+
|
83
|
+
it "should parse a :rendered line correctly" do
|
84
|
+
line = prefix + 'Rendered layouts/_footer (2.9ms)'
|
85
|
+
@rails.should parse_line(line).as(:rendered).and_capture(:render_file => 'layouts/_footer', :render_duration => 0.0029)
|
86
|
+
end
|
87
|
+
|
88
|
+
it "should parse a :query_executed line with colors" do
|
89
|
+
line = prefix + ' [4;36;1mUser Load (0.4ms)[0m [0;1mSELECT * FROM `users` WHERE (`users`.`id` = 18205844) [0m'
|
90
|
+
@rails.should parse_line(line).as(:query_executed).and_capture(:query_class => 'User', :query_duration => 0.0004, :query_sql => 'SELECT * FROM users WHERE (users.id = :int)')
|
91
|
+
end
|
92
|
+
|
93
|
+
it "should parse a :query_executed line without colors" do
|
94
|
+
line = prefix + ' User Load (0.4ms) SELECT * FROM `users` WHERE (`users`.`id` = 18205844) '
|
95
|
+
@rails.should parse_line(line).as(:query_executed).and_capture(:query_class => 'User', :query_duration => 0.0004, :query_sql => 'SELECT * FROM users WHERE (users.id = :int)')
|
96
|
+
end
|
97
|
+
|
98
|
+
it "should parse a :query_cached line with colors" do
|
99
|
+
line = prefix + ' [4;35;1mCACHE (0.0ms)[0m [0mSELECT * FROM `users` WHERE (`users`.`id` = 0) [0m'
|
100
|
+
@rails.should parse_line(line).as(:query_cached).and_capture(:cached_duration => 0.0, :cached_sql => 'SELECT * FROM users WHERE (users.id = :int)')
|
101
|
+
end
|
102
|
+
|
103
|
+
it "should parse a :query_cached line without colors" do
|
104
|
+
line = prefix + ' CACHE (0.0ms) SELECT * FROM `users` WHERE (`users`.`id` = 0) '
|
105
|
+
@rails.should parse_line(line).as(:query_cached).and_capture(:cached_duration => 0.0, :cached_sql => 'SELECT * FROM users WHERE (users.id = :int)')
|
106
|
+
end
|
107
|
+
|
108
|
+
it "should not parse an unsupported line" do
|
109
|
+
line = prefix + 'nonsense line that should not be parsed as anything'
|
110
|
+
@rails.should_not parse_line(line)
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
100
114
|
end
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
115
|
+
|
116
|
+
describe '#parse_io' do
|
117
|
+
before(:each) do
|
118
|
+
@log_parser = RequestLogAnalyzer::Source::LogParser.new(
|
119
|
+
RequestLogAnalyzer::FileFormat.load(:rails), :parse_strategy => 'cautious')
|
120
|
+
end
|
121
|
+
|
122
|
+
it "should parse a Rails 2.1 style log and find valid Rails requests without warnings" do
|
123
|
+
@log_parser.should_not_receive(:warn)
|
124
|
+
@log_parser.parse_file(log_fixture(:rails_1x)) do |request|
|
125
|
+
request.should be_kind_of(RequestLogAnalyzer::FileFormat::Rails::Request)
|
126
|
+
request.should be_completed
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
it "should parse a Rails 2.2 style log and find valid Rails requests without warnings" do
|
131
|
+
@log_parser.should_not_receive(:warn)
|
132
|
+
@log_parser.parse_file(log_fixture(:rails_22)) do |request|
|
133
|
+
request.should be_kind_of(RequestLogAnalyzer::FileFormat::Rails::Request)
|
134
|
+
request.should be_completed
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
it "should parse a Rails SyslogLogger file with prefix and find valid requests without warnings" do
|
139
|
+
@log_parser.should_not_receive(:warn)
|
140
|
+
@log_parser.parse_file(log_fixture(:syslog_1x)) do |request|
|
141
|
+
request.should be_kind_of(RequestLogAnalyzer::FileFormat::Rails::Request)
|
142
|
+
request.should be_completed
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
it "should find 4 completed requests" do
|
147
|
+
@log_parser.should_not_receive(:warn)
|
148
|
+
@log_parser.should_receive(:handle_request).exactly(4).times
|
149
|
+
@log_parser.parse_file(log_fixture(:rails_1x))
|
150
|
+
end
|
151
|
+
|
152
|
+
it "should parse cached requests" do
|
153
|
+
@log_parser.should_not_receive(:warn)
|
154
|
+
@log_parser.parse_file(log_fixture(:rails_22_cached)) do |request|
|
155
|
+
request.should be_completed
|
156
|
+
request =~ :cache_hit
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
it "should detect unordered requests in the logs" do
|
161
|
+
@log_parser.should_not_receive(:handle_request)
|
162
|
+
@log_parser.should_receive(:warn).with(:unclosed_request, anything).once
|
163
|
+
@log_parser.should_receive(:warn).with(:no_current_request, anything).twice
|
164
|
+
@log_parser.parse_file(log_fixture(:rails_unordered))
|
165
|
+
end
|
120
166
|
end
|
121
|
-
|
122
|
-
it "should parse a cached query line without colors" do
|
123
|
-
info = @file_format.line_definitions[:query_cached].match_for(' CACHE (0.0ms) SELECT * FROM `users` WHERE (`users`.`id` = 0) ', @request)
|
124
|
-
info[:cached_duration].should == 0.0
|
125
|
-
info[:cached_sql].should == 'SELECT * FROM users WHERE (users.id = :int)'
|
126
|
-
end
|
127
|
-
end
|
167
|
+
end
|