rubycut-metriks 0.9.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.
@@ -0,0 +1,59 @@
1
+ module Metriks
2
+ class Snapshot
3
+ MEDIAN_Q = 0.5
4
+ P75_Q = 0.75
5
+ P95_Q = 0.95
6
+ P98_Q = 0.98
7
+ P99_Q = 0.99
8
+ P999_Q = 0.999
9
+
10
+ attr_reader :values
11
+
12
+ def initialize(values)
13
+ @values = values.sort
14
+ end
15
+
16
+ def value(quantile)
17
+ raise ArgumentError, "quantile must be between 0.0 and 1.0" if quantile < 0.0 || quantile > 1.0
18
+
19
+ return 0.0 if @values.empty?
20
+
21
+ pos = quantile * (@values.length + 1)
22
+
23
+ return @values.first if pos < 1
24
+ return @values.last if pos >= @values.length
25
+
26
+ lower = @values[pos.to_i - 1]
27
+ upper = @values[pos.to_i]
28
+ lower + (pos - pos.floor) * (upper - lower)
29
+ end
30
+
31
+ def size
32
+ @values.length
33
+ end
34
+
35
+ def median
36
+ value(MEDIAN_Q)
37
+ end
38
+
39
+ def get_75th_percentile
40
+ value(P75_Q)
41
+ end
42
+
43
+ def get_95th_percentile
44
+ value(P95_Q)
45
+ end
46
+
47
+ def get_98th_percentile
48
+ value(P98_Q)
49
+ end
50
+
51
+ def get_99th_percentile
52
+ value(P99_Q)
53
+ end
54
+
55
+ def get_999th_percentile
56
+ value(P999_Q)
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,26 @@
1
+ module Metriks
2
+ class TimeTracker
3
+ def initialize(interval)
4
+ @interval = interval
5
+ @next_time = Time.now.to_f
6
+ end
7
+
8
+ def sleep
9
+ sleep_time = next_time - Time.now.to_f
10
+ if sleep_time > 0
11
+ Kernel.sleep(sleep_time)
12
+ end
13
+ end
14
+
15
+ def now_floored
16
+ time = Time.now.to_i
17
+ time - (time % @interval)
18
+ end
19
+
20
+ def next_time
21
+ now = Time.now.to_f
22
+ @next_time = now if @next_time <= now
23
+ @next_time += @interval - (@next_time % @interval)
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,101 @@
1
+ require 'atomic'
2
+ require 'hitimes'
3
+
4
+ require 'metriks/meter'
5
+ require 'metriks/histogram'
6
+
7
+ module Metriks
8
+ class Timer
9
+ class Context
10
+ def initialize(timer)
11
+ @timer = timer
12
+ @interval = Hitimes::Interval.now
13
+ end
14
+
15
+ def restart
16
+ @interval = Hitimes::Interval.now
17
+ end
18
+
19
+ def stop
20
+ @interval.stop
21
+ @timer.update(@interval.duration)
22
+ end
23
+ end
24
+
25
+ def initialize(histogram = Metriks::Histogram.new_exponentially_decaying)
26
+ @meter = Metriks::Meter.new
27
+ @histogram = histogram
28
+ end
29
+
30
+ def clear
31
+ @meter.clear
32
+ @histogram.clear
33
+ end
34
+
35
+ def update(duration)
36
+ if duration >= 0
37
+ @meter.mark
38
+ @histogram.update(duration)
39
+ end
40
+ end
41
+
42
+ def time(callable = nil, &block)
43
+ callable ||= block
44
+ context = Context.new(self)
45
+
46
+ if callable.nil?
47
+ return context
48
+ end
49
+
50
+ begin
51
+ return callable.call
52
+ ensure
53
+ context.stop
54
+ end
55
+ end
56
+
57
+ def snapshot
58
+ @histogram.snapshot
59
+ end
60
+
61
+ def count
62
+ @histogram.count
63
+ end
64
+
65
+ def one_minute_rate
66
+ @meter.one_minute_rate
67
+ end
68
+
69
+ def five_minute_rate
70
+ @meter.five_minute_rate
71
+ end
72
+
73
+ def fifteen_minute_rate
74
+ @meter.fifteen_minute_rate
75
+ end
76
+
77
+ def mean_rate
78
+ @meter.mean_rate
79
+ end
80
+
81
+ def min
82
+ @histogram.min
83
+ end
84
+
85
+ def max
86
+ @histogram.max
87
+ end
88
+
89
+ def mean
90
+ @histogram.mean
91
+ end
92
+
93
+ def stddev
94
+ @histogram.stddev
95
+ end
96
+
97
+ def stop
98
+ @meter.stop
99
+ end
100
+ end
101
+ end
@@ -0,0 +1,40 @@
1
+ require 'atomic'
2
+ require 'metriks/snapshot'
3
+
4
+ module Metriks
5
+ class UniformSample
6
+ def initialize(reservoir_size)
7
+ @values = Array.new(reservoir_size, 0)
8
+ @count = Atomic.new(0)
9
+ end
10
+
11
+ def clear
12
+ @values.length.times do |idx|
13
+ @values[idx] = 0
14
+ end
15
+ @count.value = 0
16
+ end
17
+
18
+ def size
19
+ count = @count.value
20
+ count > @values.length ? @values.length : count
21
+ end
22
+
23
+ def snapshot
24
+ Snapshot.new(@values.slice(0, size))
25
+ end
26
+
27
+ def update(value)
28
+ new_count = @count.update { |v| v + 1 }
29
+
30
+ if new_count <= @values.length
31
+ @values[new_count - 1] = value
32
+ else
33
+ idx = rand(new_count)
34
+ if idx < @values.length
35
+ @values[idx] = value
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,43 @@
1
+ require 'metriks/timer'
2
+
3
+ module Metriks
4
+ class UtilizationTimer < Metriks::Timer
5
+ def initialize
6
+ super
7
+ @duration_meter = Metriks::Meter.new
8
+ end
9
+
10
+ def clear
11
+ super
12
+ @duration_meter.clear
13
+ end
14
+
15
+ def update(duration)
16
+ super
17
+ if duration >= 0
18
+ @duration_meter.mark(duration)
19
+ end
20
+ end
21
+
22
+ def one_minute_utilization
23
+ @duration_meter.one_minute_rate
24
+ end
25
+
26
+ def five_minute_utilization
27
+ @duration_meter.five_minute_rate
28
+ end
29
+
30
+ def fifteen_minute_utilization
31
+ @duration_meter.fifteen_minute_rate
32
+ end
33
+
34
+ def mean_utilization
35
+ @duration_meter.mean_rate
36
+ end
37
+
38
+ def stop
39
+ super
40
+ @duration_meter.stop
41
+ end
42
+ end
43
+ end
data/lib/metriks.rb ADDED
@@ -0,0 +1,35 @@
1
+
2
+ module Metriks
3
+ VERSION = '0.9.9.4'
4
+
5
+ def self.get(name)
6
+ Metriks::Registry.default.get(name)
7
+ end
8
+
9
+ def self.counter(name)
10
+ Metriks::Registry.default.counter(name)
11
+ end
12
+
13
+ def self.gauge(name, callable = nil, &block)
14
+ Metriks::Registry.default.gauge(name, callable, &block)
15
+ end
16
+
17
+ def self.timer(name)
18
+ Metriks::Registry.default.timer(name)
19
+ end
20
+
21
+ def self.utilization_timer(name)
22
+ Metriks::Registry.default.utilization_timer(name)
23
+ end
24
+
25
+ def self.meter(name)
26
+ Metriks::Registry.default.meter(name)
27
+ end
28
+
29
+ def self.histogram(name)
30
+ Metriks::Registry.default.histogram(name)
31
+ end
32
+ end
33
+
34
+ require 'metriks/registry'
35
+ require 'metriks/reporter/proc_title'
data/metriks.gemspec ADDED
@@ -0,0 +1,100 @@
1
+ ## This is the rakegem gemspec template. Make sure you read and understand
2
+ ## all of the comments. Some sections require modification, and others can
3
+ ## be deleted if you don't need them. Once you understand the contents of
4
+ ## this file, feel free to delete any comments that begin with two hash marks.
5
+ ## You can find comprehensive Gem::Specification documentation, at
6
+ ## http://docs.rubygems.org/read/chapter/20
7
+ Gem::Specification.new do |s|
8
+ s.specification_version = 2 if s.respond_to? :specification_version=
9
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
10
+ s.rubygems_version = '1.3.5'
11
+
12
+ ## Leave these as is they will be modified for you by the rake gemspec task.
13
+ ## If your rubyforge_project name is different, then edit it and comment out
14
+ ## the sub! line in the Rakefile
15
+ s.name = 'rubycut-metriks'
16
+ s.version = '0.9.9.4'
17
+ s.date = '2013-02-22'
18
+
19
+ ## Make sure your summary is short. The description may be as long
20
+ ## as you like.
21
+ s.summary = "An experimental metrics client"
22
+ s.description = "An experimental metrics client."
23
+
24
+ ## List the primary authors. If there are a bunch of authors, it's probably
25
+ ## better to set the email to an email list or something. If you don't have
26
+ ## a custom homepage, consider using your GitHub URL or the like.
27
+ s.authors = ["Eric Lindvall"]
28
+ s.email = 'eric@sevenscale.com'
29
+ s.homepage = 'https://github.com/eric/metriks'
30
+
31
+ ## This gets added to the $LOAD_PATH so that 'lib/NAME.rb' can be required as
32
+ ## require 'NAME.rb' or'/lib/NAME/file.rb' can be as require 'NAME/file.rb'
33
+ s.require_paths = %w[lib]
34
+
35
+ ## Specify any RDoc options here. You'll want to add your README and
36
+ ## LICENSE files to the extra_rdoc_files list.
37
+ s.rdoc_options = ["--charset=UTF-8"]
38
+ s.extra_rdoc_files = %w[README.md LICENSE]
39
+
40
+ ## List your runtime dependencies here. Runtime dependencies are those
41
+ ## that are needed for an end user to actually USE your code.
42
+ s.add_dependency('atomic', ["~> 1.0"])
43
+ s.add_dependency('hitimes', [ "~> 1.1"])
44
+ s.add_dependency('avl_tree', [ "~> 1.1.2" ])
45
+
46
+ ## List your development dependencies here. Development dependencies are
47
+ ## those that are only needed during development
48
+ # s.add_development_dependency('tomdoc', ["~> 0.2"])
49
+ s.add_development_dependency('mocha', ['~> 0.10'])
50
+
51
+ ## Leave this section as-is. It will be automatically generated from the
52
+ ## contents of your Git repository via the gemspec task. DO NOT REMOVE
53
+ ## THE MANIFEST COMMENTS, they are used as delimiters by the task.
54
+ # = MANIFEST =
55
+ s.files = %w[
56
+ Gemfile
57
+ LICENSE
58
+ README.md
59
+ Rakefile
60
+ benchmark/samplers.rb
61
+ lib/metriks.rb
62
+ lib/metriks/counter.rb
63
+ lib/metriks/ewma.rb
64
+ lib/metriks/exponentially_decaying_sample.rb
65
+ lib/metriks/histogram.rb
66
+ lib/metriks/meter.rb
67
+ lib/metriks/registry.rb
68
+ lib/metriks/reporter/graphite.rb
69
+ lib/metriks/reporter/librato_metrics.rb
70
+ lib/metriks/reporter/logger.rb
71
+ lib/metriks/reporter/proc_title.rb
72
+ lib/metriks/reporter/riemann.rb
73
+ lib/metriks/simple_moving_average.rb
74
+ lib/metriks/snapshot.rb
75
+ lib/metriks/time_tracker.rb
76
+ lib/metriks/timer.rb
77
+ lib/metriks/uniform_sample.rb
78
+ lib/metriks/utilization_timer.rb
79
+ metriks.gemspec
80
+ test/counter_test.rb
81
+ test/graphite_reporter_test.rb
82
+ test/histogram_test.rb
83
+ test/librato_metrics_reporter_test.rb
84
+ test/logger_reporter_test.rb
85
+ test/meter_test.rb
86
+ test/metriks_test.rb
87
+ test/proc_title_reporter_test.rb
88
+ test/registry_test.rb
89
+ test/riemann_reporter_test.rb
90
+ test/test_helper.rb
91
+ test/thread_error_handling_tests.rb
92
+ test/timer_test.rb
93
+ test/utilization_timer_test.rb
94
+ ]
95
+ # = MANIFEST =
96
+
97
+ ## Test files will be grabbed from the file list. Make sure the path glob
98
+ ## matches what you actually use.
99
+ s.test_files = s.files.select { |path| path =~ /^test\/.*_test\.rb/ }
100
+ end
@@ -0,0 +1,39 @@
1
+ require 'test_helper'
2
+
3
+ require 'metriks/counter'
4
+
5
+ class CounterTest < Test::Unit::TestCase
6
+ include ThreadHelper
7
+
8
+ def setup
9
+ @counter = Metriks::Counter.new
10
+ end
11
+
12
+ def test_increment
13
+ @counter.increment
14
+
15
+ assert_equal 1, @counter.count
16
+ end
17
+
18
+ def test_increment_threaded
19
+ thread 10, :n => 100 do
20
+ @counter.increment
21
+ end
22
+
23
+ assert_equal 1000, @counter.count
24
+ end
25
+
26
+ def test_increment_by_more
27
+ @counter.increment 10
28
+
29
+ assert_equal 10, @counter.count
30
+ end
31
+
32
+ def test_increment_by_more_threaded
33
+ thread 10, :n => 100 do
34
+ @counter.increment 10
35
+ end
36
+
37
+ assert_equal 10000, @counter.count
38
+ end
39
+ end
@@ -0,0 +1,41 @@
1
+ require 'test_helper'
2
+ require 'thread_error_handling_tests'
3
+
4
+ require 'metriks/reporter/graphite'
5
+
6
+ class GraphiteReporterTest < Test::Unit::TestCase
7
+ include ThreadErrorHandlingTests
8
+
9
+ def build_reporter(options={})
10
+ Metriks::Reporter::Graphite.new('localhost', 3333, { :registry => @registry }.merge(options))
11
+ end
12
+
13
+ def setup
14
+ @registry = Metriks::Registry.new
15
+ @reporter = build_reporter
16
+ @stringio = StringIO.new
17
+
18
+ @reporter.stubs(:socket).returns(@stringio)
19
+ end
20
+
21
+ def teardown
22
+ @reporter.stop
23
+ @registry.stop
24
+ end
25
+
26
+ def test_write
27
+ @registry.meter('meter.testing').mark
28
+ @registry.counter('counter.testing').increment
29
+ @registry.timer('timer.testing').update(1.5)
30
+ @registry.histogram('histogram.testing').update(1.5)
31
+ @registry.utilization_timer('utilization_timer.testing').update(1.5)
32
+ @registry.gauge('gauge.testing').set(123)
33
+ @registry.gauge('gauge.testing.block') { 456 }
34
+
35
+ @reporter.write
36
+
37
+ assert_match /timer.testing.median \d/, @stringio.string
38
+ assert_match /gauge.testing.value 123/, @stringio.string
39
+ assert_match /gauge.testing.block.value 456/, @stringio.string
40
+ end
41
+ end
@@ -0,0 +1,199 @@
1
+ require 'test_helper'
2
+
3
+ require 'metriks/histogram'
4
+
5
+ class HistogramTest < Test::Unit::TestCase
6
+ include ThreadHelper
7
+
8
+ def setup
9
+ end
10
+
11
+ def test_uniform_sample_min
12
+ @histogram = Metriks::Histogram.new(Metriks::UniformSample.new(Metriks::Histogram::DEFAULT_SAMPLE_SIZE))
13
+
14
+ @histogram.update(5)
15
+ @histogram.update(10)
16
+
17
+ assert_equal 5, @histogram.min
18
+ end
19
+
20
+ def test_uniform_sample_max
21
+ @histogram = Metriks::Histogram.new(Metriks::UniformSample.new(Metriks::Histogram::DEFAULT_SAMPLE_SIZE))
22
+
23
+ @histogram.update(5)
24
+ @histogram.update(10)
25
+
26
+ assert_equal 10, @histogram.max
27
+ end
28
+
29
+ def test_uniform_sample_mean
30
+ @histogram = Metriks::Histogram.new(Metriks::UniformSample.new(Metriks::Histogram::DEFAULT_SAMPLE_SIZE))
31
+
32
+ @histogram.update(5)
33
+ @histogram.update(10)
34
+
35
+ assert_equal 7, @histogram.mean
36
+ end
37
+
38
+ def test_uniform_sample_mean_threaded
39
+ @histogram = Metriks::Histogram.new(Metriks::UniformSample.new(Metriks::Histogram::DEFAULT_SAMPLE_SIZE))
40
+
41
+ thread 10, :n => 100 do
42
+ @histogram.update(5)
43
+ @histogram.update(10)
44
+ end
45
+
46
+ assert_equal 7, @histogram.mean
47
+ end
48
+
49
+ def test_uniform_sample_2000
50
+ @histogram = Metriks::Histogram.new(Metriks::UniformSample.new(Metriks::Histogram::DEFAULT_SAMPLE_SIZE))
51
+
52
+ 2000.times do |idx|
53
+ @histogram.update(idx)
54
+ end
55
+
56
+ assert_equal 1999, @histogram.max
57
+ end
58
+
59
+ def test_uniform_sample_2000_threaded
60
+ @histogram = Metriks::Histogram.new(Metriks::UniformSample.new(Metriks::Histogram::DEFAULT_SAMPLE_SIZE))
61
+
62
+ t = 10
63
+ thread t do |i|
64
+ 2000.times do |x|
65
+ if (x % t) == i
66
+ @histogram.update x
67
+ end
68
+ end
69
+ end
70
+
71
+ assert_equal 1999, @histogram.max
72
+ end
73
+
74
+ def test_uniform_sample_snashot
75
+ @histogram = Metriks::Histogram.new(Metriks::UniformSample.new(Metriks::Histogram::DEFAULT_SAMPLE_SIZE))
76
+
77
+ 100.times do |idx|
78
+ @histogram.update(idx)
79
+ end
80
+
81
+ snapshot = @histogram.snapshot
82
+
83
+ assert_equal 49.5, snapshot.median
84
+ end
85
+
86
+ def test_uniform_sample_snapshot_threaded
87
+ @histogram = Metriks::Histogram.new(Metriks::UniformSample.new(Metriks::Histogram::DEFAULT_SAMPLE_SIZE))
88
+
89
+ thread 10 do
90
+ 100.times do |idx|
91
+ @histogram.update(idx)
92
+ end
93
+ end
94
+
95
+ snapshot = @histogram.snapshot
96
+
97
+ assert_equal 49.5, snapshot.median
98
+ end
99
+
100
+ def test_exponential_sample_min
101
+ @histogram = Metriks::Histogram.new(Metriks::ExponentiallyDecayingSample.new(Metriks::Histogram::DEFAULT_SAMPLE_SIZE, Metriks::Histogram::DEFAULT_ALPHA))
102
+
103
+ @histogram.update(5)
104
+ @histogram.update(10)
105
+
106
+ assert_equal 5, @histogram.min
107
+ end
108
+
109
+ def test_exponential_sample_max
110
+ @histogram = Metriks::Histogram.new(Metriks::ExponentiallyDecayingSample.new(Metriks::Histogram::DEFAULT_SAMPLE_SIZE, Metriks::Histogram::DEFAULT_ALPHA))
111
+
112
+ @histogram.update(5)
113
+ @histogram.update(10)
114
+
115
+ assert_equal 10, @histogram.max
116
+ end
117
+
118
+ def test_exponential_sample_mean
119
+ @histogram = Metriks::Histogram.new(Metriks::ExponentiallyDecayingSample.new(Metriks::Histogram::DEFAULT_SAMPLE_SIZE, Metriks::Histogram::DEFAULT_ALPHA))
120
+
121
+ @histogram.update(5)
122
+ @histogram.update(10)
123
+
124
+ assert_equal 7, @histogram.mean
125
+ end
126
+
127
+ def test_exponential_sample_mean_threaded
128
+ @histogram = Metriks::Histogram.new(Metriks::ExponentiallyDecayingSample.new(Metriks::Histogram::DEFAULT_SAMPLE_SIZE, Metriks::Histogram::DEFAULT_ALPHA))
129
+
130
+ thread 10, :n => 100 do
131
+ @histogram.update(5)
132
+ @histogram.update(10)
133
+ end
134
+
135
+ assert_equal 7, @histogram.mean
136
+ end
137
+
138
+ def test_exponential_sample_2000
139
+ @histogram = Metriks::Histogram.new(Metriks::ExponentiallyDecayingSample.new(Metriks::Histogram::DEFAULT_SAMPLE_SIZE, Metriks::Histogram::DEFAULT_ALPHA))
140
+
141
+ 2000.times do |idx|
142
+ @histogram.update(idx)
143
+ end
144
+
145
+ assert_equal 1999, @histogram.max
146
+ end
147
+
148
+ def test_exponential_sample_2000_threaded
149
+ @histogram = Metriks::Histogram.new(Metriks::ExponentiallyDecayingSample.new(Metriks::Histogram::DEFAULT_SAMPLE_SIZE, Metriks::Histogram::DEFAULT_ALPHA))
150
+
151
+ t = 10
152
+ thread t do |i|
153
+ 2000.times do |idx|
154
+ if (idx % t) == i
155
+ @histogram.update(idx)
156
+ end
157
+ end
158
+ end
159
+
160
+ assert_equal 1999, @histogram.max
161
+ end
162
+
163
+ def test_exponential_sample_snashot
164
+ @histogram = Metriks::Histogram.new(Metriks::ExponentiallyDecayingSample.new(Metriks::Histogram::DEFAULT_SAMPLE_SIZE, Metriks::Histogram::DEFAULT_ALPHA))
165
+
166
+ 100.times do |idx|
167
+ @histogram.update(idx)
168
+ end
169
+
170
+ snapshot = @histogram.snapshot
171
+
172
+ assert_equal 49.5, snapshot.median
173
+ end
174
+
175
+ def test_exponential_sample_snapshot_threaded
176
+ @histogram = Metriks::Histogram.new(Metriks::ExponentiallyDecayingSample.new(Metriks::Histogram::DEFAULT_SAMPLE_SIZE, Metriks::Histogram::DEFAULT_ALPHA))
177
+
178
+ thread 10 do
179
+ 100.times do |idx|
180
+ @histogram.update(idx)
181
+ end
182
+ end
183
+
184
+ snapshot = @histogram.snapshot
185
+
186
+ assert_equal 49.5, snapshot.median
187
+ end
188
+
189
+ def test_long_idle_sample
190
+ Time.stubs(:now).returns(Time.at(2000))
191
+ sample = Metriks::ExponentiallyDecayingSample.new(Metriks::Histogram::DEFAULT_SAMPLE_SIZE, Metriks::Histogram::DEFAULT_ALPHA)
192
+ Time.unstub(:now)
193
+ @histogram = Metriks::Histogram.new(sample)
194
+
195
+ @histogram.update(5)
196
+
197
+ assert_equal 5, @histogram.min
198
+ end
199
+ end