request-log-analyzer 1.3.7 → 1.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (84) hide show
  1. data/LICENSE +3 -3
  2. data/README.rdoc +1 -1
  3. data/bin/request-log-analyzer +17 -14
  4. data/lib/cli/command_line_arguments.rb +51 -51
  5. data/lib/cli/database_console.rb +3 -3
  6. data/lib/cli/database_console_init.rb +2 -2
  7. data/lib/cli/progressbar.rb +10 -10
  8. data/lib/cli/tools.rb +3 -3
  9. data/lib/request_log_analyzer.rb +4 -4
  10. data/lib/request_log_analyzer/aggregator.rb +10 -10
  11. data/lib/request_log_analyzer/aggregator/database_inserter.rb +9 -9
  12. data/lib/request_log_analyzer/aggregator/echo.rb +14 -9
  13. data/lib/request_log_analyzer/aggregator/summarizer.rb +26 -26
  14. data/lib/request_log_analyzer/controller.rb +153 -69
  15. data/lib/request_log_analyzer/database.rb +13 -13
  16. data/lib/request_log_analyzer/database/base.rb +17 -17
  17. data/lib/request_log_analyzer/database/connection.rb +3 -3
  18. data/lib/request_log_analyzer/database/request.rb +2 -2
  19. data/lib/request_log_analyzer/database/source.rb +1 -1
  20. data/lib/request_log_analyzer/file_format.rb +15 -15
  21. data/lib/request_log_analyzer/file_format/amazon_s3.rb +16 -16
  22. data/lib/request_log_analyzer/file_format/apache.rb +20 -19
  23. data/lib/request_log_analyzer/file_format/merb.rb +12 -12
  24. data/lib/request_log_analyzer/file_format/rack.rb +4 -4
  25. data/lib/request_log_analyzer/file_format/rails.rb +146 -70
  26. data/lib/request_log_analyzer/file_format/rails_development.rb +4 -49
  27. data/lib/request_log_analyzer/filter.rb +6 -6
  28. data/lib/request_log_analyzer/filter/anonymize.rb +6 -6
  29. data/lib/request_log_analyzer/filter/field.rb +9 -9
  30. data/lib/request_log_analyzer/filter/timespan.rb +12 -10
  31. data/lib/request_log_analyzer/line_definition.rb +15 -14
  32. data/lib/request_log_analyzer/log_processor.rb +22 -22
  33. data/lib/request_log_analyzer/mailer.rb +15 -9
  34. data/lib/request_log_analyzer/output.rb +53 -12
  35. data/lib/request_log_analyzer/output/fixed_width.rb +40 -41
  36. data/lib/request_log_analyzer/output/html.rb +20 -20
  37. data/lib/request_log_analyzer/request.rb +35 -36
  38. data/lib/request_log_analyzer/source.rb +7 -7
  39. data/lib/request_log_analyzer/source/database_loader.rb +7 -7
  40. data/lib/request_log_analyzer/source/log_parser.rb +48 -43
  41. data/lib/request_log_analyzer/tracker.rb +128 -14
  42. data/lib/request_log_analyzer/tracker/duration.rb +39 -132
  43. data/lib/request_log_analyzer/tracker/frequency.rb +31 -32
  44. data/lib/request_log_analyzer/tracker/hourly_spread.rb +20 -19
  45. data/lib/request_log_analyzer/tracker/timespan.rb +17 -17
  46. data/lib/request_log_analyzer/tracker/traffic.rb +36 -116
  47. data/request-log-analyzer.gemspec +19 -15
  48. data/spec/fixtures/rails_22.log +1 -1
  49. data/spec/integration/command_line_usage_spec.rb +1 -1
  50. data/spec/lib/helpers.rb +7 -7
  51. data/spec/lib/macros.rb +3 -3
  52. data/spec/lib/matchers.rb +41 -27
  53. data/spec/lib/mocks.rb +15 -14
  54. data/spec/lib/testing_format.rb +9 -9
  55. data/spec/spec_helper.rb +6 -6
  56. data/spec/unit/aggregator/database_inserter_spec.rb +13 -13
  57. data/spec/unit/aggregator/summarizer_spec.rb +4 -4
  58. data/spec/unit/controller/controller_spec.rb +2 -2
  59. data/spec/unit/controller/log_processor_spec.rb +1 -1
  60. data/spec/unit/database/base_class_spec.rb +19 -19
  61. data/spec/unit/database/connection_spec.rb +3 -3
  62. data/spec/unit/database/database_spec.rb +25 -25
  63. data/spec/unit/file_format/amazon_s3_format_spec.rb +5 -5
  64. data/spec/unit/file_format/apache_format_spec.rb +13 -13
  65. data/spec/unit/file_format/file_format_api_spec.rb +13 -13
  66. data/spec/unit/file_format/line_definition_spec.rb +24 -17
  67. data/spec/unit/file_format/merb_format_spec.rb +41 -45
  68. data/spec/unit/file_format/rails_format_spec.rb +157 -117
  69. data/spec/unit/filter/anonymize_filter_spec.rb +2 -2
  70. data/spec/unit/filter/field_filter_spec.rb +13 -13
  71. data/spec/unit/filter/filter_spec.rb +1 -1
  72. data/spec/unit/filter/timespan_filter_spec.rb +15 -15
  73. data/spec/unit/mailer_spec.rb +30 -0
  74. data/spec/unit/{source/request_spec.rb → request_spec.rb} +30 -30
  75. data/spec/unit/source/log_parser_spec.rb +27 -27
  76. data/spec/unit/tracker/duration_tracker_spec.rb +115 -78
  77. data/spec/unit/tracker/frequency_tracker_spec.rb +74 -63
  78. data/spec/unit/tracker/hourly_spread_spec.rb +28 -20
  79. data/spec/unit/tracker/timespan_tracker_spec.rb +25 -13
  80. data/spec/unit/tracker/tracker_api_spec.rb +13 -13
  81. data/spec/unit/tracker/traffic_tracker_spec.rb +81 -79
  82. data/tasks/github-gem.rake +125 -75
  83. data/tasks/request_log_analyzer.rake +2 -2
  84. 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.should_not parse("nonmatching")
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.should_not parse("Testing LineDefinition")
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.should parse("Testing LineDefinition, tries: 123").capturing('LineDefinition', '123')
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 find 11 completed requests" do
22
- @log_parser.should_receive(:handle_request).exactly(11).times
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
- it "should parse all details from the first request correctly" do
27
- request = nil
28
- @log_parser.parse_file(log_fixture(:merb)) { |found_request| request ||= found_request }
8
+
9
+ describe '#parse_line' do
10
+ before(:each) do
11
+ @file_format = RequestLogAnalyzer::FileFormat.load(:merb)
12
+ end
29
13
 
30
- request.should be_completed
31
- request[:controller].should == 'session'
32
- request[:action].should == 'destroy'
33
- request[:method].should == 'delete'
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
- it "should parse a prefixed Merb file correctly" do
44
- request = nil
45
- @log_parser.parse_file(log_fixture(:merb_prefixed)) { |found_request| request ||= found_request }
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
- before(:each) do
6
- @log_parser = RequestLogAnalyzer::Source::LogParser.new(
7
- RequestLogAnalyzer::FileFormat.load(:rails), :parse_strategy => 'cautious')
8
- end
9
-
10
- it "should have a valid language definitions" do
11
- @log_parser.file_format.should be_valid
12
- end
13
-
14
- it "should parse a stream and find valid requests" do
15
- io = File.new(log_fixture(:rails_1x), 'r')
16
- @log_parser.parse_io(io) do |request|
17
- request.should be_kind_of(RequestLogAnalyzer::Request)
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
- end
43
-
44
- it "should parse a syslog file with prefix correctly" do
45
- @log_parser.should_not_receive(:warn)
46
- @log_parser.parse_file(log_fixture(:syslog_1x)) do |request|
47
-
48
- request.should be_completed
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
- request[:controller].should == 'EmployeeController'
51
- request[:action].should == 'index'
52
- request[:url].should == 'http://example.com/employee.xml'
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
- describe RequestLogAnalyzer::FileFormat::RailsDevelopment do
81
-
82
- before(:each) do
83
- @file_format = RequestLogAnalyzer::FileFormat.load(:rails_development)
84
- @request = @file_format.request
85
- end
86
-
87
- it "should have a valid language definitions" do
88
- @file_format.should be_valid
89
- end
90
-
91
- it "should have a different line definer than Rails" do
92
- rails = RequestLogAnalyzer::FileFormat.load(:rails)
93
- rails.class.line_definer.should_not == @file_format.class.line_definer
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
- it "should parse a rendered line" do
97
- info = @file_format.line_definitions[:rendered].match_for("Rendered layouts/_footer (2.9ms)", @request)
98
- info[:render_file].should == 'layouts/_footer'
99
- info[:render_duration].should == 0.0029
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 + ' User Load (0.4ms) SELECT * FROM `users` WHERE (`users`.`id` = 18205844) '
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 + ' CACHE (0.0ms) SELECT * FROM `users` WHERE (`users`.`id` = 0) '
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
- it "should parse a query executed line with colors" do
103
- info = @file_format.line_definitions[:query_executed].match_for(" User Load (0.4ms) SELECT * FROM `users` WHERE (`users`.`id` = 18205844) ", @request)
104
- info[:query_class].should == 'User'
105
- info[:query_duration].should == 0.0004
106
- info[:query_sql].should == 'SELECT * FROM users WHERE (users.id = :int)'
107
- end
108
-
109
- it "should parse a query executed line without colors" do
110
- info = @file_format.line_definitions[:query_executed].match_for(" User Load (0.4ms) SELECT * FROM `users` WHERE (`users`.`id` = 18205844) ", @request)
111
- info[:query_class].should == 'User'
112
- info[:query_duration].should == 0.0004
113
- info[:query_sql].should == 'SELECT * FROM users WHERE (users.id = :int)'
114
- end
115
-
116
- it "should parse a cached query line with colors" do
117
- info = @file_format.line_definitions[:query_cached].match_for(' CACHE (0.0ms) SELECT * FROM `users` WHERE (`users`.`id` = 0) ', @request)
118
- info[:cached_duration].should == 0.0
119
- info[:cached_sql].should == 'SELECT * FROM users WHERE (users.id = :int)'
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