drone 0.0.3 → 1.0.1
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/.rvmrc +1 -0
- data/README.md +73 -49
- data/Rakefile +1 -1
- data/examples/simple.rb +10 -11
- data/lib/drone/core.rb +46 -30
- data/lib/drone/metrics/counter.rb +19 -7
- data/lib/drone/metrics/gauge.rb +4 -3
- data/lib/drone/metrics/histogram.rb +47 -26
- data/lib/drone/metrics/meter.rb +36 -16
- data/lib/drone/metrics/metric.rb +16 -0
- data/lib/drone/metrics/timer.rb +26 -19
- data/lib/drone/monitoring.rb +2 -2
- data/lib/drone/storage/base.rb +122 -0
- data/lib/drone/storage/memory.rb +58 -0
- data/lib/drone/utils/ewma.rb +44 -39
- data/lib/drone/utils/exponentially_decaying_sample.rb +61 -51
- data/lib/drone/utils/uniform_sample.rb +43 -28
- data/lib/drone/version.rb +1 -1
- data/specs/metrics/counter_spec.rb +2 -0
- data/specs/metrics/timer_spec.rb +2 -2
- data/specs/unit/ewma_spec.rb +6 -3
- data/specs/unit/exponentially_decaying_sample_spec.rb +6 -3
- data/specs/unit/histogram_spec.rb +6 -2
- data/specs/unit/monitoring_spec.rb +3 -3
- data/specs/unit/uniform_sample_spec.rb +5 -2
- metadata +6 -2
@@ -1,71 +1,81 @@
|
|
1
|
+
require File.expand_path('../../core', __FILE__)
|
1
2
|
|
2
|
-
|
3
|
-
|
4
|
-
|
3
|
+
module Drone
|
4
|
+
class ExponentiallyDecayingSample
|
5
|
+
# 1 hour in ms
|
6
|
+
RESCALE_THRESHOLD = (1 * 60 * 60 * 1000).freeze
|
5
7
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
8
|
+
def initialize(id, reservoir_size, alpha)
|
9
|
+
@id = id
|
10
|
+
@values = Drone::request_hash("#{@id}:values")
|
11
|
+
@count = Drone::request_number("#{@id}:count", 0)
|
12
|
+
@start_time = Drone::request_number("#{@id}:start_time", current_time())
|
13
|
+
@next_scale_time = Drone::request_number("#{@id}:next_scale_time", current_time() + RESCALE_THRESHOLD)
|
14
|
+
|
15
|
+
@alpha = alpha
|
16
|
+
@reservoir_size = reservoir_size
|
17
|
+
end
|
12
18
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
+
def clear
|
20
|
+
@values.clear()
|
21
|
+
@count.set(0)
|
22
|
+
@start_time.set(current_time())
|
23
|
+
@next_scale_time.set( current_time() + RESCALE_THRESHOLD )
|
24
|
+
end
|
19
25
|
|
20
|
-
|
21
|
-
|
22
|
-
|
26
|
+
def size
|
27
|
+
count = @count.get
|
28
|
+
(@values.size < count) ? @values.size : count
|
29
|
+
end
|
23
30
|
|
24
31
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
@values[priority] = val
|
30
|
-
else
|
31
|
-
first = @values.keys.min
|
32
|
-
if first < priority
|
32
|
+
def update(val, time = current_time)
|
33
|
+
priority = weight(time - @start_time.get) / rand()
|
34
|
+
count = @count.inc
|
35
|
+
if count <= @reservoir_size
|
33
36
|
@values[priority] = val
|
34
|
-
|
35
|
-
|
37
|
+
else
|
38
|
+
first = @values.keys.min
|
39
|
+
if first < priority
|
40
|
+
@values[priority] = val
|
41
|
+
while @values.delete(first) == nil
|
42
|
+
first = @values.keys.min
|
43
|
+
end
|
36
44
|
end
|
37
45
|
end
|
38
|
-
end
|
39
46
|
|
40
|
-
|
41
|
-
|
42
|
-
|
47
|
+
now = current_time()
|
48
|
+
if now >= @next_scale_time.get
|
49
|
+
rescale(now)
|
50
|
+
end
|
43
51
|
end
|
44
|
-
end
|
45
52
|
|
46
|
-
|
47
|
-
|
48
|
-
|
53
|
+
def values
|
54
|
+
@values.keys.sort.inject([]) do |buff, key|
|
55
|
+
buff << @values[key]
|
56
|
+
end
|
57
|
+
end
|
49
58
|
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
59
|
+
def rescale(now)
|
60
|
+
@next_scale_time.set( current_time() + RESCALE_THRESHOLD )
|
61
|
+
new_start = current_time()
|
62
|
+
old_start = @start_time.get_and_set(new_start)
|
54
63
|
|
55
|
-
|
56
|
-
|
57
|
-
|
64
|
+
@values = Hash[ @values.map{ |k,v|
|
65
|
+
[k * Math.exp(-@alpha * (new_start - old_start)), v]
|
66
|
+
}]
|
58
67
|
|
59
|
-
|
68
|
+
end
|
60
69
|
|
61
|
-
private
|
70
|
+
private
|
62
71
|
|
63
|
-
|
64
|
-
|
65
|
-
|
72
|
+
def current_time
|
73
|
+
Time.now.to_f * 1000
|
74
|
+
end
|
66
75
|
|
67
|
-
|
68
|
-
|
69
|
-
|
76
|
+
def weight(n)
|
77
|
+
Math.exp(@alpha * n)
|
78
|
+
end
|
70
79
|
|
80
|
+
end
|
71
81
|
end
|
@@ -1,37 +1,52 @@
|
|
1
|
-
|
1
|
+
require File.expand_path('../../core', __FILE__)
|
2
|
+
|
3
|
+
module Drone
|
4
|
+
class UniformSample
|
5
|
+
|
6
|
+
##
|
7
|
+
# Create a new instance.
|
8
|
+
#
|
9
|
+
# @param [String] id A string which will be used by distributed
|
10
|
+
# storage backend to use the same value for all instances with
|
11
|
+
# the same id
|
12
|
+
# @param [Number] size The size of the requested array
|
13
|
+
#
|
14
|
+
def initialize(id, size)
|
15
|
+
@id = id
|
16
|
+
@values = Drone::request_fixed_size_array("#{id}:values", size, 0)
|
17
|
+
@count = Drone::request_number("#{id}:count", 0)
|
18
|
+
end
|
2
19
|
|
3
|
-
|
4
|
-
@values
|
5
|
-
|
6
|
-
|
20
|
+
# def clear
|
21
|
+
# @values.size.times do |n|
|
22
|
+
# @values[n] = 0
|
23
|
+
# end
|
24
|
+
#
|
25
|
+
# @count.set(0)
|
26
|
+
# end
|
7
27
|
|
8
|
-
|
9
|
-
|
10
|
-
@values
|
28
|
+
def size
|
29
|
+
c = @count.get
|
30
|
+
(c > @values.size) ? @values.size : c
|
11
31
|
end
|
12
|
-
|
13
|
-
@count = 0
|
14
|
-
end
|
15
32
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
if r < @values.size
|
27
|
-
@values[r] = val
|
33
|
+
def update(val)
|
34
|
+
@count.inc
|
35
|
+
count = @count.get
|
36
|
+
if count <= @values.size
|
37
|
+
@values[count - 1] = val
|
38
|
+
else
|
39
|
+
r = rand(2**64 - 1) % count
|
40
|
+
if r < @values.size
|
41
|
+
@values[r] = val
|
42
|
+
end
|
28
43
|
end
|
29
44
|
end
|
30
|
-
end
|
31
45
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
46
|
+
def values
|
47
|
+
# only return @count elements
|
48
|
+
@values[0,@count.get]
|
49
|
+
end
|
36
50
|
|
51
|
+
end
|
37
52
|
end
|
data/lib/drone/version.rb
CHANGED
data/specs/metrics/timer_spec.rb
CHANGED
@@ -11,7 +11,7 @@ EM.describe 'Timer Metrics' do
|
|
11
11
|
|
12
12
|
describe "A blank timer" do
|
13
13
|
before do
|
14
|
-
@timer = Metrics::Timer.new()
|
14
|
+
@timer = Metrics::Timer.new('id')
|
15
15
|
end
|
16
16
|
|
17
17
|
should "have a max of zero" do
|
@@ -59,7 +59,7 @@ EM.describe 'Timer Metrics' do
|
|
59
59
|
|
60
60
|
describe "Timing a series of events" do
|
61
61
|
before do
|
62
|
-
@timer = Metrics::Timer.new()
|
62
|
+
@timer = Metrics::Timer.new('id')
|
63
63
|
@timer.update(10)
|
64
64
|
@timer.update(20)
|
65
65
|
@timer.update(20)
|
data/specs/unit/ewma_spec.rb
CHANGED
@@ -3,10 +3,13 @@ require File.expand_path('../../common', __FILE__)
|
|
3
3
|
require 'drone/utils/ewma'
|
4
4
|
|
5
5
|
describe 'EWMA' do
|
6
|
+
before do
|
7
|
+
Drone::init_drone
|
8
|
+
end
|
6
9
|
|
7
10
|
describe 'A 1min EWMA with a value of 3' do
|
8
11
|
before do
|
9
|
-
@ewma = EWMA.one_minute_ewma
|
12
|
+
@ewma = Drone::EWMA.one_minute_ewma('id2')
|
10
13
|
@ewma.update(3)
|
11
14
|
@ewma.tick()
|
12
15
|
end
|
@@ -52,7 +55,7 @@ describe 'EWMA' do
|
|
52
55
|
|
53
56
|
describe 'A 5min EWMA with a value of 3' do
|
54
57
|
before do
|
55
|
-
@ewma = EWMA.five_minutes_ewma
|
58
|
+
@ewma = Drone::EWMA.five_minutes_ewma('id1')
|
56
59
|
@ewma.update(3)
|
57
60
|
@ewma.tick()
|
58
61
|
end
|
@@ -95,7 +98,7 @@ describe 'EWMA' do
|
|
95
98
|
|
96
99
|
describe 'A 15min EWMA with a value of 3' do
|
97
100
|
before do
|
98
|
-
@ewma = EWMA.fifteen_minutes_ewma
|
101
|
+
@ewma = Drone::EWMA.fifteen_minutes_ewma('id')
|
99
102
|
@ewma.update(3)
|
100
103
|
@ewma.tick()
|
101
104
|
end
|
@@ -1,12 +1,15 @@
|
|
1
1
|
require File.expand_path('../../common', __FILE__)
|
2
2
|
|
3
3
|
require 'drone/utils/exponentially_decaying_sample'
|
4
|
+
include Drone
|
4
5
|
|
5
6
|
describe 'Exponentially Decaying Sample' do
|
6
7
|
describe "A sample of 100 out of 1000 elements" do
|
7
8
|
before do
|
9
|
+
Drone::init_drone(nil, Storage::Memory.new)
|
10
|
+
|
8
11
|
@population = (0...100)
|
9
|
-
@sample = ExponentiallyDecayingSample.new(1000, 0.99)
|
12
|
+
@sample = ExponentiallyDecayingSample.new('id1', 1000, 0.99)
|
10
13
|
@population.step(1){|n| @sample.update(n) }
|
11
14
|
end
|
12
15
|
|
@@ -27,7 +30,7 @@ describe 'Exponentially Decaying Sample' do
|
|
27
30
|
describe "A sample of 100 out of 10 elements" do
|
28
31
|
before do
|
29
32
|
@population = (0...10)
|
30
|
-
@sample = ExponentiallyDecayingSample.new(100, 0.99)
|
33
|
+
@sample = ExponentiallyDecayingSample.new('id1', 100, 0.99)
|
31
34
|
@population.step(1){|n| @sample.update(n) }
|
32
35
|
end
|
33
36
|
|
@@ -47,7 +50,7 @@ describe 'Exponentially Decaying Sample' do
|
|
47
50
|
describe "A heavily-biased sample of 100 out of 1000 elements" do
|
48
51
|
before do
|
49
52
|
@population = (0...100)
|
50
|
-
@sample = ExponentiallyDecayingSample.new(1000, 0.99)
|
53
|
+
@sample = ExponentiallyDecayingSample.new('id1', 1000, 0.99)
|
51
54
|
@population.step(1){|n| @sample.update(n) }
|
52
55
|
end
|
53
56
|
|
@@ -5,9 +5,13 @@ require 'drone/metrics/histogram'
|
|
5
5
|
include Drone
|
6
6
|
|
7
7
|
describe 'Histogram' do
|
8
|
+
before do
|
9
|
+
Drone::init_drone()
|
10
|
+
end
|
11
|
+
|
8
12
|
describe "A histogram with zero recorded valeus" do
|
9
13
|
before do
|
10
|
-
@histogram = Histogram.new(UniformSample.new(100))
|
14
|
+
@histogram = Histogram.new("id1", UniformSample.new("id1:sample", 100))
|
11
15
|
end
|
12
16
|
|
13
17
|
should "have a count of 0" do
|
@@ -46,7 +50,7 @@ describe 'Histogram' do
|
|
46
50
|
|
47
51
|
describe "A histogram of the numbers 1 through 10000" do
|
48
52
|
before do
|
49
|
-
@histogram = Histogram.new( UniformSample.new(100000) )
|
53
|
+
@histogram = Histogram.new("id1", UniformSample.new("id1:sample", 100000) )
|
50
54
|
(1..10000).each{|n| @histogram.update(n) }
|
51
55
|
end
|
52
56
|
|
@@ -93,7 +93,7 @@ EM.describe 'Monitoring' do
|
|
93
93
|
|
94
94
|
should 'time call with no args' do
|
95
95
|
Drone::Metrics::Timer.any_instance.expects(:update).with{|delay|
|
96
|
-
delay.should.be.close?(0, 0.
|
96
|
+
delay.should.be.close?(0, 0.1)
|
97
97
|
true
|
98
98
|
}
|
99
99
|
|
@@ -104,7 +104,7 @@ EM.describe 'Monitoring' do
|
|
104
104
|
|
105
105
|
should 'time call with args' do
|
106
106
|
Drone::Metrics::Timer.any_instance.expects(:update).with{|delay|
|
107
|
-
delay.should.be.close?(0, 0.
|
107
|
+
delay.should.be.close?(0, 0.1)
|
108
108
|
true
|
109
109
|
}
|
110
110
|
|
@@ -115,7 +115,7 @@ EM.describe 'Monitoring' do
|
|
115
115
|
|
116
116
|
should 'time call with a block' do
|
117
117
|
Drone::Metrics::Timer.any_instance.expects(:update).with{|delay|
|
118
|
-
delay.should.be.close?(0, 0.
|
118
|
+
delay.should.be.close?(0, 0.1)
|
119
119
|
true
|
120
120
|
}
|
121
121
|
|
@@ -1,12 +1,15 @@
|
|
1
1
|
require File.expand_path('../../common', __FILE__)
|
2
2
|
|
3
3
|
require 'drone/utils/uniform_sample'
|
4
|
+
include Drone
|
4
5
|
|
5
6
|
describe 'EWMA' do
|
6
7
|
describe "A sample of 100 out of 1000 elements" do
|
7
8
|
before do
|
9
|
+
Drone::init_drone()
|
10
|
+
|
8
11
|
@population = (0...1000)
|
9
|
-
@sample = UniformSample.new(100)
|
12
|
+
@sample = UniformSample.new('id1', 100)
|
10
13
|
@population.step(1){|n| @sample.update(n) }
|
11
14
|
end
|
12
15
|
|
@@ -24,7 +27,7 @@ describe 'EWMA' do
|
|
24
27
|
describe "A sample of 100 out of 10 elements" do
|
25
28
|
before do
|
26
29
|
@population = (0...10)
|
27
|
-
@sample = UniformSample.new(100)
|
30
|
+
@sample = UniformSample.new('id1', 100)
|
28
31
|
@population.step(1){|n| @sample.update(n) }
|
29
32
|
end
|
30
33
|
|
metadata
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
name: drone
|
3
3
|
version: !ruby/object:Gem::Version
|
4
4
|
prerelease:
|
5
|
-
version:
|
5
|
+
version: 1.0.1
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Julien Ammous
|
@@ -10,7 +10,7 @@ autorequire:
|
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
12
|
|
13
|
-
date: 2011-
|
13
|
+
date: 2011-05-09 00:00:00 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: eventmachine
|
@@ -89,6 +89,7 @@ extra_rdoc_files: []
|
|
89
89
|
|
90
90
|
files:
|
91
91
|
- .gitignore
|
92
|
+
- .rvmrc
|
92
93
|
- .yardopts
|
93
94
|
- Gemfile
|
94
95
|
- LICENSE
|
@@ -104,9 +105,12 @@ files:
|
|
104
105
|
- lib/drone/metrics/gauge.rb
|
105
106
|
- lib/drone/metrics/histogram.rb
|
106
107
|
- lib/drone/metrics/meter.rb
|
108
|
+
- lib/drone/metrics/metric.rb
|
107
109
|
- lib/drone/metrics/timer.rb
|
108
110
|
- lib/drone/monitoring.rb
|
109
111
|
- lib/drone/schedulers/eventmachine.rb
|
112
|
+
- lib/drone/storage/base.rb
|
113
|
+
- lib/drone/storage/memory.rb
|
110
114
|
- lib/drone/utils/ewma.rb
|
111
115
|
- lib/drone/utils/exponentially_decaying_sample.rb
|
112
116
|
- lib/drone/utils/uniform_sample.rb
|