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