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.
Files changed (47) hide show
  1. data/bin/request-log-analyzer +0 -1
  2. data/lib/request_log_analyzer.rb +15 -29
  3. data/lib/request_log_analyzer/aggregator.rb +5 -5
  4. data/lib/request_log_analyzer/aggregator/database_inserter.rb +2 -1
  5. data/lib/request_log_analyzer/controller.rb +0 -3
  6. data/lib/request_log_analyzer/database.rb +6 -7
  7. data/lib/request_log_analyzer/file_format.rb +42 -13
  8. data/lib/request_log_analyzer/file_format/apache.rb +1 -1
  9. data/lib/request_log_analyzer/file_format/delayed_job2.rb +2 -2
  10. data/lib/request_log_analyzer/file_format/delayed_job21.rb +2 -2
  11. data/lib/request_log_analyzer/file_format/haproxy.rb +107 -13
  12. data/lib/request_log_analyzer/file_format/mysql.rb +5 -5
  13. data/lib/request_log_analyzer/file_format/rails3.rb +7 -0
  14. data/lib/request_log_analyzer/filter.rb +4 -5
  15. data/lib/request_log_analyzer/line_definition.rb +6 -4
  16. data/lib/request_log_analyzer/output.rb +3 -5
  17. data/lib/request_log_analyzer/source.rb +3 -4
  18. data/lib/request_log_analyzer/source/log_parser.rb +56 -4
  19. data/lib/request_log_analyzer/tracker.rb +8 -8
  20. data/request-log-analyzer.gemspec +3 -3
  21. data/spec/fixtures/mysql_slow_query.log +0 -1
  22. data/spec/integration/command_line_usage_spec.rb +0 -5
  23. data/spec/lib/helpers.rb +2 -2
  24. data/spec/lib/matchers.rb +38 -7
  25. data/spec/lib/mocks.rb +1 -5
  26. data/spec/unit/database/base_class_spec.rb +1 -0
  27. data/spec/unit/file_format/amazon_s3_format_spec.rb +58 -55
  28. data/spec/unit/file_format/apache_format_spec.rb +74 -162
  29. data/spec/unit/file_format/common_regular_expressions_spec.rb +51 -26
  30. data/spec/unit/file_format/delayed_job21_format_spec.rb +22 -31
  31. data/spec/unit/file_format/delayed_job2_format_spec.rb +27 -32
  32. data/spec/unit/file_format/delayed_job_format_spec.rb +44 -63
  33. data/spec/unit/file_format/haproxy_format_spec.rb +69 -71
  34. data/spec/unit/file_format/line_definition_spec.rb +26 -33
  35. data/spec/unit/file_format/merb_format_spec.rb +22 -37
  36. data/spec/unit/file_format/mysql_format_spec.rb +80 -123
  37. data/spec/unit/file_format/oink_format_spec.rb +29 -61
  38. data/spec/unit/file_format/postgresql_format_spec.rb +2 -4
  39. data/spec/unit/file_format/rack_format_spec.rb +49 -44
  40. data/spec/unit/file_format/rails3_format_spec.rb +17 -20
  41. data/spec/unit/file_format/rails_format_spec.rb +52 -68
  42. data/spec/unit/file_format/w3c_format_spec.rb +40 -39
  43. data/spec/unit/source/log_parser_spec.rb +1 -1
  44. metadata +4 -7
  45. data/lib/mixins/gets_memory_protection.rb +0 -80
  46. data/lib/request_log_analyzer/output/fancy_html.rb +0 -44
  47. 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
- context '"Sinatra" access log parsing' do
6
-
7
- before(:each) do
8
- @file_format = RequestLogAnalyzer::FileFormat.load(:rack)
9
- @log_parser = RequestLogAnalyzer::Source::LogParser.new(@file_format)
10
- @sample = '127.0.0.1 - - [23/Nov/2009 21:47:47] "GET /css/stylesheet.css HTTP/1.1" 200 3782 0.0024'
11
- end
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 be_valid }
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
- @file_format.should parse_line(line).as(:failure).and_capture(:line => 3,
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
- request_counter.should_receive(:hit!).once
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
- request_counter.should_receive(:hit!).once
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
- request_counter.should_receive(:hit!).once
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
- before(:each) { @rails = RequestLogAnalyzer::FileFormat.load(:rails) }
8
+ subject { RequestLogAnalyzer::FileFormat::Rails.create }
9
9
 
10
- it "should create a valid file format" do
11
- @rails.should be_valid
12
- end
10
+ it { should be_well_formed }
11
+ it { should have(11).report_trackers }
13
12
 
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
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
- 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
19
+ subject { RequestLogAnalyzer::FileFormat.load(:rails, 'minimal,failure') }
26
20
 
27
- it "should at least parse :processing and :completed lines" do
28
- @rails.line_definitions.should include(:processing, :completed, :failure)
29
- end
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
- before(:each) { @rails = RequestLogAnalyzer::FileFormat.load(:rails, constant) }
32
+ subject { RequestLogAnalyzer::FileFormat.load(:rails, constant) }
36
33
 
37
- it "should return a valid language" do
38
- @rails.should be_valid
39
- end
34
+ it { should be_well_formed }
35
+ it { should have_at_least(9).report_trackers }
40
36
 
41
- it "should at least parse :processing and :completed lines" do
42
- @rails.line_definitions.should include(:processing, :completed)
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
- @rails.should parse_line(line).as(:processing).and_capture(:controller => 'PeopleController', :action => 'index', :timestamp => 20080814211630, :method => 'GET', :ip => '1.1.1.1')
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
- @rails.should parse_line(line).as(:processing).and_capture(:controller => 'PeopleController', :action => 'index', :timestamp => 20080814211630, :method => 'GET', :ip => '::1')
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
- @rails.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')
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
- @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')
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
- @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')
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
- @rails.should parse_line(line).as(:completed).and_capture(:duration => 0.597, :db => nil, :view => 0.298, :status => 200, :url => 'http://shapado.com')
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
- @rails.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')
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
- @rails.should parse_line(line).as(:failure).and_capture(:error => 'NoMethodError', :message => "undefined method `update_domain_account' for nil:NilClass")
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
- @rails.should parse_line(line).as(:cache_hit)
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
- @rails.should parse_line(line).as(:cache_hit)
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
- @rails.should parse_line(line).as(:parameters).and_capture(:params => {:action => 'cached', :controller => 'cached'})
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
- @rails.should parse_line(line).as(:rendered).and_capture(:render_file => 'layouts/_footer', :render_duration => 0.0029)
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 + ' User Load (0.4ms) SELECT * FROM `users` WHERE (`users`.`id` = 18205844) '
116
- @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)')
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
- @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)')
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 + ' CACHE (0.0ms) SELECT * FROM `users` WHERE (`users`.`id` = 0) '
126
- @rails.should parse_line(line).as(:query_cached).and_capture(:cached_duration => 0.0, :cached_sql => 'SELECT * FROM users WHERE (users.id = :int)')
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
- @rails.should parse_line(line).as(:query_cached).and_capture(:cached_duration => 0.0, :cached_sql => 'SELECT * FROM users WHERE (users.id = :int)')
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
- @rails.should_not parse_line(line)
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
- before(:each) do
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
- request_counter.should_receive(:hit!).exactly(4).times
150
- @log_parser.should_not_receive(:warn)
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
- request_counter.should_receive(:hit!).once
159
- @log_parser.should_not_receive(:warn)
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
- request_counter.should_receive(:hit!).once
168
- @log_parser.should_not_receive(:warn)
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
- @log_parser.should_not_receive(:warn)
177
- @log_parser.parse_file(log_fixture(:rails_22_cached)) do |request|
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
- @log_parser.should_not_receive(:handle_request)
185
- @log_parser.should_receive(:warn).with(:unclosed_request, anything).once
186
- @log_parser.should_receive(:warn).with(:no_current_request, anything).twice
187
- @log_parser.parse_file(log_fixture(:rails_unordered))
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
- before(:each) do
6
- @file_format = RequestLogAnalyzer::FileFormat.load(:w3c)
7
- @log_parser = RequestLogAnalyzer::Source::LogParser.new(@file_format)
8
- # date time c-ip cs-username s-ip s-port cs-method cs-uri-stem cs-uri-query sc-status sc-bytes cs-bytes time-taken cs(User-Agent) cs(Referrer)
9
- @sample = '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/'
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
- it "should be a valid file format" do
13
- @file_format.should be_valid
14
- end
15
-
16
- it "should parse access lines and capture all of its fields" do
17
- @file_format.should have_line_definition(:access).capturing(:timestamp, :remote_ip, :username, :local_ip, :port, :method, :path, :http_status, :bytes_sent, :bytes_received, :duration, :user_agent, :referer)
18
- end
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