drone 1.0.1 → 1.0.2

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