ruby-metrics 0.9.3 → 0.9.4

Sign up to get free protection for your applications and to get access to all the features.
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