drone 1.0.1 → 1.0.2
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.
- metadata +3 -41
- data/.gitignore +0 -8
- data/.rvmrc +0 -1
- data/.yardopts +0 -1
- data/Gemfile +0 -4
- data/LICENSE +0 -20
- data/README.md +0 -162
- data/Rakefile +0 -20
- data/drone.gemspec +0 -29
- data/examples/simple.rb +0 -50
- data/lib/drone.rb +0 -23
- data/lib/drone/core.rb +0 -141
- data/lib/drone/interfaces/base.rb +0 -17
- data/lib/drone/interfaces/console.rb +0 -82
- data/lib/drone/metrics/counter.rb +0 -40
- data/lib/drone/metrics/gauge.rb +0 -25
- data/lib/drone/metrics/histogram.rb +0 -153
- data/lib/drone/metrics/meter.rb +0 -82
- data/lib/drone/metrics/metric.rb +0 -16
- data/lib/drone/metrics/timer.rb +0 -57
- data/lib/drone/monitoring.rb +0 -107
- data/lib/drone/schedulers/eventmachine.rb +0 -70
- data/lib/drone/storage/base.rb +0 -122
- data/lib/drone/storage/memory.rb +0 -58
- data/lib/drone/utils/ewma.rb +0 -55
- data/lib/drone/utils/exponentially_decaying_sample.rb +0 -81
- data/lib/drone/utils/uniform_sample.rb +0 -52
- data/lib/drone/version.rb +0 -3
- data/specs/all.rb +0 -11
- data/specs/common.rb +0 -63
- data/specs/metrics/counter_spec.rb +0 -43
- data/specs/metrics/gauge_spec.rb +0 -28
- data/specs/metrics/meter_spec.rb +0 -61
- data/specs/metrics/timer_spec.rb +0 -111
- data/specs/schedulers/eventmachine_spec.rb +0 -76
- data/specs/unit/ewma_spec.rb +0 -141
- data/specs/unit/exponentially_decaying_sample_spec.rb +0 -86
- data/specs/unit/histogram_spec.rb +0 -91
- data/specs/unit/monitoring_spec.rb +0 -129
- data/specs/unit/uniform_sample_spec.rb +0 -46
data/lib/drone/monitoring.rb
DELETED
@@ -1,107 +0,0 @@
|
|
1
|
-
require File.expand_path('../metrics/meter', __FILE__)
|
2
|
-
require File.expand_path('../metrics/timer', __FILE__)
|
3
|
-
|
4
|
-
module Drone
|
5
|
-
##
|
6
|
-
# This module contains what is needed to instruments
|
7
|
-
# class methods easily
|
8
|
-
#
|
9
|
-
module Monitoring
|
10
|
-
def self.included(base)
|
11
|
-
base.class_eval do
|
12
|
-
extend ClassMethods
|
13
|
-
end
|
14
|
-
|
15
|
-
Drone::register_monitored_class(base)
|
16
|
-
end
|
17
|
-
|
18
|
-
module ClassMethods
|
19
|
-
# external API
|
20
|
-
|
21
|
-
##
|
22
|
-
# Monitor the call rate of the following method
|
23
|
-
#
|
24
|
-
# @param [String] name metric name, it must be unique and will be shared
|
25
|
-
# among all the objects of this class
|
26
|
-
# @api public
|
27
|
-
#
|
28
|
-
def monitor_rate(name)
|
29
|
-
meter = Drone::find_metric(name) || Metrics::Meter.new(name)
|
30
|
-
unless meter.is_a?(Metrics::Meter)
|
31
|
-
raise(TypeError, "metric #{name} is already defined as #{rate.class}")
|
32
|
-
end
|
33
|
-
|
34
|
-
Drone::register_metric(meter)
|
35
|
-
@_rate_waiting = meter
|
36
|
-
end
|
37
|
-
|
38
|
-
##
|
39
|
-
# Monitor the time of execution as well as the
|
40
|
-
# call rate
|
41
|
-
#
|
42
|
-
# @param [String] name metric name, it must be unique and will be shared
|
43
|
-
# among all the objects of this class
|
44
|
-
#
|
45
|
-
# @api public
|
46
|
-
#
|
47
|
-
def monitor_time(name)
|
48
|
-
timer = Drone::find_metric(name) || Metrics::Timer.new(name)
|
49
|
-
unless timer.is_a?(Metrics::Timer)
|
50
|
-
raise(TypeError, "metric #{name} is already defined as #{rate.class}")
|
51
|
-
end
|
52
|
-
Drone::register_metric(timer)
|
53
|
-
@_timer_waiting = timer
|
54
|
-
end
|
55
|
-
|
56
|
-
|
57
|
-
# internals
|
58
|
-
|
59
|
-
##
|
60
|
-
# @private
|
61
|
-
#
|
62
|
-
def method_added(m)
|
63
|
-
return if @_ignore_added
|
64
|
-
|
65
|
-
@_ignore_added = true
|
66
|
-
ma_rate_meter(m) if @_rate_waiting
|
67
|
-
ma_timer_meter(m) if @_timer_waiting
|
68
|
-
@_ignore_added = false
|
69
|
-
end
|
70
|
-
|
71
|
-
##
|
72
|
-
# @private
|
73
|
-
#
|
74
|
-
def ma_rate_meter(m)
|
75
|
-
rate = @_rate_waiting
|
76
|
-
@_rate_waiting = nil
|
77
|
-
|
78
|
-
define_method("#{m}_with_meter") do |*args, &block|
|
79
|
-
rate.mark()
|
80
|
-
send("#{m}_without_meter", *args, &block)
|
81
|
-
end
|
82
|
-
|
83
|
-
alias_method "#{m}_without_meter", m
|
84
|
-
alias_method m, "#{m}_with_meter"
|
85
|
-
end
|
86
|
-
|
87
|
-
##
|
88
|
-
# @private
|
89
|
-
#
|
90
|
-
def ma_timer_meter(m)
|
91
|
-
timer = @_timer_waiting
|
92
|
-
@_timer_waiting = nil
|
93
|
-
|
94
|
-
define_method("#{m}_with_timer") do |*args, &block|
|
95
|
-
timer.time do
|
96
|
-
send("#{m}_without_timer", *args, &block)
|
97
|
-
end
|
98
|
-
end
|
99
|
-
|
100
|
-
alias_method "#{m}_without_timer", m
|
101
|
-
alias_method m, "#{m}_with_timer"
|
102
|
-
end
|
103
|
-
|
104
|
-
end
|
105
|
-
|
106
|
-
end
|
107
|
-
end
|
@@ -1,70 +0,0 @@
|
|
1
|
-
require 'eventmachine'
|
2
|
-
|
3
|
-
module Drone
|
4
|
-
module Schedulers
|
5
|
-
module EMScheduler
|
6
|
-
|
7
|
-
@started = false
|
8
|
-
@timers_once = []
|
9
|
-
@timers_periodic = []
|
10
|
-
|
11
|
-
##
|
12
|
-
# Schedule a block to be called immediatly and after
|
13
|
-
# that at a specified interval
|
14
|
-
#
|
15
|
-
# @param [Number] delay the interval
|
16
|
-
#
|
17
|
-
def self.schedule_periodic(delay, &block)
|
18
|
-
raise "Block required" unless block
|
19
|
-
if @started
|
20
|
-
block.call()
|
21
|
-
EM::add_periodic_timer(delay, &block)
|
22
|
-
else
|
23
|
-
@timers_periodic << [delay, block]
|
24
|
-
end
|
25
|
-
end
|
26
|
-
|
27
|
-
|
28
|
-
##
|
29
|
-
# Schedule a block to be called after a specified
|
30
|
-
# delay
|
31
|
-
#
|
32
|
-
# @param [Number] delay the interval
|
33
|
-
#
|
34
|
-
def self.schedule_once(delay, &block)
|
35
|
-
raise "Block required" unless block
|
36
|
-
if @started
|
37
|
-
EM::add_timer(delay, &block)
|
38
|
-
else
|
39
|
-
@timers_once << [delay, block]
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
|
-
|
44
|
-
##
|
45
|
-
# Start the timers.
|
46
|
-
#
|
47
|
-
def self.start
|
48
|
-
@started = true
|
49
|
-
@timers_once.each do |(delay, block)|
|
50
|
-
schedule_once(delay, &block)
|
51
|
-
end
|
52
|
-
|
53
|
-
@timers_periodic.each do |(delay, block)|
|
54
|
-
schedule_periodic(delay, &block)
|
55
|
-
end
|
56
|
-
|
57
|
-
end
|
58
|
-
|
59
|
-
##
|
60
|
-
# @private
|
61
|
-
#
|
62
|
-
def self.reset
|
63
|
-
@timers_once.clear()
|
64
|
-
@timers_periodic.clear()
|
65
|
-
@started = false
|
66
|
-
end
|
67
|
-
|
68
|
-
end
|
69
|
-
end
|
70
|
-
end
|
data/lib/drone/storage/base.rb
DELETED
@@ -1,122 +0,0 @@
|
|
1
|
-
module Drone
|
2
|
-
module Storage
|
3
|
-
|
4
|
-
##
|
5
|
-
# Represents a number but procide a specific api
|
6
|
-
# allowing this number to shared anywhere
|
7
|
-
#
|
8
|
-
class SharedNumber
|
9
|
-
##
|
10
|
-
# Constructor
|
11
|
-
#
|
12
|
-
# @param [Number] initial_value The initial value
|
13
|
-
#
|
14
|
-
def initialize(initial_value)
|
15
|
-
raise "needs to be redefined"
|
16
|
-
end
|
17
|
-
|
18
|
-
##
|
19
|
-
# Increment the value
|
20
|
-
#
|
21
|
-
# @param [Number] n Increment by n
|
22
|
-
#
|
23
|
-
def inc(n = 1)
|
24
|
-
raise "needs to be redefined"
|
25
|
-
end
|
26
|
-
|
27
|
-
##
|
28
|
-
# Decrement the value
|
29
|
-
#
|
30
|
-
# @param [Number] n Decrement by n
|
31
|
-
#
|
32
|
-
def dec(n = 1)
|
33
|
-
raise "needs to be redefined"
|
34
|
-
end
|
35
|
-
|
36
|
-
##
|
37
|
-
# Set the value
|
38
|
-
#
|
39
|
-
# @param [Number] n The new value
|
40
|
-
#
|
41
|
-
def set(n)
|
42
|
-
raise "needs to be redefined"
|
43
|
-
end
|
44
|
-
|
45
|
-
##
|
46
|
-
# Get the current value
|
47
|
-
#
|
48
|
-
# @return [Number] The current value
|
49
|
-
#
|
50
|
-
def get
|
51
|
-
raise "needs to be redefined"
|
52
|
-
end
|
53
|
-
|
54
|
-
##
|
55
|
-
# Set a new value and return the old one
|
56
|
-
#
|
57
|
-
# @param [Number] n The new value
|
58
|
-
#
|
59
|
-
# @return [Number] The old value
|
60
|
-
#
|
61
|
-
def get_and_set(n)
|
62
|
-
raise "needs to be redefined"
|
63
|
-
end
|
64
|
-
|
65
|
-
##
|
66
|
-
# Set the new value but only if the current value
|
67
|
-
# is equal to expected.
|
68
|
-
#
|
69
|
-
# @param [Number] expected The expected current value
|
70
|
-
# @param [Number] new_value The new value
|
71
|
-
#
|
72
|
-
def compare_and_set(expected, new_value)
|
73
|
-
raise "needs to be redefined"
|
74
|
-
end
|
75
|
-
|
76
|
-
end
|
77
|
-
|
78
|
-
class Base
|
79
|
-
|
80
|
-
##
|
81
|
-
# Request a fixed size array.
|
82
|
-
#
|
83
|
-
# @param [String] id Any string which makes sense in the context
|
84
|
-
# @param [Number] size The Array size
|
85
|
-
# @param [Number] initial_value The default value for the cells
|
86
|
-
#
|
87
|
-
# @return [Object] Returns an object which share the same external interface as
|
88
|
-
# the Array class
|
89
|
-
#
|
90
|
-
def request_fixed_size_array(id, size, initial_value = nil)
|
91
|
-
raise "needs to be redefined"
|
92
|
-
end
|
93
|
-
|
94
|
-
##
|
95
|
-
# Request a hash.
|
96
|
-
#
|
97
|
-
# @param [String] id Any string which makes sense in the context
|
98
|
-
#
|
99
|
-
# @return [Object] Returns an object which share the same external interface as
|
100
|
-
# the Hash class
|
101
|
-
#
|
102
|
-
def request_hash(id)
|
103
|
-
raise "needs to be redefined"
|
104
|
-
end
|
105
|
-
|
106
|
-
##
|
107
|
-
# Request a number "slot".
|
108
|
-
#
|
109
|
-
# @param [String] id Any string which makes sense in the context
|
110
|
-
# @param [Number] initial_value The intial value
|
111
|
-
#
|
112
|
-
# @return [SharedNumber] An intance of a class inheriting SharedNumber
|
113
|
-
#
|
114
|
-
# @see SharedNumber
|
115
|
-
#
|
116
|
-
def request_number(id, initial_value = 0)
|
117
|
-
raise "needs to be redefined"
|
118
|
-
end
|
119
|
-
end
|
120
|
-
|
121
|
-
end
|
122
|
-
end
|
data/lib/drone/storage/memory.rb
DELETED
@@ -1,58 +0,0 @@
|
|
1
|
-
require File.expand_path('../base', __FILE__)
|
2
|
-
|
3
|
-
module Drone
|
4
|
-
module Storage
|
5
|
-
|
6
|
-
class Memory < Base
|
7
|
-
|
8
|
-
class MemorySharedNumber
|
9
|
-
def initialize(initial_value)
|
10
|
-
@store = initial_value
|
11
|
-
end
|
12
|
-
|
13
|
-
def inc(n = 1)
|
14
|
-
@store += n
|
15
|
-
end
|
16
|
-
|
17
|
-
def dec(n = 1)
|
18
|
-
@store -= n
|
19
|
-
end
|
20
|
-
|
21
|
-
def set(n)
|
22
|
-
@store = n
|
23
|
-
end
|
24
|
-
|
25
|
-
def get
|
26
|
-
@store
|
27
|
-
end
|
28
|
-
|
29
|
-
def get_and_set(n)
|
30
|
-
ret = @store
|
31
|
-
set(n)
|
32
|
-
ret
|
33
|
-
end
|
34
|
-
|
35
|
-
def compare_and_set(expected, new_value)
|
36
|
-
# dummy implementation, with memory storage nothing can
|
37
|
-
# happen to our data
|
38
|
-
set(new_value)
|
39
|
-
end
|
40
|
-
|
41
|
-
end
|
42
|
-
|
43
|
-
def request_fixed_size_array(id, size, initial_value = nil)
|
44
|
-
Array.new(size, initial_value)
|
45
|
-
end
|
46
|
-
|
47
|
-
def request_hash(id)
|
48
|
-
Hash.new
|
49
|
-
end
|
50
|
-
|
51
|
-
def request_number(id, initial_value = 0)
|
52
|
-
MemorySharedNumber.new(initial_value)
|
53
|
-
end
|
54
|
-
|
55
|
-
end
|
56
|
-
|
57
|
-
end
|
58
|
-
end
|
data/lib/drone/utils/ewma.rb
DELETED
@@ -1,55 +0,0 @@
|
|
1
|
-
require File.expand_path('../../core', __FILE__)
|
2
|
-
|
3
|
-
module Drone
|
4
|
-
class EWMA
|
5
|
-
M1_ALPHA = (1 - Math.exp(-5 / 60.0)).freeze
|
6
|
-
M5_ALPHA = (1 - Math.exp(-5 / 60.0 / 5)).freeze
|
7
|
-
M15_ALPHA = (1 - Math.exp(-5 / 60.0 / 15)).freeze
|
8
|
-
|
9
|
-
def self.one_minute_ewma(id)
|
10
|
-
new(id, M1_ALPHA, 5000)
|
11
|
-
end
|
12
|
-
|
13
|
-
def self.five_minutes_ewma(id)
|
14
|
-
new(id, M5_ALPHA, 5000)
|
15
|
-
end
|
16
|
-
|
17
|
-
def self.fifteen_minutes_ewma(id)
|
18
|
-
new(id, M15_ALPHA, 5000)
|
19
|
-
end
|
20
|
-
|
21
|
-
|
22
|
-
# interval: in ms
|
23
|
-
def initialize(name, alpha, interval)
|
24
|
-
@alpha = alpha
|
25
|
-
@interval = interval.to_f # * (1000*1000)
|
26
|
-
@uncounted = Drone::request_number("#{name}:uncounted", 0)
|
27
|
-
@rate = Drone::request_number("#{name}:rate", nil)
|
28
|
-
end
|
29
|
-
|
30
|
-
def update(n)
|
31
|
-
@uncounted.inc(n)
|
32
|
-
end
|
33
|
-
|
34
|
-
def tick()
|
35
|
-
count = @uncounted.get_and_set(0)
|
36
|
-
|
37
|
-
instant_rate = count / @interval
|
38
|
-
rate = @rate.get
|
39
|
-
|
40
|
-
if rate
|
41
|
-
@rate.inc( @alpha * (instant_rate - rate) )
|
42
|
-
else
|
43
|
-
@rate.set( instant_rate )
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
def rate(as = :seconds)
|
48
|
-
case as
|
49
|
-
when :ms then @rate.get
|
50
|
-
when :seconds then @rate.get * 1000
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
|
-
end
|
55
|
-
end
|
@@ -1,81 +0,0 @@
|
|
1
|
-
require File.expand_path('../../core', __FILE__)
|
2
|
-
|
3
|
-
module Drone
|
4
|
-
class ExponentiallyDecayingSample
|
5
|
-
# 1 hour in ms
|
6
|
-
RESCALE_THRESHOLD = (1 * 60 * 60 * 1000).freeze
|
7
|
-
|
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
|
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
|
25
|
-
|
26
|
-
def size
|
27
|
-
count = @count.get
|
28
|
-
(@values.size < count) ? @values.size : count
|
29
|
-
end
|
30
|
-
|
31
|
-
|
32
|
-
def update(val, time = current_time)
|
33
|
-
priority = weight(time - @start_time.get) / rand()
|
34
|
-
count = @count.inc
|
35
|
-
if count <= @reservoir_size
|
36
|
-
@values[priority] = val
|
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
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
now = current_time()
|
48
|
-
if now >= @next_scale_time.get
|
49
|
-
rescale(now)
|
50
|
-
end
|
51
|
-
end
|
52
|
-
|
53
|
-
def values
|
54
|
-
@values.keys.sort.inject([]) do |buff, key|
|
55
|
-
buff << @values[key]
|
56
|
-
end
|
57
|
-
end
|
58
|
-
|
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)
|
63
|
-
|
64
|
-
@values = Hash[ @values.map{ |k,v|
|
65
|
-
[k * Math.exp(-@alpha * (new_start - old_start)), v]
|
66
|
-
}]
|
67
|
-
|
68
|
-
end
|
69
|
-
|
70
|
-
private
|
71
|
-
|
72
|
-
def current_time
|
73
|
-
Time.now.to_f * 1000
|
74
|
-
end
|
75
|
-
|
76
|
-
def weight(n)
|
77
|
-
Math.exp(@alpha * n)
|
78
|
-
end
|
79
|
-
|
80
|
-
end
|
81
|
-
end
|