request-log-analyzer 1.3.7 → 1.4.0

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