ruby-metrics 0.8.6 → 0.9.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/.bundle/config +1 -2
- data/.gitignore +2 -0
- data/.rvmrc +1 -1
- data/.travis.yml +5 -0
- data/CHANGELOG.md +48 -0
- data/Gemfile +8 -2
- data/README.md +2 -1
- data/Rakefile +20 -7
- data/examples/gmontest.rb +17 -0
- data/examples/opentsdb_reporter.rb +77 -0
- data/lib/ruby-metrics.rb +3 -4
- data/lib/ruby-metrics/agent.rb +72 -16
- data/lib/ruby-metrics/instruments/counter.rb +19 -12
- data/lib/ruby-metrics/instruments/gauge.rb +13 -9
- data/lib/ruby-metrics/instruments/histogram.rb +46 -45
- data/lib/ruby-metrics/instruments/meter.rb +29 -26
- data/lib/ruby-metrics/instruments/timer.rb +38 -37
- data/lib/ruby-metrics/integration.rb +3 -4
- data/lib/ruby-metrics/logging.rb +0 -2
- data/lib/ruby-metrics/reporter.rb +28 -0
- data/lib/ruby-metrics/statistics/exponential_sample.rb +4 -5
- data/lib/ruby-metrics/statistics/uniform_sample.rb +1 -2
- data/lib/ruby-metrics/time_units.rb +13 -11
- data/lib/ruby-metrics/version.rb +1 -1
- data/ruby-metrics-ganglia.gemspec +21 -0
- data/ruby-metrics-librato.gemspec +20 -0
- data/ruby-metrics-opentsdb.gemspec +21 -0
- data/ruby-metrics.gemspec +18 -15
- data/spec/agent_spec.rb +13 -4
- data/spec/instruments/meter_spec.rb +40 -3
- data/spec/instruments/timer_spec.rb +1 -1
- data/spec/spec_helper.rb +1 -1
- metadata +106 -105
- data/Gemfile.lock +0 -34
- data/lib/ruby-metrics/instruments.rb +0 -89
- data/lib/ruby-metrics/instruments/base.rb +0 -23
- data/lib/ruby-metrics/statistics/sample.rb +0 -21
- data/spec/instruments/base_spec.rb +0 -16
- data/spec/instruments_spec.rb +0 -76
- data/spec/integration/webrick_spec.rb +0 -18
- data/spec/statistics/sample_spec.rb +0 -22
@@ -1,32 +1,33 @@
|
|
1
|
-
require
|
1
|
+
require 'ruby-metrics/time_units'
|
2
2
|
|
3
3
|
module Metrics
|
4
4
|
module Instruments
|
5
|
-
class Meter
|
6
|
-
include Metrics::TimeConversion
|
7
|
-
|
5
|
+
class Meter
|
6
|
+
include Metrics::TimeConversion
|
7
|
+
|
8
8
|
# From http://www.teamquest.com/pdfs/whitepaper/ldavg2.pdf
|
9
9
|
INTERVAL = 5.0
|
10
10
|
INTERVAL_IN_NS = 5000000000.0
|
11
11
|
ONE_MINUTE_FACTOR = 1 - Math.exp(-INTERVAL / 60.0)
|
12
12
|
FIVE_MINUTE_FACTOR = 1 - Math.exp(-INTERVAL / (60.0 * 5.0))
|
13
13
|
FIFTEEN_MINUTE_FACTOR = 1 - Math.exp(-INTERVAL / (60.0 * 15.0))
|
14
|
-
|
14
|
+
|
15
15
|
attr_reader :count
|
16
|
+
attr_reader :units
|
16
17
|
alias_method :counted, :count
|
17
|
-
|
18
|
+
|
18
19
|
def initialize(options = {})
|
19
20
|
@one_minute_rate = @five_minute_rate = @fifteen_minute_rate = 0.0
|
20
21
|
@count = 0
|
21
22
|
@initialized = false
|
22
23
|
@start_time = Time.now.to_f
|
23
|
-
|
24
|
+
@units = "#{options[:units]}"
|
25
|
+
|
24
26
|
@timer_thread = Thread.new do
|
25
|
-
sleep_time = INTERVAL
|
26
27
|
begin
|
27
28
|
loop do
|
28
29
|
self.tick
|
29
|
-
sleep(
|
30
|
+
sleep(INTERVAL)
|
30
31
|
end
|
31
32
|
rescue Exception => e
|
32
33
|
logger.error "Error in timer thread: #{e.class.name}: #{e}\n #{e.backtrace.join("\n ")}"
|
@@ -34,19 +35,19 @@ module Metrics
|
|
34
35
|
end # thread new
|
35
36
|
|
36
37
|
end
|
37
|
-
|
38
|
+
|
38
39
|
def clear
|
39
40
|
end
|
40
|
-
|
41
|
+
|
41
42
|
def mark(count = 1)
|
42
43
|
@count += count
|
43
44
|
end
|
44
|
-
|
45
|
+
|
45
46
|
def calc_rate(rate, factor, count)
|
46
47
|
rate = rate.to_f + (factor.to_f * (count.to_f - rate.to_f))
|
47
48
|
rate.to_f
|
48
49
|
end
|
49
|
-
|
50
|
+
|
50
51
|
def tick
|
51
52
|
count = @count.to_f / Seconds.to_nsec(INTERVAL).to_f
|
52
53
|
|
@@ -58,42 +59,44 @@ module Metrics
|
|
58
59
|
@one_minute_rate = @five_minute_rate = @fifteen_minute_rate = (count)
|
59
60
|
@initialized = true
|
60
61
|
end
|
61
|
-
|
62
|
+
|
62
63
|
@count = 0
|
63
64
|
end
|
64
|
-
|
65
|
+
|
65
66
|
def one_minute_rate(rate_unit = :seconds)
|
66
67
|
convert_to_ns @one_minute_rate, rate_unit
|
67
68
|
end
|
68
|
-
|
69
|
+
|
69
70
|
def five_minute_rate(rate_unit = :seconds)
|
70
71
|
convert_to_ns @five_minute_rate, rate_unit
|
71
72
|
end
|
72
|
-
|
73
|
+
|
73
74
|
def fifteen_minute_rate(rate_unit = :seconds)
|
74
75
|
convert_to_ns @fifteen_minute_rate, rate_unit
|
75
76
|
end
|
76
|
-
|
77
|
+
|
77
78
|
def mean_rate(rate_unit = :seconds)
|
78
79
|
count = @count
|
79
80
|
if count == 0
|
80
|
-
return 0.0
|
81
|
+
return 0.0
|
81
82
|
else
|
82
83
|
elapsed = Time.now.to_f - @start_time.to_f
|
83
|
-
|
84
|
+
mult = scale_time_units(:seconds, rate_unit)
|
85
|
+
count.to_f / (mult * elapsed.to_f)
|
84
86
|
end
|
85
87
|
end
|
86
|
-
|
87
|
-
def
|
88
|
+
|
89
|
+
def as_json(*_)
|
88
90
|
{
|
89
91
|
:one_minute_rate => self.one_minute_rate,
|
90
92
|
:five_minute_rate => self.five_minute_rate,
|
91
93
|
:fifteen_minute_rate => self.fifteen_minute_rate
|
92
|
-
}
|
94
|
+
}
|
93
95
|
end
|
94
|
-
|
95
|
-
end
|
96
96
|
|
97
|
-
|
97
|
+
def to_json(*_)
|
98
|
+
as_json.to_json
|
99
|
+
end
|
100
|
+
end
|
98
101
|
end
|
99
102
|
end
|
@@ -2,39 +2,40 @@ require File.join(File.dirname(__FILE__), '..', 'time_units')
|
|
2
2
|
|
3
3
|
module Metrics
|
4
4
|
module Instruments
|
5
|
-
class Timer
|
6
|
-
include Metrics::TimeConversion
|
7
|
-
|
8
|
-
attr_reader :duration_unit, :rate_unit
|
9
|
-
|
5
|
+
class Timer
|
6
|
+
include Metrics::TimeConversion
|
7
|
+
|
8
|
+
attr_reader :duration_unit, :rate_unit, :units
|
9
|
+
|
10
10
|
def initialize(options = {})
|
11
11
|
@meter = Meter.new
|
12
12
|
@histogram = ExponentialHistogram.new
|
13
13
|
|
14
14
|
@duration_unit = options[:duration_unit] || :seconds
|
15
15
|
@rate_unit = options[:rate_unit] || :seconds
|
16
|
+
@units = options[:units]
|
16
17
|
|
17
18
|
clear
|
18
19
|
end
|
19
|
-
|
20
|
+
|
20
21
|
def clear
|
21
22
|
@histogram.clear
|
22
23
|
end
|
23
24
|
|
24
25
|
def update(duration, unit)
|
25
26
|
mult = convert_to_ns(1, unit)
|
26
|
-
self.update_timer
|
27
|
+
self.update_timer(duration * mult)
|
27
28
|
end
|
28
29
|
|
29
|
-
def time(&block)
|
30
|
+
def time(&block)
|
30
31
|
start_time = Time.now.to_f
|
31
32
|
result = block.call
|
32
33
|
time_diff = Time.now.to_f - start_time
|
33
|
-
time_in_ns = convert_to_ns time_diff, :seconds
|
34
|
+
time_in_ns = convert_to_ns time_diff, :seconds
|
34
35
|
update_timer(time_in_ns)
|
35
36
|
result
|
36
37
|
end
|
37
|
-
|
38
|
+
|
38
39
|
def count
|
39
40
|
@histogram.count
|
40
41
|
end
|
@@ -50,7 +51,7 @@ module Metrics
|
|
50
51
|
def one_minute_rate
|
51
52
|
@meter.one_minute_rate(@rate_unit)
|
52
53
|
end
|
53
|
-
|
54
|
+
|
54
55
|
def mean_rate
|
55
56
|
@meter.mean_rate(@rate_unit)
|
56
57
|
end
|
@@ -58,26 +59,26 @@ module Metrics
|
|
58
59
|
def max
|
59
60
|
scale_duration_to_ns @histogram.max, @duration_unit
|
60
61
|
end
|
61
|
-
|
62
|
+
|
62
63
|
def min
|
63
64
|
scale_duration_to_ns @histogram.min, @duration_unit
|
64
65
|
end
|
65
|
-
|
66
|
+
|
66
67
|
def mean
|
67
68
|
scale_duration_to_ns @histogram.mean, @duration_unit
|
68
69
|
end
|
69
|
-
|
70
|
+
|
70
71
|
def std_dev
|
71
72
|
scale_duration_to_ns @histogram.std_dev, @duration_unit
|
72
73
|
end
|
73
|
-
|
74
|
+
|
74
75
|
def quantiles(percentiles = [0.99,0.97,0.95,0.75,0.5,0.25])
|
75
76
|
result = {}
|
76
|
-
|
77
|
+
|
77
78
|
@histogram.quantiles(percentiles).each do |k,v|
|
78
79
|
result[k] = scale_duration_to_ns v, @duration_unit
|
79
80
|
end
|
80
|
-
|
81
|
+
|
81
82
|
result
|
82
83
|
end
|
83
84
|
|
@@ -87,44 +88,44 @@ module Metrics
|
|
87
88
|
@histogram.values.each do |value|
|
88
89
|
result << (scale_duration_to_ns value, @duration_unit)
|
89
90
|
end
|
90
|
-
|
91
|
+
|
91
92
|
result
|
92
93
|
end
|
93
|
-
|
94
|
+
|
94
95
|
def update_timer(duration)
|
95
96
|
if duration >= 0
|
96
97
|
@histogram.update(duration)
|
97
98
|
@meter.mark
|
98
99
|
end
|
99
100
|
end
|
100
|
-
|
101
|
-
def
|
101
|
+
|
102
|
+
def as_json(*_)
|
102
103
|
{
|
103
|
-
:count =>
|
104
|
+
:count => count,
|
104
105
|
:rates => {
|
105
|
-
:one_minute_rate =>
|
106
|
-
:five_minute_rate =>
|
107
|
-
:fifteen_minute_rate =>
|
106
|
+
:one_minute_rate => one_minute_rate,
|
107
|
+
:five_minute_rate => five_minute_rate,
|
108
|
+
:fifteen_minute_rate => fifteen_minute_rate,
|
108
109
|
:unit => @rate_unit
|
109
110
|
},
|
110
|
-
:durations => {
|
111
|
-
:min =>
|
112
|
-
:max =>
|
113
|
-
:mean =>
|
114
|
-
:percentiles =>
|
111
|
+
:durations => {
|
112
|
+
:min => min,
|
113
|
+
:max => max,
|
114
|
+
:mean => mean,
|
115
|
+
:percentiles => quantiles([0.25, 0.50, 0.75, 0.95, 0.97, 0.98, 0.99]),
|
115
116
|
:unit => @duration_unit
|
116
117
|
}
|
117
|
-
}
|
118
|
+
}
|
118
119
|
end
|
119
|
-
|
120
|
+
|
121
|
+
def to_json(*_)
|
122
|
+
as_json.to_json
|
123
|
+
end
|
124
|
+
|
120
125
|
private
|
121
126
|
def scale_duration_to_ns(value, unit)
|
122
127
|
value.to_f / convert_to_ns(1, unit).to_f
|
123
128
|
end
|
124
|
-
|
125
129
|
end
|
126
|
-
|
127
|
-
register_instrument(:timer, Timer)
|
128
130
|
end
|
129
|
-
end
|
130
|
-
|
131
|
+
end
|
@@ -1,12 +1,11 @@
|
|
1
1
|
module Metrics
|
2
2
|
module Integration
|
3
3
|
|
4
|
-
autoload :WEBrick, File.
|
4
|
+
autoload :WEBrick, File.expand_path('../integration/webrick', __FILE__)
|
5
5
|
|
6
6
|
module Rack
|
7
|
-
autoload :Middleware, File.
|
8
|
-
autoload :Endpoint, File.
|
7
|
+
autoload :Middleware, File.expand_path('../integration/rack_middleware', __FILE__)
|
8
|
+
autoload :Endpoint, File.expand_path('../integration/rack_endpoint', __FILE__)
|
9
9
|
end
|
10
|
-
|
11
10
|
end
|
12
11
|
end
|
data/lib/ruby-metrics/logging.rb
CHANGED
@@ -0,0 +1,28 @@
|
|
1
|
+
module Metrics
|
2
|
+
class Reporter
|
3
|
+
# Default reporting delay is 60 seconds
|
4
|
+
DEFAULT_REPORTING_DELAY = 60
|
5
|
+
|
6
|
+
include Logging
|
7
|
+
|
8
|
+
def initialize(options = {})
|
9
|
+
|
10
|
+
if options[:agent] == nil
|
11
|
+
raise "Need an agent to report data from"
|
12
|
+
end
|
13
|
+
|
14
|
+
delay = options[:delay] || DEFAULT_REPORTING_DELAY
|
15
|
+
agent = options[:agent]
|
16
|
+
|
17
|
+
Thread.new {
|
18
|
+
while(true)
|
19
|
+
agent.reporters.each do |name, service|
|
20
|
+
service.report(agent)
|
21
|
+
end
|
22
|
+
sleep delay
|
23
|
+
end
|
24
|
+
}.join
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
end
|
@@ -1,7 +1,6 @@
|
|
1
1
|
module Metrics
|
2
2
|
module Statistics
|
3
|
-
class ExponentialSample
|
4
|
-
|
3
|
+
class ExponentialSample
|
5
4
|
def initialize(size = 1028, alpha = 0.015)
|
6
5
|
@values = Hash.new
|
7
6
|
@count = 0
|
@@ -23,7 +22,7 @@ module Metrics
|
|
23
22
|
end
|
24
23
|
|
25
24
|
def tick
|
26
|
-
|
25
|
+
Time.now.to_f
|
27
26
|
end
|
28
27
|
|
29
28
|
def update(value)
|
@@ -38,7 +37,7 @@ module Metrics
|
|
38
37
|
@values[priority] = value
|
39
38
|
else
|
40
39
|
firstkey = @values.keys[0]
|
41
|
-
if (firstkey < priority)
|
40
|
+
if firstkey && (firstkey < priority)
|
42
41
|
@values[priority] = value
|
43
42
|
|
44
43
|
while(@values.delete(firstkey) == nil)
|
@@ -85,7 +84,7 @@ module Metrics
|
|
85
84
|
result << @values[key]
|
86
85
|
end
|
87
86
|
|
88
|
-
|
87
|
+
result
|
89
88
|
end
|
90
89
|
end
|
91
90
|
end
|
@@ -43,19 +43,21 @@ module Metrics
|
|
43
43
|
end
|
44
44
|
|
45
45
|
module TimeConversion
|
46
|
-
|
46
|
+
UNITS = {
|
47
|
+
:nanoseconds => Nanoseconds,
|
48
|
+
:microseconds => Microseconds,
|
49
|
+
:milliseconds => Milliseconds,
|
50
|
+
:seconds => Seconds,
|
51
|
+
:minutes => Minutes,
|
52
|
+
:hours => Hours
|
53
|
+
}
|
47
54
|
|
48
55
|
def convert_to_ns(value, unit)
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
:minutes => Minutes,
|
55
|
-
:hours => Hours
|
56
|
-
}
|
57
|
-
|
58
|
-
return units[unit].to_nsec * value
|
56
|
+
(UNITS[unit].to_nsec.to_f * value.to_f)
|
57
|
+
end
|
58
|
+
|
59
|
+
def scale_time_units(source, dest)
|
60
|
+
(UNITS[source].to_nsec.to_f) / (UNITS[dest].to_nsec.to_f)
|
59
61
|
end
|
60
62
|
end
|
61
63
|
end
|
data/lib/ruby-metrics/version.rb
CHANGED
@@ -0,0 +1,21 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path('../lib', __FILE__)
|
3
|
+
require 'ruby-metrics/version'
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = 'ruby-metrics-ganglia'
|
7
|
+
s.version = Metrics::VERSION
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.authors = ['John Ewart']
|
10
|
+
s.email = ['john@johnewart.net']
|
11
|
+
s.homepage = 'https://github.com/johnewart/ruby-metrics'
|
12
|
+
s.summary = %q{Ganglia reporter for ruby-metrics}
|
13
|
+
s.description = %q{A reporter that uses Ganglia's to stash metric data}
|
14
|
+
s.license = 'MIT'
|
15
|
+
|
16
|
+
s.files = ['lib/ruby-metrics/reporters/ganglia.rb']
|
17
|
+
s.require_paths = ['lib']
|
18
|
+
|
19
|
+
s.add_dependency 'gmetric', '0.1.3'
|
20
|
+
s.add_dependency 'ruby-metrics', Metrics::VERSION
|
21
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path('../lib', __FILE__)
|
3
|
+
require 'ruby-metrics/version'
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = 'ruby-metrics-librato'
|
7
|
+
s.version = Metrics::VERSION
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.authors = ['John Ewart']
|
10
|
+
s.email = ['john@johnewart.net']
|
11
|
+
s.homepage = 'https://github.com/johnewart/ruby-metrics'
|
12
|
+
s.summary = %q{Librato reporter for ruby-metrics}
|
13
|
+
s.description = %q{A reporter that uses Librato to stash metric data}
|
14
|
+
s.license = 'MIT'
|
15
|
+
|
16
|
+
s.files = ['lib/ruby-metrics/reporters/librato.rb']
|
17
|
+
s.require_paths = ['lib']
|
18
|
+
|
19
|
+
s.add_dependency 'ruby-metrics', Metrics::VERSION
|
20
|
+
end
|