request-log-analyzer 1.3.5 → 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.
- data/LICENSE +3 -3
- data/README.rdoc +1 -1
- data/bin/request-log-analyzer +17 -14
- data/lib/cli/command_line_arguments.rb +51 -51
- data/lib/cli/database_console.rb +3 -3
- data/lib/cli/database_console_init.rb +4 -3
- data/lib/cli/progressbar.rb +10 -10
- data/lib/cli/tools.rb +3 -3
- data/lib/request_log_analyzer/aggregator/database_inserter.rb +13 -14
- data/lib/request_log_analyzer/aggregator/echo.rb +14 -9
- data/lib/request_log_analyzer/aggregator/summarizer.rb +26 -26
- data/lib/request_log_analyzer/aggregator.rb +11 -15
- data/lib/request_log_analyzer/controller.rb +162 -89
- data/lib/request_log_analyzer/database/base.rb +21 -21
- data/lib/request_log_analyzer/database/connection.rb +3 -3
- data/lib/request_log_analyzer/database/request.rb +22 -0
- data/lib/request_log_analyzer/database/source.rb +13 -0
- data/lib/request_log_analyzer/database/warning.rb +14 -0
- data/lib/request_log_analyzer/database.rb +28 -103
- data/lib/request_log_analyzer/file_format/amazon_s3.rb +17 -18
- data/lib/request_log_analyzer/file_format/apache.rb +26 -27
- data/lib/request_log_analyzer/file_format/merb.rb +30 -13
- data/lib/request_log_analyzer/file_format/rack.rb +4 -4
- data/lib/request_log_analyzer/file_format/rails.rb +143 -73
- data/lib/request_log_analyzer/file_format/rails_development.rb +4 -49
- data/lib/request_log_analyzer/file_format.rb +16 -28
- data/lib/request_log_analyzer/filter/anonymize.rb +8 -7
- data/lib/request_log_analyzer/filter/field.rb +9 -9
- data/lib/request_log_analyzer/filter/timespan.rb +12 -10
- data/lib/request_log_analyzer/filter.rb +12 -16
- data/lib/request_log_analyzer/line_definition.rb +15 -14
- data/lib/request_log_analyzer/log_processor.rb +27 -29
- data/lib/request_log_analyzer/mailer.rb +15 -9
- data/lib/request_log_analyzer/output/fixed_width.rb +40 -41
- data/lib/request_log_analyzer/output/html.rb +20 -20
- data/lib/request_log_analyzer/output.rb +53 -12
- data/lib/request_log_analyzer/request.rb +75 -68
- data/lib/request_log_analyzer/source/database_loader.rb +10 -14
- data/lib/request_log_analyzer/source/log_parser.rb +57 -50
- data/lib/request_log_analyzer/source.rb +10 -12
- data/lib/request_log_analyzer/tracker/duration.rb +39 -132
- data/lib/request_log_analyzer/tracker/frequency.rb +31 -32
- data/lib/request_log_analyzer/tracker/hourly_spread.rb +21 -21
- data/lib/request_log_analyzer/tracker/timespan.rb +17 -17
- data/lib/request_log_analyzer/tracker/traffic.rb +36 -116
- data/lib/request_log_analyzer/tracker.rb +139 -32
- data/lib/request_log_analyzer.rb +4 -4
- data/request-log-analyzer.gemspec +19 -15
- data/spec/database.yml +6 -0
- data/spec/fixtures/rails_22.log +1 -1
- data/spec/integration/command_line_usage_spec.rb +7 -1
- data/spec/lib/helpers.rb +7 -7
- data/spec/lib/macros.rb +3 -3
- data/spec/lib/matchers.rb +41 -27
- data/spec/lib/mocks.rb +15 -14
- data/spec/lib/testing_format.rb +9 -9
- data/spec/spec_helper.rb +6 -6
- data/spec/unit/aggregator/database_inserter_spec.rb +16 -16
- data/spec/unit/aggregator/summarizer_spec.rb +4 -4
- data/spec/unit/controller/controller_spec.rb +2 -2
- data/spec/unit/controller/log_processor_spec.rb +1 -1
- data/spec/unit/database/base_class_spec.rb +26 -33
- data/spec/unit/database/connection_spec.rb +3 -3
- data/spec/unit/database/database_spec.rb +33 -38
- data/spec/unit/file_format/amazon_s3_format_spec.rb +5 -5
- data/spec/unit/file_format/apache_format_spec.rb +13 -13
- data/spec/unit/file_format/file_format_api_spec.rb +13 -13
- data/spec/unit/file_format/line_definition_spec.rb +24 -17
- data/spec/unit/file_format/merb_format_spec.rb +41 -45
- data/spec/unit/file_format/rails_format_spec.rb +157 -117
- data/spec/unit/filter/anonymize_filter_spec.rb +2 -2
- data/spec/unit/filter/field_filter_spec.rb +13 -13
- data/spec/unit/filter/filter_spec.rb +1 -1
- data/spec/unit/filter/timespan_filter_spec.rb +15 -15
- data/spec/unit/mailer_spec.rb +30 -0
- data/spec/unit/{source/request_spec.rb → request_spec.rb} +30 -30
- data/spec/unit/source/log_parser_spec.rb +27 -27
- data/spec/unit/tracker/duration_tracker_spec.rb +115 -78
- data/spec/unit/tracker/frequency_tracker_spec.rb +74 -63
- data/spec/unit/tracker/hourly_spread_spec.rb +28 -20
- data/spec/unit/tracker/timespan_tracker_spec.rb +25 -13
- data/spec/unit/tracker/tracker_api_spec.rb +117 -42
- data/spec/unit/tracker/traffic_tracker_spec.rb +81 -79
- data/tasks/github-gem.rake +125 -75
- data/tasks/request_log_analyzer.rake +2 -2
- metadata +13 -8
|
@@ -1,28 +1,28 @@
|
|
|
1
1
|
require File.dirname(__FILE__) + '/../../spec_helper'
|
|
2
2
|
|
|
3
3
|
describe RequestLogAnalyzer::Database do
|
|
4
|
-
|
|
4
|
+
|
|
5
5
|
describe '#load_database_schema!' do
|
|
6
|
-
|
|
6
|
+
|
|
7
7
|
context 'for a Rails request database' do
|
|
8
8
|
before(:each) do
|
|
9
9
|
@database = RequestLogAnalyzer::Database.new(log_fixture(:rails, :db))
|
|
10
10
|
@database.load_database_schema!
|
|
11
11
|
end
|
|
12
|
-
|
|
12
|
+
|
|
13
13
|
after(:each) { @database.remove_orm_classes! }
|
|
14
|
-
|
|
14
|
+
|
|
15
15
|
# FileFormat-agnostic classes
|
|
16
16
|
default_orm_class_names.each do |const|
|
|
17
17
|
it "should create the default #{const} constant" do
|
|
18
|
-
|
|
18
|
+
RequestLogAnalyzer::Database.const_defined?(const).should be_true
|
|
19
19
|
end
|
|
20
20
|
|
|
21
21
|
it "should create the default #{const} class inheriting from ActiveRecord::Base and RequestLogAnalyzer::Database::Base" do
|
|
22
|
-
|
|
22
|
+
RequestLogAnalyzer::Database.const_get(const).ancestors.should include(ActiveRecord::Base, RequestLogAnalyzer::Database::Base)
|
|
23
23
|
end
|
|
24
24
|
end
|
|
25
|
-
|
|
25
|
+
|
|
26
26
|
# Some Fileformat-specific classes
|
|
27
27
|
['CompletedLine', 'ProcessingLine'].each do |const|
|
|
28
28
|
it "should create the #{const} constant" do
|
|
@@ -32,19 +32,19 @@ describe RequestLogAnalyzer::Database do
|
|
|
32
32
|
it "should create the #{const} class inheriting from ActiveRecord::Base and RequestLogAnalyzer::Database::Base" do
|
|
33
33
|
Object.const_get(const).ancestors.should include(ActiveRecord::Base, RequestLogAnalyzer::Database::Base)
|
|
34
34
|
end
|
|
35
|
-
|
|
35
|
+
|
|
36
36
|
it "should create a :belongs_to relation from the #{const} class to Request and Source" do
|
|
37
37
|
Object.const_get(const).send(:reflections).should include(:request, :source)
|
|
38
38
|
end
|
|
39
|
-
|
|
39
|
+
|
|
40
40
|
it "should create a :has_many relation from the Request and Source class to the #{const} class" do
|
|
41
|
-
|
|
42
|
-
|
|
41
|
+
RequestLogAnalyzer::Database::Request.send(:reflections).should include(const.underscore.pluralize.to_sym)
|
|
42
|
+
RequestLogAnalyzer::Database::Source.send(:reflections).should include(const.underscore.pluralize.to_sym)
|
|
43
43
|
end
|
|
44
44
|
end
|
|
45
45
|
end
|
|
46
46
|
end
|
|
47
|
-
|
|
47
|
+
|
|
48
48
|
describe '#create_database_schema!' do
|
|
49
49
|
|
|
50
50
|
before(:each) do
|
|
@@ -56,10 +56,11 @@ describe RequestLogAnalyzer::Database do
|
|
|
56
56
|
@mock_class = Class.new(RequestLogAnalyzer::Database::Base)
|
|
57
57
|
@mock_class.stub!(:create_table!)
|
|
58
58
|
end
|
|
59
|
-
|
|
59
|
+
|
|
60
60
|
after(:each) { @database.remove_orm_classes! }
|
|
61
61
|
|
|
62
62
|
default_orm_class_names.each do |klass|
|
|
63
|
+
|
|
63
64
|
it "should create a table for the default #{klass} class" do
|
|
64
65
|
@database.connection.should_receive(:create_table).with(klass.underscore.pluralize.to_sym)
|
|
65
66
|
@database.send :create_database_schema!
|
|
@@ -67,69 +68,63 @@ describe RequestLogAnalyzer::Database do
|
|
|
67
68
|
|
|
68
69
|
it "should create a #{klass} class inheriting from ActiveRecord and the base class of the ORM module" do
|
|
69
70
|
@database.send :create_database_schema!
|
|
70
|
-
|
|
71
|
+
RequestLogAnalyzer::Database.const_get(klass).ancestors.should include(ActiveRecord::Base, RequestLogAnalyzer::Database::Base)
|
|
71
72
|
end
|
|
72
73
|
end
|
|
73
74
|
|
|
74
75
|
testing_format.line_definitions.each do |name, definition|
|
|
75
|
-
|
|
76
|
+
|
|
76
77
|
it "should create the #{(name.to_s + '_line').camelize} class for #{name.inspect} lines" do
|
|
77
78
|
@database.send :create_database_schema!
|
|
78
79
|
Object.const_defined?("#{name}_line".camelize).should be_true
|
|
79
80
|
end
|
|
80
|
-
|
|
81
|
+
|
|
81
82
|
it "should create the #{name.to_s + '_lines'} table for the parsed #{name.inspect} lines" do
|
|
82
83
|
@database.connection.should_receive(:create_table).with("#{name}_lines".to_sym)
|
|
83
84
|
@database.send :create_database_schema!
|
|
84
85
|
end
|
|
85
86
|
end
|
|
86
87
|
end
|
|
87
|
-
|
|
88
|
+
|
|
88
89
|
describe '#load_activerecord_class' do
|
|
89
|
-
|
|
90
|
-
before(:each) do
|
|
90
|
+
|
|
91
|
+
before(:each) do
|
|
91
92
|
@database = RequestLogAnalyzer::Database.new
|
|
92
93
|
@connection = mock_connection
|
|
93
94
|
@database.stub!(:connection).and_return(@connection)
|
|
94
|
-
|
|
95
|
-
# Mock the
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
@source_class = mock('Source ActiveRecord::Base class')
|
|
100
|
-
@source_class.stub!(:has_many)
|
|
101
|
-
|
|
102
|
-
@database.stub!(:request_class).and_return(@request_class)
|
|
103
|
-
@database.stub!(:source_class).and_return(@source_class)
|
|
104
|
-
|
|
95
|
+
|
|
96
|
+
# Mock the has_many method of the defaukt ORM classes
|
|
97
|
+
RequestLogAnalyzer::Database::Request.stub!(:has_many)
|
|
98
|
+
RequestLogAnalyzer::Database::Source.stub!(:has_many)
|
|
99
|
+
|
|
105
100
|
@mock_class = Class.new(RequestLogAnalyzer::Database::Base)
|
|
106
|
-
|
|
101
|
+
|
|
107
102
|
RequestLogAnalyzer::Database::Base.stub!(:subclass_from_table).and_return(@mock_class)
|
|
108
103
|
RequestLogAnalyzer::Database::Base.stub!(:subclass_from_line_definition).and_return(@mock_class)
|
|
109
104
|
end
|
|
110
|
-
|
|
105
|
+
|
|
111
106
|
after(:each) { @database.remove_orm_classes! }
|
|
112
|
-
|
|
107
|
+
|
|
113
108
|
it "should call :subclass_from_table when a table name is given as string" do
|
|
114
109
|
RequestLogAnalyzer::Database::Base.should_receive(:subclass_from_table).and_return(@mock_class)
|
|
115
110
|
@database.load_activerecord_class('test_lines')
|
|
116
111
|
end
|
|
117
|
-
|
|
112
|
+
|
|
118
113
|
it "should call :subclass_from_table when a table name is given as symbol" do
|
|
119
114
|
RequestLogAnalyzer::Database::Base.should_receive(:subclass_from_table).and_return(@mock_class)
|
|
120
115
|
@database.load_activerecord_class(:test_lines)
|
|
121
116
|
end
|
|
122
|
-
|
|
117
|
+
|
|
123
118
|
it "should call :subclass_from_table when a LineDefinition is given" do
|
|
124
119
|
RequestLogAnalyzer::Database::Base.should_receive(:subclass_from_line_definition).and_return(@mock_class)
|
|
125
120
|
@database.load_activerecord_class(RequestLogAnalyzer::LineDefinition.new(:test))
|
|
126
|
-
end
|
|
127
|
-
|
|
121
|
+
end
|
|
122
|
+
|
|
128
123
|
it "should define the class in the ORM module" do
|
|
129
124
|
@database.load_activerecord_class(:test_lines)
|
|
130
125
|
Object.const_defined?('TestLine').should be_true
|
|
131
126
|
end
|
|
132
|
-
|
|
127
|
+
|
|
133
128
|
it "should add the class to the line_classes array of the database" do
|
|
134
129
|
@database.load_activerecord_class(:test_lines)
|
|
135
130
|
@database.line_classes.should include(TestLine)
|
|
@@ -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.
|
|
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.
|
|
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.
|
|
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
|
|
22
|
-
|
|
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
|
-
|
|
27
|
-
|
|
28
|
-
|
|
8
|
+
|
|
9
|
+
describe '#parse_line' do
|
|
10
|
+
before(:each) do
|
|
11
|
+
@file_format = RequestLogAnalyzer::FileFormat.load(:merb)
|
|
12
|
+
end
|
|
29
13
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
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
|
-
|
|
44
|
-
|
|
45
|
-
|
|
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
|