request-log-analyzer 1.10.1 → 1.11.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/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
|