pulse-meter 0.2.3 → 0.2.5
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.
- 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;
|