ruby-metrics 0.9.3 → 0.9.4

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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: '04971d78af7ca682008c7d66db2eac34111c089bb17778cc18ff434843707126'
4
+ data.tar.gz: e1ec094ef4a2082d12df838b211fac9cebaf207bf4fabb33fb3b30eaef1f97ff
5
+ SHA512:
6
+ metadata.gz: 60b859a4037eb7f22d2bbaa0965cc1ed55845817a613701a9a3f19bba088c6886feb68aad020e421506d330fb87eafa612b0c364773d850dbcd92d9e95798e56
7
+ data.tar.gz: 1b2f48bee677fadfffb53335058aa036985f64f9ce2f6f7901bae3fe8b996dc26c36b83d0303d1ea93065e5eef6cf298ff8c4328c8c13df0182592b694c2d02a
data/Rakefile CHANGED
@@ -15,7 +15,7 @@ task :build do
15
15
  FileUtils.mv(Dir['*.gem'], 'pkg')
16
16
  end
17
17
 
18
- desc "Tags version as #{Metrics::VERSION}, pushes to remote, and pushes gem"
18
+ desc 'Tags version, pushes to remote, and pushes gem'
19
19
  task :release => :build do
20
20
  puts "Releasing v#{Metrics::VERSION}"
21
21
  sh 'git', 'tag', '-m', "Version #{Metrics::VERSION}", "v#{Metrics::VERSION}"
@@ -5,20 +5,20 @@ require 'ruby-metrics/statistics/exponential_sample'
5
5
  module Metrics
6
6
  module Instruments
7
7
  class Histogram < Instrument
8
+ attr_reader :count
8
9
 
9
10
  def initialize(type = :uniform)
10
- @count = 0
11
- case type
12
- when :uniform
13
- @sample = Metrics::Statistics::UniformSample.new
14
- when :exponential
15
- @sample = Metrics::Statistics::ExponentialSample.new
16
- end
17
- @min = nil
18
- @max = nil
19
- @sum = 0
20
- @variance_s = 0
21
- @variance_m = -1
11
+ @sample =
12
+ case type
13
+ when :uniform
14
+ Metrics::Statistics::UniformSample.new
15
+ when :exponential
16
+ Metrics::Statistics::ExponentialSample.new
17
+ else
18
+ raise ArgumentError, "Unknown type #{type.inspect}"
19
+ end
20
+
21
+ clear
22
22
  end
23
23
 
24
24
  def update(value)
@@ -27,7 +27,7 @@ module Metrics
27
27
  @sample.update(value)
28
28
  update_max(value)
29
29
  update_min(value)
30
- update_variance(value);
30
+ update_variance(value)
31
31
  end
32
32
 
33
33
  def clear
@@ -41,111 +41,80 @@ module Metrics
41
41
  end
42
42
 
43
43
  def quantiles(percentiles)
44
- # Calculated using the same logic as R and Ecxel use
44
+ # Calculated using the same logic as R and Excel use
45
45
  # as outlined by the NIST here: http://www.itl.nist.gov/div898/handbook/prc/section2/prc252.htm
46
- count = @count
47
- scores = {}
48
- values = @sample.values[0..count-1]
49
46
 
47
+ sorted_values = @sample.values[0...@count].sort
48
+ scores = { }
50
49
  percentiles.each do |pct|
51
- scores[pct] = 0.0
52
- end
53
-
54
- if count > 0
55
- values.sort!
56
- percentiles.each do |pct|
57
- idx = pct * (values.length - 1) + 1.0
58
- if idx <= 1
59
- scores[pct] = values[0]
60
- elsif idx >= values.length
61
- scores[pct] = values[values.length-1]
50
+ scores[pct] =
51
+ if @count == 0
52
+ 0.0
62
53
  else
63
- lower = values[idx.to_i - 1]
64
- upper = values[idx.to_i]
65
- scores[pct] = lower + (idx - idx.floor) * (upper - lower)
66
- end
54
+ index = pct * (sorted_values.length - 1) + 1.0
55
+ if index <= 1
56
+ sorted_values.first
57
+ elsif index >= sorted_values.length
58
+ sorted_values.last
59
+ else
60
+ lower = sorted_values[index.to_i - 1]
61
+ upper = sorted_values[index.to_i]
62
+ lower + (index - index.floor) * (upper - lower)
63
+ end
67
64
  end
68
65
  end
69
-
70
- return scores
66
+ scores
71
67
  end
72
68
 
73
69
  def update_min(value)
74
- if (@min == nil || value < @min)
70
+ if @min.nil? || value < @min
75
71
  @min = value
76
72
  end
77
73
  end
78
74
 
79
75
  def update_max(value)
80
- if (@max == nil || value > @max)
76
+ if @max.nil? || value > @max
81
77
  @max = value
82
78
  end
83
79
  end
84
80
 
85
81
  def update_variance(value)
86
- count = @count
87
- old_m = @variance_m
88
- new_m = @variance_m + ((value - old_m) / count)
89
- new_s = @variance_s + ((value - old_m) * (value - new_m))
82
+ new_m = @variance_m + ((value - @variance_m) / @count)
83
+ new_s = @variance_s + ((value - @variance_m) * (value - new_m))
90
84
 
91
85
  @variance_m = new_m
92
86
  @variance_s = new_s
93
87
  end
94
88
 
95
89
  def variance
96
- count = @count
97
- variance_s = @variance_s
98
-
99
- if count <= 1
100
- return 0.0
90
+ if @count <= 1
91
+ 0.0
101
92
  else
102
- return variance_s.to_f / (count - 1).to_i
93
+ @variance_s.to_f / (@count - 1)
103
94
  end
104
95
  end
105
96
 
106
- def count
107
- count = @count
108
- return count
109
- end
110
-
111
-
112
97
  def max
113
- max = @max
114
- if max != nil
115
- return max
116
- else
117
- return 0.0
118
- end
98
+ @max || 0.0
119
99
  end
120
100
 
121
101
  def min
122
- min = @min
123
- if min != nil
124
- return min
125
- else
126
- return 0.0
127
- end
102
+ @min || 0.0
128
103
  end
129
104
 
130
105
  def mean
131
- count = @count
132
- sum = @sum
133
-
134
- if count > 0
135
- return sum / count
106
+ if @count > 0
107
+ @sum / @count
136
108
  else
137
- return 0.0
109
+ 0.0
138
110
  end
139
111
  end
140
112
 
141
113
  def std_dev
142
- count = @count
143
- variance = self.variance()
144
-
145
- if count > 0
146
- return Math.sqrt(variance)
114
+ if @count > 0
115
+ Math.sqrt(variance)
147
116
  else
148
- return 0.0
117
+ 0.0
149
118
  end
150
119
  end
151
120
 
@@ -155,11 +124,11 @@ module Metrics
155
124
 
156
125
  def as_json(*_)
157
126
  {
158
- :min => self.min,
159
- :max => self.max,
160
- :mean => self.mean,
161
- :variance => self.variance,
162
- :percentiles => self.quantiles([0.25, 0.50, 0.75, 0.95, 0.97, 0.98, 0.99])
127
+ :min => min,
128
+ :max => max,
129
+ :mean => mean,
130
+ :variance => variance,
131
+ :percentiles => quantiles(Timer::DEFAULT_PERCENTILES)
163
132
  }
164
133
  end
165
134
 
@@ -6,9 +6,8 @@ module Metrics
6
6
  end
7
7
 
8
8
  def tag(key, value)
9
- @tags ||= {}
10
- @tags[key] = value
9
+ tags[key] = value
11
10
  end
12
11
  end
13
12
  end
14
- end
13
+ end
@@ -7,37 +7,35 @@ module Metrics
7
7
  include Metrics::TimeConversion
8
8
 
9
9
  # From http://www.teamquest.com/pdfs/whitepaper/ldavg2.pdf
10
- INTERVAL = 5.0
11
- INTERVAL_IN_NS = 5000000000.0
12
- ONE_MINUTE_FACTOR = 1 - Math.exp(-INTERVAL / 60.0)
13
- FIVE_MINUTE_FACTOR = 1 - Math.exp(-INTERVAL / (60.0 * 5.0))
14
- FIFTEEN_MINUTE_FACTOR = 1 - Math.exp(-INTERVAL / (60.0 * 15.0))
15
-
16
- attr_reader :count
17
- attr_reader :units
10
+ INTERVAL_SECONDS = 5.0
11
+ ONE_MINUTE_FACTOR = 1 - Math.exp(-INTERVAL_SECONDS / 60.0)
12
+ FIVE_MINUTE_FACTOR = 1 - Math.exp(-INTERVAL_SECONDS / (60.0 * 5.0))
13
+ FIFTEEN_MINUTE_FACTOR = 1 - Math.exp(-INTERVAL_SECONDS / (60.0 * 15.0))
14
+
15
+ attr_reader :count, :units
18
16
  alias_method :counted, :count
19
17
 
20
18
  def initialize(options = {})
21
- @one_minute_rate = @five_minute_rate = @fifteen_minute_rate = 0.0
22
- @count = 0
23
- @initialized = false
24
- @start_time = Time.now.to_f
25
19
  @units = options[:units]
20
+ clear
26
21
 
27
22
  @timer_thread = Thread.new do
28
23
  begin
29
24
  loop do
30
- self.tick
31
- sleep(INTERVAL)
25
+ tick
26
+ sleep(INTERVAL_SECONDS)
32
27
  end
33
28
  rescue Exception => e
34
29
  logger.error "Error in timer thread: #{e.class.name}: #{e}\n #{e.backtrace.join("\n ")}"
35
- end # begin
36
- end # thread new
37
-
30
+ end
31
+ end
38
32
  end
39
33
 
40
34
  def clear
35
+ @one_minute_rate = @five_minute_rate = @fifteen_minute_rate = 0.0
36
+ @count = 0
37
+ @initialized = false
38
+ @start_time = Time.now.to_f
41
39
  end
42
40
 
43
41
  def mark(count = 1)
@@ -45,19 +43,18 @@ module Metrics
45
43
  end
46
44
 
47
45
  def calc_rate(rate, factor, count)
48
- rate = rate.to_f + (factor.to_f * (count.to_f - rate.to_f))
49
- rate.to_f
46
+ rate.to_f + factor.to_f * (count.to_f - rate.to_f)
50
47
  end
51
48
 
52
49
  def tick
53
- count = @count.to_f / Seconds.to_nsec(INTERVAL).to_f
50
+ count = @count.to_f / Seconds.to_nsec(INTERVAL_SECONDS).to_f
54
51
 
55
- if (@initialized)
52
+ if @initialized
56
53
  @one_minute_rate = calc_rate(@one_minute_rate, ONE_MINUTE_FACTOR, count)
57
54
  @five_minute_rate = calc_rate(@five_minute_rate, FIVE_MINUTE_FACTOR, count)
58
55
  @fifteen_minute_rate = calc_rate(@fifteen_minute_rate, FIFTEEN_MINUTE_FACTOR, count)
59
56
  else
60
- @one_minute_rate = @five_minute_rate = @fifteen_minute_rate = (count)
57
+ @one_minute_rate = @five_minute_rate = @fifteen_minute_rate = count
61
58
  @initialized = true
62
59
  end
63
60
 
@@ -77,21 +74,20 @@ module Metrics
77
74
  end
78
75
 
79
76
  def mean_rate(rate_unit = :seconds)
80
- count = @count
81
- if count == 0
82
- return 0.0
77
+ if @count == 0
78
+ 0.0
83
79
  else
84
80
  elapsed = Time.now.to_f - @start_time.to_f
85
- mult = scale_time_units(:seconds, rate_unit)
86
- count.to_f / (mult * elapsed.to_f)
81
+ scale_factor = scale_time_units(:seconds, rate_unit)
82
+ @count.to_f / (elapsed * scale_factor)
87
83
  end
88
84
  end
89
85
 
90
86
  def as_json(*_)
91
87
  {
92
- :one_minute_rate => self.one_minute_rate,
93
- :five_minute_rate => self.five_minute_rate,
94
- :fifteen_minute_rate => self.fifteen_minute_rate
88
+ :one_minute_rate => one_minute_rate,
89
+ :five_minute_rate => five_minute_rate,
90
+ :fifteen_minute_rate => fifteen_minute_rate
95
91
  }
96
92
  end
97
93
 
@@ -8,6 +8,8 @@ module Metrics
8
8
 
9
9
  attr_reader :duration_unit, :rate_unit, :units
10
10
 
11
+ DEFAULT_PERCENTILES = [0.25, 0.50, 0.75, 0.95, 0.97, 0.98, 0.99]
12
+
11
13
  def initialize(options = {})
12
14
  @meter = Meter.new
13
15
  @histogram = ExponentialHistogram.new
@@ -20,17 +22,17 @@ module Metrics
20
22
  end
21
23
 
22
24
  def clear
25
+ @meter.clear
23
26
  @histogram.clear
24
27
  end
25
28
 
26
29
  def update(duration, unit)
27
- mult = convert_to_ns(1, unit)
28
- self.update_timer(duration * mult)
30
+ update_timer(convert_to_ns(duration, unit))
29
31
  end
30
32
 
31
- def time(&block)
33
+ def time
32
34
  start_time = Time.now.to_f
33
- result = block.call
35
+ result = yield
34
36
  time_diff = Time.now.to_f - start_time
35
37
  time_in_ns = convert_to_ns time_diff, :seconds
36
38
  update_timer(time_in_ns)
@@ -73,24 +75,17 @@ module Metrics
73
75
  scale_duration_to_ns @histogram.std_dev, @duration_unit
74
76
  end
75
77
 
76
- def quantiles(percentiles = [0.99,0.97,0.95,0.75,0.5,0.25])
77
- result = {}
78
-
79
- @histogram.quantiles(percentiles).each do |k,v|
78
+ def quantiles(percentiles = DEFAULT_PERCENTILES)
79
+ @histogram.quantiles(percentiles).inject({}) do |result, (k, v)|
80
80
  result[k] = scale_duration_to_ns v, @duration_unit
81
+ result
81
82
  end
82
-
83
- result
84
83
  end
85
84
 
86
85
  def values
87
- result = []
88
-
89
- @histogram.values.each do |value|
90
- result << (scale_duration_to_ns value, @duration_unit)
86
+ @histogram.values.map do |value|
87
+ scale_duration_to_ns value, @duration_unit
91
88
  end
92
-
93
- result
94
89
  end
95
90
 
96
91
  def update_timer(duration)
@@ -113,7 +108,7 @@ module Metrics
113
108
  :min => min,
114
109
  :max => max,
115
110
  :mean => mean,
116
- :percentiles => quantiles([0.25, 0.50, 0.75, 0.95, 0.97, 0.98, 0.99]),
111
+ :percentiles => quantiles,
117
112
  :unit => @duration_unit
118
113
  }
119
114
  }
@@ -125,7 +120,7 @@ module Metrics
125
120
 
126
121
  private
127
122
  def scale_duration_to_ns(value, unit)
128
- value.to_f / convert_to_ns(1, unit).to_f
123
+ value.to_f / convert_to_ns(1.0, unit)
129
124
  end
130
125
  end
131
126
  end
@@ -12,7 +12,7 @@ module Metrics
12
12
  :requests, :uncaught_exceptions,
13
13
  :status_codes
14
14
 
15
- def initialize(options ={})
15
+ def initialize(options = {})
16
16
  @options = options
17
17
  @agent = @options.delete(:agent) || Agent.new
18
18
  end
@@ -15,54 +15,41 @@ module Metrics
15
15
  module Rack
16
16
  class Middleware
17
17
 
18
- attr_accessor :app, :options, :agent,
19
- # integration metrics
20
- :requests, :uncaught_exceptions,
21
- :status_codes
22
-
18
+ attr_accessor :app, :options, :agent
19
+
23
20
  def initialize(app, options ={})
24
21
  @app = app
25
22
  @options = {:show => "/stats"}.merge(options)
26
23
  @agent = @options.delete(:agent) || Agent.new
27
-
28
- # Integration Metrics
29
- @requests = @agent.timer(:_requests)
30
- @uncaught_exceptions = @agent.counter(:_uncaught_exceptions)
31
-
32
- # HTTP Status Codes
33
- @status_codes = {
34
- 1 => @agent.counter(:_status_1xx),
35
- 2 => @agent.counter(:_status_2xx),
36
- 3 => @agent.counter(:_status_3xx),
37
- 4 => @agent.counter(:_status_4xx),
38
- 5 => @agent.counter(:_status_5xx)
39
- }
40
24
  end
41
-
25
+
42
26
  def call(env)
43
27
  return show(env) if show?(env)
44
28
 
45
29
  env['metrics.agent'] = @agent
46
30
 
47
- status, headers, body = self.requests.time{ @app.call(env) }
48
-
49
- if status_counter = self.status_codes[status / 100]
50
- status_counter.incr
51
- end
52
-
31
+ status, headers, body = time_request { @app.call(env) }
32
+
33
+ incr_status_code_counter(status / 100)
34
+
53
35
  [status, headers, body]
54
36
  rescue Exception
55
37
  # TODO: add "last_uncaught_exception" with string of error
56
- self.uncaught_exceptions.incr
38
+ incr_uncaught_exceptions
57
39
  raise
58
40
  end
59
-
60
- def show?(env, test = self.options[:show])
41
+
42
+ private
43
+ def show?(env, test = options[:show])
61
44
  case
62
- when String === test; env['PATH_INFO'] == test
63
- when Regexp === test; env['PATH_INFO'] =~ test
64
- when test.respond_to?(:call); test.call(env)
65
- else test
45
+ when String === test
46
+ env['PATH_INFO'] == test
47
+ when Regexp === test
48
+ env['PATH_INFO'] =~ test
49
+ when test.respond_to?(:call)
50
+ test.call(env)
51
+ else
52
+ test
66
53
  end
67
54
  end
68
55
 
@@ -75,7 +62,18 @@ module Metrics
75
62
  [body]
76
63
  ]
77
64
  end
78
-
65
+
66
+ def time_request(&block)
67
+ @agent.timer(:_requests).time(&block)
68
+ end
69
+
70
+ def incr_uncaught_exceptions
71
+ @agent.counter(:_uncaught_exceptions).incr
72
+ end
73
+
74
+ def incr_status_code_counter(hundred)
75
+ @agent.counter(:"_status_#{hundred}xx").incr
76
+ end
79
77
  end
80
78
  end
81
79
  end
@@ -20,7 +20,7 @@ module Metrics
20
20
  agent = options[:agent]
21
21
 
22
22
  Thread.new {
23
- while(@running)
23
+ while @running
24
24
  agent.reporters.each do |name, service|
25
25
  service.report(agent)
26
26
  end
@@ -7,8 +7,7 @@ module Metrics
7
7
  module Reporters
8
8
  class GangliaReporter
9
9
 
10
- attr_reader :host_ip
11
- attr_reader :host_port
10
+ attr_reader :host_ip, :host_port
12
11
 
13
12
  def initialize(options = {})
14
13
  @host_ip = options[:host_ip]
@@ -17,18 +16,19 @@ module Metrics
17
16
 
18
17
  def send_data(data)
19
18
  puts "Sending data: #{data.inspect}"
20
- data_type = case data[:value].class.to_s
21
- when "Fixnum"
22
- "uint32"
23
- when "Float"
24
- "float"
25
- when "String"
26
- "string"
27
- else
28
- "unknown"
29
- end
19
+ data_type =
20
+ case data[:value]
21
+ Fixnum
22
+ "uint32"
23
+ Float
24
+ "float"
25
+ String
26
+ "string"
27
+ else
28
+ "unknown"
29
+ end
30
30
 
31
- Ganglia::GMetric.send(@host_ip, @host_port.to_i, {
31
+ Ganglia::GMetric.send(@host_ip, @host_port.to_i,
32
32
  :spoof => 0,
33
33
  :name => data[:name],
34
34
  :units => data[:units],
@@ -36,44 +36,45 @@ module Metrics
36
36
  :value => data[:value],
37
37
  :tmax => 60,
38
38
  :dmax => 300,
39
- })
39
+ )
40
40
  end
41
41
 
42
42
  def report(agent)
43
-
44
43
  agent.instruments.each do |name, instrument|
45
- nothing_to_do = false
46
- data = { :name => name, :units => instrument.units }
47
44
  case instrument
48
- when Metrics::Instruments::Counter
49
- value = instrument.to_i
50
- data.merge! :value => value.to_i
51
- send_data data
52
- when Metrics::Instruments::Gauge
53
- if instrument.get.is_a? Hash
54
- instrument.get.each do |key, value|
55
- data.merge! :name => "#{name}_#{key}", :value => value
56
- send_data data
57
- end
58
- else
59
- data.merge! :value => instrument.get
60
- send_data data
61
- end
62
- when Metrics::Instruments::Timer
63
- [:count, :fifteen_minute_rate, :five_minute_rate, :one_minute_rate, :min, :max, :mean].each do |attribute|
64
- data.merge!(:name => "#{name}_#{attribute}", :value => instrument.send(attribute))
65
- send_data data
45
+ when Metrics::Instruments::Counter
46
+ send_data :name => name,
47
+ :value => instrument.to_i,
48
+ :units => instrument.units
49
+ when Metrics::Instruments::Gauge
50
+ if instrument.get.is_a? Hash
51
+ instrument.get.each do |key, value|
52
+ send_data :name => "#{name}_#{key}",
53
+ :value => value,
54
+ :units => instrument.units
66
55
  end
67
- when Metrics::Instruments::Meter
68
- [:count, :fifteen_minute_rate, :five_minute_rate, :one_minute_rate, :mean_rate].each do |attribute|
69
- data.merge!(:name => "#{name_attribute}", :value => instrument.send(attribute) )
70
- end
71
- else
72
- puts "Unhandled instrument"
56
+ else
57
+ send_data :name => name,
58
+ :value => instrument.get,
59
+ :units => instrument.units
60
+ end
61
+ when Metrics::Instruments::Timer
62
+ [:count, :fifteen_minute_rate, :five_minute_rate, :one_minute_rate, :min, :max, :mean].each do |attribute|
63
+ send_data :name => "#{name}_#{attribute}",
64
+ :value => instrument.send(attribute),
65
+ :units => instrument.units
66
+ end
67
+ when Metrics::Instruments::Meter
68
+ [:count, :fifteen_minute_rate, :five_minute_rate, :one_minute_rate, :mean_rate].each do |attribute|
69
+ send_data :name => "#{name_attribute}",
70
+ :value => instrument.send(attribute),
71
+ :units => instrument.units
72
+ end
73
+ else
74
+ puts "Unhandled instrument"
73
75
  end
74
76
  end
75
77
  end
76
78
  end
77
79
  end
78
80
  end
79
-
@@ -33,48 +33,50 @@ module Metrics
33
33
  https.start do |http|
34
34
  result = http.request(req)
35
35
  case result
36
- when Net::HTTPCreated
37
- # OK
38
- puts "SENT!"
39
- else
40
- puts "FAILED TO SEND: #{https.inspect}"
36
+ when Net::HTTPCreated
37
+ # OK
38
+ puts "SENT!"
39
+ else
40
+ puts "FAILED TO SEND: #{https.inspect}"
41
41
  end
42
42
  end
43
43
  end
44
44
 
45
45
  def report(agent)
46
-
47
46
  agent.instruments.each do |name, instrument|
48
- nothing_to_do = false
49
47
  measure_time = Time.now.to_i
50
48
 
51
- case instrument.class.to_s
52
- when "Metrics::Instruments::Counter"
53
- value = instrument.to_i
54
- post_url = "#{API_URL}/counters/#{name}.json"
55
- post_data = {:measure_time => measure_time, :value => value.to_i}
56
- send_data(post_url, post_data)
57
- when "Metrics::Instruments::Gauge"
58
- post_url = "#{API_URL}/gauges/#{name}.json"
59
- if instrument.get.is_a? Hash
60
- instrument.get.each do |key, value|
61
- post_data = {:measure_time => measure_time, :source => key, :value => value}
62
- send_data(post_url, post_data)
63
- end
64
- else
65
- post_data = {:measure_time => measure_time, :value => instrument.get}
66
- send_data(post_url, post_data)
67
- end
68
- when "Metrics::Instruments::Timer"
69
- post_url = "#{API_URL}/gauges/#{name}.json"
70
- common_data = {:measure_time => measure_time}
49
+ case instrument
50
+ when Metrics::Instruments::Counter
51
+ send_data "#{API_URL}/counters/#{name}.json",
52
+ :measure_time => measure_time,
53
+ :value => instrument.to_i
71
54
 
72
- [:count, :fifteen_minute_rate, :five_minute_rate, :one_minute_rate, :min, :max, :mean].each do |attribute|
73
- post_data = {:source => attribute, :value => instrument.send(attribute)}.merge(common_data)
74
- send_data(post_url, post_data)
55
+ when Metrics::Instruments::Gauge
56
+ post_url = "#{API_URL}/gauges/#{name}.json"
57
+ if instrument.get.is_a? Hash
58
+ instrument.get.each do |key, value|
59
+ send_data post_url,
60
+ :measure_time => measure_time,
61
+ :source => key,
62
+ :value => value
75
63
  end
76
- else
77
- puts "Unhandled instrument"
64
+ else
65
+ send_data post_url,
66
+ :measure_time => measure_time,
67
+ :value => instrument.get
68
+ end
69
+
70
+ when Metrics::Instruments::Timer
71
+ [:count, :fifteen_minute_rate, :five_minute_rate, :one_minute_rate, :min, :max, :mean].each do |attribute|
72
+ send_data "#{API_URL}/gauges/#{name}.json",
73
+ :measure_time => measure_time,
74
+ :source => attribute,
75
+ :value => instrument.send(attribute)
76
+ end
77
+
78
+ else
79
+ puts "Unhandled instrument"
78
80
  end
79
81
  end
80
82
  end
@@ -1,24 +1,23 @@
1
1
  module Metrics
2
2
  module Statistics
3
3
  class ExponentialSample
4
+ RESCALE_WINDOW_SECONDS = 60 * 60 # 1 hour
5
+
4
6
  def initialize(size = 1028, alpha = 0.015)
5
- @values = Hash.new
6
- @count = 0
7
7
  @size = size
8
8
  @alpha = alpha
9
- @rescale_window = 3600 #seconds -- 1 hour
10
- self.clear
9
+ clear
11
10
  end
12
11
 
13
12
  def clear
14
- @values = Hash.new
13
+ @values = { }
15
14
  @start_time = tick
16
- @next_scale_time = Time.now.to_f + @rescale_window
15
+ @next_scale_time = Time.now.to_f + RESCALE_WINDOW_SECONDS
17
16
  @count = 0
18
17
  end
19
18
 
20
19
  def size
21
- [@values.keys.length, @count].min
20
+ [@values.size, @count].min
22
21
  end
23
22
 
24
23
  def tick
@@ -32,59 +31,50 @@ module Metrics
32
31
  def update_with_timestamp(value, timestamp)
33
32
  priority = weight(timestamp.to_f - @start_time.to_f) / rand
34
33
  @count += 1
35
- newcount = @count
36
- if (newcount <= @size)
34
+ if @count <= @size
37
35
  @values[priority] = value
38
36
  else
39
- firstkey = @values.keys[0]
40
- if firstkey && (firstkey < priority)
37
+ first_key = @values.keys.first
38
+ if first_key && first_key < priority
41
39
  @values[priority] = value
42
40
 
43
- while(@values.delete(firstkey) == nil)
44
- firstkey = @values.keys[0]
41
+ while values.any? && @values.delete(first_key).nil?
42
+ first_key = @values.keys.first
45
43
  end
46
44
  end
47
45
  end
48
46
 
49
47
  now = Time.now.to_f
50
- next_scale_time = @next_scale_time
51
-
52
- if (now >= next_scale_time)
53
- self.rescale(now, next_scale_time)
48
+
49
+ if now >= @next_scale_time
50
+ rescale(now + RESCALE_WINDOW_SECONDS)
54
51
  end
55
52
  end
56
-
57
-
58
- def rescale(now, next_scale_time)
59
- if @next_scale_time == next_scale_time
60
- # writelock
61
- @next_scale_time = now + @rescale_window
62
- old_start_time = @start_time
63
- @start_time = tick
64
- time_delta = @start_time - old_start_time
65
- keys = @values.keys
66
- keys.each do |key|
67
- value = @values.delete(key)
68
- new_key = (key * Math.exp(-@alpha * time_delta))
69
- @values[new_key] = value
70
- end
71
- # unlock
72
- end
73
- end
74
-
75
- def weight(factor)
76
- return @alpha.to_f * factor.to_f
77
- end
78
-
53
+
79
54
  def values
80
55
  # read-lock?
81
- result = Array.new
82
- keys = @values.keys.sort
83
- keys.each do |key|
84
- result << @values[key]
56
+ @values.keys.sort.map do |key|
57
+ @values[key]
85
58
  end
86
-
87
- result
59
+ end
60
+
61
+ private
62
+ def rescale(next_scale_time)
63
+ # writelock
64
+ @next_scale_time = next_scale_time
65
+ old_start_time = @start_time
66
+ @start_time = tick
67
+ time_delta = @start_time - old_start_time
68
+ @values.keys.each do |key|
69
+ value = @values.delete(key)
70
+ new_key = key * Math.exp(-@alpha * time_delta)
71
+ @values[new_key] = value
72
+ end
73
+ # unlock
74
+ end
75
+
76
+ def weight(factor)
77
+ @alpha.to_f * factor.to_f
88
78
  end
89
79
  end
90
80
  end
@@ -3,22 +3,21 @@ module Metrics
3
3
  class UniformSample
4
4
  def initialize(size = 1028)
5
5
  @values = Array.new(size)
6
- @count = 0
7
6
  @size = size
8
- self.clear
7
+ clear
9
8
  end
10
-
9
+
11
10
  def clear
12
- (0..@values.length-1).each do |i|
11
+ (0...@values.size).each do |i|
13
12
  @values[i] = 0
14
13
  end
15
14
  @count = 0
16
15
  end
17
-
16
+
18
17
  def size
19
- @values.length
18
+ @values.size
20
19
  end
21
-
20
+
22
21
  def update(value)
23
22
  if @count < @values.length
24
23
  @values[@count] = value
@@ -28,10 +27,10 @@ module Metrics
28
27
  @values[index] = value
29
28
  end
30
29
  end
31
-
30
+
32
31
  def values
33
32
  @values.dup
34
33
  end
35
34
  end
36
35
  end
37
- end
36
+ end
@@ -1,42 +1,36 @@
1
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
2
+
3
+ module Nanoseconds
10
4
  def self.to_nsec(mult = 1)
11
5
  mult
12
6
  end
13
7
  end
14
8
 
15
- class Microseconds < TimeUnit
9
+ module Microseconds
16
10
  def self.to_nsec(mult = 1)
17
11
  1000 * mult
18
12
  end
19
13
  end
20
14
 
21
- class Milliseconds < TimeUnit
15
+ module Milliseconds
22
16
  def self.to_nsec(mult = 1)
23
17
  1000000 * mult
24
18
  end
25
19
  end
26
20
 
27
- class Seconds < TimeUnit
21
+ module Seconds
28
22
  def self.to_nsec(mult = 1)
29
23
  1000000000 * mult
30
24
  end
31
25
  end
32
26
 
33
- class Minutes < TimeUnit
27
+ module Minutes
34
28
  def self.to_nsec(mult = 1)
35
29
  60000000000 * mult
36
30
  end
37
31
  end
38
32
 
39
- class Hours < TimeUnit
33
+ module Hours
40
34
  def self.to_nsec(mult = 1)
41
35
  3600000000000 * mult
42
36
  end
@@ -53,11 +47,11 @@ module Metrics
53
47
  }
54
48
 
55
49
  def convert_to_ns(value, unit)
56
- (UNITS[unit].to_nsec.to_f * value.to_f)
50
+ UNITS[unit].to_nsec.to_f * value.to_f
57
51
  end
58
52
 
59
53
  def scale_time_units(source, dest)
60
- (UNITS[source].to_nsec.to_f) / (UNITS[dest].to_nsec.to_f)
54
+ UNITS[source].to_nsec.to_f / UNITS[dest].to_nsec.to_f
61
55
  end
62
56
  end
63
57
  end
@@ -1,3 +1,3 @@
1
1
  module Metrics
2
- VERSION = '0.9.3'
2
+ VERSION = '0.9.4'
3
3
  end
data/ruby-metrics.gemspec CHANGED
@@ -17,7 +17,7 @@ Gem::Specification.new do |s|
17
17
  s.description = %q{A Ruby implementation of metrics inspired by @coda's JVM metrics for those of us in Ruby land}
18
18
  s.license = 'MIT'
19
19
 
20
- s.add_dependency 'json', '~> 1.5', '>= 1.5.5'
20
+ s.add_dependency 'json', '~> 2.3', '>= 2.3.0'
21
21
 
22
22
  s.add_development_dependency 'rspec', '~> 2.14', '>= 2.14.0'
23
23
  s.add_development_dependency 'simplecov', '~> 0.3', '>= 0.3.8'
@@ -71,7 +71,7 @@ describe Metrics::Instruments::Histogram do
71
71
 
72
72
  it "should clear data correctly" do
73
73
  sample = Metrics::Statistics::UniformSample.new
74
- sample.should_receive(:clear)
74
+ sample.should_receive(:clear).twice
75
75
  Metrics::Statistics::UniformSample.should_receive(:new).and_return sample
76
76
 
77
77
  histogram = Metrics::Instruments::Histogram.new
@@ -29,7 +29,7 @@ describe Metrics::Instruments::Timer do
29
29
  end
30
30
 
31
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}
32
+ @timer.quantiles.should == {0.25=>0.0, 0.50=>0.0, 0.75=>0.0, 0.95=>0.0, 0.97=>0.0, 0.98=>0.0, 0.99=>0.0 }
33
33
  end
34
34
 
35
35
  it "should have a mean rate of zero" do
@@ -85,7 +85,7 @@ describe Metrics::Instruments::Timer do
85
85
  end
86
86
 
87
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}
88
+ @timer.quantiles.should == {0.25=>20.0, 0.5=>20.0, 0.75=>30.0, 0.95=>38.0, 0.97=>38.8, 0.98=>39.2, 0.99=>39.6}
89
89
  end
90
90
 
91
91
  it "should contain the series added" do
@@ -54,7 +54,7 @@ describe Metrics::Integration::Rack::Middleware do
54
54
  it "should count all requests" do
55
55
  lambda do
56
56
  get '/'
57
- end.should change{ app.requests.count }.by(1)
57
+ end.should change{ app.agent.timer(:_requests).count }.by(1)
58
58
  end
59
59
 
60
60
  it "should count uncaught exceptions" do
@@ -63,22 +63,22 @@ describe Metrics::Integration::Rack::Middleware do
63
63
  lambda do
64
64
  get '/'
65
65
  end.should raise_error
66
- end.should change{ app.uncaught_exceptions.to_i }.by(1)
66
+ end.should change{ app.agent.counter(:_uncaught_exceptions).to_i }.by(1)
67
67
  end
68
68
 
69
69
  it "should time request length" do
70
70
  length = 0.1
71
71
  @app = lambda{ |env| sleep(length); [200, {}, ['']] }
72
72
  get '/'
73
- app.requests.mean.should be_within(length / 10).of(length)
73
+ app.agent.timer(:_requests).mean.should be_within(length / 10).of(length)
74
74
  end
75
-
76
- [ 200, 304, 404, 500].each do |status|
75
+
76
+ [200, 304, 404, 500].each do |status|
77
77
  it "should count #{status} HTTP status code as #{status / 100}xx" do
78
78
  @app = lambda{ |env| [status, {}, []] }
79
79
  lambda do
80
80
  get '/'
81
- end.should change{ app.status_codes[status / 100].to_i }.by(1)
81
+ end.should change{ app.agent.counter(:"_status_#{status / 100}xx").to_i }.by(1)
82
82
  end
83
83
  end
84
84
 
metadata CHANGED
@@ -1,102 +1,93 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruby-metrics
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.3
5
- prerelease:
4
+ version: 0.9.4
6
5
  platform: ruby
7
6
  authors:
8
7
  - John Ewart
9
- autorequire:
8
+ autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
- date: 2014-05-09 00:00:00.000000000 Z
11
+ date: 2021-11-04 00:00:00.000000000 Z
13
12
  dependencies:
14
13
  - !ruby/object:Gem::Dependency
15
14
  name: json
16
15
  requirement: !ruby/object:Gem::Requirement
17
- none: false
18
16
  requirements:
19
- - - ~>
17
+ - - "~>"
20
18
  - !ruby/object:Gem::Version
21
- version: '1.5'
22
- - - ! '>='
19
+ version: '2.3'
20
+ - - ">="
23
21
  - !ruby/object:Gem::Version
24
- version: 1.5.5
22
+ version: 2.3.0
25
23
  type: :runtime
26
24
  prerelease: false
27
25
  version_requirements: !ruby/object:Gem::Requirement
28
- none: false
29
26
  requirements:
30
- - - ~>
27
+ - - "~>"
31
28
  - !ruby/object:Gem::Version
32
- version: '1.5'
33
- - - ! '>='
29
+ version: '2.3'
30
+ - - ">="
34
31
  - !ruby/object:Gem::Version
35
- version: 1.5.5
32
+ version: 2.3.0
36
33
  - !ruby/object:Gem::Dependency
37
34
  name: rspec
38
35
  requirement: !ruby/object:Gem::Requirement
39
- none: false
40
36
  requirements:
41
- - - ~>
37
+ - - "~>"
42
38
  - !ruby/object:Gem::Version
43
39
  version: '2.14'
44
- - - ! '>='
40
+ - - ">="
45
41
  - !ruby/object:Gem::Version
46
42
  version: 2.14.0
47
43
  type: :development
48
44
  prerelease: false
49
45
  version_requirements: !ruby/object:Gem::Requirement
50
- none: false
51
46
  requirements:
52
- - - ~>
47
+ - - "~>"
53
48
  - !ruby/object:Gem::Version
54
49
  version: '2.14'
55
- - - ! '>='
50
+ - - ">="
56
51
  - !ruby/object:Gem::Version
57
52
  version: 2.14.0
58
53
  - !ruby/object:Gem::Dependency
59
54
  name: simplecov
60
55
  requirement: !ruby/object:Gem::Requirement
61
- none: false
62
56
  requirements:
63
- - - ~>
57
+ - - "~>"
64
58
  - !ruby/object:Gem::Version
65
59
  version: '0.3'
66
- - - ! '>='
60
+ - - ">="
67
61
  - !ruby/object:Gem::Version
68
62
  version: 0.3.8
69
63
  type: :development
70
64
  prerelease: false
71
65
  version_requirements: !ruby/object:Gem::Requirement
72
- none: false
73
66
  requirements:
74
- - - ~>
67
+ - - "~>"
75
68
  - !ruby/object:Gem::Version
76
69
  version: '0.3'
77
- - - ! '>='
70
+ - - ">="
78
71
  - !ruby/object:Gem::Version
79
72
  version: 0.3.8
80
73
  - !ruby/object:Gem::Dependency
81
74
  name: rack-test
82
75
  requirement: !ruby/object:Gem::Requirement
83
- none: false
84
76
  requirements:
85
- - - ~>
77
+ - - "~>"
86
78
  - !ruby/object:Gem::Version
87
79
  version: '0.5'
88
- - - ! '>='
80
+ - - ">="
89
81
  - !ruby/object:Gem::Version
90
82
  version: 0.5.7
91
83
  type: :development
92
84
  prerelease: false
93
85
  version_requirements: !ruby/object:Gem::Requirement
94
- none: false
95
86
  requirements:
96
- - - ~>
87
+ - - "~>"
97
88
  - !ruby/object:Gem::Version
98
89
  version: '0.5'
99
- - - ! '>='
90
+ - - ">="
100
91
  - !ruby/object:Gem::Version
101
92
  version: 0.5.7
102
93
  description: A Ruby implementation of metrics inspired by @coda's JVM metrics for
@@ -107,10 +98,10 @@ executables: []
107
98
  extensions: []
108
99
  extra_rdoc_files: []
109
100
  files:
110
- - .bundle/config
111
- - .gitignore
112
- - .rvmrc
113
- - .travis.yml
101
+ - ".bundle/config"
102
+ - ".gitignore"
103
+ - ".rvmrc"
104
+ - ".travis.yml"
114
105
  - CHANGELOG.md
115
106
  - Gemfile
116
107
  - LICENSE
@@ -162,30 +153,40 @@ files:
162
153
  - spec/spec_helper.rb
163
154
  - spec/statistics/exponential_sample_spec.rb
164
155
  - spec/statistics/uniform_sample_spec.rb
165
- - spec/time_units_spec.rb
166
156
  homepage: https://github.com/johnewart/ruby-metrics
167
157
  licenses:
168
158
  - MIT
169
- post_install_message:
159
+ metadata: {}
160
+ post_install_message:
170
161
  rdoc_options: []
171
162
  require_paths:
172
163
  - lib
173
164
  required_ruby_version: !ruby/object:Gem::Requirement
174
- none: false
175
165
  requirements:
176
- - - ! '>='
166
+ - - ">="
177
167
  - !ruby/object:Gem::Version
178
168
  version: '0'
179
169
  required_rubygems_version: !ruby/object:Gem::Requirement
180
- none: false
181
170
  requirements:
182
- - - ! '>='
171
+ - - ">="
183
172
  - !ruby/object:Gem::Version
184
173
  version: '0'
185
174
  requirements: []
186
- rubyforge_project:
187
- rubygems_version: 1.8.23.2
188
- signing_key:
189
- specification_version: 3
175
+ rubygems_version: 3.1.2
176
+ signing_key:
177
+ specification_version: 4
190
178
  summary: Metrics for Ruby
191
- test_files: []
179
+ test_files:
180
+ - spec/agent_spec.rb
181
+ - spec/instruments/counter_spec.rb
182
+ - spec/instruments/gauge_spec.rb
183
+ - spec/instruments/histogram_spec.rb
184
+ - spec/instruments/meter_spec.rb
185
+ - spec/instruments/timer_spec.rb
186
+ - spec/integration/rack_endpoint_spec.rb
187
+ - spec/integration/rack_middleware_spec.rb
188
+ - spec/reporter_spec.rb
189
+ - spec/reporters/opentsdb_spec.rb
190
+ - spec/spec_helper.rb
191
+ - spec/statistics/exponential_sample_spec.rb
192
+ - spec/statistics/uniform_sample_spec.rb
@@ -1,13 +0,0 @@
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