ruby-metrics 0.9.0 → 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 +7 -0
- data/Rakefile +1 -1
- data/lib/ruby-metrics/agent.rb +4 -0
- data/lib/ruby-metrics/instruments/counter.rb +4 -1
- data/lib/ruby-metrics/instruments/gauge.rb +3 -1
- data/lib/ruby-metrics/instruments/histogram.rb +52 -82
- data/lib/ruby-metrics/instruments/instrument.rb +13 -0
- data/lib/ruby-metrics/instruments/meter.rb +29 -32
- data/lib/ruby-metrics/instruments/timer.rb +16 -20
- data/lib/ruby-metrics/integration/rack_endpoint.rb +1 -1
- data/lib/ruby-metrics/integration/rack_middleware.rb +31 -33
- data/lib/ruby-metrics/reporter.rb +7 -2
- data/lib/ruby-metrics/reporters/ganglia.rb +80 -0
- data/lib/ruby-metrics/reporters/librato.rb +85 -0
- data/lib/ruby-metrics/statistics/exponential_sample.rb +36 -46
- data/lib/ruby-metrics/statistics/uniform_sample.rb +8 -9
- data/lib/ruby-metrics/time_units.rb +9 -15
- data/lib/ruby-metrics/version.rb +1 -1
- data/ruby-metrics-opentsdb.gemspec +1 -1
- data/ruby-metrics.gemspec +1 -1
- data/spec/instruments/counter_spec.rb +37 -27
- data/spec/instruments/histogram_spec.rb +1 -1
- data/spec/instruments/timer_spec.rb +2 -2
- data/spec/integration/rack_middleware_spec.rb +6 -6
- data/spec/reporter_spec.rb +27 -0
- data/spec/reporters/opentsdb_spec.rb +297 -0
- metadata +53 -49
- data/ruby-metrics-ganglia.gemspec +0 -21
- data/ruby-metrics-librato.gemspec +0 -20
- data/spec/time_units_spec.rb +0 -13
@@ -0,0 +1,80 @@
|
|
1
|
+
require 'ruby-metrics/version'
|
2
|
+
require 'ruby-metrics'
|
3
|
+
|
4
|
+
require 'gmetric'
|
5
|
+
|
6
|
+
module Metrics
|
7
|
+
module Reporters
|
8
|
+
class GangliaReporter
|
9
|
+
|
10
|
+
attr_reader :host_ip, :host_port
|
11
|
+
|
12
|
+
def initialize(options = {})
|
13
|
+
@host_ip = options[:host_ip]
|
14
|
+
@host_port = options[:host_port]
|
15
|
+
end
|
16
|
+
|
17
|
+
def send_data(data)
|
18
|
+
puts "Sending data: #{data.inspect}"
|
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
|
+
|
31
|
+
Ganglia::GMetric.send(@host_ip, @host_port.to_i,
|
32
|
+
:spoof => 0,
|
33
|
+
:name => data[:name],
|
34
|
+
:units => data[:units],
|
35
|
+
:type => data_type,
|
36
|
+
:value => data[:value],
|
37
|
+
:tmax => 60,
|
38
|
+
:dmax => 300,
|
39
|
+
)
|
40
|
+
end
|
41
|
+
|
42
|
+
def report(agent)
|
43
|
+
agent.instruments.each do |name, instrument|
|
44
|
+
case instrument
|
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
|
55
|
+
end
|
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"
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
require 'net/https'
|
2
|
+
require 'ruby-metrics/version'
|
3
|
+
require 'ruby-metrics'
|
4
|
+
|
5
|
+
module Metrics
|
6
|
+
module Reporters
|
7
|
+
class Librato
|
8
|
+
attr_reader :api_token
|
9
|
+
attr_reader :user
|
10
|
+
|
11
|
+
API_URL = "https://metrics-api.librato.com/v1"
|
12
|
+
|
13
|
+
def initialize(options = {})
|
14
|
+
@api_token = options[:api_token]
|
15
|
+
@user = options[:user]
|
16
|
+
@headers = {
|
17
|
+
'User-Agent' => "ruby-metrics #{Metrics::VERSION}"
|
18
|
+
}
|
19
|
+
end
|
20
|
+
|
21
|
+
def send_data(post_url, post_data)
|
22
|
+
url = URI.parse(post_url)
|
23
|
+
req = Net::HTTP::Post.new(url.path)
|
24
|
+
req.basic_auth @user, @api_token
|
25
|
+
@headers.each do |k,v|
|
26
|
+
req.add_field(k, v)
|
27
|
+
end
|
28
|
+
req.set_form_data(post_data)
|
29
|
+
https = Net::HTTP.new(url.host, url.port)
|
30
|
+
https.use_ssl = true
|
31
|
+
#https.set_debug_output($stdout)
|
32
|
+
|
33
|
+
https.start do |http|
|
34
|
+
result = http.request(req)
|
35
|
+
case result
|
36
|
+
when Net::HTTPCreated
|
37
|
+
# OK
|
38
|
+
puts "SENT!"
|
39
|
+
else
|
40
|
+
puts "FAILED TO SEND: #{https.inspect}"
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
def report(agent)
|
46
|
+
agent.instruments.each do |name, instrument|
|
47
|
+
measure_time = Time.now.to_i
|
48
|
+
|
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
|
54
|
+
|
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
|
63
|
+
end
|
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"
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
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
|
-
|
10
|
-
self.clear
|
9
|
+
clear
|
11
10
|
end
|
12
11
|
|
13
12
|
def clear
|
14
|
-
@values =
|
13
|
+
@values = { }
|
15
14
|
@start_time = tick
|
16
|
-
@next_scale_time = Time.now.to_f +
|
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.
|
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
|
-
|
36
|
-
if (newcount <= @size)
|
34
|
+
if @count <= @size
|
37
35
|
@values[priority] = value
|
38
36
|
else
|
39
|
-
|
40
|
-
if
|
37
|
+
first_key = @values.keys.first
|
38
|
+
if first_key && first_key < priority
|
41
39
|
@values[priority] = value
|
42
40
|
|
43
|
-
while
|
44
|
-
|
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
|
-
|
51
|
-
|
52
|
-
|
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
|
-
|
82
|
-
|
83
|
-
keys.each do |key|
|
84
|
-
result << @values[key]
|
56
|
+
@values.keys.sort.map do |key|
|
57
|
+
@values[key]
|
85
58
|
end
|
86
|
-
|
87
|
-
|
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
|
-
|
7
|
+
clear
|
9
8
|
end
|
10
|
-
|
9
|
+
|
11
10
|
def clear
|
12
|
-
(0
|
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.
|
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
|
-
|
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
|
-
|
9
|
+
module Microseconds
|
16
10
|
def self.to_nsec(mult = 1)
|
17
11
|
1000 * mult
|
18
12
|
end
|
19
13
|
end
|
20
14
|
|
21
|
-
|
15
|
+
module Milliseconds
|
22
16
|
def self.to_nsec(mult = 1)
|
23
17
|
1000000 * mult
|
24
18
|
end
|
25
19
|
end
|
26
20
|
|
27
|
-
|
21
|
+
module Seconds
|
28
22
|
def self.to_nsec(mult = 1)
|
29
23
|
1000000000 * mult
|
30
24
|
end
|
31
25
|
end
|
32
26
|
|
33
|
-
|
27
|
+
module Minutes
|
34
28
|
def self.to_nsec(mult = 1)
|
35
29
|
60000000000 * mult
|
36
30
|
end
|
37
31
|
end
|
38
32
|
|
39
|
-
|
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
|
-
|
50
|
+
UNITS[unit].to_nsec.to_f * value.to_f
|
57
51
|
end
|
58
52
|
|
59
53
|
def scale_time_units(source, dest)
|
60
|
-
|
54
|
+
UNITS[source].to_nsec.to_f / UNITS[dest].to_nsec.to_f
|
61
55
|
end
|
62
56
|
end
|
63
57
|
end
|
data/lib/ruby-metrics/version.rb
CHANGED
@@ -16,6 +16,6 @@ Gem::Specification.new do |s|
|
|
16
16
|
s.files = ['lib/ruby-metrics/reporters/opentsdb.rb']
|
17
17
|
s.require_paths = ["lib"]
|
18
18
|
|
19
|
-
s.add_dependency "opentsdb", '0.1.0'
|
19
|
+
s.add_dependency "opentsdb", '~> 0.1', '>= 0.1.0'
|
20
20
|
s.add_dependency 'ruby-metrics', Metrics::VERSION
|
21
21
|
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', '~>
|
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'
|
@@ -1,78 +1,88 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe Metrics::Instruments::Counter do
|
4
|
-
|
5
|
-
|
4
|
+
let(:counter) {
|
5
|
+
Metrics::Instruments::Counter.new
|
6
|
+
}
|
7
|
+
|
8
|
+
it 'can be tagged' do
|
9
|
+
counter.tag(:foo, 'bar')
|
10
|
+
expect(counter.tags.keys).to include(:foo)
|
11
|
+
expect(counter.tags.values).to include('bar')
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'does not need to be tagged' do
|
15
|
+
expect(counter.tags.keys.size).to be 0
|
6
16
|
end
|
7
17
|
|
8
|
-
it
|
9
|
-
|
18
|
+
it 'should create a new entity with zero as its value' do
|
19
|
+
counter.to_i.should == 0
|
10
20
|
end
|
11
21
|
|
12
22
|
it "should increment its counter by the value specified" do
|
13
23
|
value = 1
|
14
24
|
lambda do
|
15
|
-
|
16
|
-
end.should change{
|
25
|
+
counter.inc(value)
|
26
|
+
end.should change{ counter.to_i }.by(value)
|
17
27
|
end
|
18
28
|
|
19
29
|
it "should increment its counter by one by default" do
|
20
30
|
lambda do
|
21
|
-
|
22
|
-
end.should change{
|
31
|
+
counter.inc
|
32
|
+
end.should change{ counter.to_i }.by(1)
|
23
33
|
end
|
24
34
|
|
25
35
|
it "should decrement its counter by the value specified" do
|
26
36
|
value = 1
|
27
37
|
lambda do
|
28
|
-
|
29
|
-
end.should change{
|
38
|
+
counter.dec(value)
|
39
|
+
end.should change{ counter.to_i }.by(-value)
|
30
40
|
end
|
31
41
|
|
32
42
|
it "should decrement its counter by one by default" do
|
33
43
|
lambda do
|
34
|
-
|
35
|
-
end.should change{
|
44
|
+
counter.dec
|
45
|
+
end.should change{ counter.to_i }.by(-1)
|
36
46
|
end
|
37
47
|
|
38
48
|
it "should alias #incr to #inc" do
|
39
49
|
lambda do
|
40
|
-
|
41
|
-
end.should change{
|
50
|
+
counter.incr
|
51
|
+
end.should change{ counter.to_i }.by(1)
|
42
52
|
end
|
43
53
|
|
44
54
|
it "should alias #decr to #dec" do
|
45
55
|
lambda do
|
46
|
-
|
47
|
-
end.should change{
|
56
|
+
counter.decr
|
57
|
+
end.should change{ counter.to_i }.by(-1)
|
48
58
|
end
|
49
59
|
|
50
60
|
it "should clear the counter correctly" do
|
51
|
-
|
52
|
-
|
61
|
+
counter.clear
|
62
|
+
counter.to_i.should == 0
|
53
63
|
end
|
54
64
|
|
55
65
|
it "should correctly represent the value as a string" do
|
56
|
-
|
57
|
-
|
58
|
-
|
66
|
+
counter.clear
|
67
|
+
counter.to_i.should == 0
|
68
|
+
counter.to_s.should == "0"
|
59
69
|
end
|
60
70
|
|
61
71
|
it "should return the new count when incrementing" do
|
62
|
-
count =
|
63
|
-
|
72
|
+
count = counter.to_i
|
73
|
+
counter.inc(value = 1).should == count + value
|
64
74
|
end
|
65
75
|
|
66
76
|
it "should return the new count when decrementing" do
|
67
77
|
lambda do
|
68
|
-
|
69
|
-
end.should change{
|
78
|
+
counter.dec(1)
|
79
|
+
end.should change{ counter.to_i }.by(-1)
|
70
80
|
end
|
71
81
|
|
72
82
|
context "to_json" do
|
73
|
-
let(:json) {
|
83
|
+
let(:json) { counter.to_json }
|
74
84
|
it "should serialize to its current value" do
|
75
|
-
json.should ==
|
85
|
+
json.should == counter.to_s
|
76
86
|
end
|
77
87
|
end
|
78
88
|
|
@@ -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.
|
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.
|
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.
|
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.
|
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.
|
73
|
+
app.agent.timer(:_requests).mean.should be_within(length / 10).of(length)
|
74
74
|
end
|
75
|
-
|
76
|
-
[
|
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.
|
81
|
+
end.should change{ app.agent.counter(:"_status_#{status / 100}xx").to_i }.by(1)
|
82
82
|
end
|
83
83
|
end
|
84
84
|
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'ruby-metrics/agent'
|
2
|
+
require 'ruby-metrics/reporter'
|
3
|
+
require 'ruby-metrics/reporters/opentsdb'
|
4
|
+
|
5
|
+
module Metrics
|
6
|
+
describe 'Reporter' do
|
7
|
+
let(:mock_reporter) {
|
8
|
+
double(Metrics::Reporters::OpenTSDBReporter)
|
9
|
+
}
|
10
|
+
|
11
|
+
let(:agent) {
|
12
|
+
agent = Metrics::Agent.new
|
13
|
+
agent.report_to 'opentsdb', mock_reporter
|
14
|
+
agent
|
15
|
+
}
|
16
|
+
|
17
|
+
it 'should report three times in 4 seconds with a 1 second interval' do
|
18
|
+
expect(mock_reporter).to receive(:report).exactly(3).times
|
19
|
+
agent.report_periodically(1)
|
20
|
+
puts "Sleeping"
|
21
|
+
sleep(4)
|
22
|
+
puts "Stopping..."
|
23
|
+
agent.stop_reporting
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
end
|