ruby-metrics 0.6.0 → 0.7.0

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/Gemfile.lock CHANGED
@@ -1,15 +1,16 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- ruby-metrics (0.6.0)
4
+ ruby-metrics (0.7.0)
5
5
  json
6
- ruby-units
6
+ quantity
7
7
 
8
8
  GEM
9
9
  remote: http://rubygems.org/
10
10
  specs:
11
11
  diff-lcs (1.1.2)
12
12
  json (1.5.1)
13
+ quantity (0.1.1)
13
14
  rspec (2.5.0)
14
15
  rspec-core (~> 2.5.0)
15
16
  rspec-expectations (~> 2.5.0)
@@ -18,7 +19,6 @@ GEM
18
19
  rspec-expectations (2.5.0)
19
20
  diff-lcs (~> 1.1.2)
20
21
  rspec-mocks (2.5.0)
21
- ruby-units (1.2.0)
22
22
  simplecov (0.4.0)
23
23
  simplecov-html (~> 0.4.0)
24
24
  simplecov-html (0.4.3)
@@ -145,6 +145,10 @@ module Metrics
145
145
  end
146
146
  end
147
147
 
148
+ def values
149
+ @sample.values
150
+ end
151
+
148
152
  def to_s
149
153
  {
150
154
  :min => self.min,
@@ -154,7 +158,7 @@ module Metrics
154
158
  :percentiles => self.quantiles([0.25, 0.50, 0.75, 0.95, 0.97, 0.98, 0.99])
155
159
  }.to_json
156
160
  end
157
-
161
+
158
162
  end
159
163
 
160
164
  class ExponentialHistogram < Histogram
@@ -1,5 +1,3 @@
1
- require 'ruby-units'
2
-
3
1
  module Metrics
4
2
  module Instruments
5
3
  class Meter < Base
@@ -10,31 +8,17 @@ module Metrics
10
8
  FIVE_MINUTE_FACTOR = 1 - Math.exp(-INTERVAL / (60.0 * 5.0))
11
9
  FIFTEEN_MINUTE_FACTOR = 1 - Math.exp(-INTERVAL / (60.0 * 15.0))
12
10
 
13
- attr_reader :counted, :uncounted
11
+ attr_reader :count
12
+ alias_method :counted, :count
14
13
 
15
14
  def initialize(options = {})
16
15
  @one_minute_rate = @five_minute_rate = @fifteen_minute_rate = 0.0
17
- @counted = @uncounted = 0
16
+ @count = 0
18
17
  @initialized = false
19
-
20
- if options[:interval]
21
- interval = options[:interval]
22
- else
23
- interval = "5 seconds"
24
- end
25
-
26
- if options[:rateunit]
27
- @rateunit = options[:rateunit]
28
- else
29
- @rateunit = interval
30
- end
31
-
32
- # HACK: this is here because ruby-units thinks 1s in ns is 999,999,999.9999999 not 1bn
33
- # TODO: either fix ruby-units, or remove it?
34
- @ratemultiplier = @rateunit.to("nanoseconds").scalar.ceil
35
-
18
+ @start_time = Time.now.to_f
19
+
36
20
  @timer_thread = Thread.new do
37
- sleep_time = interval.to("seconds").scalar
21
+ sleep_time = INTERVAL
38
22
  begin
39
23
  loop do
40
24
  self.tick
@@ -51,8 +35,7 @@ module Metrics
51
35
  end
52
36
 
53
37
  def mark(count = 1)
54
- @uncounted += count
55
- @counted += count
38
+ @count += count
56
39
  end
57
40
 
58
41
  def calc_rate(rate, factor, count)
@@ -61,7 +44,7 @@ module Metrics
61
44
  end
62
45
 
63
46
  def tick
64
- count = @uncounted.to_f / INTERVAL_IN_NS.to_f
47
+ count = @count.to_f / Seconds.to_nsec(INTERVAL).to_f
65
48
 
66
49
  if (@initialized)
67
50
  @one_minute_rate = calc_rate(@one_minute_rate, ONE_MINUTE_FACTOR, count)
@@ -72,19 +55,29 @@ module Metrics
72
55
  @initialized = true
73
56
  end
74
57
 
75
- @uncounted = 0
58
+ @count = 0
76
59
  end
77
60
 
78
- def one_minute_rate
79
- @one_minute_rate * @ratemultiplier
61
+ def one_minute_rate(rate_unit = :seconds)
62
+ scale_to_ns @one_minute_rate, rate_unit
80
63
  end
81
64
 
82
- def five_minute_rate
83
- @five_minute_rate * @ratemultiplier
65
+ def five_minute_rate(rate_unit = :seconds)
66
+ scale_to_ns @five_minute_rate, rate_unit
84
67
  end
85
68
 
86
- def fifteen_minute_rate
87
- @fifteen_minute_rate * @ratemultiplier
69
+ def fifteen_minute_rate(rate_unit = :seconds)
70
+ scale_to_ns @fifteen_minute_rate, rate_unit
71
+ end
72
+
73
+ def mean_rate(rate_unit = seconds)
74
+ count = @count
75
+ if count == 0
76
+ return 0.0;
77
+ else
78
+ elapsed = Time.now.to_f - @start_time.to_f
79
+ scale_to_ns (count / elapsed), rate_unit
80
+ end
88
81
  end
89
82
 
90
83
  def to_s
@@ -94,6 +87,24 @@ module Metrics
94
87
  :fifteen_minute_rate => self.fifteen_minute_rate
95
88
  }.to_json
96
89
  end
90
+
91
+ private
92
+ def scale_to_ns(value, unit)
93
+ mult = case unit
94
+ when :seconds
95
+ Seconds.to_nsec
96
+ when :minutes
97
+ Minutes.to_nsec
98
+ when :hours
99
+ Hours.to_nsec
100
+ when :days
101
+ Days.to_nsec
102
+ when :weeks
103
+ Weeks.to_nsec
104
+ end
105
+
106
+ value * mult
107
+ end
97
108
  end
98
109
  end
99
110
  end
@@ -0,0 +1,108 @@
1
+ require File.join(File.dirname(__FILE__), '..', 'time_units')
2
+
3
+ module Metrics
4
+ module Instruments
5
+ class Timer < Base
6
+ include Metrics::TimeConversion
7
+
8
+ attr_reader :duration_unit, :rate_unit
9
+
10
+ def initialize(duration_unit = :seconds, rate_unit = :seconds)
11
+ @meter = Meter.new
12
+ @histogram = ExponentialHistogram.new
13
+
14
+ @duration_unit = duration_unit
15
+ @rate_unit = rate_unit
16
+
17
+ clear
18
+ end
19
+
20
+ def clear
21
+ @histogram.clear
22
+ end
23
+
24
+ def update(duration, unit)
25
+ mult = convert_to_ns(1, unit)
26
+ self.update_timer (duration * mult)
27
+ end
28
+
29
+ def time(&block)
30
+ start_time = Time.now.to_f
31
+ result = block.call
32
+ time_diff = Time.now.to_f - start_time
33
+ update_timer(time_diff)
34
+ result
35
+ end
36
+
37
+ def count
38
+ @histogram.count
39
+ end
40
+
41
+ def fifteen_minute_rate
42
+ @meter.fifteen_minute_rate(@rate_unit)
43
+ end
44
+
45
+ def five_minute_rate
46
+ @meter.five_minute_rate(@rate_unit)
47
+ end
48
+
49
+ def one_minute_rate
50
+ @meter.one_minute_rate(@rate_unit)
51
+ end
52
+
53
+ def mean_rate
54
+ @meter.mean_rate(@rate_unit)
55
+ end
56
+
57
+ def max
58
+ scale_duration_to_ns @histogram.max, @duration_unit
59
+ end
60
+
61
+ def min
62
+ scale_duration_to_ns @histogram.min, @duration_unit
63
+ end
64
+
65
+ def mean
66
+ scale_duration_to_ns @histogram.mean, @duration_unit
67
+ end
68
+
69
+ def std_dev
70
+ scale_duration_to_ns @histogram.std_dev, @duration_unit
71
+ end
72
+
73
+ def quantiles(percentiles = [0.99,0.97,0.95,0.75,0.5,0.25])
74
+ result = {}
75
+
76
+ @histogram.quantiles(percentiles).each do |k,v|
77
+ result[k] = scale_duration_to_ns v, @duration_unit
78
+ end
79
+
80
+ result
81
+ end
82
+
83
+ def values
84
+ result = []
85
+
86
+ @histogram.values.each do |value|
87
+ result << (scale_duration_to_ns value, @duration_unit)
88
+ end
89
+
90
+ result
91
+ end
92
+
93
+ def update_timer(duration)
94
+ if duration >= 0
95
+ @histogram.update(duration)
96
+ @meter.mark
97
+ end
98
+ end
99
+
100
+ private
101
+ def scale_duration_to_ns(value, unit)
102
+ value / convert_to_ns(1, unit)
103
+ end
104
+
105
+ end
106
+ end
107
+ end
108
+
@@ -1,3 +1,5 @@
1
+ require File.join(File.dirname(__FILE__), 'time_units')
2
+
1
3
  require File.join(File.dirname(__FILE__), 'statistics', 'sample')
2
4
  require File.join(File.dirname(__FILE__), 'statistics', 'uniform_sample')
3
5
  require File.join(File.dirname(__FILE__), 'statistics', 'exponential_sample')
@@ -7,6 +9,7 @@ require File.join(File.dirname(__FILE__), 'instruments', 'counter')
7
9
  require File.join(File.dirname(__FILE__), 'instruments', 'meter')
8
10
  require File.join(File.dirname(__FILE__), 'instruments', 'gauge')
9
11
  require File.join(File.dirname(__FILE__), 'instruments', 'histogram')
12
+ require File.join(File.dirname(__FILE__), 'instruments', 'timer')
10
13
 
11
14
 
12
15
  require 'json'
@@ -7,7 +7,7 @@ module Metrics
7
7
  @count = 0
8
8
  @size = size
9
9
  @alpha = alpha
10
- @rescale_window = "1 hour".to("seconds").scalar
10
+ @rescale_window = 1.hour.to_seconds.to_i
11
11
  self.clear
12
12
  end
13
13
 
@@ -0,0 +1,61 @@
1
+ module Metrics
2
+
3
+ class TimeUnit
4
+ def self.to_nsec(mult = 1)
5
+ raise NotImplementedError
6
+ end
7
+ end
8
+
9
+ class Nanoseconds < TimeUnit
10
+ def self.to_nsec(mult = 1)
11
+ mult
12
+ end
13
+ end
14
+
15
+ class Microseconds < TimeUnit
16
+ def self.to_nsec(mult = 1)
17
+ 1000 * mult
18
+ end
19
+ end
20
+
21
+ class Milliseconds < TimeUnit
22
+ def self.to_nsec(mult = 1)
23
+ 1000000 * mult
24
+ end
25
+ end
26
+
27
+ class Seconds < TimeUnit
28
+ def self.to_nsec(mult = 1)
29
+ 1000000000 * mult
30
+ end
31
+ end
32
+
33
+ class Minutes < TimeUnit
34
+ def self.to_nsec(mult = 1)
35
+ 60000000000 * mult
36
+ end
37
+ end
38
+
39
+ class Hours < TimeUnit
40
+ def self.to_nsec(mult = 1)
41
+ 3600000000000 * mult
42
+ end
43
+ end
44
+
45
+ module TimeConversion
46
+
47
+
48
+ def convert_to_ns(value, unit)
49
+ units = {
50
+ :nanoseconds => Nanoseconds,
51
+ :microseconds => Microseconds,
52
+ :milliseconds => Milliseconds,
53
+ :seconds => Seconds,
54
+ :minutes => Minutes,
55
+ :hours => Hours
56
+ }
57
+
58
+ return units[unit].to_nsec * value
59
+ end
60
+ end
61
+ end
@@ -1,3 +1,3 @@
1
1
  module Metrics
2
- VERSION = "0.6.0"
2
+ VERSION = "0.7.0"
3
3
  end
data/lib/ruby-metrics.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  # == Metrics Initialization
2
2
  #
3
+ require 'quantity/all'
3
4
 
4
5
  module Metrics
5
6
 
@@ -12,4 +13,10 @@ module Metrics
12
13
 
13
14
  end
14
15
 
16
+ Quantity::Unit.add_unit :minute, :time, 60000, :minutes
17
+ Quantity::Unit.add_unit :hour, :time, 3600000, :hours
18
+ Quantity::Unit.add_unit :day, :time, 86400000, :days
19
+ Quantity::Unit.add_unit :week, :time, 604800000, :weeks
20
+
21
+
15
22
  require File.join(File.dirname(__FILE__), 'ruby-metrics', 'agent')
data/ruby-metrics.gemspec CHANGED
@@ -15,7 +15,7 @@ Gem::Specification.new do |s|
15
15
  s.rubyforge_project = "ruby-metrics"
16
16
 
17
17
  s.add_dependency "json"
18
- s.add_dependency "ruby-units"
18
+ s.add_dependency "quantity"
19
19
 
20
20
  s.add_development_dependency "rspec"
21
21
  s.add_development_dependency "simplecov", [">= 0.3.8"] #, :require => false
@@ -1,5 +1,4 @@
1
1
  require 'spec_helper'
2
- require 'ruby-units'
3
2
 
4
3
  describe Metrics::Instruments::Meter do
5
4
  before(:each) do
@@ -19,23 +18,22 @@ describe Metrics::Instruments::Meter do
19
18
  meter = Metrics::Instruments::Meter.new
20
19
  meter.mark(500)
21
20
  meter.counted.should == 500
22
- meter.uncounted.should == 500
23
21
  end
24
22
 
25
23
  it "should accept options for the constructor" do
26
- meter = Metrics::Instruments::Meter.new({:interval => "10 seconds", :rateunit => "5 seconds"})
24
+ meter = Metrics::Instruments::Meter.new
27
25
  end
28
26
 
29
27
  context "A timer with an initial mark of 3 at a 1 second rate unit on a 5 second interval" do
30
28
 
31
29
  before(:each) do
32
- @meter = Metrics::Instruments::Meter.new({:interval => "5 seconds", :rateunit => "1 second"})
30
+ @meter = Metrics::Instruments::Meter.new
33
31
  @meter.mark(3)
34
32
  @meter.tick()
35
33
  end
36
34
 
37
35
  def tick_for(time)
38
- count = ((time.to("seconds")) / 5).scalar
36
+ count = ((time.to_seconds) / 5).to_i
39
37
  (1..count).each do
40
38
  @meter.tick()
41
39
  end
@@ -47,7 +45,7 @@ describe Metrics::Instruments::Meter do
47
45
  end
48
46
 
49
47
  it "should have a rate of 0.22072766470286553 events/sec after 1 minute" do
50
- tick_for("1 minute")
48
+ tick_for(1.minute)
51
49
  @meter.one_minute_rate.should == 0.22072766470286553
52
50
  end
53
51
  end
@@ -58,7 +56,7 @@ describe Metrics::Instruments::Meter do
58
56
  end
59
57
 
60
58
  it "should have a rate of 0.49123845184678905 events/sec after 1 minute" do
61
- tick_for("1 minute")
59
+ tick_for(1.minute)
62
60
  @meter.five_minute_rate.should == 0.49123845184678905
63
61
  end
64
62
  end
@@ -67,9 +65,17 @@ describe Metrics::Instruments::Meter do
67
65
  it "should have a rate of 0.6 events/sec after the first tick" do
68
66
  @meter.fifteen_minute_rate.should == 0.6
69
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
70
76
 
71
77
  it "should have a rate of 0.5613041910189706 events/sec after 1 minute" do
72
- tick_for("1 minute")
78
+ tick_for(1.minute)
73
79
  @meter.fifteen_minute_rate.should == 0.5613041910189706
74
80
  end
75
81
  end
@@ -0,0 +1,115 @@
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(:milliseconds, :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
+ end
95
+
96
+ context "Timing blocks of code" do
97
+ before(:each) do
98
+ @timer = Metrics::Instruments::Timer.new(:nanoseconds, :nanoseconds)
99
+ end
100
+
101
+ it "should return the result of the block passed" do
102
+ result = @timer.time do
103
+ sleep(5)
104
+ "narf"
105
+ end
106
+
107
+ result.should == "narf"
108
+
109
+ @timer.max.should >= 5.0
110
+ @timer.max.should <= 6.0
111
+
112
+ end
113
+ end
114
+
115
+ end
@@ -0,0 +1,13 @@
1
+ require 'spec_helper'
2
+
3
+ describe Metrics::TimeUnit do
4
+ it "should raise NotImplementedError for #to_nsec" do
5
+ begin
6
+ Metrics::TimeUnit.to_nsec
7
+ rescue NotImplementedError
8
+ true
9
+ else
10
+ fail
11
+ end
12
+ end
13
+ end
metadata CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
4
4
  prerelease: false
5
5
  segments:
6
6
  - 0
7
- - 6
7
+ - 7
8
8
  - 0
9
- version: 0.6.0
9
+ version: 0.7.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-15 00:00:00 -07:00
17
+ date: 2011-04-18 00:00:00 -07:00
18
18
  default_executable:
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
@@ -31,7 +31,7 @@ dependencies:
31
31
  prerelease: false
32
32
  version_requirements: *id001
33
33
  - !ruby/object:Gem::Dependency
34
- name: ruby-units
34
+ name: quantity
35
35
  requirement: &id002 !ruby/object:Gem::Requirement
36
36
  none: false
37
37
  requirements:
@@ -101,10 +101,12 @@ files:
101
101
  - lib/ruby-metrics/instruments/gauge.rb
102
102
  - lib/ruby-metrics/instruments/histogram.rb
103
103
  - lib/ruby-metrics/instruments/meter.rb
104
+ - lib/ruby-metrics/instruments/timer.rb
104
105
  - lib/ruby-metrics/logging.rb
105
106
  - lib/ruby-metrics/statistics/exponential_sample.rb
106
107
  - lib/ruby-metrics/statistics/sample.rb
107
108
  - lib/ruby-metrics/statistics/uniform_sample.rb
109
+ - lib/ruby-metrics/time_units.rb
108
110
  - lib/ruby-metrics/version.rb
109
111
  - ruby-metrics.gemspec
110
112
  - spec/agent_spec.rb
@@ -113,11 +115,13 @@ files:
113
115
  - spec/instruments/gauge_spec.rb
114
116
  - spec/instruments/histogram_spec.rb
115
117
  - spec/instruments/meter_spec.rb
118
+ - spec/instruments/timer_spec.rb
116
119
  - spec/instruments_spec.rb
117
120
  - spec/spec_helper.rb
118
121
  - spec/statistics/exponential_sample_spec.rb
119
122
  - spec/statistics/sample_spec.rb
120
123
  - spec/statistics/uniform_sample_spec.rb
124
+ - spec/time_units_spec.rb
121
125
  has_rdoc: true
122
126
  homepage: https://github.com/johnewart/ruby-metrics
123
127
  licenses: []
@@ -132,7 +136,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
132
136
  requirements:
133
137
  - - ">="
134
138
  - !ruby/object:Gem::Version
135
- hash: 764509393290573048
139
+ hash: -24047821763014180
136
140
  segments:
137
141
  - 0
138
142
  version: "0"
@@ -141,7 +145,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
141
145
  requirements:
142
146
  - - ">="
143
147
  - !ruby/object:Gem::Version
144
- hash: 764509393290573048
148
+ hash: -24047821763014180
145
149
  segments:
146
150
  - 0
147
151
  version: "0"
@@ -159,8 +163,10 @@ test_files:
159
163
  - spec/instruments/gauge_spec.rb
160
164
  - spec/instruments/histogram_spec.rb
161
165
  - spec/instruments/meter_spec.rb
166
+ - spec/instruments/timer_spec.rb
162
167
  - spec/instruments_spec.rb
163
168
  - spec/spec_helper.rb
164
169
  - spec/statistics/exponential_sample_spec.rb
165
170
  - spec/statistics/sample_spec.rb
166
171
  - spec/statistics/uniform_sample_spec.rb
172
+ - spec/time_units_spec.rb