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.
@@ -1,17 +0,0 @@
1
- module Drone
2
- module Interfaces
3
-
4
- class Base
5
- def initialize(period)
6
- @period = period
7
- Drone::schedule_periodic(period){ output() }
8
- end
9
-
10
- def output
11
- raise "Uninmplemented"
12
- end
13
-
14
- end
15
-
16
- end
17
- end
@@ -1,82 +0,0 @@
1
- require File.expand_path('../base', __FILE__)
2
-
3
- module Drone
4
- module Interfaces
5
- ##
6
- # This interface is meant for debug mainly, it will
7
- # simply output all the available metrics at a regular
8
- # interval on the console.
9
- #
10
- # @example
11
- # require 'drone'
12
- # Drone::init_drone()
13
- # Drone::add_output(:console, 1)
14
- #
15
- class Console < Base
16
-
17
- def output()
18
- puts ""
19
- puts "[#{Time.now.strftime('%M:%S')}] Drone report:"
20
- Drone::each_metric do |m|
21
- case m
22
- when Metrics::Gauge
23
- puts "[Gauge] #{m.name} : #{m.value}"
24
-
25
- when Metrics::Counter
26
- puts "[Counter] #{m.name} : #{m.value}"
27
-
28
- when Metrics::Timer
29
- puts "[Timer] #{m.name}"
30
- print_histogram(m)
31
-
32
- when Metrics::Meter
33
- puts "[Meter] #{m.name}"
34
- print_meter(m)
35
-
36
- when Metrics::Histogram
37
- puts "[Histogram] #{m.name}"
38
- print_histogram(m)
39
-
40
- else
41
- puts "Unknown metric: #{m}"
42
- end
43
- end
44
- end
45
-
46
-
47
- private
48
- def print_meter(m)
49
- puts format("%20s : %d", "count", m.count)
50
-
51
- {
52
- 'mean rate' => m.mean_rate,
53
- '1-minute rate' => m.one_minute_rate,
54
- '5-minute rate' => m.five_minutes_rate,
55
- '15-minute rate' => m.fifteen_minutes_rate
56
- }.each do |label, value|
57
- puts format("%20s : %2.2f", label, value)
58
- end
59
- end
60
-
61
- def print_histogram(m)
62
- percentiles = m.percentiles(0.5, 0.75, 0.95, 0.98, 0.99, 0.999)
63
- {
64
- 'min' => m.min,
65
- 'max' => m.max,
66
- 'mean' => m.mean,
67
- 'stddev' => m.stdDev,
68
- 'median' => percentiles[0],
69
- '75%' => percentiles[1],
70
- '%95' => percentiles[2],
71
- '%98' => percentiles[3],
72
- '%99' => percentiles[4],
73
- '%99.9' => percentiles[5]
74
- }.each do |label, value|
75
- puts format("%20s : %2.2f", label, value)
76
- end
77
- end
78
-
79
- end
80
-
81
- end
82
- end
@@ -1,40 +0,0 @@
1
- require File.expand_path('../metric', __FILE__)
2
-
3
- module Drone
4
- module Metrics
5
-
6
- ##
7
- # A Counter store a number which can go up or down,
8
- # the counter can change a counter value with
9
- # the methods increment and decrement aliased
10
- # as inc and dec
11
- #
12
- class Counter < Metric
13
-
14
- def initialize(name, initial_value = 0)
15
- super(name)
16
-
17
- @value = Drone::request_number("#{name}:value", initial_value)
18
- end
19
-
20
- def value
21
- @value.get
22
- end
23
-
24
- def increment(n = 1)
25
- @value.inc(n)
26
- end
27
- alias :inc :increment
28
-
29
- def decrement(n = 1)
30
- @value.dec(n)
31
- end
32
- alias :dec :decrement
33
-
34
- def clear
35
- @value.set(0)
36
- end
37
- end
38
-
39
- end
40
- end
@@ -1,25 +0,0 @@
1
- require File.expand_path('../metric', __FILE__)
2
-
3
- module Drone
4
- module Metrics
5
-
6
- ##
7
- # Gauge are linked to a block of code which
8
- # will be called when the value is asked, the block
9
- # is expected to return a number
10
- #
11
- class Gauge < Metric
12
-
13
- def initialize(name, &block)
14
- raise "Block expected" unless block
15
- super(name)
16
- @block = block
17
- end
18
-
19
- def value
20
- @block.call()
21
- end
22
- end
23
-
24
- end
25
- end
@@ -1,153 +0,0 @@
1
- require File.expand_path('../../utils/uniform_sample', __FILE__)
2
- require File.expand_path('../../utils/exponentially_decaying_sample', __FILE__)
3
- require File.expand_path('../metric', __FILE__)
4
-
5
- module Drone
6
-
7
- ##
8
- # An Histogram store a list of values (1028) and can
9
- # compute on demand statistics on those values:
10
- # - min/max
11
- # - mean
12
- # - stddev
13
- # - percentiles
14
- #
15
- class Histogram < Metric
16
- MIN = (-(2**63)).freeze
17
- MAX = ((2**64) - 1).freeze
18
-
19
- def initialize(name, sample_or_type = :uniform)
20
- super(name)
21
-
22
- if sample_or_type.is_a?(Symbol)
23
- case sample_or_type
24
- when :uniform then @sample = UniformSample.new("#{name}:sample", 1028)
25
- when :biased then @sample = ExponentiallyDecayingSample.new("#{name}:sample", 1028, 0.015)
26
- else
27
- raise ArgumentError, "unknown type: #{sample_or_type}"
28
- end
29
- else
30
- @sample = sample_or_type
31
- end
32
-
33
- @count = Drone::request_number("#{name}:count", 0)
34
- @_min = Drone::request_number("#{name}:min", MAX)
35
- @_max = Drone::request_number("#{name}:max", MIN)
36
- @_sum = Drone::request_number("#{name}:max", 0)
37
- @varianceM = Drone::request_number("#{name}:varianceM", -1)
38
- @varianceS = Drone::request_number("#{name}:varianceS", 0)
39
-
40
- end
41
-
42
- def clear
43
- @sample.clear()
44
- @count = 0
45
- @_min = MAX
46
- @_max = MIN
47
- @_sum = 0
48
- @varianceM = -1
49
- @varianceS = 0
50
- end
51
-
52
- def update(val)
53
- @count.inc
54
- @sample.update(val)
55
- set_max(val);
56
- set_min(val);
57
- @_sum.inc(val)
58
- update_variance(val)
59
- end
60
-
61
- def count
62
- @count.get
63
- end
64
-
65
- def max
66
- (@count.get > 0) ? @_max.get : 0.0
67
- end
68
-
69
- def min
70
- (@count.get > 0) ? @_min.get : 0.0
71
- end
72
-
73
- def mean
74
- (@count.get > 0) ? @_sum.get.to_f / @count.get : 0.0
75
- end
76
-
77
- def stdDev
78
- (@count.get > 0) ? Math.sqrt( variance() ) : 0.0
79
- end
80
-
81
- def percentiles(*percentiles)
82
- scores = Array.new(percentiles.size, 0)
83
- if @count.get > 0
84
- values = @sample.values.sort
85
- percentiles.each.with_index do |p, i|
86
- pos = p * (values.size + 1)
87
- if pos < 1
88
- scores[i] = values[0]
89
- elsif pos >= values.size
90
- scores[i] = values[-1]
91
- else
92
- lower = values[pos - 1]
93
- upper = values[pos]
94
- scores[i] = lower + (pos - pos.floor) * (upper - lower)
95
- end
96
- end
97
- end
98
-
99
- scores
100
- end
101
-
102
- def values
103
- @sample.values
104
- end
105
-
106
- private
107
-
108
- def doubleToLongBits(n)
109
- [n].pack('D').unpack('q')[0]
110
- end
111
-
112
- def longBitsToDouble(n)
113
- [n].pack('q').unpack('D')[0]
114
- end
115
-
116
- def update_variance(val)
117
- if @varianceM.get == -1
118
- @varianceM.set( doubleToLongBits(val) )
119
- else
120
- oldMCas = @varianceM.get
121
- oldM = longBitsToDouble(oldMCas)
122
- newM = oldM + ((val - oldM) / count())
123
-
124
- oldSCas = @varianceS.get
125
- oldS = longBitsToDouble(oldSCas)
126
- newS = oldS + ((val - oldM) * (val - newM))
127
-
128
- @varianceM.set( doubleToLongBits(newM) )
129
- @varianceS.set( doubleToLongBits(newS) )
130
- end
131
- end
132
-
133
- def variance
134
- count = @count.get
135
- if count <= 1
136
- 0.0
137
- else
138
- longBitsToDouble(@varianceS.get) / (count - 1)
139
- end
140
- end
141
-
142
- def set_max(val)
143
- (@_max.get >= val) || @_max.set(val)
144
- end
145
-
146
- def set_min(val)
147
- (@_min.get <= val) || @_min.set(val)
148
- end
149
-
150
-
151
-
152
- end
153
- end
@@ -1,82 +0,0 @@
1
- require 'eventmachine'
2
-
3
- require File.expand_path('../metric', __FILE__)
4
- require File.expand_path('../../core', __FILE__)
5
- require File.expand_path('../../utils/ewma', __FILE__)
6
-
7
- module Drone
8
- module Metrics
9
- ##
10
- # A meter measures mean throughput and one-, five-, and
11
- # fifteen-minute exponentially-weighted moving average throughputs.
12
- #
13
- class Meter < Metric
14
- INTERVAL = 5
15
-
16
- def initialize(name)
17
- super(name)
18
- @start_time = Drone::request_number("#{name}:start_time", Time.now)
19
- @next_tick = Drone::request_number("#{name}:next_tick_lock", 1)
20
-
21
- @count = Drone::request_number("#{name}:count", 0)
22
- @rates = {
23
- 1 => EWMA.one_minute_ewma("#{name}:rate1"),
24
- 5 => EWMA.five_minutes_ewma("#{name}:rate5"),
25
- 15 => EWMA.fifteen_minutes_ewma("#{name}:rate15")
26
- }
27
-
28
- Drone::schedule_periodic(INTERVAL) do
29
- Fiber.new{ tick() }.resume
30
- end
31
- end
32
-
33
- def tick
34
- # init if required
35
- @local_next_tick ||= @next_tick.get
36
-
37
- # ensure only one process will trigger the tick
38
- if @next_tick.compare_and_set(@local_next_tick, @local_next_tick + 1)
39
- @rates.values.each(&:tick)
40
- @local_next_tick += 1
41
- else
42
- # reset the tick counter to give a chance to this
43
- # process to trigger the next tick
44
- @local_next_tick = @next_tick.get()
45
- end
46
- end
47
-
48
- def mark(events = 1)
49
- @count.inc(events)
50
- @rates.each do |_, r|
51
- r.update(events)
52
- end
53
- end
54
-
55
- def count
56
- @count.get
57
- end
58
-
59
- def mean_rate
60
- count = @count.get
61
- if count == 0
62
- 0.0
63
- else
64
- count / (Time.now.to_f - @start_time.get.to_f)
65
- end
66
- end
67
-
68
- def one_minute_rate
69
- @rates[1].rate()
70
- end
71
-
72
- def five_minutes_rate
73
- @rates[5].rate()
74
- end
75
-
76
- def fifteen_minutes_rate
77
- @rates[15].rate()
78
- end
79
-
80
- end
81
- end
82
- end
@@ -1,16 +0,0 @@
1
- module Drone
2
- class Metric
3
- ##
4
- # Every metric must have a name to be referenced by
5
- #
6
- # @attr_reader [String] name The metric's name
7
- # (which is also its id)
8
- #
9
- attr_reader :name
10
-
11
- def initialize(name)
12
- @name = name
13
- end
14
-
15
- end
16
- end
@@ -1,57 +0,0 @@
1
- require 'forwardable'
2
- require File.expand_path('../histogram', __FILE__)
3
- require File.expand_path('../meter', __FILE__)
4
- require File.expand_path('../metric', __FILE__)
5
-
6
- module Drone
7
- module Metrics
8
- ##
9
- # The timer metric will record the time spent in a given method
10
- # or any block of code.
11
- #
12
- # All the times are in milliseconds.
13
- #
14
- class Timer < Metric
15
- extend Forwardable
16
-
17
- def_delegators :@histogram, :count, :min, :max, :mean, :stdDev, :percentiles, :values
18
-
19
- def initialize(name)
20
- super(name)
21
-
22
- @histogram = Histogram.new("#{name}:histogram", :biased)
23
- end
24
-
25
- def count
26
- @histogram.count
27
- end
28
-
29
- def clear
30
- @histogram.clear()
31
- end
32
-
33
- ##
34
- # Method used to record a new duration
35
- #
36
- # @param [Float] duration A duration in milliseconds
37
- #
38
- def update(duration)
39
- if duration >= 0
40
- @histogram.update(duration)
41
- end
42
- end
43
-
44
- ##
45
- # time and record the duration of the block
46
- # @yield [] The block to time
47
- #
48
- def time
49
- started_at = Time.now.to_f
50
- yield()
51
- ensure
52
- update((Time.now.to_f - started_at.to_f) * 1000)
53
- end
54
-
55
- end
56
- end
57
- end