ruby-metrics 0.5.0 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile.lock +1 -1
- data/README.md +2 -2
- data/examples/histogram.rb +7 -3
- data/examples/meter.rb +3 -2
- data/lib/ruby-metrics/agent.rb +3 -2
- data/lib/ruby-metrics/instruments.rb +15 -6
- data/lib/ruby-metrics/instruments/histogram.rb +21 -2
- data/lib/ruby-metrics/statistics/exponential_sample.rb +92 -0
- data/lib/ruby-metrics/version.rb +1 -1
- data/spec/agent_spec.rb +18 -0
- data/spec/instruments/histogram_spec.rb +74 -64
- data/spec/instruments_spec.rb +15 -0
- data/spec/spec_helper.rb +2 -1
- data/spec/statistics/exponential_sample_spec.rb +138 -0
- metadata +8 -5
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -15,10 +15,10 @@ Right now, I have:
|
|
15
15
|
* Meters
|
16
16
|
* Gauges
|
17
17
|
* Histograms w/ uniform sampling
|
18
|
+
* Histograms w/ exponentially decaying sampling
|
18
19
|
|
19
20
|
Upcoming:
|
20
21
|
|
21
|
-
* Histograms w/ exponentially decaying sampling
|
22
22
|
* Timers
|
23
23
|
|
24
24
|
## Getting Started
|
@@ -32,7 +32,7 @@ The goal of ruby-metrics is to get up and running quickly. You start an agent, r
|
|
32
32
|
counter.incr
|
33
33
|
counter.incr
|
34
34
|
|
35
|
-
Then, hitting localhost:
|
35
|
+
Then, hitting localhost:8001/status would yield:
|
36
36
|
|
37
37
|
{"my_counter":"2"}
|
38
38
|
|
data/examples/histogram.rb
CHANGED
@@ -4,10 +4,13 @@ require '../lib/ruby-metrics'
|
|
4
4
|
@metrics = Metrics::Agent.new
|
5
5
|
@metrics.start
|
6
6
|
|
7
|
-
|
7
|
+
exponential_histogram = @metrics.exponential_histogram :exponential_histogram
|
8
|
+
uniform_histogram = @metrics.uniform_histogram :uniform_histogram
|
9
|
+
|
8
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)
|
9
11
|
data.each do |point|
|
10
|
-
|
12
|
+
exponential_histogram.update(point.to_f)
|
13
|
+
uniform_histogram.update(point.to_f)
|
11
14
|
end
|
12
15
|
|
13
16
|
step = 0
|
@@ -24,5 +27,6 @@ loop do
|
|
24
27
|
modifier *= -1
|
25
28
|
end
|
26
29
|
|
27
|
-
|
30
|
+
uniform_histogram.update((2 + modifier).to_f)
|
31
|
+
exponential_histogram.update((2 + modifier).to_f)
|
28
32
|
end
|
data/examples/meter.rb
CHANGED
@@ -1,7 +1,8 @@
|
|
1
1
|
require 'rubygems'
|
2
2
|
require '../lib/ruby-metrics'
|
3
3
|
|
4
|
-
|
4
|
+
# Specify a port for the agent
|
5
|
+
@metrics = Metrics::Agent.new(8081)
|
5
6
|
@metrics.start
|
6
7
|
|
7
8
|
timer = @metrics.meter :my_meter
|
@@ -10,7 +11,7 @@ timer.mark(500)
|
|
10
11
|
step = 0
|
11
12
|
|
12
13
|
# This is here so that we will run indefinitely so you can hit the
|
13
|
-
# status page on localhost:
|
14
|
+
# status page on localhost:8081/status
|
14
15
|
loop do
|
15
16
|
sleep 1
|
16
17
|
|
data/lib/ruby-metrics/agent.rb
CHANGED
@@ -29,9 +29,10 @@ module Metrics
|
|
29
29
|
|
30
30
|
attr_reader :instruments
|
31
31
|
|
32
|
-
def initialize
|
32
|
+
def initialize(port = 8001)
|
33
33
|
logger.debug "Initializing Metrics..."
|
34
34
|
@instruments = Metrics::Instruments
|
35
|
+
@port = port
|
35
36
|
end
|
36
37
|
|
37
38
|
def start
|
@@ -43,7 +44,7 @@ module Metrics
|
|
43
44
|
logger.debug "Creating Metrics daemon thread."
|
44
45
|
@daemon_thread = Thread.new do
|
45
46
|
begin
|
46
|
-
server = WEBrick::HTTPServer.new ({:Port =>
|
47
|
+
server = WEBrick::HTTPServer.new ({:Port => @port})
|
47
48
|
server.mount "/status", Status, @instruments
|
48
49
|
server.start
|
49
50
|
rescue Exception => e
|
@@ -1,5 +1,6 @@
|
|
1
1
|
require File.join(File.dirname(__FILE__), 'statistics', 'sample')
|
2
2
|
require File.join(File.dirname(__FILE__), 'statistics', 'uniform_sample')
|
3
|
+
require File.join(File.dirname(__FILE__), 'statistics', 'exponential_sample')
|
3
4
|
|
4
5
|
require File.join(File.dirname(__FILE__), 'instruments', 'base')
|
5
6
|
require File.join(File.dirname(__FILE__), 'instruments', 'counter')
|
@@ -15,10 +16,11 @@ module Metrics
|
|
15
16
|
@instruments = {}
|
16
17
|
|
17
18
|
@types = {
|
18
|
-
:counter
|
19
|
-
:meter
|
20
|
-
:gauge
|
21
|
-
:
|
19
|
+
:counter => Counter,
|
20
|
+
:meter => Meter,
|
21
|
+
:gauge => Gauge,
|
22
|
+
:exponential_histogram => ExponentialHistogram,
|
23
|
+
:uniform_histogram => UniformHistogram
|
22
24
|
}
|
23
25
|
|
24
26
|
def self.register(type, name, &block)
|
@@ -55,8 +57,15 @@ module Metrics
|
|
55
57
|
register(:gauge, name, &block)
|
56
58
|
end
|
57
59
|
|
58
|
-
def
|
59
|
-
register(:
|
60
|
+
def uniform_histogram(name)
|
61
|
+
register(:uniform_histogram, name)
|
62
|
+
end
|
63
|
+
|
64
|
+
# For backwards compatibility
|
65
|
+
alias_method :histogram, :uniform_histogram
|
66
|
+
|
67
|
+
def exponential_histogram(name)
|
68
|
+
register(:exponential_histogram, name)
|
60
69
|
end
|
61
70
|
end
|
62
71
|
|
@@ -2,9 +2,14 @@ module Metrics
|
|
2
2
|
module Instruments
|
3
3
|
class Histogram < Base
|
4
4
|
|
5
|
-
def initialize
|
5
|
+
def initialize(type = :uniform)
|
6
6
|
@count = 0
|
7
|
-
|
7
|
+
case type
|
8
|
+
when :uniform
|
9
|
+
@sample = Metrics::Statistics::UniformSample.new
|
10
|
+
when :exponential
|
11
|
+
@sample = Metrics::Statistics::ExponentialSample.new
|
12
|
+
end
|
8
13
|
@min = nil
|
9
14
|
@max = nil
|
10
15
|
@sum = 0
|
@@ -151,5 +156,19 @@ module Metrics
|
|
151
156
|
end
|
152
157
|
|
153
158
|
end
|
159
|
+
|
160
|
+
class ExponentialHistogram < Histogram
|
161
|
+
def initialize
|
162
|
+
super(:exponential)
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
166
|
+
class UniformHistogram < Histogram
|
167
|
+
def initialize
|
168
|
+
super(:uniform)
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
154
172
|
end
|
173
|
+
|
155
174
|
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
module Metrics
|
2
|
+
module Statistics
|
3
|
+
class ExponentialSample < Sample
|
4
|
+
|
5
|
+
def initialize(size = 1028, alpha = 0.015)
|
6
|
+
@values = Hash.new
|
7
|
+
@count = 0
|
8
|
+
@size = size
|
9
|
+
@alpha = alpha
|
10
|
+
@rescale_window = "1 hour".to("seconds").scalar
|
11
|
+
self.clear
|
12
|
+
end
|
13
|
+
|
14
|
+
def clear
|
15
|
+
@values = Hash.new
|
16
|
+
@start_time = tick
|
17
|
+
@next_scale_time = Time.now.to_f + @rescale_window
|
18
|
+
@count = 0
|
19
|
+
end
|
20
|
+
|
21
|
+
def size
|
22
|
+
[@values.keys.length, @count].min
|
23
|
+
end
|
24
|
+
|
25
|
+
def tick
|
26
|
+
return Time.now.to_f
|
27
|
+
end
|
28
|
+
|
29
|
+
def update(value)
|
30
|
+
update_with_timestamp(value, tick)
|
31
|
+
end
|
32
|
+
|
33
|
+
def update_with_timestamp(value, timestamp)
|
34
|
+
priority = weight(timestamp.to_f - @start_time.to_f) / rand
|
35
|
+
@count += 1
|
36
|
+
newcount = @count
|
37
|
+
if (newcount <= @size)
|
38
|
+
@values[priority] = value
|
39
|
+
else
|
40
|
+
firstkey = @values.keys[0]
|
41
|
+
if (firstkey < priority)
|
42
|
+
@values[priority] = value
|
43
|
+
|
44
|
+
while(@values.delete(firstkey) == nil)
|
45
|
+
firstkey = @values.keys[0]
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
now = Time.now.to_f
|
51
|
+
next_scale_time = @next_scale_time
|
52
|
+
|
53
|
+
if (now >= next_scale_time)
|
54
|
+
self.rescale(now, next_scale_time)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
|
59
|
+
def rescale(now, next_scale_time)
|
60
|
+
if @next_scale_time == next_scale_time
|
61
|
+
# writelock
|
62
|
+
@next_scale_time = now + @rescale_window
|
63
|
+
old_start_time = @start_time
|
64
|
+
@start_time = tick
|
65
|
+
time_delta = @start_time - old_start_time
|
66
|
+
keys = @values.keys
|
67
|
+
keys.each do |key|
|
68
|
+
value = @values.delete(key)
|
69
|
+
new_key = (key * Math.exp(-@alpha * time_delta))
|
70
|
+
@values[new_key] = value
|
71
|
+
end
|
72
|
+
# unlock
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def weight(factor)
|
77
|
+
return @alpha.to_f * factor.to_f
|
78
|
+
end
|
79
|
+
|
80
|
+
def values
|
81
|
+
# read-lock?
|
82
|
+
result = Array.new
|
83
|
+
keys = @values.keys.sort
|
84
|
+
keys.each do |key|
|
85
|
+
result << @values[key]
|
86
|
+
end
|
87
|
+
|
88
|
+
return result
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
data/lib/ruby-metrics/version.rb
CHANGED
data/spec/agent_spec.rb
CHANGED
@@ -20,6 +20,24 @@ describe Metrics::Agent do
|
|
20
20
|
end
|
21
21
|
end
|
22
22
|
|
23
|
+
it "should add a Histogram instrument using uniform sampling" do
|
24
|
+
histogram = Metrics::Instruments::UniformHistogram.new
|
25
|
+
Metrics::Instruments::UniformHistogram.stub!(:new).and_return histogram
|
26
|
+
@agent.uniform_histogram(:test_histogram).should == histogram
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should allow for registering a Histogram instrument using exponentially decaying sampling" do
|
30
|
+
histogram = Metrics::Instruments::ExponentialHistogram.new
|
31
|
+
Metrics::Instruments::ExponentialHistogram.stub!(:new).and_return histogram
|
32
|
+
@agent.exponential_histogram(:test_histogram).should == histogram
|
33
|
+
end
|
34
|
+
|
35
|
+
it "should set up a histogram using uniform distribution if just a histogram is registered" do
|
36
|
+
histogram = Metrics::Instruments::UniformHistogram.new
|
37
|
+
Metrics::Instruments::UniformHistogram.stub!(:new).and_return histogram
|
38
|
+
@agent.histogram(:test_histogram).should == histogram
|
39
|
+
end
|
40
|
+
|
23
41
|
it "should add a meter instrument correctly" do
|
24
42
|
@meter = Metrics::Instruments::Meter.new
|
25
43
|
Metrics::Instruments::Meter.stub!(:new).and_return @meter
|
@@ -4,86 +4,96 @@ require 'spec_helper'
|
|
4
4
|
|
5
5
|
describe Metrics::Instruments::Histogram do
|
6
6
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
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
|
12
15
|
end
|
13
|
-
@histogram.count.should == 272
|
14
|
-
end
|
15
16
|
|
16
|
-
|
17
|
-
|
18
|
-
|
17
|
+
it "should update variance correctly" do
|
18
|
+
@histogram.variance.should == 1.3027283328494685
|
19
|
+
end
|
19
20
|
|
20
|
-
|
21
|
-
|
22
|
-
|
21
|
+
it "should calculate standard deviations properly" do
|
22
|
+
@histogram.std_dev.should == 1.1413712511052083
|
23
|
+
end
|
23
24
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
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
|
36
37
|
|
37
|
-
|
38
|
-
|
39
|
-
|
38
|
+
it "should accurately calculate the mean" do
|
39
|
+
@histogram.mean.should == 3.4877830882352936
|
40
|
+
end
|
40
41
|
|
41
|
-
|
42
|
-
|
43
|
-
|
42
|
+
it "should accurately represent itself using JSON" do
|
43
|
+
@histogram.to_s.should == "{\"min\":1.6,\"max\":5.1,\"mean\":3.4877830882352936,\"variance\":1.3027283328494685,\"percentiles\":{\"0.25\":2.16275,\"0.5\":4.0,\"0.75\":4.45425,\"0.95\":4.817,\"0.97\":4.8977900000000005,\"0.98\":4.933,\"0.99\":5.009570000000001}}"
|
44
|
+
end
|
44
45
|
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
46
|
+
it "should return correct values for mean, std. deviation and variance when no elements are in the histogram" do
|
47
|
+
histogram = Metrics::Instruments::Histogram.new
|
48
|
+
histogram.variance.should == 0.0
|
49
|
+
histogram.mean.should == 0.0
|
50
|
+
histogram.std_dev.should == 0.0
|
51
|
+
end
|
51
52
|
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
53
|
+
it "should return the first value as the quantile if only one value" do
|
54
|
+
histogram = Metrics::Instruments::Histogram.new
|
55
|
+
histogram.update(42)
|
56
|
+
histogram.quantiles([0.50]).should == {0.50 => 42}
|
57
|
+
end
|
57
58
|
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
59
|
+
it "should return the last value as the 100%" do
|
60
|
+
histogram = Metrics::Instruments::Histogram.new
|
61
|
+
histogram.update(42)
|
62
|
+
histogram.update(64)
|
63
|
+
histogram.quantiles([1.00]).should == {1.00 => 64}
|
64
|
+
end
|
64
65
|
|
65
66
|
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
67
|
+
it "should return correct values for min and max" do
|
68
|
+
histogram = Metrics::Instruments::Histogram.new
|
69
|
+
histogram.update(42)
|
70
|
+
histogram.min.should == 42
|
71
|
+
histogram.max.should == 42
|
72
|
+
end
|
72
73
|
|
73
|
-
|
74
|
+
context "resetting the histogram" do
|
74
75
|
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
76
|
+
it "should clear data correctly" do
|
77
|
+
sample = Metrics::Statistics::UniformSample.new
|
78
|
+
sample.should_receive(:clear)
|
79
|
+
Metrics::Statistics::UniformSample.should_receive(:new).and_return sample
|
79
80
|
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
81
|
+
histogram = Metrics::Instruments::Histogram.new
|
82
|
+
histogram.clear
|
83
|
+
histogram.max.should == 0.0
|
84
|
+
histogram.min.should == 0.0
|
85
|
+
end
|
85
86
|
|
87
|
+
end
|
86
88
|
end
|
87
89
|
|
90
|
+
context "using an exponentially weighted sample" do
|
91
|
+
it "should return correct values for mean, std. deviation and variance when no elements are in the histogram" do
|
92
|
+
histogram = Metrics::Instruments::Histogram.new(:exponential)
|
93
|
+
histogram.variance.should == 0.0
|
94
|
+
histogram.mean.should == 0.0
|
95
|
+
histogram.std_dev.should == 0.0
|
96
|
+
end
|
97
|
+
end
|
88
98
|
|
89
99
|
end
|
data/spec/instruments_spec.rb
CHANGED
@@ -24,6 +24,21 @@ describe Metrics::Instruments do
|
|
24
24
|
@instruments.register(:meter, :test_meter).should == @meter
|
25
25
|
@instruments.registered.should == {:test_meter => @meter}
|
26
26
|
end
|
27
|
+
|
28
|
+
it "should allow for registering a Histogram instrument using uniform sampling" do
|
29
|
+
histogram = Metrics::Instruments::UniformHistogram.new
|
30
|
+
Metrics::Instruments::UniformHistogram.stub!(:new).and_return histogram
|
31
|
+
@instruments.register(:uniform_histogram, :test_histogram).should == histogram
|
32
|
+
@instruments.registered.should == {:test_histogram => histogram}
|
33
|
+
end
|
34
|
+
|
35
|
+
it "should allow for registering a Histogram instrument using exponentially decaying sampling" do
|
36
|
+
histogram = Metrics::Instruments::ExponentialHistogram.new
|
37
|
+
Metrics::Instruments::ExponentialHistogram.stub!(:new).and_return histogram
|
38
|
+
@instruments.register(:exponential_histogram, :test_histogram).should == histogram
|
39
|
+
@instruments.registered.should == {:test_histogram => histogram}
|
40
|
+
end
|
41
|
+
|
27
42
|
|
28
43
|
it "should generate JSON correctly" do
|
29
44
|
Metrics::Instruments::Meter.stub!(:new).and_return @meter
|
data/spec/spec_helper.rb
CHANGED
@@ -0,0 +1,138 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Metrics::Statistics::ExponentialSample do
|
4
|
+
before(:each) do
|
5
|
+
end
|
6
|
+
|
7
|
+
it "should have a size equal 0 intially no matter to the initialization parameter" do
|
8
|
+
sample = Metrics::Statistics::ExponentialSample.new(100)
|
9
|
+
sample.size.should == 0
|
10
|
+
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should have an empty backing hash initially" do
|
14
|
+
sample = Metrics::Statistics::ExponentialSample.new(100)
|
15
|
+
sample.values.length.should == 0
|
16
|
+
end
|
17
|
+
|
18
|
+
|
19
|
+
context "A sample of 100 out of 1000 elements" do
|
20
|
+
before(:each) do
|
21
|
+
@population = (0..99).to_a
|
22
|
+
@sample = Metrics::Statistics::ExponentialSample.new(1000, 0.99)
|
23
|
+
@population.each do |datum|
|
24
|
+
@sample.update(datum)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
it "should have 100 elements" do
|
29
|
+
@sample.size.should == 100
|
30
|
+
@sample.values.length.should == 100
|
31
|
+
end
|
32
|
+
|
33
|
+
it "should only have elements from the population" do
|
34
|
+
values = @sample.values
|
35
|
+
@population.each do |datum|
|
36
|
+
values.should include datum
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
context "A heavily-biased sample of 100 out of 1000 elements" do
|
42
|
+
before(:each) do
|
43
|
+
@population = (0..99).to_a
|
44
|
+
@sample = Metrics::Statistics::ExponentialSample.new(1000, 0.01)
|
45
|
+
@population.each do |datum|
|
46
|
+
@sample.update(datum)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
it "should have 100 elements" do
|
51
|
+
@sample.size.should == 100
|
52
|
+
@sample.values.length.should == 100
|
53
|
+
end
|
54
|
+
|
55
|
+
it "should only have elements from the population" do
|
56
|
+
values = @sample.values
|
57
|
+
@population.each do |datum|
|
58
|
+
values.should include datum
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
it "should add another element when updating" do
|
63
|
+
@sample.update(42)
|
64
|
+
@sample.size.should == 101
|
65
|
+
@sample.values.should include 42
|
66
|
+
end
|
67
|
+
|
68
|
+
it "should rescale when the clock is one hour in the future or more" do
|
69
|
+
future_time = Time.now + (60 * 60)
|
70
|
+
Time.stub(:now).and_return future_time
|
71
|
+
@sample.update(42)
|
72
|
+
@sample.size.should == 101
|
73
|
+
|
74
|
+
values = @sample.values
|
75
|
+
|
76
|
+
@population.each do |datum|
|
77
|
+
values.should include datum
|
78
|
+
end
|
79
|
+
|
80
|
+
values.should include 42
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
context "A heavily-biased sample of 1000 out of 1000 elements" do
|
85
|
+
before(:each) do
|
86
|
+
@population = (0..999).to_a
|
87
|
+
@sample = Metrics::Statistics::ExponentialSample.new(1000, 0.01)
|
88
|
+
@population.each do |datum|
|
89
|
+
@sample.update(datum)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
it "should have 1000 elements" do
|
94
|
+
@sample.size.should == 1000
|
95
|
+
@sample.values.length.should == 1000
|
96
|
+
end
|
97
|
+
|
98
|
+
it "should only have elements from the population" do
|
99
|
+
values = @sample.values
|
100
|
+
@population.each do |datum|
|
101
|
+
values.should include datum
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
it "should replace an element when updating" do
|
106
|
+
@sample.update(4242)
|
107
|
+
@sample.size.should == 1000
|
108
|
+
@sample.values.should include 4242
|
109
|
+
end
|
110
|
+
|
111
|
+
it "should rescale so that newer events are higher in priority in the hash" do
|
112
|
+
future_time = Time.now + (60 * 60)
|
113
|
+
Time.stub(:now).and_return future_time
|
114
|
+
|
115
|
+
@sample.update(2121)
|
116
|
+
|
117
|
+
|
118
|
+
@sample.size.should == 1000
|
119
|
+
|
120
|
+
future_time = Time.now + (60 * 60 * 2)
|
121
|
+
Time.stub(:now).and_return future_time
|
122
|
+
|
123
|
+
@sample.update(4242)
|
124
|
+
@sample.size.should == 1000
|
125
|
+
|
126
|
+
values = @sample.values
|
127
|
+
|
128
|
+
values.length.should == 1000
|
129
|
+
values.should include 4242
|
130
|
+
values.should include 2121
|
131
|
+
|
132
|
+
# Most recently added values in time should be at the end with the highest priority
|
133
|
+
values[999].should == 4242
|
134
|
+
values[998].should == 2121
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
end
|
metadata
CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
|
|
4
4
|
prerelease: false
|
5
5
|
segments:
|
6
6
|
- 0
|
7
|
-
-
|
7
|
+
- 6
|
8
8
|
- 0
|
9
|
-
version: 0.
|
9
|
+
version: 0.6.0
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- John Ewart
|
@@ -14,7 +14,7 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2011-04-
|
17
|
+
date: 2011-04-15 00:00:00 -07:00
|
18
18
|
default_executable:
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
@@ -102,6 +102,7 @@ files:
|
|
102
102
|
- lib/ruby-metrics/instruments/histogram.rb
|
103
103
|
- lib/ruby-metrics/instruments/meter.rb
|
104
104
|
- lib/ruby-metrics/logging.rb
|
105
|
+
- lib/ruby-metrics/statistics/exponential_sample.rb
|
105
106
|
- lib/ruby-metrics/statistics/sample.rb
|
106
107
|
- lib/ruby-metrics/statistics/uniform_sample.rb
|
107
108
|
- lib/ruby-metrics/version.rb
|
@@ -114,6 +115,7 @@ files:
|
|
114
115
|
- spec/instruments/meter_spec.rb
|
115
116
|
- spec/instruments_spec.rb
|
116
117
|
- spec/spec_helper.rb
|
118
|
+
- spec/statistics/exponential_sample_spec.rb
|
117
119
|
- spec/statistics/sample_spec.rb
|
118
120
|
- spec/statistics/uniform_sample_spec.rb
|
119
121
|
has_rdoc: true
|
@@ -130,7 +132,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
130
132
|
requirements:
|
131
133
|
- - ">="
|
132
134
|
- !ruby/object:Gem::Version
|
133
|
-
hash:
|
135
|
+
hash: 764509393290573048
|
134
136
|
segments:
|
135
137
|
- 0
|
136
138
|
version: "0"
|
@@ -139,7 +141,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
139
141
|
requirements:
|
140
142
|
- - ">="
|
141
143
|
- !ruby/object:Gem::Version
|
142
|
-
hash:
|
144
|
+
hash: 764509393290573048
|
143
145
|
segments:
|
144
146
|
- 0
|
145
147
|
version: "0"
|
@@ -159,5 +161,6 @@ test_files:
|
|
159
161
|
- spec/instruments/meter_spec.rb
|
160
162
|
- spec/instruments_spec.rb
|
161
163
|
- spec/spec_helper.rb
|
164
|
+
- spec/statistics/exponential_sample_spec.rb
|
162
165
|
- spec/statistics/sample_spec.rb
|
163
166
|
- spec/statistics/uniform_sample_spec.rb
|