pulse-meter 0.2.3 → 0.2.5
Sign up to get free protection for your applications and to get access to all the features.
- data/examples/basic.ru +0 -1
- data/lib/pulse-meter/mixins/cmd.rb +3 -1
- data/lib/pulse-meter/sensor/base.rb +11 -2
- data/lib/pulse-meter/sensor/counter.rb +9 -6
- data/lib/pulse-meter/sensor/hashed_counter.rb +9 -7
- data/lib/pulse-meter/sensor/hashed_indicator.rb +8 -6
- data/lib/pulse-meter/sensor/indicator.rb +8 -6
- data/lib/pulse-meter/sensor/timeline.rb +37 -18
- data/lib/pulse-meter/sensor/timelined/average.rb +6 -0
- data/lib/pulse-meter/sensor/timelined/counter.rb +8 -1
- data/lib/pulse-meter/sensor/timelined/hashed_counter.rb +6 -0
- data/lib/pulse-meter/sensor/timelined/max.rb +7 -1
- data/lib/pulse-meter/sensor/timelined/min.rb +7 -1
- data/lib/pulse-meter/sensor/timelined/percentile.rb +7 -1
- data/lib/pulse-meter/sensor/timelined/uniq_counter.rb +6 -0
- data/lib/pulse-meter/sensor/uniq_counter.rb +8 -6
- data/lib/pulse-meter/version.rb +1 -1
- data/lib/pulse-meter/visualize/public/js/application.coffee +6 -2
- data/lib/pulse-meter/visualize/public/js/application.js +8 -2
- data/spec/pulse_meter/sensor/base_spec.rb +11 -2
- data/spec/pulse_meter/sensor/timeline_spec.rb +30 -0
- data/spec/shared_examples/timeline_sensor.rb +10 -1
- data/spec/shared_examples/timelined_subclass.rb +1 -1
- metadata +2 -19
- data/perl/PulseMeter/Sensor/Base.pm +0 -42
- data/perl/PulseMeter/Sensor/Counter.pm +0 -19
- data/perl/PulseMeter/Sensor/HashedIndicator.pm +0 -12
- data/perl/PulseMeter/Sensor/Indicator.pm +0 -17
- data/perl/PulseMeter/Sensor/Timeline.pm +0 -51
- data/perl/PulseMeter/Sensor/Timelined/Average.pm +0 -13
- data/perl/PulseMeter/Sensor/Timelined/Counter.pm +0 -12
- data/perl/PulseMeter/Sensor/Timelined/HashedCounter.pm +0 -12
- data/perl/PulseMeter/Sensor/Timelined/Max.pm +0 -18
- data/perl/PulseMeter/Sensor/Timelined/Median.pm +0 -8
- data/perl/PulseMeter/Sensor/Timelined/Min.pm +0 -18
- data/perl/PulseMeter/Sensor/Timelined/Percentile.pm +0 -17
- data/perl/PulseMeter/Sensor/Timelined/UniqCounter.pm +0 -13
- data/perl/PulseMeter/Sensor/UniqCounter.pm +0 -12
data/examples/basic.ru
CHANGED
@@ -15,7 +15,9 @@ module Enumerable
|
|
15
15
|
self.each {|row| csv << row.convert_time}
|
16
16
|
end
|
17
17
|
else
|
18
|
-
self.each_with_object(Terminal::Table.new)
|
18
|
+
self.each_with_object(Terminal::Table.new) do |row, table|
|
19
|
+
table << row.map(&:to_s)
|
20
|
+
end
|
19
21
|
end
|
20
22
|
end
|
21
23
|
end
|
@@ -49,10 +49,13 @@ module PulseMeter
|
|
49
49
|
cleanup_dump
|
50
50
|
end
|
51
51
|
|
52
|
-
#
|
52
|
+
# Processes event
|
53
53
|
# @param value [Object] value produced by some kind of event
|
54
54
|
def event(value)
|
55
|
-
|
55
|
+
process_event(value)
|
56
|
+
true
|
57
|
+
rescue StandardError
|
58
|
+
false
|
56
59
|
end
|
57
60
|
|
58
61
|
protected
|
@@ -70,6 +73,12 @@ module PulseMeter
|
|
70
73
|
end
|
71
74
|
end
|
72
75
|
|
76
|
+
private
|
77
|
+
|
78
|
+
def process_event(value)
|
79
|
+
# do nothing here
|
80
|
+
end
|
81
|
+
|
73
82
|
end
|
74
83
|
end
|
75
84
|
end
|
@@ -14,12 +14,6 @@ module PulseMeter
|
|
14
14
|
event(1)
|
15
15
|
end
|
16
16
|
|
17
|
-
# Processes event by incremnting counter by given value
|
18
|
-
# @param value [Fixnum] increment
|
19
|
-
def event(value)
|
20
|
-
redis.incrby(value_key, value.to_i)
|
21
|
-
end
|
22
|
-
|
23
17
|
# Gets counter value
|
24
18
|
# @return [Fixnum]
|
25
19
|
def value
|
@@ -31,6 +25,15 @@ module PulseMeter
|
|
31
25
|
def value_key
|
32
26
|
@value_key ||= "pulse_meter:value:#{name}"
|
33
27
|
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
# Processes event by incremnting counter by given value
|
32
|
+
# @param value [Fixnum] increment
|
33
|
+
def process_event(value)
|
34
|
+
redis.incrby(value_key, value.to_i)
|
35
|
+
end
|
36
|
+
|
34
37
|
end
|
35
38
|
end
|
36
39
|
end
|
@@ -11,13 +11,6 @@ module PulseMeter
|
|
11
11
|
event({key => 1})
|
12
12
|
end
|
13
13
|
|
14
|
-
# Processes events for multiple keys
|
15
|
-
# @param data [Hash] hash where keys represent counter keys
|
16
|
-
# and values are increments for their keys
|
17
|
-
def event(data)
|
18
|
-
data.each_pair {|k, v| redis.hincrby(value_key, k, v.to_i)}
|
19
|
-
end
|
20
|
-
|
21
14
|
# Returs data stored in counter
|
22
15
|
# @return [Hash]
|
23
16
|
def value
|
@@ -26,6 +19,15 @@ module PulseMeter
|
|
26
19
|
inject(Hash.new(0)) {|h, (k, v)| h[k] = v.to_i; h}
|
27
20
|
end
|
28
21
|
|
22
|
+
private
|
23
|
+
|
24
|
+
# Processes events for multiple keys
|
25
|
+
# @param data [Hash] hash where keys represent counter keys
|
26
|
+
# and values are increments for their keys
|
27
|
+
def process_event(data)
|
28
|
+
data.each_pair {|k, v| redis.hincrby(value_key, k, v.to_i)}
|
29
|
+
end
|
30
|
+
|
29
31
|
end
|
30
32
|
end
|
31
33
|
end
|
@@ -3,12 +3,6 @@ module PulseMeter
|
|
3
3
|
# Static hashed indicator. In fact is is just a named hash with float value
|
4
4
|
class HashedIndicator < Indicator
|
5
5
|
|
6
|
-
# Sets indicator values
|
7
|
-
# @param value [Hash] new indicator values
|
8
|
-
def event(events)
|
9
|
-
events.each_pair {|name, value| redis.hset(value_key, name, value.to_f)}
|
10
|
-
end
|
11
|
-
|
12
6
|
# Get indicator values
|
13
7
|
# @return [Fixnum] indicator value or zero unless it was initialized
|
14
8
|
def value
|
@@ -17,6 +11,14 @@ module PulseMeter
|
|
17
11
|
inject(Hash.new(0)) {|h, (k, v)| h[k] = v.to_f; h}
|
18
12
|
end
|
19
13
|
|
14
|
+
private
|
15
|
+
|
16
|
+
# Sets indicator values
|
17
|
+
# @param value [Hash] new indicator values
|
18
|
+
def process_event(events)
|
19
|
+
events.each_pair {|name, value| redis.hset(value_key, name, value.to_f)}
|
20
|
+
end
|
21
|
+
|
20
22
|
end
|
21
23
|
end
|
22
24
|
end
|
@@ -9,12 +9,6 @@ module PulseMeter
|
|
9
9
|
super
|
10
10
|
end
|
11
11
|
|
12
|
-
# Sets indicator value
|
13
|
-
# @param value [Float] new indicator value
|
14
|
-
def event(value)
|
15
|
-
redis.set(value_key, value.to_f)
|
16
|
-
end
|
17
|
-
|
18
12
|
# Get indicator value
|
19
13
|
# @return [Fixnum] indicator value or zero unless it was initialized
|
20
14
|
def value
|
@@ -28,6 +22,14 @@ module PulseMeter
|
|
28
22
|
@value_key ||= "pulse_meter:value:#{name}"
|
29
23
|
end
|
30
24
|
|
25
|
+
private
|
26
|
+
|
27
|
+
# Sets indicator value
|
28
|
+
# @param value [Float] new indicator value
|
29
|
+
def process_event(value)
|
30
|
+
redis.set(value_key, value.to_f)
|
31
|
+
end
|
32
|
+
|
31
33
|
end
|
32
34
|
end
|
33
35
|
end
|
@@ -48,16 +48,6 @@ module PulseMeter
|
|
48
48
|
super
|
49
49
|
end
|
50
50
|
|
51
|
-
# Processes event
|
52
|
-
# @param value event value
|
53
|
-
def event(value = nil)
|
54
|
-
multi do
|
55
|
-
current_key = current_raw_data_key
|
56
|
-
aggregate_event(current_key, value)
|
57
|
-
redis.expire(current_key, raw_data_ttl)
|
58
|
-
end
|
59
|
-
end
|
60
|
-
|
61
51
|
# Processes event from the past
|
62
52
|
# @param time [Time] event time
|
63
53
|
# @param value event value
|
@@ -132,17 +122,13 @@ module PulseMeter
|
|
132
122
|
keys << data_key(current_interval_id)
|
133
123
|
current_interval_id += actual_interval
|
134
124
|
end
|
135
|
-
values =
|
136
|
-
[]
|
137
|
-
else
|
138
|
-
redis.mget(*keys)
|
139
|
-
end
|
125
|
+
values = keys.empty? ? [] : redis.mget(*keys)
|
140
126
|
res = []
|
141
127
|
ids.zip(values) do |(id, val)|
|
142
128
|
res << if val.nil?
|
143
129
|
get_raw_value(id)
|
144
130
|
else
|
145
|
-
|
131
|
+
sensor_data(id, val)
|
146
132
|
end
|
147
133
|
end
|
148
134
|
res
|
@@ -167,8 +153,11 @@ module PulseMeter
|
|
167
153
|
# @return [SensorData]
|
168
154
|
def get_raw_value(interval_id)
|
169
155
|
interval_raw_data_key = raw_data_key(interval_id)
|
170
|
-
|
171
|
-
|
156
|
+
if redis.exists(interval_raw_data_key)
|
157
|
+
sensor_data(interval_id, summarize(interval_raw_data_key))
|
158
|
+
else
|
159
|
+
sensor_data(interval_id, nil)
|
160
|
+
end
|
172
161
|
end
|
173
162
|
|
174
163
|
# Drops sensor data within given time
|
@@ -236,6 +225,36 @@ module PulseMeter
|
|
236
225
|
redis.get(key)
|
237
226
|
end
|
238
227
|
|
228
|
+
# @abstract Deflates data taken from redis as string preserving nil values
|
229
|
+
# @param value [String] raw data
|
230
|
+
def deflate_safe(value)
|
231
|
+
value.nil? ? nil : deflate(value)
|
232
|
+
rescue
|
233
|
+
nil
|
234
|
+
end
|
235
|
+
|
236
|
+
private
|
237
|
+
|
238
|
+
def deflate(value)
|
239
|
+
# simple
|
240
|
+
value
|
241
|
+
end
|
242
|
+
|
243
|
+
def sensor_data(interval_id, value)
|
244
|
+
value = deflate(value) unless value.nil?
|
245
|
+
SensorData.new(Time.at(interval_id), value)
|
246
|
+
end
|
247
|
+
|
248
|
+
# Processes event
|
249
|
+
# @param value event value
|
250
|
+
def process_event(value = nil)
|
251
|
+
multi do
|
252
|
+
current_key = current_raw_data_key
|
253
|
+
aggregate_event(current_key, value)
|
254
|
+
redis.expire(current_key, raw_data_ttl)
|
255
|
+
end
|
256
|
+
end
|
257
|
+
|
239
258
|
end
|
240
259
|
end
|
241
260
|
end
|
@@ -13,12 +13,18 @@ module PulseMeter
|
|
13
13
|
count = redis.zcard(key)
|
14
14
|
if count > 0
|
15
15
|
max_el = redis.zrange(key, -1, -1)[0]
|
16
|
-
redis.zscore(key, max_el)
|
16
|
+
redis.zscore(key, max_el)
|
17
17
|
else
|
18
18
|
nil
|
19
19
|
end
|
20
20
|
end
|
21
21
|
|
22
|
+
private
|
23
|
+
|
24
|
+
def deflate(value)
|
25
|
+
value.to_f
|
26
|
+
end
|
27
|
+
|
22
28
|
end
|
23
29
|
end
|
24
30
|
end
|
@@ -13,12 +13,18 @@ module PulseMeter
|
|
13
13
|
count = redis.zcard(key)
|
14
14
|
if count > 0
|
15
15
|
min_el = redis.zrange(key, 0, 0)[0]
|
16
|
-
redis.zscore(key, min_el)
|
16
|
+
redis.zscore(key, min_el)
|
17
17
|
else
|
18
18
|
nil
|
19
19
|
end
|
20
20
|
end
|
21
21
|
|
22
|
+
private
|
23
|
+
|
24
|
+
def deflate(value)
|
25
|
+
value.to_f
|
26
|
+
end
|
27
|
+
|
22
28
|
end
|
23
29
|
end
|
24
30
|
end
|
@@ -19,12 +19,18 @@ module PulseMeter
|
|
19
19
|
if count > 0
|
20
20
|
position = @p_value > 0 ? (@p_value * count).round - 1 : 0
|
21
21
|
el = redis.zrange(key, position, position)[0]
|
22
|
-
redis.zscore(key, el)
|
22
|
+
redis.zscore(key, el)
|
23
23
|
else
|
24
24
|
nil
|
25
25
|
end
|
26
26
|
end
|
27
27
|
|
28
|
+
private
|
29
|
+
|
30
|
+
def deflate(value)
|
31
|
+
value.to_f
|
32
|
+
end
|
33
|
+
|
28
34
|
end
|
29
35
|
end
|
30
36
|
end
|
@@ -5,18 +5,20 @@ module PulseMeter
|
|
5
5
|
module Sensor
|
6
6
|
class UniqCounter < Counter
|
7
7
|
|
8
|
-
# Processes event
|
9
|
-
# @param name [String] value to be counted
|
10
|
-
def event(name)
|
11
|
-
redis.sadd(value_key, name)
|
12
|
-
end
|
13
|
-
|
14
8
|
# Returs number of unique values ever sent to counter
|
15
9
|
# @return [Fixnum]
|
16
10
|
def value
|
17
11
|
redis.scard(value_key)
|
18
12
|
end
|
19
13
|
|
14
|
+
private
|
15
|
+
|
16
|
+
# Processes event
|
17
|
+
# @param name [String] value to be counted
|
18
|
+
def process_event(name)
|
19
|
+
redis.sadd(value_key, name)
|
20
|
+
end
|
21
|
+
|
20
22
|
end
|
21
23
|
end
|
22
24
|
end
|
data/lib/pulse-meter/version.rb
CHANGED
@@ -141,7 +141,7 @@ document.startApp = ->
|
|
141
141
|
data: ->
|
142
142
|
data = super()
|
143
143
|
data.addColumn('datetime', 'Time')
|
144
|
-
dateOffset = @dateOffset()
|
144
|
+
dateOffset = @dateOffset() + @get('interval') * 1000
|
145
145
|
series = @get('series')
|
146
146
|
_.each series.titles, (t) ->
|
147
147
|
data.addColumn('number', t)
|
@@ -233,7 +233,11 @@ document.startApp = ->
|
|
233
233
|
timespan: -> @get('timespan') + @timespanInc
|
234
234
|
|
235
235
|
url: ->
|
236
|
-
|
236
|
+
timespan = @timespan()
|
237
|
+
if _.isNaN(timespan)
|
238
|
+
"#{@collection.url()}/#{@get('id')}"
|
239
|
+
else
|
240
|
+
"#{@collection.url()}/#{@get('id')}?timespan=#{timespan}"
|
237
241
|
|
238
242
|
time: -> (new Date()).getTime()
|
239
243
|
|
@@ -188,7 +188,7 @@
|
|
188
188
|
var data, dateOffset, series;
|
189
189
|
data = TimelinePresenter.__super__.data.call(this);
|
190
190
|
data.addColumn('datetime', 'Time');
|
191
|
-
dateOffset = this.dateOffset();
|
191
|
+
dateOffset = this.dateOffset() + this.get('interval') * 1000;
|
192
192
|
series = this.get('series');
|
193
193
|
_.each(series.titles, function(t) {
|
194
194
|
return data.addColumn('number', t);
|
@@ -351,7 +351,13 @@
|
|
351
351
|
return this.get('timespan') + this.timespanInc;
|
352
352
|
},
|
353
353
|
url: function() {
|
354
|
-
|
354
|
+
var timespan;
|
355
|
+
timespan = this.timespan();
|
356
|
+
if (_.isNaN(timespan)) {
|
357
|
+
return "" + (this.collection.url()) + "/" + (this.get('id'));
|
358
|
+
} else {
|
359
|
+
return "" + (this.collection.url()) + "/" + (this.get('id')) + "?timespan=" + timespan;
|
360
|
+
}
|
355
361
|
},
|
356
362
|
time: function() {
|
357
363
|
return (new Date()).getTime();
|
@@ -89,8 +89,17 @@ describe PulseMeter::Sensor::Base do
|
|
89
89
|
end
|
90
90
|
|
91
91
|
describe "#event" do
|
92
|
-
|
93
|
-
|
92
|
+
context "when everything is ok" do
|
93
|
+
it "should do nothing and return true" do
|
94
|
+
sensor.event(nil).should be_true
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
context "when an error occures while processing event" do
|
99
|
+
it "should catch StandardErrors and return false" do
|
100
|
+
sensor.stub(:process_event) {raise StandardError}
|
101
|
+
sensor.event(nil).should be_false
|
102
|
+
end
|
94
103
|
end
|
95
104
|
end
|
96
105
|
|
@@ -55,4 +55,34 @@ describe PulseMeter::Sensor::Timeline do
|
|
55
55
|
end
|
56
56
|
|
57
57
|
end
|
58
|
+
|
59
|
+
describe "#deflate_safe" do
|
60
|
+
class GoodSubclass < described_class
|
61
|
+
def deflate(value)
|
62
|
+
value.to_i
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
class BadSubclass < described_class
|
67
|
+
def deflate(value)
|
68
|
+
raise "Any conversion error"
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
let!(:good_instance) { GoodSubclass.new("good", good_init_values) }
|
73
|
+
let!(:bad_instance) { BadSubclass.new("bad", good_init_values) }
|
74
|
+
|
75
|
+
it "preserves nil values" do
|
76
|
+
good_instance.deflate_safe(nil).should be_nil
|
77
|
+
end
|
78
|
+
|
79
|
+
it "converts value as defined in subclass" do
|
80
|
+
good_instance.deflate_safe("10").should == 10
|
81
|
+
end
|
82
|
+
|
83
|
+
it "returns nil if conversion fails" do
|
84
|
+
bad_instance.deflate_safe(:foo).should be_nil
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
58
88
|
end
|
@@ -78,6 +78,15 @@ shared_examples_for "timeline sensor" do |extra_init_values, default_event|
|
|
78
78
|
end
|
79
79
|
}.to change{ redis.ttl(@raw_data_key) }
|
80
80
|
end
|
81
|
+
|
82
|
+
it "returns true if event processed correctly" do
|
83
|
+
sensor.event(sample_event).should be_true
|
84
|
+
end
|
85
|
+
|
86
|
+
it "catches StandardErrors and returns false" do
|
87
|
+
sensor.stub(:aggregate_event) {raise StandardError}
|
88
|
+
sensor.event(sample_event).should be_false
|
89
|
+
end
|
81
90
|
end
|
82
91
|
|
83
92
|
describe "#event_at" do
|
@@ -343,7 +352,7 @@ shared_examples_for "timeline sensor" do |extra_init_values, default_event|
|
|
343
352
|
describe "SensorData value for an interval" do
|
344
353
|
def check_sensor_data(sensor, value)
|
345
354
|
data = sensor.timeline(2).first
|
346
|
-
data.value.should
|
355
|
+
data.value.should be_generally_equal(sensor.deflate_safe(value))
|
347
356
|
data.start_time.to_i.should == @interval_id
|
348
357
|
end
|
349
358
|
|
@@ -16,7 +16,7 @@ shared_examples_for "timelined subclass" do |events, result, extra_options|
|
|
16
16
|
end
|
17
17
|
Timecop.freeze(start_of_interval + interval) do
|
18
18
|
data = sensor.timeline(interval + epsilon).first
|
19
|
-
data.value.should be_generally_equal(result)
|
19
|
+
data.value.should be_generally_equal(sensor.deflate_safe(result))
|
20
20
|
end
|
21
21
|
end
|
22
22
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pulse-meter
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.5
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2012-07-
|
13
|
+
date: 2012-07-19 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: gon-sinatra
|
@@ -402,20 +402,6 @@ files:
|
|
402
402
|
- lib/pulse-meter/visualize/widgets/pie.rb
|
403
403
|
- lib/pulse-meter/visualize/widgets/timeline.rb
|
404
404
|
- lib/pulse-meter/visualizer.rb
|
405
|
-
- perl/PulseMeter/Sensor/Base.pm
|
406
|
-
- perl/PulseMeter/Sensor/Counter.pm
|
407
|
-
- perl/PulseMeter/Sensor/HashedIndicator.pm
|
408
|
-
- perl/PulseMeter/Sensor/Indicator.pm
|
409
|
-
- perl/PulseMeter/Sensor/Timeline.pm
|
410
|
-
- perl/PulseMeter/Sensor/Timelined/Average.pm
|
411
|
-
- perl/PulseMeter/Sensor/Timelined/Counter.pm
|
412
|
-
- perl/PulseMeter/Sensor/Timelined/HashedCounter.pm
|
413
|
-
- perl/PulseMeter/Sensor/Timelined/Max.pm
|
414
|
-
- perl/PulseMeter/Sensor/Timelined/Median.pm
|
415
|
-
- perl/PulseMeter/Sensor/Timelined/Min.pm
|
416
|
-
- perl/PulseMeter/Sensor/Timelined/Percentile.pm
|
417
|
-
- perl/PulseMeter/Sensor/Timelined/UniqCounter.pm
|
418
|
-
- perl/PulseMeter/Sensor/UniqCounter.pm
|
419
405
|
- pulse-meter.gemspec
|
420
406
|
- spec/pulse_meter/mixins/dumper_spec.rb
|
421
407
|
- spec/pulse_meter/mixins/utils_spec.rb
|
@@ -480,9 +466,6 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
480
466
|
- - ! '>='
|
481
467
|
- !ruby/object:Gem::Version
|
482
468
|
version: '0'
|
483
|
-
segments:
|
484
|
-
- 0
|
485
|
-
hash: -1244879308775683986
|
486
469
|
requirements: []
|
487
470
|
rubyforge_project:
|
488
471
|
rubygems_version: 1.8.24
|
@@ -1,42 +0,0 @@
|
|
1
|
-
package PulseMeter::Sensor::Base;
|
2
|
-
use strict;
|
3
|
-
use warnings 'all';
|
4
|
-
|
5
|
-
use base qw/Exporter/;
|
6
|
-
use Data::Dumper;
|
7
|
-
use Redis;
|
8
|
-
|
9
|
-
use constant REDIS_DEFAULTS => {
|
10
|
-
host => 'localhost',
|
11
|
-
port => 6379,
|
12
|
-
db => 0
|
13
|
-
};
|
14
|
-
|
15
|
-
sub new {
|
16
|
-
my $class = shift;
|
17
|
-
my $self = {};
|
18
|
-
bless($self, $class);
|
19
|
-
$self->init(@_);
|
20
|
-
return $self;
|
21
|
-
}
|
22
|
-
|
23
|
-
sub init {
|
24
|
-
my $self = shift;
|
25
|
-
my $name = shift;
|
26
|
-
my $opts = {@_};
|
27
|
-
|
28
|
-
my $redis_options = $opts->{redis} || {};
|
29
|
-
$redis_options->{$_} ||= REDIS_DEFAULTS->{$_} for qw/host port db/;
|
30
|
-
my $redis = Redis->new(
|
31
|
-
server => sprintf("%s:%s", $redis_options->{host}, $redis_options->{port})
|
32
|
-
);
|
33
|
-
$redis->select($redis_options->{db});
|
34
|
-
$self->{redis} = $redis;
|
35
|
-
|
36
|
-
$self->{name} = $name;
|
37
|
-
}
|
38
|
-
|
39
|
-
sub r { shift->{redis} }
|
40
|
-
sub name { shift->{name} }
|
41
|
-
|
42
|
-
1;
|
@@ -1,19 +0,0 @@
|
|
1
|
-
package PulseMeter::Sensor::Counter;
|
2
|
-
use strict;
|
3
|
-
use warnings 'all';
|
4
|
-
|
5
|
-
use base qw/PulseMeter::Sensor::Base/;
|
6
|
-
|
7
|
-
sub event {
|
8
|
-
my ($self, $value) = @_;
|
9
|
-
$self->r->incrby($self->value_key, $value);
|
10
|
-
}
|
11
|
-
|
12
|
-
sub incr { shift->event(1) }
|
13
|
-
|
14
|
-
sub value_key {
|
15
|
-
my $self = shift;
|
16
|
-
sprintf("pulse_meter:value:%s", $self->name);
|
17
|
-
}
|
18
|
-
|
19
|
-
1;
|
@@ -1,17 +0,0 @@
|
|
1
|
-
package PulseMeter::Sensor::Indicator;
|
2
|
-
use strict;
|
3
|
-
use warnings 'all';
|
4
|
-
|
5
|
-
use base qw/PulseMeter::Sensor::Base/;
|
6
|
-
|
7
|
-
sub event {
|
8
|
-
my ($self, $value) = @_;
|
9
|
-
$self->r->set($self->value_key, $value);
|
10
|
-
}
|
11
|
-
|
12
|
-
sub value_key {
|
13
|
-
my $self = shift;
|
14
|
-
sprintf("pulse_meter:value:%s", $self->name);
|
15
|
-
}
|
16
|
-
|
17
|
-
1;
|
@@ -1,51 +0,0 @@
|
|
1
|
-
package PulseMeter::Sensor::Timeline;
|
2
|
-
use strict;
|
3
|
-
use warnings 'all';
|
4
|
-
|
5
|
-
use base qw/PulseMeter::Sensor::Base/;
|
6
|
-
|
7
|
-
use constant DEFAULTS => {
|
8
|
-
raw_data_ttl => 3600,
|
9
|
-
interval => 60,
|
10
|
-
};
|
11
|
-
|
12
|
-
sub init {
|
13
|
-
my $self = shift;
|
14
|
-
my $name = shift;
|
15
|
-
$self->SUPER::init($name, @_);
|
16
|
-
my $opts = {@_};
|
17
|
-
$self->{$_} = $opts->{$_} || DEFAULTS->{$_} for qw/raw_data_ttl interval/;
|
18
|
-
}
|
19
|
-
|
20
|
-
sub raw_data_ttl { shift->{raw_data_ttl} }
|
21
|
-
sub interval { shift->{interval} }
|
22
|
-
|
23
|
-
sub event {
|
24
|
-
my ($self, $value) = @_;
|
25
|
-
$self->r->multi;
|
26
|
-
my $current_key = $self->current_raw_data_key;
|
27
|
-
$self->aggregate_event($current_key, $value);
|
28
|
-
$self->r->expire($current_key, $self->raw_data_ttl);
|
29
|
-
$self->r->exec;
|
30
|
-
}
|
31
|
-
|
32
|
-
sub raw_data_key {
|
33
|
-
my ($self, $id) = @_;
|
34
|
-
sprintf("pulse_meter:raw:%s:%s", $self->name, $id);
|
35
|
-
}
|
36
|
-
|
37
|
-
sub get_interval_id {
|
38
|
-
my ($self, $time) = @_;
|
39
|
-
int($time / $self->interval) * $self->interval;
|
40
|
-
}
|
41
|
-
|
42
|
-
sub current_interval_id { shift->get_interval_id(time) }
|
43
|
-
|
44
|
-
sub current_raw_data_key {
|
45
|
-
my $self = shift;
|
46
|
-
$self->raw_data_key($self->current_interval_id);
|
47
|
-
}
|
48
|
-
|
49
|
-
sub aggregate_event { die('Abstract') }
|
50
|
-
|
51
|
-
1;
|
@@ -1,13 +0,0 @@
|
|
1
|
-
package PulseMeter::Sensor::Timelined::Average;
|
2
|
-
use strict;
|
3
|
-
use warnings 'all';
|
4
|
-
|
5
|
-
use base qw/PulseMeter::Sensor::Timeline/;
|
6
|
-
|
7
|
-
sub aggregate_event {
|
8
|
-
my ($self, $key, $value) = @_;
|
9
|
-
$self->r->hincrby($key, "count", 1);
|
10
|
-
$self->r->hincrby($key, "sum", $value);
|
11
|
-
}
|
12
|
-
|
13
|
-
1;
|
@@ -1,12 +0,0 @@
|
|
1
|
-
package PulseMeter::Sensor::Timelined::HashedCounter;
|
2
|
-
use strict;
|
3
|
-
use warnings 'all';
|
4
|
-
|
5
|
-
use base qw/PulseMeter::Sensor::Timeline/;
|
6
|
-
|
7
|
-
sub aggregate_event {
|
8
|
-
my ($self, $key, $data) = @_;
|
9
|
-
$self->r->hincrby($key, $_, $data->{$_}) for (keys(%$data));
|
10
|
-
}
|
11
|
-
|
12
|
-
1;
|
@@ -1,18 +0,0 @@
|
|
1
|
-
package PulseMeter::Sensor::Timelined::Max;
|
2
|
-
use strict;
|
3
|
-
use warnings 'all';
|
4
|
-
use Data::Uniqid qw/uniqid/;
|
5
|
-
|
6
|
-
use base qw/PulseMeter::Sensor::Timeline/;
|
7
|
-
|
8
|
-
sub aggregate_event {
|
9
|
-
my ($self, $key, $value) = @_;
|
10
|
-
$self->r->zadd(
|
11
|
-
$key,
|
12
|
-
$value,
|
13
|
-
sprintf("%s::%s", $value, uniqid())
|
14
|
-
);
|
15
|
-
$self->r->zremrangebyrank($key, 0, -2);
|
16
|
-
}
|
17
|
-
|
18
|
-
1;
|
@@ -1,18 +0,0 @@
|
|
1
|
-
package PulseMeter::Sensor::Timelined::Min;
|
2
|
-
use strict;
|
3
|
-
use warnings 'all';
|
4
|
-
use Data::Uniqid qw/uniqid/;
|
5
|
-
|
6
|
-
use base qw/PulseMeter::Sensor::Timeline/;
|
7
|
-
|
8
|
-
sub aggregate_event {
|
9
|
-
my ($self, $key, $value) = @_;
|
10
|
-
$self->r->zadd(
|
11
|
-
$key,
|
12
|
-
$value,
|
13
|
-
sprintf("%s::%s", $value, uniqid())
|
14
|
-
);
|
15
|
-
$self->r->zremrangebyrank($key, 1, -1);
|
16
|
-
}
|
17
|
-
|
18
|
-
1;
|
@@ -1,17 +0,0 @@
|
|
1
|
-
package PulseMeter::Sensor::Timelined::Percentile;
|
2
|
-
use strict;
|
3
|
-
use warnings 'all';
|
4
|
-
use Data::Uniqid qw/uniqid/;
|
5
|
-
|
6
|
-
use base qw/PulseMeter::Sensor::Timeline/;
|
7
|
-
|
8
|
-
sub aggregate_event {
|
9
|
-
my ($self, $key, $value) = @_;
|
10
|
-
$self->r->zadd(
|
11
|
-
$key,
|
12
|
-
$value,
|
13
|
-
sprintf("%s::%s", $value, uniqid())
|
14
|
-
);
|
15
|
-
}
|
16
|
-
|
17
|
-
1;
|
@@ -1,13 +0,0 @@
|
|
1
|
-
package PulseMeter::Sensor::Timelined::UniqCounter;
|
2
|
-
use strict;
|
3
|
-
use warnings 'all';
|
4
|
-
use Data::Uniqid qw/uniqid/;
|
5
|
-
|
6
|
-
use base qw/PulseMeter::Sensor::Timeline/;
|
7
|
-
|
8
|
-
sub aggregate_event {
|
9
|
-
my ($self, $key, $value) = @_;
|
10
|
-
$self->r->sadd($key, $value);
|
11
|
-
}
|
12
|
-
|
13
|
-
1;
|