request-log-analyzer 1.10.1 → 1.11.0
Sign up to get free protection for your applications and to get access to all the features.
- data/bin/request-log-analyzer +0 -1
- data/lib/request_log_analyzer.rb +15 -29
- data/lib/request_log_analyzer/aggregator.rb +5 -5
- data/lib/request_log_analyzer/aggregator/database_inserter.rb +2 -1
- data/lib/request_log_analyzer/controller.rb +0 -3
- data/lib/request_log_analyzer/database.rb +6 -7
- data/lib/request_log_analyzer/file_format.rb +42 -13
- data/lib/request_log_analyzer/file_format/apache.rb +1 -1
- data/lib/request_log_analyzer/file_format/delayed_job2.rb +2 -2
- data/lib/request_log_analyzer/file_format/delayed_job21.rb +2 -2
- data/lib/request_log_analyzer/file_format/haproxy.rb +107 -13
- data/lib/request_log_analyzer/file_format/mysql.rb +5 -5
- data/lib/request_log_analyzer/file_format/rails3.rb +7 -0
- data/lib/request_log_analyzer/filter.rb +4 -5
- data/lib/request_log_analyzer/line_definition.rb +6 -4
- data/lib/request_log_analyzer/output.rb +3 -5
- data/lib/request_log_analyzer/source.rb +3 -4
- data/lib/request_log_analyzer/source/log_parser.rb +56 -4
- data/lib/request_log_analyzer/tracker.rb +8 -8
- data/request-log-analyzer.gemspec +3 -3
- data/spec/fixtures/mysql_slow_query.log +0 -1
- data/spec/integration/command_line_usage_spec.rb +0 -5
- data/spec/lib/helpers.rb +2 -2
- data/spec/lib/matchers.rb +38 -7
- data/spec/lib/mocks.rb +1 -5
- data/spec/unit/database/base_class_spec.rb +1 -0
- data/spec/unit/file_format/amazon_s3_format_spec.rb +58 -55
- data/spec/unit/file_format/apache_format_spec.rb +74 -162
- data/spec/unit/file_format/common_regular_expressions_spec.rb +51 -26
- data/spec/unit/file_format/delayed_job21_format_spec.rb +22 -31
- data/spec/unit/file_format/delayed_job2_format_spec.rb +27 -32
- data/spec/unit/file_format/delayed_job_format_spec.rb +44 -63
- data/spec/unit/file_format/haproxy_format_spec.rb +69 -71
- data/spec/unit/file_format/line_definition_spec.rb +26 -33
- data/spec/unit/file_format/merb_format_spec.rb +22 -37
- data/spec/unit/file_format/mysql_format_spec.rb +80 -123
- data/spec/unit/file_format/oink_format_spec.rb +29 -61
- data/spec/unit/file_format/postgresql_format_spec.rb +2 -4
- data/spec/unit/file_format/rack_format_spec.rb +49 -44
- data/spec/unit/file_format/rails3_format_spec.rb +17 -20
- data/spec/unit/file_format/rails_format_spec.rb +52 -68
- data/spec/unit/file_format/w3c_format_spec.rb +40 -39
- data/spec/unit/source/log_parser_spec.rb +1 -1
- metadata +4 -7
- data/lib/mixins/gets_memory_protection.rb +0 -80
- data/lib/request_log_analyzer/output/fancy_html.rb +0 -44
- data/lib/request_log_analyzer/source/database_loader.rb +0 -87
@@ -1,50 +1,55 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe RequestLogAnalyzer::FileFormat::Rack do
|
4
|
+
|
5
|
+
subject { RequestLogAnalyzer::FileFormat.load(:rack)}
|
6
|
+
let(:log_parser) { RequestLogAnalyzer::Source::LogParser.new(subject) }
|
7
|
+
|
8
|
+
it { should be_well_formed }
|
9
|
+
it { should have_line_definition(:access).capturing(:remote_host, :user, :remote_logname,
|
10
|
+
:timestamp, :http_method, :path, :http_version, :http_status, :bytes_sent, :duration) }
|
11
|
+
|
12
|
+
it { should have(7).report_trackers }
|
13
|
+
|
14
|
+
let(:sample1) { '127.0.0.1 - - [23/Nov/2009 21:47:47] "GET /css/stylesheet.css HTTP/1.1" 200 3782 0.0024' }
|
15
|
+
let(:sample2) { '127.0.0.1 - - [16/Sep/2009 07:40:08] "GET /favicon.ico HTTP/1.1" 500 63183 0.0453' }
|
16
|
+
let(:sample3) { '127.0.0.1 - - [01/Oct/2009 07:58:10] "GET / HTTP/1.1" 200 1 0.0045' }
|
17
|
+
let(:irrelevant) { '== Sinatra/0.9.4 has taken the stage on 4567 for development with backup from Mongrel' }
|
18
|
+
|
19
|
+
describe '#parse_line' do
|
20
|
+
|
21
|
+
it { should parse_line(sample1, 'a sample access line').and_capture(
|
22
|
+
:remote_host => '127.0.0.1', :timestamp => 20091123214747, :user => nil,
|
23
|
+
:http_status => 200, :http_method => 'GET', :http_version => '1.1',
|
24
|
+
:duration => 0.0024, :bytes_sent => 3782, :remote_logname => nil,
|
25
|
+
:path => '/css/stylesheet.css')
|
26
|
+
}
|
27
|
+
|
28
|
+
it { should parse_line(sample2, 'another sample access line').and_capture(
|
29
|
+
:remote_host => '127.0.0.1', :timestamp => 20090916074008, :user => nil,
|
30
|
+
:http_status => 500, :http_method => 'GET', :http_version => '1.1',
|
31
|
+
:duration => 0.0453, :bytes_sent => 63183, :remote_logname => nil,
|
32
|
+
:path => '/favicon.ico')
|
33
|
+
}
|
34
|
+
|
35
|
+
it { should parse_line(sample3, 'a third sample access line').and_capture(
|
36
|
+
:remote_host => '127.0.0.1', :timestamp => 20091001075810, :user => nil,
|
37
|
+
:http_status => 200, :http_method => 'GET', :http_version => '1.1',
|
38
|
+
:duration => 0.0045, :bytes_sent => 1, :remote_logname => nil,
|
39
|
+
:path => '/')
|
40
|
+
}
|
41
|
+
|
42
|
+
it { should_not parse_line(irrelevant, 'an irrelevant line') }
|
43
|
+
it { should_not parse_line('nonsense', 'a nonsense line') }
|
44
|
+
end
|
4
45
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
it "should be a valid file format" do
|
14
|
-
@file_format.should be_valid
|
15
|
-
end
|
16
|
-
|
17
|
-
it "should parse access lines and capture all of its fields" do
|
18
|
-
@file_format.should have_line_definition(:access).capturing(:remote_host, :timestamp, :http_method, :path, :http_version,
|
19
|
-
:http_status, :bytes_sent, :duration)
|
20
|
-
end
|
21
|
-
|
22
|
-
it "should match the sample line" do
|
23
|
-
@file_format.parse_line(@sample).should include(:line_definition, :captures)
|
24
|
-
end
|
25
|
-
|
26
|
-
it "should not match a nonsense line" do
|
27
|
-
@file_format.parse_line('== Sinatra/0.9.4 has taken the stage on 4567 for development with backup from Mongrel').should be_nil
|
28
|
-
end
|
29
|
-
|
30
|
-
it "should parse the sample fields correctly" do
|
31
|
-
match = @file_format.parse_line(@sample)
|
32
|
-
match.should_not be_nil
|
33
|
-
end
|
34
|
-
|
35
|
-
it "should parse and convert the sample fields correctly" do
|
36
|
-
@log_parser.parse_io(StringIO.new(@sample)) do |request|
|
37
|
-
request[:remote_host].should == '127.0.0.1'
|
38
|
-
request[:timestamp].should == 20091123214747
|
39
|
-
request[:http_method].should == 'GET'
|
40
|
-
request[:path].should == '/css/stylesheet.css'
|
41
|
-
request[:http_version].should == '1.1'
|
42
|
-
request[:http_status].should == 200
|
43
|
-
request[:bytes_sent].should == 3782
|
44
|
-
request[:duration].should == 0.0024
|
45
|
-
end
|
46
|
+
describe '#parse_io' do
|
47
|
+
let(:snippet) { log_snippet(irrelevant, sample1, sample2, sample3) }
|
48
|
+
|
49
|
+
it "shouldparse a snippet without warnings" do
|
50
|
+
log_parser.should_receive(:handle_request).exactly(3).times
|
51
|
+
log_parser.should_not_receive(:warn)
|
52
|
+
log_parser.parse_io(snippet)
|
46
53
|
end
|
47
|
-
|
48
54
|
end
|
49
|
-
|
50
|
-
end
|
55
|
+
end
|
@@ -3,12 +3,11 @@ require 'spec_helper'
|
|
3
3
|
describe RequestLogAnalyzer::FileFormat::Rails3 do
|
4
4
|
|
5
5
|
subject { RequestLogAnalyzer::FileFormat.load(:rails3) }
|
6
|
-
let(:log_parser) {RequestLogAnalyzer::Source::LogParser.new(subject) }
|
7
6
|
|
8
|
-
it { should
|
9
|
-
|
7
|
+
it { should be_well_formed }
|
8
|
+
it { should have(9).report_trackers }
|
9
|
+
|
10
10
|
describe '#parse_line' do
|
11
|
-
before(:each) { @file_format = RequestLogAnalyzer::FileFormat.load(:rails3) }
|
12
11
|
|
13
12
|
it "should parse :started lines correctly" do
|
14
13
|
line = 'Started GET "/queries" for 127.0.0.1 at Thu Feb 25 16:15:18 -0800 2010'
|
@@ -51,6 +50,11 @@ describe RequestLogAnalyzer::FileFormat::Rails3 do
|
|
51
50
|
subject.should parse_line(line).as(:processing).and_capture(
|
52
51
|
:controller => 'ProjectsController', :action => 'avatar', :format => '')
|
53
52
|
end
|
53
|
+
|
54
|
+
it "should parse a :parameters line correctly" do
|
55
|
+
line = ' Parameters: {"action"=>"cached", "controller"=>"cached"}'
|
56
|
+
subject.should parse_line(line).as(:parameters).and_capture(:params => {:action => 'cached', :controller => 'cached'})
|
57
|
+
end
|
54
58
|
|
55
59
|
it "should parse :completed lines correctly" do
|
56
60
|
line = 'Completed 200 OK in 170ms (Views: 78.0ms | ActiveRecord: 48.2ms)'
|
@@ -72,7 +76,7 @@ describe RequestLogAnalyzer::FileFormat::Rails3 do
|
|
72
76
|
|
73
77
|
it "should pase :failure lines correctly" do
|
74
78
|
line = "ActionView::Template::Error (undefined local variable or method `field' for #<Class>) on line #3 of /Users/willem/Code/warehouse/app/views/queries/execute.csv.erb:"
|
75
|
-
|
79
|
+
subject.should parse_line(line).as(:failure).and_capture(:line => 3,
|
76
80
|
:error => 'ActionView::Template::Error',
|
77
81
|
:message => "undefined local variable or method `field' for #<Class>",
|
78
82
|
:file => '/Users/willem/Code/warehouse/app/views/queries/execute.csv.erb')
|
@@ -80,6 +84,8 @@ describe RequestLogAnalyzer::FileFormat::Rails3 do
|
|
80
84
|
end
|
81
85
|
|
82
86
|
describe '#parse_io' do
|
87
|
+
let(:log_parser) { RequestLogAnalyzer::Source::LogParser.new(subject) }
|
88
|
+
|
83
89
|
it "should parse a successful request correctly" do
|
84
90
|
log = <<-EOLOG
|
85
91
|
Started GET "/" for 127.0.0.1 at Fri Mar 19 06:40:41 -0700 2010
|
@@ -90,12 +96,9 @@ describe RequestLogAnalyzer::FileFormat::Rails3 do
|
|
90
96
|
Completed 200 OK in 170ms (Views: 78.4ms | ActiveRecord: 48.2ms)
|
91
97
|
EOLOG
|
92
98
|
|
93
|
-
|
99
|
+
log_parser.should_receive(:handle_request).once
|
94
100
|
log_parser.should_not_receive(:warn)
|
95
|
-
|
96
|
-
log_parser.parse_io(StringIO.new(log)) do |request|
|
97
|
-
request_counter.hit! if request.kind_of?(RequestLogAnalyzer::FileFormat::Rails3::Request) && request.completed?
|
98
|
-
end
|
101
|
+
log_parser.parse_string(log)
|
99
102
|
end
|
100
103
|
|
101
104
|
it "should parse an unroutable request correctly" do
|
@@ -109,12 +112,9 @@ describe RequestLogAnalyzer::FileFormat::Rails3 do
|
|
109
112
|
|
110
113
|
EOLOG
|
111
114
|
|
112
|
-
|
115
|
+
log_parser.should_receive(:handle_request).once
|
113
116
|
log_parser.should_not_receive(:warn)
|
114
|
-
|
115
|
-
log_parser.parse_io(StringIO.new(log)) do |request|
|
116
|
-
request_counter.hit! if request.kind_of?(RequestLogAnalyzer::FileFormat::Rails3::Request) && request.completed?
|
117
|
-
end
|
117
|
+
log_parser.parse_string(log)
|
118
118
|
end
|
119
119
|
|
120
120
|
it "should parse a failing request correctly" do
|
@@ -141,12 +141,9 @@ describe RequestLogAnalyzer::FileFormat::Rails3 do
|
|
141
141
|
|
142
142
|
EOLOG
|
143
143
|
|
144
|
-
|
144
|
+
log_parser.should_receive(:handle_request).once
|
145
145
|
log_parser.should_not_receive(:warn)
|
146
|
-
|
147
|
-
log_parser.parse_io(StringIO.new(log)) do |request|
|
148
|
-
request_counter.hit! if request.kind_of?(RequestLogAnalyzer::FileFormat::Rails3::Request) && request.completed?
|
149
|
-
end
|
146
|
+
log_parser.parse_string(log)
|
150
147
|
end
|
151
148
|
end
|
152
149
|
end
|
@@ -5,186 +5,170 @@ describe RequestLogAnalyzer::FileFormat::Rails do
|
|
5
5
|
describe '.create' do
|
6
6
|
|
7
7
|
context 'without providing a lines argument' do
|
8
|
-
|
8
|
+
subject { RequestLogAnalyzer::FileFormat::Rails.create }
|
9
9
|
|
10
|
-
it
|
11
|
-
|
12
|
-
end
|
10
|
+
it { should be_well_formed }
|
11
|
+
it { should have(11).report_trackers }
|
13
12
|
|
14
|
-
it "should parse the production
|
15
|
-
|
16
|
-
@rails.line_definitions.should == production_rails.line_definitions
|
13
|
+
it "should parse the lines in the production set" do
|
14
|
+
subject.line_definitions.should == RequestLogAnalyzer::FileFormat.load(:rails, 'production').line_definitions
|
17
15
|
end
|
18
16
|
end
|
19
17
|
|
20
18
|
context 'using a comma separated list of lines as argument' do
|
21
|
-
|
22
|
-
|
23
|
-
it "should return a valid language" do
|
24
|
-
@rails.should be_valid
|
25
|
-
end
|
19
|
+
subject { RequestLogAnalyzer::FileFormat.load(:rails, 'minimal,failure') }
|
26
20
|
|
27
|
-
it
|
28
|
-
|
29
|
-
|
21
|
+
it { should be_well_formed }
|
22
|
+
it { should have(10).report_trackers }
|
23
|
+
|
24
|
+
it { should have_line_definition(:processing) }
|
25
|
+
it { should have_line_definition(:completed) }
|
26
|
+
it { should have_line_definition(:failure) }
|
30
27
|
end
|
31
28
|
|
32
29
|
RequestLogAnalyzer::FileFormat::Rails::LINE_COLLECTIONS.keys.each do |constant|
|
33
30
|
|
34
31
|
context "using the '#{constant}' line collection constant" do
|
35
|
-
|
32
|
+
subject { RequestLogAnalyzer::FileFormat.load(:rails, constant) }
|
36
33
|
|
37
|
-
it
|
38
|
-
|
39
|
-
end
|
34
|
+
it { should be_well_formed }
|
35
|
+
it { should have_at_least(9).report_trackers }
|
40
36
|
|
41
|
-
it
|
42
|
-
|
43
|
-
end
|
37
|
+
it { should have_line_definition(:processing) }
|
38
|
+
it { should have_line_definition(:completed) }
|
44
39
|
end
|
45
40
|
end
|
46
41
|
end
|
42
|
+
|
43
|
+
subject { RequestLogAnalyzer::FileFormat.load(:rails, :all) }
|
47
44
|
|
48
45
|
describe '#parse_line' do
|
49
|
-
before(:each) { @rails = RequestLogAnalyzer::FileFormat.load(:rails, :all) }
|
50
46
|
|
51
47
|
{'with prefix' => 'LINE PREFIX: ', 'without prefix' => '' }.each do |context, prefix|
|
52
48
|
context context do
|
53
49
|
it "should parse a :processing line correctly" do
|
54
50
|
line = prefix + 'Processing PeopleController#index (for 1.1.1.1 at 2008-08-14 21:16:30) [GET]'
|
55
|
-
|
51
|
+
subject.should parse_line(line).as(:processing).and_capture(:controller => 'PeopleController', :action => 'index', :timestamp => 20080814211630, :method => 'GET', :ip => '1.1.1.1')
|
56
52
|
end
|
57
53
|
|
58
54
|
it "should parse a :processing line correctly when it contains ipv6 localhost address" do
|
59
55
|
line = prefix + 'Processing PeopleController#index (for ::1 at 2008-08-14 21:16:30) [GET]'
|
60
|
-
|
56
|
+
subject.should parse_line(line).as(:processing).and_capture(:controller => 'PeopleController', :action => 'index', :timestamp => 20080814211630, :method => 'GET', :ip => '::1')
|
61
57
|
end
|
62
58
|
|
63
59
|
it "should parse a :processing line correctly when it contains ipv6 address" do
|
64
60
|
line = prefix + 'Processing PeopleController#index (for 3ffe:1900:4545:3:200:f8ff:fe21:67cf at 2008-08-14 21:16:30) [GET]'
|
65
|
-
|
61
|
+
subject.should parse_line(line).as(:processing).and_capture(:controller => 'PeopleController', :action => 'index', :timestamp => 20080814211630, :method => 'GET', :ip => '3ffe:1900:4545:3:200:f8ff:fe21:67cf')
|
66
62
|
end
|
67
63
|
|
68
64
|
it "should parse a Rails 2.1 style :completed line correctly" do
|
69
65
|
line = prefix + 'Completed in 0.21665 (4 reqs/sec) | Rendering: 0.00926 (4%) | DB: 0.00000 (0%) | 200 OK [http://demo.nu/employees]'
|
70
|
-
|
66
|
+
subject.should parse_line(line).as(:completed).and_capture(:duration => 0.21665, :db => 0.0, :view => 0.00926, :status => 200, :url => 'http://demo.nu/employees')
|
71
67
|
end
|
72
68
|
|
73
69
|
it "should parse a Rails 2.2 style :completed line correctly" do
|
74
70
|
line = prefix + 'Completed in 614ms (View: 120, DB: 31) | 200 OK [http://floorplanner.local/demo]'
|
75
|
-
|
71
|
+
subject.should parse_line(line).as(:completed).and_capture(:duration => 0.614, :db => 0.031, :view => 0.120, :status => 200, :url => 'http://floorplanner.local/demo')
|
76
72
|
end
|
77
73
|
|
78
74
|
it "should parse a Rails 2.2 style :completed line correctly when AR is disabled" do
|
79
75
|
line = prefix + 'Completed in 597ms (View: 298 | 200 OK [http://shapado.com]'
|
80
|
-
|
76
|
+
subject.should parse_line(line).as(:completed).and_capture(:duration => 0.597, :db => nil, :view => 0.298, :status => 200, :url => 'http://shapado.com')
|
81
77
|
end
|
82
78
|
|
83
79
|
it "should parse a Rails 2.2 style :completed line without view" do
|
84
80
|
line = prefix + "Completed in 148ms (DB: 0) | 302 Found [http://iwp-sod.hargray.org/login]"
|
85
|
-
|
81
|
+
subject.should parse_line(line).as(:completed).and_capture(:duration => 0.148, :db => 0.0, :view => nil, :status => 302, :url => 'http://iwp-sod.hargray.org/login')
|
86
82
|
end
|
87
83
|
|
88
84
|
it "should parse a :failure line with exception correctly" do
|
89
85
|
line = prefix + "NoMethodError (undefined method `update_domain_account' for nil:NilClass):"
|
90
|
-
|
86
|
+
subject.should parse_line(line).as(:failure).and_capture(:error => 'NoMethodError', :message => "undefined method `update_domain_account' for nil:NilClass")
|
91
87
|
end
|
92
88
|
|
93
89
|
it "should parse a :cache_hit line correctly with an filter instance reference" do
|
94
90
|
line = prefix + 'Filter chain halted as [#<ActionController::Filters::AroundFilter:0x2a999ad120 @identifier=nil, @kind=:filter, @options={:only=>#<Set: {"cached"}>, :if=>:not_logged_in?, :unless=>nil}, @method=#<ActionController::Caching::Actions::ActionCacheFilter:0x2a999ad620 @check=nil, @options={:store_options=>{}, :layout=>nil, :cache_path=>#<Proc:0x0000002a999b8890@/app/controllers/cached_controller.rb:8>}>>] did_not_yield.'
|
95
|
-
|
91
|
+
subject.should parse_line(line).as(:cache_hit)
|
96
92
|
end
|
97
93
|
|
98
94
|
it "should parse a :cache_hit line correctly with an proc instance reference" do
|
99
95
|
line = prefix + 'Filter chain halted as [#<ActionController::Filters::AroundFilter:0x2a9a923e38 @method=#<Proc:0x0000002a9818b3f8@/usr/local/lib/ruby/gems/1.8/gems/actionpack-2.3.5/lib/action_controller/caching/actions.rb:64>, @kind=:filter, @identifier=nil, @options={:unless=>nil, :if=>nil, :only=>#<Set: {"show"}>}>] did_not_yield.'
|
100
|
-
|
96
|
+
subject.should parse_line(line).as(:cache_hit)
|
101
97
|
end
|
102
98
|
|
103
99
|
|
104
100
|
it "should parse a :parameters line correctly" do
|
105
101
|
line = prefix + ' Parameters: {"action"=>"cached", "controller"=>"cached"}'
|
106
|
-
|
102
|
+
subject.should parse_line(line).as(:parameters).and_capture(:params => {:action => 'cached', :controller => 'cached'})
|
107
103
|
end
|
108
104
|
|
109
105
|
it "should parse a :rendered line correctly" do
|
110
106
|
line = prefix + 'Rendered layouts/_footer (2.9ms)'
|
111
|
-
|
107
|
+
subject.should parse_line(line).as(:rendered).and_capture(:render_file => 'layouts/_footer', :render_duration => 0.0029)
|
112
108
|
end
|
113
109
|
|
114
110
|
it "should parse a :query_executed line with colors" do
|
115
111
|
line = prefix + ' [4;36;1mUser Load (0.4ms)[0m [0;1mSELECT * FROM `users` WHERE (`users`.`id` = 18205844) [0m'
|
116
|
-
|
112
|
+
subject.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)')
|
117
113
|
end
|
118
114
|
|
119
115
|
it "should parse a :query_executed line without colors" do
|
120
116
|
line = prefix + ' User Load (0.4ms) SELECT * FROM `users` WHERE (`users`.`id` = 18205844) '
|
121
|
-
|
117
|
+
subject.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)')
|
122
118
|
end
|
123
119
|
|
124
120
|
it "should parse a :query_cached line with colors" do
|
125
121
|
line = prefix + ' [4;35;1mCACHE (0.0ms)[0m [0mSELECT * FROM `users` WHERE (`users`.`id` = 0) [0m'
|
126
|
-
|
122
|
+
subject.should parse_line(line).as(:query_cached).and_capture(:cached_duration => 0.0, :cached_sql => 'SELECT * FROM users WHERE (users.id = :int)')
|
127
123
|
end
|
128
124
|
|
129
125
|
it "should parse a :query_cached line without colors" do
|
130
126
|
line = prefix + ' CACHE (0.0ms) SELECT * FROM `users` WHERE (`users`.`id` = 0) '
|
131
|
-
|
127
|
+
subject.should parse_line(line).as(:query_cached).and_capture(:cached_duration => 0.0, :cached_sql => 'SELECT * FROM users WHERE (users.id = :int)')
|
132
128
|
end
|
133
129
|
|
134
130
|
it "should not parse an unsupported line" do
|
135
131
|
line = prefix + 'nonsense line that should not be parsed as anything'
|
136
|
-
|
132
|
+
subject.should_not parse_line(line)
|
137
133
|
end
|
138
134
|
end
|
139
135
|
end
|
140
136
|
end
|
141
137
|
|
142
138
|
describe '#parse_io' do
|
143
|
-
|
144
|
-
@log_parser = RequestLogAnalyzer::Source::LogParser.new(
|
145
|
-
RequestLogAnalyzer::FileFormat.load(:rails), :parse_strategy => 'cautious')
|
146
|
-
end
|
139
|
+
let(:log_parser) { RequestLogAnalyzer::Source::LogParser.new(subject, :parse_strategy => 'cautious') }
|
147
140
|
|
148
141
|
it "should parse a Rails 2.1 style log and find valid Rails requests without warnings" do
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
@log_parser.parse_file(log_fixture(:rails_1x)) do |request|
|
153
|
-
request_counter.hit! if request.kind_of?(RequestLogAnalyzer::FileFormat::Rails::Request) && request.completed?
|
154
|
-
end
|
142
|
+
log_parser.should_receive(:handle_request).exactly(4).times
|
143
|
+
log_parser.should_not_receive(:warn)
|
144
|
+
log_parser.parse_file(log_fixture(:rails_1x))\
|
155
145
|
end
|
156
146
|
|
157
147
|
it "should parse a Rails 2.2 style log and find valid Rails requests without warnings" do
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
@log_parser.parse_file(log_fixture(:rails_22)) do |request|
|
162
|
-
request_counter.hit! if request.kind_of?(RequestLogAnalyzer::FileFormat::Rails::Request) && request.completed?
|
163
|
-
end
|
148
|
+
log_parser.should_receive(:handle_request).once
|
149
|
+
log_parser.should_not_receive(:warn)
|
150
|
+
log_parser.parse_file(log_fixture(:rails_22))
|
164
151
|
end
|
165
152
|
|
166
153
|
it "should parse a Rails SyslogLogger file with prefix and find valid requests without warnings" do
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
@log_parser.parse_file(log_fixture(:syslog_1x)) do |request|
|
171
|
-
request_counter.hit! if request.kind_of?(RequestLogAnalyzer::FileFormat::Rails::Request) && request.completed?
|
172
|
-
end
|
154
|
+
log_parser.should_receive(:handle_request).once
|
155
|
+
log_parser.should_not_receive(:warn)
|
156
|
+
log_parser.parse_file(log_fixture(:syslog_1x))
|
173
157
|
end
|
174
158
|
|
175
159
|
it "should parse cached requests" do
|
176
|
-
|
177
|
-
|
160
|
+
log_parser.should_not_receive(:warn)
|
161
|
+
log_parser.parse_file(log_fixture(:rails_22_cached)) do |request|
|
178
162
|
request.should be_completed
|
179
163
|
request =~ :cache_hit
|
180
164
|
end
|
181
165
|
end
|
182
166
|
|
183
167
|
it "should detect unordered requests in the logs" do
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
168
|
+
log_parser.should_not_receive(:handle_request)
|
169
|
+
log_parser.should_receive(:warn).with(:unclosed_request, anything).once
|
170
|
+
log_parser.should_receive(:warn).with(:no_current_request, anything).at_least(:twice)
|
171
|
+
log_parser.parse_file(log_fixture(:rails_unordered))
|
188
172
|
end
|
189
173
|
end
|
190
174
|
end
|
@@ -2,45 +2,46 @@ require 'spec_helper'
|
|
2
2
|
|
3
3
|
describe RequestLogAnalyzer::FileFormat::W3c do
|
4
4
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
5
|
+
subject { RequestLogAnalyzer::FileFormat.load(:w3c) }
|
6
|
+
|
7
|
+
it { should be_well_formed }
|
8
|
+
it { should have_line_definition(:access).capturing(:timestamp, :remote_ip, :username, :local_ip, :port,
|
9
|
+
:method, :path, :http_status, :bytes_sent, :bytes_received, :duration, :user_agent, :referer) }
|
10
|
+
|
11
|
+
it { should have(10).report_trackers }
|
12
|
+
|
13
|
+
let(:sample1) { '2002-05-24 20:18:01 172.224.24.114 - 206.73.118.24 80 GET /Default.htm - 200 7930 248 31 Mozilla/4.0+(compatible;+MSIE+5.01;+Windows+2000+Server) http://64.224.24.114/' }
|
14
|
+
let(:irrelevant) { '#Software: Microsoft Internet Information Services 6.0' }
|
15
|
+
|
16
|
+
describe '#parse_line' do
|
17
|
+
it { should parse_line(sample1, 'an access line').and_capture(
|
18
|
+
:timestamp => 20020524201801,
|
19
|
+
:remote_ip => "172.224.24.114",
|
20
|
+
:username => nil,
|
21
|
+
:local_ip => "206.73.118.24",
|
22
|
+
:port => 80,
|
23
|
+
:method => 'GET',
|
24
|
+
:path => '/Default.htm',
|
25
|
+
:http_status => 200,
|
26
|
+
:bytes_sent => 7930,
|
27
|
+
:bytes_received => 248,
|
28
|
+
:duration => 0.031,
|
29
|
+
:user_agent => 'Mozilla/4.0+(compatible;+MSIE+5.01;+Windows+2000+Server)',
|
30
|
+
:referer => 'http://64.224.24.114/')
|
31
|
+
}
|
32
|
+
|
33
|
+
it { should_not parse_line(irrelevant, 'an irrelevant line') }
|
34
|
+
it { should_not parse_line('nonsense', 'a nonsense line') }
|
10
35
|
end
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
it "should match the sample line" do
|
21
|
-
@file_format.parse_line(@sample).should include(:line_definition, :captures)
|
22
|
-
end
|
23
|
-
|
24
|
-
it "should not match a nonsense line" do
|
25
|
-
@file_format.parse_line('#Software: Microsoft Internet Information Services 6.0').should be_nil
|
26
|
-
end
|
27
|
-
|
28
|
-
it "should parse and convert the sample fields correctly" do
|
29
|
-
@log_parser.parse_io(StringIO.new(@sample)) do |request|
|
30
|
-
request[:timestamp].should == 20020524201801
|
31
|
-
request[:remote_ip].should == "172.224.24.114"
|
32
|
-
request[:username].should == nil
|
33
|
-
request[:local_ip].should == "206.73.118.24"
|
34
|
-
request[:port].should == 80
|
35
|
-
request[:method].should == 'GET'
|
36
|
-
request[:path].should == '/Default.htm'
|
37
|
-
request[:http_status].should == 200
|
38
|
-
request[:bytes_sent].should == 7930
|
39
|
-
request[:bytes_received].should == 248
|
40
|
-
request[:duration].should == 0.031
|
41
|
-
request[:user_agent].should == 'Mozilla/4.0+(compatible;+MSIE+5.01;+Windows+2000+Server)'
|
42
|
-
request[:referer].should == 'http://64.224.24.114/'
|
36
|
+
|
37
|
+
describe '#parse_io' do
|
38
|
+
let(:log_parser) { RequestLogAnalyzer::Source::LogParser.new(subject) }
|
39
|
+
let(:snippet) { log_snippet(irrelevant, sample1, sample1) }
|
40
|
+
|
41
|
+
it "should parse a snippet successully without warnings" do
|
42
|
+
log_parser.should_receive(:handle_request).twice
|
43
|
+
log_parser.should_not_receive(:warn)
|
44
|
+
log_parser.parse_io(snippet)
|
43
45
|
end
|
44
46
|
end
|
45
|
-
|
46
|
-
end
|
47
|
+
end
|