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