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 CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- ruby-metrics (0.5.0)
4
+ ruby-metrics (0.6.0)
5
5
  json
6
6
  ruby-units
7
7
 
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:8081/status would yield:
35
+ Then, hitting localhost:8001/status would yield:
36
36
 
37
37
  {"my_counter":"2"}
38
38
 
@@ -4,10 +4,13 @@ require '../lib/ruby-metrics'
4
4
  @metrics = Metrics::Agent.new
5
5
  @metrics.start
6
6
 
7
- histogram = @metrics.histogram :my_histogram
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
- histogram.update(point.to_f)
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
- histogram.update((2 + modifier).to_f)
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
- @metrics = Metrics::Agent.new
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:8001/status
14
+ # status page on localhost:8081/status
14
15
  loop do
15
16
  sleep 1
16
17
 
@@ -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 => 8001})
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 => Counter,
19
- :meter => Meter,
20
- :gauge => Gauge,
21
- :histogram => Histogram
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 histogram(name)
59
- register(:histogram, name)
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
- @sample = Metrics::Statistics::UniformSample.new
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
@@ -1,3 +1,3 @@
1
1
  module Metrics
2
- VERSION = "0.5.0"
2
+ VERSION = "0.6.0"
3
3
  end
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
- before(:each) do
8
- @histogram = Metrics::Instruments::Histogram.new
9
- 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)
10
- data.each do |point|
11
- @histogram.update(point.to_f)
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
- it "should update variance correctly" do
17
- @histogram.variance.should == 1.3027283328494685
18
- end
17
+ it "should update variance correctly" do
18
+ @histogram.variance.should == 1.3027283328494685
19
+ end
19
20
 
20
- it "should calculate standard deviations properly" do
21
- @histogram.std_dev.should == 1.1413712511052083
22
- end
21
+ it "should calculate standard deviations properly" do
22
+ @histogram.std_dev.should == 1.1413712511052083
23
+ end
23
24
 
24
- it "should accurately calculate quantiles" do
25
- quantiles = @histogram.quantiles([0.99, 0.98, 0.95, 0.80, 0.57, 0.32])
26
- quantiles.should ==
27
- {
28
- 0.99 => 5.009570000000001,
29
- 0.98 => 4.93300,
30
- 0.95 => 4.81700,
31
- 0.80 => 4.53300,
32
- 0.57 => 4.13300,
33
- 0.32 => 2.39524
34
- }
35
- end
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
- it "should accurately calculate the mean" do
38
- @histogram.mean.should == 3.4877830882352936
39
- end
38
+ it "should accurately calculate the mean" do
39
+ @histogram.mean.should == 3.4877830882352936
40
+ end
40
41
 
41
- it "should accurately represent itself using JSON" do
42
- @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}}"
43
- end
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
- it "should return correct values for mean, std. deviation and variance when no elements are in the histogram" do
46
- histogram = Metrics::Instruments::Histogram.new
47
- histogram.variance.should == 0.0
48
- histogram.mean.should == 0.0
49
- histogram.std_dev.should == 0.0
50
- end
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
- it "should return the first value as the quantile if only one value" do
53
- histogram = Metrics::Instruments::Histogram.new
54
- histogram.update(42)
55
- histogram.quantiles([0.50]).should == {0.50 => 42}
56
- end
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
- it "should return the last value as the 100%" do
59
- histogram = Metrics::Instruments::Histogram.new
60
- histogram.update(42)
61
- histogram.update(64)
62
- histogram.quantiles([1.00]).should == {1.00 => 64}
63
- end
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
- it "should return correct values for min and max" do
67
- histogram = Metrics::Instruments::Histogram.new
68
- histogram.update(42)
69
- histogram.min.should == 42
70
- histogram.max.should == 42
71
- end
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
- context "resetting the histogram" do
74
+ context "resetting the histogram" do
74
75
 
75
- it "should clear data correctly" do
76
- sample = Metrics::Statistics::UniformSample.new
77
- sample.should_receive(:clear)
78
- Metrics::Statistics::UniformSample.should_receive(:new).and_return sample
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
- histogram = Metrics::Instruments::Histogram.new
81
- histogram.clear
82
- histogram.max.should == 0.0
83
- histogram.min.should == 0.0
84
- end
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
@@ -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
@@ -2,7 +2,8 @@ require 'simplecov'
2
2
 
3
3
  SimpleCov.start do
4
4
  add_filter "/spec/"
5
- add_group "Instruments", "lib/metrics/instruments"
5
+ add_group "Instruments", "metrics/instruments"
6
+ add_group "Statistical Samples", "metrics/statistics"
6
7
  merge_timeout 3600
7
8
  end
8
9
 
@@ -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
- - 5
7
+ - 6
8
8
  - 0
9
- version: 0.5.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-13 00:00:00 -07:00
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: -4356011955923517565
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: -4356011955923517565
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