ngmoco-request-log-analyzer 1.4.2
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/.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
|