rubycut-metriks 0.9.9.4

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