yam-ruby-metrics 0.8.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (49) hide show
  1. data/.bundle/config +2 -0
  2. data/.gitignore +4 -0
  3. data/.rvmrc +1 -0
  4. data/CHANGELOG.md +48 -0
  5. data/Gemfile +8 -0
  6. data/Gemfile.lock +36 -0
  7. data/LICENSE +21 -0
  8. data/README.md +86 -0
  9. data/Rakefile +19 -0
  10. data/autotest/discover.rb +3 -0
  11. data/examples/counter.rb +10 -0
  12. data/examples/gauge.rb +25 -0
  13. data/examples/histogram.rb +32 -0
  14. data/examples/integration/rack_endpoint.ru +24 -0
  15. data/examples/integration/rack_middleware.ru +21 -0
  16. data/examples/integration/webrick.rb +17 -0
  17. data/examples/meter.rb +25 -0
  18. data/examples/timer.rb +31 -0
  19. data/lib/ruby-metrics.rb +15 -0
  20. data/lib/ruby-metrics/agent.rb +62 -0
  21. data/lib/ruby-metrics/instruments/counter.rb +39 -0
  22. data/lib/ruby-metrics/instruments/gauge.rb +23 -0
  23. data/lib/ruby-metrics/instruments/histogram.rb +188 -0
  24. data/lib/ruby-metrics/instruments/meter.rb +99 -0
  25. data/lib/ruby-metrics/instruments/timer.rb +138 -0
  26. data/lib/ruby-metrics/integration.rb +11 -0
  27. data/lib/ruby-metrics/integration/rack_endpoint.rb +33 -0
  28. data/lib/ruby-metrics/integration/rack_middleware.rb +82 -0
  29. data/lib/ruby-metrics/integration/webrick.rb +47 -0
  30. data/lib/ruby-metrics/logging.rb +19 -0
  31. data/lib/ruby-metrics/statistics/exponential_sample.rb +91 -0
  32. data/lib/ruby-metrics/statistics/uniform_sample.rb +37 -0
  33. data/lib/ruby-metrics/time_units.rb +61 -0
  34. data/lib/ruby-metrics/version.rb +3 -0
  35. data/ruby-metrics.gemspec +27 -0
  36. data/spec/agent_spec.rb +48 -0
  37. data/spec/instruments/counter_spec.rb +79 -0
  38. data/spec/instruments/gauge_spec.rb +42 -0
  39. data/spec/instruments/histogram_spec.rb +115 -0
  40. data/spec/instruments/meter_spec.rb +99 -0
  41. data/spec/instruments/timer_spec.rb +146 -0
  42. data/spec/integration/rack_endpoint_spec.rb +60 -0
  43. data/spec/integration/rack_middleware_spec.rb +129 -0
  44. data/spec/integration/webrick_spec.rb +18 -0
  45. data/spec/spec_helper.rb +18 -0
  46. data/spec/statistics/exponential_sample_spec.rb +138 -0
  47. data/spec/statistics/uniform_sample_spec.rb +59 -0
  48. data/spec/time_units_spec.rb +13 -0
  49. metadata +184 -0
@@ -0,0 +1,79 @@
1
+ require 'spec_helper'
2
+
3
+ describe Metrics::Instruments::Counter do
4
+ before(:each) do
5
+ @counter = Metrics::Instruments::Counter.new
6
+ end
7
+
8
+ it "should create a new entity with zero as its value" do
9
+ @counter.to_i.should == 0
10
+ end
11
+
12
+ it "should increment its counter by the value specified" do
13
+ value = 1
14
+ lambda do
15
+ @counter.inc(value)
16
+ end.should change{ @counter.to_i }.by(value)
17
+ end
18
+
19
+ it "should increment its counter by one by default" do
20
+ lambda do
21
+ @counter.inc
22
+ end.should change{ @counter.to_i }.by(1)
23
+ end
24
+
25
+ it "should decrement its counter by the value specified" do
26
+ value = 1
27
+ lambda do
28
+ @counter.dec(value)
29
+ end.should change{ @counter.to_i }.by(-value)
30
+ end
31
+
32
+ it "should decrement its counter by one by default" do
33
+ lambda do
34
+ @counter.dec
35
+ end.should change{ @counter.to_i }.by(-1)
36
+ end
37
+
38
+ it "should alias #incr to #inc" do
39
+ lambda do
40
+ @counter.incr
41
+ end.should change{ @counter.to_i }.by(1)
42
+ end
43
+
44
+ it "should alias #decr to #dec" do
45
+ lambda do
46
+ @counter.decr
47
+ end.should change{ @counter.to_i }.by(-1)
48
+ end
49
+
50
+ it "should clear the counter correctly" do
51
+ @counter.clear
52
+ @counter.to_i.should == 0
53
+ end
54
+
55
+ it "should correctly represent the value as a string" do
56
+ @counter.clear
57
+ @counter.to_i.should == 0
58
+ @counter.to_s.should == "0"
59
+ end
60
+
61
+ it "should return the new count when incrementing" do
62
+ count = @counter.to_i
63
+ @counter.inc(value = 1).should == count + value
64
+ end
65
+
66
+ it "should return the new count when decrementing" do
67
+ lambda do
68
+ @counter.dec(1)
69
+ end.should change{ @counter.to_i }.by(-1)
70
+ end
71
+
72
+ context "to_json" do
73
+ let(:json) { @counter.to_json }
74
+ it "should serialize to its current value" do
75
+ json.should == @counter.to_s
76
+ end
77
+ end
78
+
79
+ end
@@ -0,0 +1,42 @@
1
+ require 'spec_helper'
2
+
3
+ describe Metrics::Instruments::Gauge do
4
+ before(:each) do
5
+ end
6
+
7
+ it "should create a new gauge" do
8
+ callback = Proc.new {}
9
+ @gauge = Metrics::Instruments::Gauge.new &callback
10
+ end
11
+
12
+ it "should correctly callback the block given when we call Gauge#get" do
13
+ result = 42
14
+
15
+ callback = Proc.new do
16
+ {
17
+ :result => result
18
+ }
19
+ end
20
+
21
+ @gauge = Metrics::Instruments::Gauge.new &callback
22
+
23
+ @gauge.get[:result].should == 42
24
+
25
+ result += 1
26
+
27
+ @gauge.get[:result].should == 43
28
+ end
29
+
30
+ context "to_json" do
31
+ it "should serialize the current value" do
32
+ result = 0
33
+ gauge = Metrics::Instruments::Gauge.new{ result }
34
+
35
+ gauge.to_json.should == result.to_s
36
+
37
+ result = 2
38
+ gauge.to_json.should == result.to_s
39
+ end
40
+ end
41
+
42
+ end
@@ -0,0 +1,115 @@
1
+ require 'spec_helper'
2
+
3
+ # This is compared to results from R using the built-in old-faithful dataset
4
+
5
+ describe Metrics::Instruments::Histogram do
6
+
7
+ context "using a uniform sample" do
8
+ before(:each) do
9
+ @histogram = Metrics::Instruments::Histogram.new
10
+ data = %w(3.600 1.800 3.333 2.283 4.533 2.883 4.700 3.600 1.950 4.350 1.833 3.917 4.200 1.750 4.700 2.167 1.750 4.800 1.600 4.250 1.800 1.750 3.450 3.067 4.533 3.600 1.967 4.083 3.850 4.433 4.300 4.467 3.367 4.033 3.833 2.017 1.867 4.833 1.833 4.783 4.350 1.883 4.567 1.750 4.533 3.317 3.833 2.100 4.633 2.000 4.800 4.716 1.833 4.833 1.733 4.883 3.717 1.667 4.567 4.317 2.233 4.500 1.750 4.800 1.817 4.400 4.167 4.700 2.067 4.700 4.033 1.967 4.500 4.000 1.983 5.067 2.017 4.567 3.883 3.600 4.133 4.333 4.100 2.633 4.067 4.933 3.950 4.517 2.167 4.000 2.200 4.333 1.867 4.817 1.833 4.300 4.667 3.750 1.867 4.900 2.483 4.367 2.100 4.500 4.050 1.867 4.700 1.783 4.850 3.683 4.733 2.300 4.900 4.417 1.700 4.633 2.317 4.600 1.817 4.417 2.617 4.067 4.250 1.967 4.600 3.767 1.917 4.500 2.267 4.650 1.867 4.167 2.800 4.333 1.833 4.383 1.883 4.933 2.033 3.733 4.233 2.233 4.533 4.817 4.333 1.983 4.633 2.017 5.100 1.800 5.033 4.000 2.400 4.600 3.567 4.000 4.500 4.083 1.800 3.967 2.200 4.150 2.000 3.833 3.500 4.583 2.367 5.000 1.933 4.617 1.917 2.083 4.583 3.333 4.167 4.333 4.500 2.417 4.000 4.167 1.883 4.583 4.250 3.767 2.033 4.433 4.083 1.833 4.417 2.183 4.800 1.833 4.800 4.100 3.966 4.233 3.500 4.366 2.250 4.667 2.100 4.350 4.133 1.867 4.600 1.783 4.367 3.850 1.933 4.500 2.383 4.700 1.867 3.833 3.417 4.233 2.400 4.800 2.000 4.150 1.867 4.267 1.750 4.483 4.000 4.117 4.083 4.267 3.917 4.550 4.083 2.417 4.183 2.217 4.450 1.883 1.850 4.283 3.950 2.333 4.150 2.350 4.933 2.900 4.583 3.833 2.083 4.367 2.133 4.350 2.200 4.450 3.567 4.500 4.150 3.817 3.917 4.450 2.000 4.283 4.767 4.533 1.850 4.250 1.983 2.250 4.750 4.117 2.150 4.417 1.817 4.467)
11
+ data.each do |point|
12
+ @histogram.update(point.to_f)
13
+ end
14
+ @histogram.count.should == 272
15
+ end
16
+
17
+ it "should update variance correctly" do
18
+ @histogram.variance.should == 1.3027283328494685
19
+ end
20
+
21
+ it "should calculate standard deviations properly" do
22
+ @histogram.std_dev.should == 1.1413712511052083
23
+ end
24
+
25
+ it "should accurately calculate quantiles" do
26
+ quantiles = @histogram.quantiles([0.99, 0.98, 0.95, 0.80, 0.57, 0.32])
27
+ quantiles.should ==
28
+ {
29
+ 0.99 => 5.009570000000001,
30
+ 0.98 => 4.93300,
31
+ 0.95 => 4.81700,
32
+ 0.80 => 4.53300,
33
+ 0.57 => 4.13300,
34
+ 0.32 => 2.39524
35
+ }
36
+ end
37
+
38
+ it "should accurately calculate the mean" do
39
+ @histogram.mean.should == 3.4877830882352936
40
+ end
41
+
42
+ it "should return correct values for mean, std. deviation and variance when no elements are in the histogram" do
43
+ histogram = Metrics::Instruments::Histogram.new
44
+ histogram.variance.should == 0.0
45
+ histogram.mean.should == 0.0
46
+ histogram.std_dev.should == 0.0
47
+ end
48
+
49
+ it "should return the first value as the quantile if only one value" do
50
+ histogram = Metrics::Instruments::Histogram.new
51
+ histogram.update(42)
52
+ histogram.quantiles([0.50]).should == {0.50 => 42}
53
+ end
54
+
55
+ it "should return the last value as the 100%" do
56
+ histogram = Metrics::Instruments::Histogram.new
57
+ histogram.update(42)
58
+ histogram.update(64)
59
+ histogram.quantiles([1.00]).should == {1.00 => 64}
60
+ end
61
+
62
+
63
+ it "should return correct values for min and max" do
64
+ histogram = Metrics::Instruments::Histogram.new
65
+ histogram.update(42)
66
+ histogram.min.should == 42
67
+ histogram.max.should == 42
68
+ end
69
+
70
+ context "resetting the histogram" do
71
+
72
+ it "should clear data correctly" do
73
+ sample = Metrics::Statistics::UniformSample.new
74
+ sample.should_receive(:clear)
75
+ Metrics::Statistics::UniformSample.should_receive(:new).and_return sample
76
+
77
+ histogram = Metrics::Instruments::Histogram.new
78
+ histogram.clear
79
+ histogram.max.should == 0.0
80
+ histogram.min.should == 0.0
81
+ end
82
+
83
+ end
84
+ end
85
+
86
+ context "using an exponentially weighted sample" do
87
+ it "should return correct values for mean, std. deviation and variance when no elements are in the histogram" do
88
+ histogram = Metrics::Instruments::Histogram.new(:exponential)
89
+ histogram.variance.should == 0.0
90
+ histogram.mean.should == 0.0
91
+ histogram.std_dev.should == 0.0
92
+ end
93
+ end
94
+
95
+ context "to_json" do
96
+ before(:each) do
97
+ @histogram = Metrics::Instruments::Histogram.new
98
+ @hash = JSON.parse(@histogram.to_json)
99
+ end
100
+
101
+ %w( min max mean variance ).each do |attr|
102
+ it "should serialize with the #{attr} value" do
103
+ @hash[attr].should_not be_nil
104
+ end
105
+ end
106
+
107
+ %w( 0.25 0.5 0.75 0.95 0.97 0.98 0.99 ).each do |percentile|
108
+ it "should have the #{percentile} percentile" do
109
+ @hash["percentiles"][percentile].should_not be_nil
110
+ end
111
+ end
112
+
113
+ end
114
+
115
+ end
@@ -0,0 +1,99 @@
1
+ require 'spec_helper'
2
+
3
+ describe Metrics::Instruments::Meter do
4
+ before(:each) do
5
+ Thread.stub!(:new).and_return do |block|
6
+ # Do nothing
7
+ end
8
+ end
9
+
10
+ it "should initialize averages to 0" do
11
+ meter = Metrics::Instruments::Meter.new
12
+ meter.one_minute_rate.should == 0.0
13
+ meter.five_minute_rate.should == 0.0
14
+ meter.fifteen_minute_rate.should == 0.0
15
+ end
16
+
17
+ it "should increment count" do
18
+ meter = Metrics::Instruments::Meter.new
19
+ meter.mark(500)
20
+ meter.counted.should == 500
21
+ end
22
+
23
+ it "should accept options for the constructor" do
24
+ meter = Metrics::Instruments::Meter.new
25
+ end
26
+
27
+ context "A timer with an initial mark of 3 at a 1 second rate unit on a 5 second interval" do
28
+
29
+ before(:each) do
30
+ @meter = Metrics::Instruments::Meter.new
31
+ @meter.mark(3)
32
+ @meter.tick()
33
+ end
34
+
35
+ def tick_for(seconds)
36
+ count = ((seconds) / 5).to_i
37
+ (1..count).each do
38
+ @meter.tick()
39
+ end
40
+ end
41
+
42
+ context "For a 1 minute window" do
43
+ it "should have a rate of 0.6 events/sec after the first tick" do
44
+ @meter.one_minute_rate.should == 0.6
45
+ end
46
+
47
+ it "should have a rate of 0.22072766470286553 events/sec after 1 minute" do
48
+ tick_for(60)
49
+ @meter.one_minute_rate.should == 0.22072766470286553
50
+ end
51
+ end
52
+
53
+ context "For a 5 minute window" do
54
+ it "should have a rate of 0.6 events/sec after the first tick" do
55
+ @meter.five_minute_rate.should == 0.6
56
+ end
57
+
58
+ it "should have a rate of 0.49123845184678905 events/sec after 1 minute" do
59
+ tick_for(60)
60
+ @meter.five_minute_rate.should == 0.49123845184678905
61
+ end
62
+ end
63
+
64
+ context "For a 15 minute window" do
65
+ it "should have a rate of 0.6 events/sec after the first tick" do
66
+ @meter.fifteen_minute_rate.should == 0.6
67
+ end
68
+
69
+ it "should have a rate of 36.0 events per minute after the first tick" do
70
+ @meter.fifteen_minute_rate(:minutes).should == 36.0
71
+ end
72
+
73
+ it "should have a rate of 2160.0 events per hour after the first tick" do
74
+ @meter.fifteen_minute_rate(:hours).should == 2160.0
75
+ end
76
+
77
+ it "should have a rate of 0.5613041910189706 events/sec after 1 minute" do
78
+ tick_for(60)
79
+ @meter.fifteen_minute_rate.should == 0.5613041910189706
80
+ end
81
+ end
82
+
83
+ end
84
+
85
+ context "to_json" do
86
+ before(:each) do
87
+ @meter = Metrics::Instruments::Meter.new
88
+ @hash = JSON.parse(@meter.to_json)
89
+ end
90
+
91
+ %w( one_minute_rate five_minute_rate fifteen_minute_rate ).each do |attr|
92
+ it "should serialize with the #{attr} value" do
93
+ @hash[attr].should_not be_nil
94
+ end
95
+ end
96
+
97
+ end
98
+
99
+ end
@@ -0,0 +1,146 @@
1
+ require 'spec_helper'
2
+
3
+ describe Metrics::Instruments::Timer do
4
+ before(:each) do
5
+ Thread.stub!(:new).and_return do |block|
6
+ # Do nothing
7
+ end
8
+ end
9
+
10
+ context "An empty timer" do
11
+ before(:each) do
12
+ @timer = Metrics::Instruments::Timer.new
13
+ end
14
+
15
+ it "should have a max of zero" do
16
+ @timer.max.should == 0
17
+ end
18
+
19
+ it "should have a min of zero" do
20
+ @timer.min.should == 0
21
+ end
22
+
23
+ it "should have a mean of zero" do
24
+ @timer.mean.should == 0
25
+ end
26
+
27
+ it "should have a min of zero" do
28
+ @timer.std_dev.should == 0
29
+ end
30
+
31
+ it "should have quantiles of zero" do
32
+ @timer.quantiles.should == {0.99=>0.0, 0.97=>0.0, 0.95=>0.0, 0.75=>0.0, 0.5=>0.0, 0.25=>0.0}
33
+ end
34
+
35
+ it "should have a mean rate of zero" do
36
+ @timer.mean_rate.should == 0
37
+ end
38
+
39
+ it "should have a one-minute rate of zero" do
40
+ @timer.one_minute_rate.should == 0
41
+ end
42
+
43
+ it "should have a five-minute rate of zero" do
44
+ @timer.five_minute_rate.should == 0
45
+ end
46
+
47
+ it "should have a fifteen-minute rate of zero" do
48
+ @timer.fifteen_minute_rate.should == 0
49
+ end
50
+
51
+ it "should have no values stored" do
52
+ @timer.values.length.should == 0
53
+ end
54
+
55
+ end
56
+
57
+ context "Timing some events" do
58
+ before(:each) do
59
+ @timer = Metrics::Instruments::Timer.new({:duration_unit => :milliseconds, :rate_unit => :seconds})
60
+ @timer.update(10, :milliseconds)
61
+ @timer.update(20, :milliseconds)
62
+ @timer.update(20, :milliseconds)
63
+ @timer.update(30, :milliseconds)
64
+ @timer.update(40, :milliseconds)
65
+ end
66
+
67
+ it "should have counted 5 events" do
68
+ @timer.count.should == 5
69
+ end
70
+
71
+ it "should accurately calculate the minimum duration" do
72
+ @timer.min.should == 10
73
+ end
74
+
75
+ it "should accurately calculate the maximum duration" do
76
+ @timer.max.should == 40
77
+ end
78
+
79
+ it "should accurately calculate the mean duration" do
80
+ @timer.mean.should == 24
81
+ end
82
+
83
+ it "should accurately calculate the standard deviation of the durations" do
84
+ @timer.std_dev.should == 11.401754901476078
85
+ end
86
+
87
+ it "should accurately calculate percentiles" do
88
+ @timer.quantiles.should == {0.99=>39.6, 0.97=>38.8, 0.95=>38.0, 0.75=>30.0, 0.5=>20.0, 0.25=>20.0}
89
+ end
90
+
91
+ it "should contain the series added" do
92
+ @timer.values.sort.should == [10, 20, 20, 30, 40]
93
+ end
94
+
95
+ end
96
+
97
+ context "Timing blocks of code" do
98
+ before(:each) do
99
+ @timer = Metrics::Instruments::Timer.new({:duration_unit => :nanoseconds, :rate_unit => :nanoseconds})
100
+ end
101
+
102
+ it "should return the result of the block passed" do
103
+ result = @timer.time do
104
+ sleep(0.25)
105
+ "narf"
106
+ end
107
+
108
+ result.should == "narf"
109
+
110
+ @timer.max.should >= 250000000
111
+ @timer.max.should <= 300000000
112
+
113
+ end
114
+ end
115
+
116
+ context "to_json" do
117
+ before(:each) do
118
+ @timer = Metrics::Instruments::Timer.new
119
+ @hash = JSON.parse(@timer.to_json)
120
+ end
121
+
122
+ it "should serialize with the count value" do
123
+ @hash["count"].should_not be_nil
124
+ end
125
+
126
+ %w( one_minute_rate five_minute_rate fifteen_minute_rate ).each do |rate|
127
+ it "should serialize with the #{rate} rate" do
128
+ @hash["rates"][rate].should_not be_nil
129
+ end
130
+ end
131
+
132
+ %w( min max mean ).each do |duration|
133
+ it "should serialize with the #{duration} duration" do
134
+ @hash["durations"][duration].should_not be_nil
135
+ end
136
+ end
137
+
138
+ %w( 0.25 0.5 0.75 0.95 0.97 0.98 0.99 ).each do |percentile|
139
+ it "should serialize with the #{percentile} duration percentile" do
140
+ @hash["durations"]["percentiles"][percentile].should_not be_nil
141
+ end
142
+ end
143
+
144
+ end
145
+
146
+ end