ngmoco-request-log-analyzer 1.4.2
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +10 -0
- data/DESIGN.rdoc +41 -0
- data/LICENSE +20 -0
- data/README.rdoc +39 -0
- data/Rakefile +8 -0
- data/bin/request-log-analyzer +114 -0
- data/lib/cli/command_line_arguments.rb +301 -0
- data/lib/cli/database_console.rb +26 -0
- data/lib/cli/database_console_init.rb +43 -0
- data/lib/cli/progressbar.rb +213 -0
- data/lib/cli/tools.rb +46 -0
- data/lib/request_log_analyzer.rb +44 -0
- data/lib/request_log_analyzer/aggregator.rb +49 -0
- data/lib/request_log_analyzer/aggregator/database_inserter.rb +83 -0
- data/lib/request_log_analyzer/aggregator/echo.rb +29 -0
- data/lib/request_log_analyzer/aggregator/summarizer.rb +175 -0
- data/lib/request_log_analyzer/controller.rb +332 -0
- data/lib/request_log_analyzer/database.rb +102 -0
- data/lib/request_log_analyzer/database/base.rb +115 -0
- data/lib/request_log_analyzer/database/connection.rb +38 -0
- 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/file_format.rb +160 -0
- data/lib/request_log_analyzer/file_format/amazon_s3.rb +71 -0
- data/lib/request_log_analyzer/file_format/apache.rb +141 -0
- data/lib/request_log_analyzer/file_format/merb.rb +67 -0
- data/lib/request_log_analyzer/file_format/rack.rb +11 -0
- data/lib/request_log_analyzer/file_format/rails.rb +176 -0
- data/lib/request_log_analyzer/file_format/rails_development.rb +12 -0
- data/lib/request_log_analyzer/filter.rb +30 -0
- data/lib/request_log_analyzer/filter/anonymize.rb +39 -0
- data/lib/request_log_analyzer/filter/field.rb +42 -0
- data/lib/request_log_analyzer/filter/timespan.rb +45 -0
- data/lib/request_log_analyzer/line_definition.rb +111 -0
- data/lib/request_log_analyzer/log_processor.rb +99 -0
- data/lib/request_log_analyzer/mailer.rb +62 -0
- data/lib/request_log_analyzer/output.rb +113 -0
- data/lib/request_log_analyzer/output/fixed_width.rb +220 -0
- data/lib/request_log_analyzer/output/html.rb +184 -0
- data/lib/request_log_analyzer/request.rb +175 -0
- data/lib/request_log_analyzer/source.rb +72 -0
- data/lib/request_log_analyzer/source/database_loader.rb +87 -0
- data/lib/request_log_analyzer/source/log_parser.rb +274 -0
- data/lib/request_log_analyzer/tracker.rb +206 -0
- data/lib/request_log_analyzer/tracker/duration.rb +104 -0
- data/lib/request_log_analyzer/tracker/frequency.rb +95 -0
- data/lib/request_log_analyzer/tracker/hourly_spread.rb +107 -0
- data/lib/request_log_analyzer/tracker/timespan.rb +81 -0
- data/lib/request_log_analyzer/tracker/traffic.rb +106 -0
- data/request-log-analyzer.gemspec +40 -0
- data/spec/database.yml +23 -0
- data/spec/fixtures/apache_combined.log +5 -0
- data/spec/fixtures/apache_common.log +10 -0
- data/spec/fixtures/decompression.log +12 -0
- data/spec/fixtures/decompression.log.bz2 +0 -0
- data/spec/fixtures/decompression.log.gz +0 -0
- data/spec/fixtures/decompression.log.zip +0 -0
- data/spec/fixtures/decompression.tar.gz +0 -0
- data/spec/fixtures/decompression.tgz +0 -0
- data/spec/fixtures/header_and_footer.log +6 -0
- data/spec/fixtures/merb.log +84 -0
- data/spec/fixtures/merb_prefixed.log +9 -0
- data/spec/fixtures/multiple_files_1.log +5 -0
- data/spec/fixtures/multiple_files_2.log +2 -0
- data/spec/fixtures/rails.db +0 -0
- data/spec/fixtures/rails_1x.log +59 -0
- data/spec/fixtures/rails_22.log +12 -0
- data/spec/fixtures/rails_22_cached.log +10 -0
- data/spec/fixtures/rails_unordered.log +24 -0
- data/spec/fixtures/syslog_1x.log +5 -0
- data/spec/fixtures/test_file_format.log +13 -0
- data/spec/fixtures/test_language_combined.log +14 -0
- data/spec/fixtures/test_order.log +16 -0
- data/spec/integration/command_line_usage_spec.rb +84 -0
- data/spec/integration/munin_plugins_rails_spec.rb +58 -0
- data/spec/integration/scout_spec.rb +151 -0
- data/spec/lib/helpers.rb +52 -0
- data/spec/lib/macros.rb +18 -0
- data/spec/lib/matchers.rb +77 -0
- data/spec/lib/mocks.rb +76 -0
- data/spec/lib/testing_format.rb +46 -0
- data/spec/spec_helper.rb +24 -0
- data/spec/unit/aggregator/database_inserter_spec.rb +93 -0
- data/spec/unit/aggregator/summarizer_spec.rb +26 -0
- data/spec/unit/controller/controller_spec.rb +41 -0
- data/spec/unit/controller/log_processor_spec.rb +18 -0
- data/spec/unit/database/base_class_spec.rb +183 -0
- data/spec/unit/database/connection_spec.rb +34 -0
- data/spec/unit/database/database_spec.rb +133 -0
- data/spec/unit/file_format/amazon_s3_format_spec.rb +49 -0
- data/spec/unit/file_format/apache_format_spec.rb +203 -0
- data/spec/unit/file_format/file_format_api_spec.rb +69 -0
- data/spec/unit/file_format/line_definition_spec.rb +75 -0
- data/spec/unit/file_format/merb_format_spec.rb +52 -0
- data/spec/unit/file_format/rails_format_spec.rb +164 -0
- data/spec/unit/filter/anonymize_filter_spec.rb +21 -0
- data/spec/unit/filter/field_filter_spec.rb +66 -0
- data/spec/unit/filter/filter_spec.rb +17 -0
- data/spec/unit/filter/timespan_filter_spec.rb +58 -0
- data/spec/unit/mailer_spec.rb +30 -0
- data/spec/unit/request_spec.rb +111 -0
- data/spec/unit/source/log_parser_spec.rb +119 -0
- data/spec/unit/tracker/duration_tracker_spec.rb +130 -0
- data/spec/unit/tracker/frequency_tracker_spec.rb +88 -0
- data/spec/unit/tracker/hourly_spread_spec.rb +79 -0
- data/spec/unit/tracker/timespan_tracker_spec.rb +73 -0
- data/spec/unit/tracker/tracker_api_spec.rb +124 -0
- data/spec/unit/tracker/traffic_tracker_spec.rb +107 -0
- data/tasks/github-gem.rake +323 -0
- data/tasks/request_log_analyzer.rake +26 -0
- metadata +220 -0
@@ -0,0 +1,30 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../spec_helper'
|
2
|
+
|
3
|
+
describe RequestLogAnalyzer::Mailer, 'mailer' do
|
4
|
+
|
5
|
+
it "should store printed data" do
|
6
|
+
@mailer = RequestLogAnalyzer::Mailer.new('alfa@beta.com', 'localhost', :debug => true)
|
7
|
+
|
8
|
+
@mailer << 'test1'
|
9
|
+
@mailer.puts 'test2'
|
10
|
+
|
11
|
+
@mailer.data.should eql(['test1', 'test2'])
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should send mail" do
|
15
|
+
@mailer = RequestLogAnalyzer::Mailer.new('alfa@beta.com', 'localhost', :debug => true)
|
16
|
+
|
17
|
+
@mailer << 'test1'
|
18
|
+
@mailer.puts 'test2'
|
19
|
+
|
20
|
+
mail = @mailer.mail
|
21
|
+
|
22
|
+
mail[0].should include("contact@railsdoctors.com")
|
23
|
+
mail[0].should include("test1")
|
24
|
+
mail[0].should include("test2")
|
25
|
+
|
26
|
+
mail[1].should include("contact@railsdoctors.com")
|
27
|
+
mail[2].should include("alfa@beta.com")
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
@@ -0,0 +1,111 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../spec_helper'
|
2
|
+
|
3
|
+
describe RequestLogAnalyzer::Request do
|
4
|
+
|
5
|
+
before(:each) do
|
6
|
+
@request = testing_format.request
|
7
|
+
end
|
8
|
+
|
9
|
+
it "should be empty without any captured lines in it" do
|
10
|
+
@request.should be_empty
|
11
|
+
end
|
12
|
+
|
13
|
+
context :incomplete do
|
14
|
+
|
15
|
+
before(:each) do
|
16
|
+
@request << { :line_type => :test, :lineno => 1, :test_capture => 'awesome!' }
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should be single if only one line has been added" do
|
20
|
+
@request.should_not be_empty
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should not be a completed request" do
|
24
|
+
@request.should_not be_completed
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should take the line type of the first line as global line_type" do
|
28
|
+
@request.lines[0][:line_type].should == :test
|
29
|
+
@request.should =~ :test
|
30
|
+
end
|
31
|
+
|
32
|
+
it "should return the first field value" do
|
33
|
+
@request[:test_capture].should == 'awesome!'
|
34
|
+
end
|
35
|
+
|
36
|
+
it "should return nil if no such field is present" do
|
37
|
+
@request[:nonexisting].should be_nil
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
context :completed do
|
42
|
+
|
43
|
+
before(:each) do
|
44
|
+
@request << { :line_type => :first, :lineno => 1, :name => 'first line!' }
|
45
|
+
@request << { :line_type => :test, :lineno => 4, :test_capture => 'testing' }
|
46
|
+
@request << { :line_type => :test, :lineno => 7, :test_capture => 'testing some more' }
|
47
|
+
@request << { :line_type => :last, :lineno => 10, :time => 0.03 }
|
48
|
+
end
|
49
|
+
|
50
|
+
it "should not be empty when multiple liness are added" do
|
51
|
+
@request.should_not be_empty
|
52
|
+
end
|
53
|
+
|
54
|
+
it "should be a completed request" do
|
55
|
+
@request.should be_completed
|
56
|
+
end
|
57
|
+
|
58
|
+
it "should recognize all line types" do
|
59
|
+
[:first, :test, :last].each { |type| @request.should =~ type }
|
60
|
+
end
|
61
|
+
|
62
|
+
it "should detect the correct field value" do
|
63
|
+
@request[:name].should == 'first line!'
|
64
|
+
@request[:time].should == 0.03
|
65
|
+
end
|
66
|
+
|
67
|
+
it "should detect the first matching field value" do
|
68
|
+
@request.first(:test_capture).should == 'testing'
|
69
|
+
end
|
70
|
+
|
71
|
+
it "should detect the every matching field value" do
|
72
|
+
@request.every(:test_capture).should == ['testing', "testing some more"]
|
73
|
+
end
|
74
|
+
|
75
|
+
it "should set the first_lineno for a request to the lowest lineno encountered" do
|
76
|
+
@request.first_lineno.should eql(1)
|
77
|
+
end
|
78
|
+
|
79
|
+
it "should set the first_lineno for a request if a line with a lower lineno is added" do
|
80
|
+
@request << { :line_type => :test, :lineno => 0 }
|
81
|
+
@request.first_lineno.should eql(0)
|
82
|
+
end
|
83
|
+
|
84
|
+
it "should set the last_lineno for a request to the highest encountered lineno" do
|
85
|
+
@request.last_lineno.should eql(10)
|
86
|
+
end
|
87
|
+
|
88
|
+
it "should not set the last_lineno for a request if a line with a lower lineno is added" do
|
89
|
+
@request << { :line_type => :test, :lineno => 7 }
|
90
|
+
@request.last_lineno.should eql(10)
|
91
|
+
end
|
92
|
+
|
93
|
+
it "should not have a timestamp if no such field is captured" do
|
94
|
+
@request.timestamp.should be_nil
|
95
|
+
end
|
96
|
+
|
97
|
+
it "should set return a timestamp field if such a field is captured" do
|
98
|
+
@request << { :line_type => :first, :lineno => 1, :name => 'first line!', :timestamp => Time.now}
|
99
|
+
@request.timestamp.should_not be_nil
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
context 'single line' do
|
104
|
+
# combined is both a header and a footer line
|
105
|
+
before(:each) { @request << { :line_type => :combined, :lineno => 1 } }
|
106
|
+
|
107
|
+
it "should be a completed request if the line is both header and footer" do
|
108
|
+
@request.should be_completed
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
@@ -0,0 +1,119 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../../spec_helper'
|
2
|
+
|
3
|
+
describe RequestLogAnalyzer::Source::LogParser, :requests do
|
4
|
+
|
5
|
+
before(:each) do
|
6
|
+
@log_parser = RequestLogAnalyzer::Source::LogParser.new(testing_format)
|
7
|
+
end
|
8
|
+
|
9
|
+
it "should have multiple line definitions" do
|
10
|
+
@log_parser.file_format.line_definitions.length.should >= 2
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should have a valid language" do
|
14
|
+
@log_parser.file_format.should be_valid
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should set the :source for every parsed line" do
|
18
|
+
@log_parser.parse_file(log_fixture(:rails_22)) do |request|
|
19
|
+
request.lines.all? { |line| line[:source] == log_fixture(:rails_22) }.should be_true
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
it "should set the :lineno for every parsed line" do
|
24
|
+
@log_parser.parse_file(log_fixture(:rails_22)) do |request|
|
25
|
+
request.lines.all? { |line| line.has_key?(:lineno) }.should be_true
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should parse more lines than requests" do
|
30
|
+
@log_parser.should_receive(:handle_request).with(an_instance_of(TestingFormat::Request)).twice
|
31
|
+
@log_parser.parse_file(log_fixture(:test_language_combined))
|
32
|
+
@log_parser.parsed_lines.should > 2
|
33
|
+
end
|
34
|
+
|
35
|
+
it "should parse requests spanned over multiple files" do
|
36
|
+
@log_parser.should_receive(:handle_request).with(an_instance_of(TestingFormat::Request)).once
|
37
|
+
@log_parser.parse_files([log_fixture(:multiple_files_1), log_fixture(:multiple_files_2)])
|
38
|
+
end
|
39
|
+
|
40
|
+
it "should parse all request values when spanned over multiple files" do
|
41
|
+
@log_parser.parse_files([log_fixture(:multiple_files_1), log_fixture(:multiple_files_2)]) do |request|
|
42
|
+
request.lines.should have(4).items
|
43
|
+
request[:request_no].should == 1
|
44
|
+
request[:test_capture].should == "Testing is amazing" # Note the custom converter
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
it "should parse a stream and find valid requests" do
|
49
|
+
io = File.new(log_fixture(:test_file_format), 'r')
|
50
|
+
@log_parser.parse_io(io) do |request|
|
51
|
+
request.should be_kind_of(RequestLogAnalyzer::Request)
|
52
|
+
request.should =~ :test
|
53
|
+
request[:test_capture].should_not be_nil
|
54
|
+
end
|
55
|
+
io.close
|
56
|
+
end
|
57
|
+
|
58
|
+
it "should parse a request that only consists of one line" do
|
59
|
+
@log_parser.parse_file(log_fixture(:header_and_footer))
|
60
|
+
@log_parser.parsed_requests.should == 2
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
describe RequestLogAnalyzer::Source::LogParser, :warnings do
|
65
|
+
|
66
|
+
before(:each) do
|
67
|
+
@log_parser = RequestLogAnalyzer::Source::LogParser.new(testing_format, :parse_strategy => 'cautious')
|
68
|
+
end
|
69
|
+
|
70
|
+
it "should warn about teaser matching problems" do
|
71
|
+
@log_parser.should_receive(:warn).with(:teaser_check_failed, anything).exactly(5).times
|
72
|
+
@log_parser.parse_file(log_fixture(:test_file_format))
|
73
|
+
end
|
74
|
+
|
75
|
+
it "should warn about unmatching request headers and footers" do
|
76
|
+
@log_parser.should_receive(:warn).with(:unclosed_request, anything).at_least(1).times
|
77
|
+
@log_parser.should_receive(:warn).with(:no_current_request, anything).at_least(1).times
|
78
|
+
@log_parser.should_not_receive(:handle_request)
|
79
|
+
@log_parser.parse_file(log_fixture(:test_order))
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
describe RequestLogAnalyzer::Source::LogParser, :decompression do
|
84
|
+
|
85
|
+
before(:each) do
|
86
|
+
@log_parser = RequestLogAnalyzer::Source::LogParser.new(RequestLogAnalyzer::FileFormat::Rails.create)
|
87
|
+
end
|
88
|
+
|
89
|
+
it "should parse a rails gzipped log file" do
|
90
|
+
@log_parser.should_receive(:handle_request).once
|
91
|
+
@log_parser.parse_file(log_fixture(:decompression, "log.gz"))
|
92
|
+
@log_parser.parsed_lines.should > 0
|
93
|
+
end
|
94
|
+
|
95
|
+
it "should parse a rails tar gzipped log folder" do
|
96
|
+
@log_parser.should_receive(:handle_request).twice
|
97
|
+
@log_parser.parse_file(log_fixture(:decompression, "tar.gz"))
|
98
|
+
@log_parser.parsed_lines.should > 1
|
99
|
+
end
|
100
|
+
|
101
|
+
it "should parse a rails tar gzipped log folder" do
|
102
|
+
@log_parser.should_receive(:handle_request).twice
|
103
|
+
@log_parser.parse_file(log_fixture(:decompression, "tgz"))
|
104
|
+
@log_parser.parsed_lines.should > 1
|
105
|
+
end
|
106
|
+
|
107
|
+
it "should parse a rails bz2 zipped log file" do
|
108
|
+
@log_parser.should_receive(:handle_request).once
|
109
|
+
@log_parser.parse_file(log_fixture(:decompression, "log.bz2"))
|
110
|
+
@log_parser.parsed_lines.should > 0
|
111
|
+
end
|
112
|
+
|
113
|
+
it "should parse a rails zipped log file" do
|
114
|
+
@log_parser.should_receive(:handle_request).once
|
115
|
+
@log_parser.parse_file(log_fixture(:decompression, "log.zip"))
|
116
|
+
@log_parser.parsed_lines.should > 0
|
117
|
+
end
|
118
|
+
|
119
|
+
end
|
@@ -0,0 +1,130 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../../spec_helper'
|
2
|
+
|
3
|
+
describe RequestLogAnalyzer::Tracker::Duration do
|
4
|
+
|
5
|
+
context 'using a static category' do
|
6
|
+
|
7
|
+
before(:each) do
|
8
|
+
@tracker = RequestLogAnalyzer::Tracker::Duration.new(:duration => :duration, :category => :category)
|
9
|
+
@tracker.prepare
|
10
|
+
end
|
11
|
+
|
12
|
+
it "should create a category for every request using the category field" do
|
13
|
+
@tracker.update(request(:category => 'a', :duration => 0.2))
|
14
|
+
@tracker.categories.keys.should include('a')
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should register a request as hit in the right category" do
|
18
|
+
@tracker.update(request(:category => 'a', :duration => 0.2))
|
19
|
+
@tracker.update(request(:category => 'b', :duration => 0.3))
|
20
|
+
@tracker.update(request(:category => 'b', :duration => 0.4))
|
21
|
+
|
22
|
+
@tracker.hits('a').should == 1
|
23
|
+
@tracker.hits('b').should == 2
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
context 'using a dynamic category' do
|
28
|
+
before(:each) do
|
29
|
+
@categorizer = Proc.new { |request| request[:duration] > 0.2 ? 'slow' : 'fast' }
|
30
|
+
@tracker = RequestLogAnalyzer::Tracker::Duration.new(:duration => :duration, :category => @categorizer)
|
31
|
+
@tracker.prepare
|
32
|
+
end
|
33
|
+
|
34
|
+
it "should use the categorizer to determine the right category" do
|
35
|
+
@tracker.update(request(:category => 'a', :duration => 0.2))
|
36
|
+
@tracker.update(request(:category => 'b', :duration => 0.3))
|
37
|
+
@tracker.update(request(:category => 'b', :duration => 0.4))
|
38
|
+
|
39
|
+
@tracker.hits('fast').should == 1
|
40
|
+
@tracker.hits('slow').should == 2
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
describe '#update' do
|
45
|
+
|
46
|
+
before(:each) do
|
47
|
+
@tracker = RequestLogAnalyzer::Tracker::Duration.new(:duration => :duration, :category => :category)
|
48
|
+
@tracker.prepare
|
49
|
+
|
50
|
+
@tracker.update(request(:category => 'a', :duration => 0.4))
|
51
|
+
@tracker.update(request(:category => 'a', :duration => 0.2))
|
52
|
+
@tracker.update(request(:category => 'a', :duration => 0.3))
|
53
|
+
end
|
54
|
+
|
55
|
+
it "should sum of the durations for a category correctly" do
|
56
|
+
@tracker.sum('a').should be_close(0.9, 0.000001)
|
57
|
+
end
|
58
|
+
|
59
|
+
it "should overall sum of the durations correctly" do
|
60
|
+
@tracker.sum_overall.should be_close(0.9, 0.000001)
|
61
|
+
end
|
62
|
+
|
63
|
+
it "should keep track of the minimum and maximum duration" do
|
64
|
+
@tracker.min('a').should == 0.2
|
65
|
+
@tracker.max('a').should == 0.4
|
66
|
+
end
|
67
|
+
|
68
|
+
it "should calculate the mean duration correctly" do
|
69
|
+
@tracker.mean('a').should be_close(0.3, 0.000001)
|
70
|
+
end
|
71
|
+
|
72
|
+
it "should calculate the overall mean duration correctly" do
|
73
|
+
@tracker.mean_overall.should be_close(0.3, 0.000001)
|
74
|
+
end
|
75
|
+
|
76
|
+
it "should calculate the duration variance correctly" do
|
77
|
+
@tracker.variance('a').should be_close(0.01, 0.000001)
|
78
|
+
end
|
79
|
+
|
80
|
+
it "should calculate the duration standard deviation correctly" do
|
81
|
+
@tracker.stddev('a').should be_close(0.1, 0.000001)
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
describe '#report' do
|
86
|
+
|
87
|
+
before(:each) do
|
88
|
+
@tracker = RequestLogAnalyzer::Tracker::Duration.new(:category => :category, :duration => :duration)
|
89
|
+
@tracker.prepare
|
90
|
+
end
|
91
|
+
|
92
|
+
it "should generate a report without errors when one category is present" do
|
93
|
+
@tracker.update(request(:category => 'a', :duration => 0.2))
|
94
|
+
lambda { @tracker.report(mock_output) }.should_not raise_error
|
95
|
+
end
|
96
|
+
|
97
|
+
it "should generate a report without errors when no category is present" do
|
98
|
+
lambda { @tracker.report(mock_output) }.should_not raise_error
|
99
|
+
end
|
100
|
+
|
101
|
+
it "should generate a report without errors when multiple categories are present" do
|
102
|
+
@tracker.update(request(:category => 'a', :duration => 0.2))
|
103
|
+
@tracker.update(request(:category => 'b', :duration => 0.2))
|
104
|
+
lambda { @tracker.report(mock_output) }.should_not raise_error
|
105
|
+
end
|
106
|
+
|
107
|
+
it "should generate a YAML output" do
|
108
|
+
@tracker.update(request(:category => 'a', :duration => 0.2))
|
109
|
+
@tracker.update(request(:category => 'b', :duration => 0.2))
|
110
|
+
@tracker.to_yaml_object.should == {"a"=>{:hits=>1, :min=>0.2, :mean=>0.2, :max=>0.2, :sum_of_squares=>0.0, :sum=>0.2}, "b"=>{:hits=>1, :min=>0.2, :mean=>0.2, :max=>0.2, :sum_of_squares=>0.0, :sum=>0.2}}
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
describe '#display_value' do
|
115
|
+
before(:each) { @tracker = RequestLogAnalyzer::Tracker::Duration.new(:category => :category, :duration => :duration) }
|
116
|
+
|
117
|
+
it "should only display seconds when time < 60" do
|
118
|
+
@tracker.display_value(33.12).should == '33.12s'
|
119
|
+
end
|
120
|
+
|
121
|
+
it "should display minutes and wholeseconds when time > 60" do
|
122
|
+
@tracker.display_value(63.12).should == '1m03s'
|
123
|
+
end
|
124
|
+
|
125
|
+
it "should display minutes and wholeseconds when time > 60" do
|
126
|
+
@tracker.display_value(3601.12).should == '1h00m01s'
|
127
|
+
end
|
128
|
+
|
129
|
+
end
|
130
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../../spec_helper'
|
2
|
+
|
3
|
+
describe RequestLogAnalyzer::Tracker::Frequency do
|
4
|
+
|
5
|
+
context 'static category' do
|
6
|
+
before(:each) do
|
7
|
+
@tracker = RequestLogAnalyzer::Tracker::Frequency.new(:category => :category)
|
8
|
+
@tracker.prepare
|
9
|
+
end
|
10
|
+
|
11
|
+
it "should register a request in the right category" do
|
12
|
+
@tracker.update(request(:category => 'a', :blah => 0.2))
|
13
|
+
@tracker.categories.should include('a')
|
14
|
+
end
|
15
|
+
|
16
|
+
it "should register a request in the right category" do
|
17
|
+
@tracker.update(request(:category => 'a', :blah => 0.2))
|
18
|
+
@tracker.update(request(:category => 'b', :blah => 0.2))
|
19
|
+
@tracker.update(request(:category => 'b', :blah => 0.2))
|
20
|
+
|
21
|
+
@tracker.frequency('a').should == 1
|
22
|
+
@tracker.frequency('b').should == 2
|
23
|
+
@tracker.overall_frequency.should == 3
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should sort correctly by frequency" do
|
27
|
+
@tracker.update(request(:category => 'a', :blah => 0.2))
|
28
|
+
@tracker.update(request(:category => 'b', :blah => 0.2))
|
29
|
+
@tracker.update(request(:category => 'b', :blah => 0.2))
|
30
|
+
|
31
|
+
@tracker.sorted_by_frequency.should == [['b', 2], ['a', 1]]
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
|
36
|
+
context 'dynamic category' do
|
37
|
+
before(:each) do
|
38
|
+
@categorizer = Proc.new { |request| request[:duration] > 0.2 ? 'slow' : 'fast' }
|
39
|
+
@tracker = RequestLogAnalyzer::Tracker::Frequency.new(:category => @categorizer)
|
40
|
+
@tracker.prepare
|
41
|
+
end
|
42
|
+
|
43
|
+
it "should use the categorizer to determine the right category" do
|
44
|
+
@tracker.update(request(:category => 'a', :duration => 0.2))
|
45
|
+
@tracker.update(request(:category => 'b', :duration => 0.3))
|
46
|
+
@tracker.update(request(:category => 'b', :duration => 0.4))
|
47
|
+
|
48
|
+
@tracker.frequency('fast').should == 1
|
49
|
+
@tracker.frequency('slow').should == 2
|
50
|
+
@tracker.frequency('moderate').should == 0
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
describe '#report' do
|
55
|
+
before(:each) do
|
56
|
+
@tracker = RequestLogAnalyzer::Tracker::Frequency.new(:category => :category)
|
57
|
+
@tracker.prepare
|
58
|
+
end
|
59
|
+
|
60
|
+
it "should generate a report without errors when one category is present" do
|
61
|
+
@tracker.update(request(:category => 'a', :blah => 0.2))
|
62
|
+
lambda { @tracker.report(mock_output) }.should_not raise_error
|
63
|
+
end
|
64
|
+
|
65
|
+
it "should generate a report without errors when no category is present" do
|
66
|
+
lambda { @tracker.report(mock_output) }.should_not raise_error
|
67
|
+
end
|
68
|
+
|
69
|
+
it "should generate a report without errors when multiple categories are present" do
|
70
|
+
@tracker.update(request(:category => 'a', :blah => 0.2))
|
71
|
+
@tracker.update(request(:category => 'b', :blah => 0.2))
|
72
|
+
lambda { @tracker.report(mock_output) }.should_not raise_error
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
describe '#to_yaml_object' do
|
77
|
+
before(:each) do
|
78
|
+
@tracker = RequestLogAnalyzer::Tracker::Frequency.new(:category => :category)
|
79
|
+
@tracker.prepare
|
80
|
+
end
|
81
|
+
|
82
|
+
it "should generate a YAML output" do
|
83
|
+
@tracker.update(request(:category => 'a', :blah => 0.2))
|
84
|
+
@tracker.update(request(:category => 'b', :blah => 0.2))
|
85
|
+
@tracker.to_yaml_object.should == { "a" => 1, "b" => 1 }
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|