pulse-meter 0.4.9 → 0.4.11
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/Rakefile +1 -48
- data/lib/pulse-meter.rb +1 -68
- data/lib/pulse-meter/visualizer.rb +1 -40
- data/pulse-meter.gemspec +4 -26
- metadata +10 -558
- data/Procfile +0 -3
- data/bin/pulse +0 -6
- data/examples/basic.ru +0 -145
- data/examples/basic_sensor_data.rb +0 -96
- data/examples/udp_benchmark.rb +0 -29
- data/lib/cmd.rb +0 -171
- data/lib/pulse-meter/command_aggregator/async.rb +0 -83
- data/lib/pulse-meter/command_aggregator/sync.rb +0 -18
- data/lib/pulse-meter/command_aggregator/udp.rb +0 -48
- data/lib/pulse-meter/extensions/enumerable.rb +0 -24
- data/lib/pulse-meter/mixins/cmd.rb +0 -46
- data/lib/pulse-meter/mixins/dumper.rb +0 -87
- data/lib/pulse-meter/mixins/utils.rb +0 -155
- data/lib/pulse-meter/observer.rb +0 -120
- data/lib/pulse-meter/observer/extended.rb +0 -34
- data/lib/pulse-meter/sensor.rb +0 -61
- data/lib/pulse-meter/sensor/base.rb +0 -88
- data/lib/pulse-meter/sensor/configuration.rb +0 -106
- data/lib/pulse-meter/sensor/counter.rb +0 -39
- data/lib/pulse-meter/sensor/hashed_counter.rb +0 -36
- data/lib/pulse-meter/sensor/hashed_indicator.rb +0 -24
- data/lib/pulse-meter/sensor/indicator.rb +0 -35
- data/lib/pulse-meter/sensor/multi.rb +0 -97
- data/lib/pulse-meter/sensor/timeline.rb +0 -236
- data/lib/pulse-meter/sensor/timeline_reduce.rb +0 -68
- data/lib/pulse-meter/sensor/timelined/average.rb +0 -32
- data/lib/pulse-meter/sensor/timelined/counter.rb +0 -23
- data/lib/pulse-meter/sensor/timelined/hashed_counter.rb +0 -31
- data/lib/pulse-meter/sensor/timelined/hashed_indicator.rb +0 -30
- data/lib/pulse-meter/sensor/timelined/indicator.rb +0 -23
- data/lib/pulse-meter/sensor/timelined/max.rb +0 -19
- data/lib/pulse-meter/sensor/timelined/median.rb +0 -14
- data/lib/pulse-meter/sensor/timelined/min.rb +0 -19
- data/lib/pulse-meter/sensor/timelined/multi_percentile.rb +0 -34
- data/lib/pulse-meter/sensor/timelined/percentile.rb +0 -22
- data/lib/pulse-meter/sensor/timelined/uniq_counter.rb +0 -22
- data/lib/pulse-meter/sensor/timelined/zset_based.rb +0 -38
- data/lib/pulse-meter/sensor/uniq_counter.rb +0 -24
- data/lib/pulse-meter/server.rb +0 -0
- data/lib/pulse-meter/server/command_line_options.rb +0 -0
- data/lib/pulse-meter/server/config_options.rb +0 -0
- data/lib/pulse-meter/server/sensors.rb +0 -0
- data/lib/pulse-meter/udp_server.rb +0 -45
- data/lib/pulse-meter/version.rb +0 -3
- data/lib/pulse-meter/visualize/app.rb +0 -78
- data/lib/pulse-meter/visualize/base.rb +0 -15
- data/lib/pulse-meter/visualize/coffee/application.coffee +0 -40
- data/lib/pulse-meter/visualize/coffee/collections/page_info_list.coffee +0 -17
- data/lib/pulse-meter/visualize/coffee/collections/sensor_info_list.coffee +0 -4
- data/lib/pulse-meter/visualize/coffee/collections/widget_list.coffee +0 -14
- data/lib/pulse-meter/visualize/coffee/extensions.coffee +0 -26
- data/lib/pulse-meter/visualize/coffee/models/dinamic_widget.coffee +0 -34
- data/lib/pulse-meter/visualize/coffee/models/page_info.coffee +0 -2
- data/lib/pulse-meter/visualize/coffee/models/sensor_info.coffee +0 -2
- data/lib/pulse-meter/visualize/coffee/models/widget.coffee +0 -54
- data/lib/pulse-meter/visualize/coffee/presenters/area.coffee +0 -2
- data/lib/pulse-meter/visualize/coffee/presenters/gauge.coffee +0 -11
- data/lib/pulse-meter/visualize/coffee/presenters/line.coffee +0 -2
- data/lib/pulse-meter/visualize/coffee/presenters/pie.coffee +0 -20
- data/lib/pulse-meter/visualize/coffee/presenters/series.coffee +0 -44
- data/lib/pulse-meter/visualize/coffee/presenters/table.coffee +0 -10
- data/lib/pulse-meter/visualize/coffee/presenters/timeline.coffee +0 -13
- data/lib/pulse-meter/visualize/coffee/presenters/widget.coffee +0 -65
- data/lib/pulse-meter/visualize/coffee/router.coffee +0 -21
- data/lib/pulse-meter/visualize/coffee/views/dynamic_chart.coffee +0 -91
- data/lib/pulse-meter/visualize/coffee/views/dynamic_widget.coffee +0 -58
- data/lib/pulse-meter/visualize/coffee/views/page_title.coffee +0 -17
- data/lib/pulse-meter/visualize/coffee/views/page_titles.coffee +0 -15
- data/lib/pulse-meter/visualize/coffee/views/sensor_info_list.coffee +0 -19
- data/lib/pulse-meter/visualize/coffee/views/widget.coffee +0 -99
- data/lib/pulse-meter/visualize/coffee/views/widget_chart.coffee +0 -13
- data/lib/pulse-meter/visualize/coffee/views/widget_list.coffee +0 -15
- data/lib/pulse-meter/visualize/dsl/base.rb +0 -131
- data/lib/pulse-meter/visualize/dsl/errors.rb +0 -40
- data/lib/pulse-meter/visualize/dsl/layout.rb +0 -27
- data/lib/pulse-meter/visualize/dsl/page.rb +0 -33
- data/lib/pulse-meter/visualize/dsl/sensor.rb +0 -20
- data/lib/pulse-meter/visualize/dsl/widget.rb +0 -37
- data/lib/pulse-meter/visualize/dsl/widgets/area.rb +0 -20
- data/lib/pulse-meter/visualize/dsl/widgets/gauge.rb +0 -12
- data/lib/pulse-meter/visualize/dsl/widgets/line.rb +0 -21
- data/lib/pulse-meter/visualize/dsl/widgets/pie.rb +0 -16
- data/lib/pulse-meter/visualize/dsl/widgets/table.rb +0 -19
- data/lib/pulse-meter/visualize/layout.rb +0 -79
- data/lib/pulse-meter/visualize/page.rb +0 -25
- data/lib/pulse-meter/visualize/public/css/application.css +0 -56
- data/lib/pulse-meter/visualize/public/css/bootstrap.css +0 -4883
- data/lib/pulse-meter/visualize/public/css/bootstrap.min.css +0 -729
- data/lib/pulse-meter/visualize/public/css/images/ui-bg_flat_0_aaaaaa_40x100.png +0 -0
- data/lib/pulse-meter/visualize/public/css/images/ui-bg_glass_55_fbf9ee_1x400.png +0 -0
- data/lib/pulse-meter/visualize/public/css/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
- data/lib/pulse-meter/visualize/public/css/images/ui-bg_glass_75_dadada_1x400.png +0 -0
- data/lib/pulse-meter/visualize/public/css/images/ui-bg_glass_75_e6e6e6_1x400.png +0 -0
- data/lib/pulse-meter/visualize/public/css/images/ui-bg_glass_75_ffffff_1x400.png +0 -0
- data/lib/pulse-meter/visualize/public/css/images/ui-bg_highlight-soft_75_cccccc_1x100.png +0 -0
- data/lib/pulse-meter/visualize/public/css/images/ui-bg_inset-soft_95_fef1ec_1x100.png +0 -0
- data/lib/pulse-meter/visualize/public/css/images/ui-icons_222222_256x240.png +0 -0
- data/lib/pulse-meter/visualize/public/css/images/ui-icons_2e83ff_256x240.png +0 -0
- data/lib/pulse-meter/visualize/public/css/images/ui-icons_454545_256x240.png +0 -0
- data/lib/pulse-meter/visualize/public/css/images/ui-icons_888888_256x240.png +0 -0
- data/lib/pulse-meter/visualize/public/css/images/ui-icons_cd0a0a_256x240.png +0 -0
- data/lib/pulse-meter/visualize/public/css/images/ui-icons_f6cf3b_256x240.png +0 -0
- data/lib/pulse-meter/visualize/public/css/jquery-ui-1.8.16.bootstrap.css +0 -1320
- data/lib/pulse-meter/visualize/public/favicon.ico +0 -208
- data/lib/pulse-meter/visualize/public/img/glyphicons-halflings-white.png +0 -0
- data/lib/pulse-meter/visualize/public/img/glyphicons-halflings.png +0 -0
- data/lib/pulse-meter/visualize/public/js/application.js +0 -973
- data/lib/pulse-meter/visualize/public/js/backbone-min.js +0 -38
- data/lib/pulse-meter/visualize/public/js/bootstrap.js +0 -1835
- data/lib/pulse-meter/visualize/public/js/jquery-1.7.2.min.js +0 -4
- data/lib/pulse-meter/visualize/public/js/jquery-ui-1.8.16.bootstrap.min.js +0 -791
- data/lib/pulse-meter/visualize/public/js/jquery-ui-1.8.23.custom.min.js +0 -21
- data/lib/pulse-meter/visualize/public/js/jquery-ui-timepicker-addon.js +0 -1687
- data/lib/pulse-meter/visualize/public/js/json2.js +0 -487
- data/lib/pulse-meter/visualize/public/js/underscore-min.js +0 -32
- data/lib/pulse-meter/visualize/sensor.rb +0 -63
- data/lib/pulse-meter/visualize/series_extractor.rb +0 -107
- data/lib/pulse-meter/visualize/views/main.haml +0 -30
- data/lib/pulse-meter/visualize/views/sensors.haml +0 -76
- data/lib/pulse-meter/visualize/views/widgets/area.haml +0 -53
- data/lib/pulse-meter/visualize/views/widgets/extend_options.haml +0 -11
- data/lib/pulse-meter/visualize/views/widgets/gauge.haml +0 -13
- data/lib/pulse-meter/visualize/views/widgets/line.haml +0 -54
- data/lib/pulse-meter/visualize/views/widgets/pie.haml +0 -13
- data/lib/pulse-meter/visualize/views/widgets/table.haml +0 -45
- data/lib/pulse-meter/visualize/widget.rb +0 -38
- data/lib/pulse-meter/visualize/widgets/gauge.rb +0 -47
- data/lib/pulse-meter/visualize/widgets/pie.rb +0 -36
- data/lib/pulse-meter/visualize/widgets/timeline.rb +0 -114
- data/spec/pulse_meter/command_aggregator/async_spec.rb +0 -53
- data/spec/pulse_meter/command_aggregator/sync_spec.rb +0 -25
- data/spec/pulse_meter/command_aggregator/udp_spec.rb +0 -45
- data/spec/pulse_meter/extensions/enumerable_spec.rb +0 -58
- data/spec/pulse_meter/mixins/cmd_spec.rb +0 -117
- data/spec/pulse_meter/mixins/dumper_spec.rb +0 -162
- data/spec/pulse_meter/mixins/utils_spec.rb +0 -212
- data/spec/pulse_meter/observer/extended_spec.rb +0 -92
- data/spec/pulse_meter/observer_spec.rb +0 -207
- data/spec/pulse_meter/sensor/base_spec.rb +0 -106
- data/spec/pulse_meter/sensor/configuration_spec.rb +0 -103
- data/spec/pulse_meter/sensor/counter_spec.rb +0 -54
- data/spec/pulse_meter/sensor/hashed_counter_spec.rb +0 -43
- data/spec/pulse_meter/sensor/hashed_indicator_spec.rb +0 -39
- data/spec/pulse_meter/sensor/indicator_spec.rb +0 -43
- data/spec/pulse_meter/sensor/multi_spec.rb +0 -137
- data/spec/pulse_meter/sensor/timeline_spec.rb +0 -88
- data/spec/pulse_meter/sensor/timelined/average_spec.rb +0 -6
- data/spec/pulse_meter/sensor/timelined/counter_spec.rb +0 -6
- data/spec/pulse_meter/sensor/timelined/hashed_counter_spec.rb +0 -8
- data/spec/pulse_meter/sensor/timelined/hashed_indicator_spec.rb +0 -8
- data/spec/pulse_meter/sensor/timelined/indicator_spec.rb +0 -6
- data/spec/pulse_meter/sensor/timelined/max_spec.rb +0 -7
- data/spec/pulse_meter/sensor/timelined/median_spec.rb +0 -7
- data/spec/pulse_meter/sensor/timelined/min_spec.rb +0 -7
- data/spec/pulse_meter/sensor/timelined/multi_percentile_spec.rb +0 -21
- data/spec/pulse_meter/sensor/timelined/percentile_spec.rb +0 -17
- data/spec/pulse_meter/sensor/timelined/uniq_counter_spec.rb +0 -9
- data/spec/pulse_meter/sensor/uniq_counter_spec.rb +0 -28
- data/spec/pulse_meter/udp_server_spec.rb +0 -36
- data/spec/pulse_meter/visualize/app_spec.rb +0 -27
- data/spec/pulse_meter/visualize/dsl/layout_spec.rb +0 -64
- data/spec/pulse_meter/visualize/dsl/page_spec.rb +0 -62
- data/spec/pulse_meter/visualize/dsl/sensor_spec.rb +0 -30
- data/spec/pulse_meter/visualize/dsl/widget_spec.rb +0 -6
- data/spec/pulse_meter/visualize/dsl/widgets/area_spec.rb +0 -44
- data/spec/pulse_meter/visualize/dsl/widgets/gauge_spec.rb +0 -22
- data/spec/pulse_meter/visualize/dsl/widgets/line_spec.rb +0 -44
- data/spec/pulse_meter/visualize/dsl/widgets/pie_spec.rb +0 -35
- data/spec/pulse_meter/visualize/dsl/widgets/table_spec.rb +0 -36
- data/spec/pulse_meter/visualize/layout_spec.rb +0 -54
- data/spec/pulse_meter/visualize/page_spec.rb +0 -153
- data/spec/pulse_meter/visualize/sensor_spec.rb +0 -120
- data/spec/pulse_meter/visualize/series_extractor_spec.rb +0 -80
- data/spec/pulse_meter/visualize/widgets/area_spec.rb +0 -6
- data/spec/pulse_meter/visualize/widgets/gauge_spec.rb +0 -63
- data/spec/pulse_meter/visualize/widgets/line_spec.rb +0 -6
- data/spec/pulse_meter/visualize/widgets/pie_spec.rb +0 -73
- data/spec/pulse_meter/visualize/widgets/table_spec.rb +0 -6
- data/spec/pulse_meter/visualizer_spec.rb +0 -42
- data/spec/pulse_meter_spec.rb +0 -73
- data/spec/shared_examples/dsl_widget.rb +0 -106
- data/spec/shared_examples/timeline_sensor.rb +0 -439
- data/spec/shared_examples/timelined_subclass.rb +0 -23
- data/spec/shared_examples/widget.rb +0 -97
- data/spec/spec_helper.rb +0 -40
- data/spec/support/matchers.rb +0 -34
- data/spec/support/observered.rb +0 -40
@@ -1,36 +0,0 @@
|
|
1
|
-
require 'json'
|
2
|
-
|
3
|
-
# Static hashed counter to count values by multiple keys
|
4
|
-
module PulseMeter
|
5
|
-
module Sensor
|
6
|
-
class HashedCounter < Counter
|
7
|
-
|
8
|
-
# Increments counter value by 1 for given key
|
9
|
-
# @param key [String] key to be incremented
|
10
|
-
def incr(key)
|
11
|
-
event({key => 1})
|
12
|
-
end
|
13
|
-
|
14
|
-
# Returs data stored in counter
|
15
|
-
# @return [Hash]
|
16
|
-
def value
|
17
|
-
redis.
|
18
|
-
hgetall(value_key).
|
19
|
-
inject(Hash.new(0)) {|h, (k, v)| h[k] = v.to_i; h}
|
20
|
-
end
|
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 do |k, v|
|
29
|
-
command_aggregator.hincrby(value_key, k, v.to_i)
|
30
|
-
command_aggregator.hincrby(value_key, :total, v.to_i)
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
|
-
end
|
35
|
-
end
|
36
|
-
end
|
@@ -1,24 +0,0 @@
|
|
1
|
-
module PulseMeter
|
2
|
-
module Sensor
|
3
|
-
# Static hashed indicator. In fact is is just a named hash with float value
|
4
|
-
class HashedIndicator < Indicator
|
5
|
-
|
6
|
-
# Get indicator values
|
7
|
-
# @return [Fixnum] indicator value or zero unless it was initialized
|
8
|
-
def value
|
9
|
-
redis.
|
10
|
-
hgetall(value_key).
|
11
|
-
inject(Hash.new(0)) {|h, (k, v)| h[k] = v.to_f; h}
|
12
|
-
end
|
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| command_aggregator.hset(value_key, name, value.to_f)}
|
20
|
-
end
|
21
|
-
|
22
|
-
end
|
23
|
-
end
|
24
|
-
end
|
@@ -1,35 +0,0 @@
|
|
1
|
-
module PulseMeter
|
2
|
-
module Sensor
|
3
|
-
# Static indicator. In fact is is just a named variable with float value
|
4
|
-
class Indicator < Base
|
5
|
-
|
6
|
-
# Cleans up all sensor metadata in Redis
|
7
|
-
def cleanup
|
8
|
-
redis.del(value_key)
|
9
|
-
super
|
10
|
-
end
|
11
|
-
|
12
|
-
# Get indicator value
|
13
|
-
# @return [Fixnum] indicator value or zero unless it was initialized
|
14
|
-
def value
|
15
|
-
val = redis.get(value_key)
|
16
|
-
val.nil? ? 0 : val.to_f
|
17
|
-
end
|
18
|
-
|
19
|
-
# Gets redis key by which counter value is stored
|
20
|
-
# @return [String]
|
21
|
-
def value_key
|
22
|
-
@value_key ||= "pulse_meter:value:#{name}"
|
23
|
-
end
|
24
|
-
|
25
|
-
private
|
26
|
-
|
27
|
-
# Sets indicator value
|
28
|
-
# @param value [Float] new indicator value
|
29
|
-
def process_event(value)
|
30
|
-
command_aggregator.set(value_key, value.to_f)
|
31
|
-
end
|
32
|
-
|
33
|
-
end
|
34
|
-
end
|
35
|
-
end
|
@@ -1,97 +0,0 @@
|
|
1
|
-
module PulseMeter
|
2
|
-
module Sensor
|
3
|
-
class Multi < Base
|
4
|
-
include PulseMeter::Mixins::Utils
|
5
|
-
include Enumerable
|
6
|
-
|
7
|
-
attr_reader :name
|
8
|
-
attr_reader :factors
|
9
|
-
attr_reader :sensors
|
10
|
-
attr_reader :configuration_options
|
11
|
-
|
12
|
-
# TODO restore in initializer
|
13
|
-
|
14
|
-
def initialize(name, options)
|
15
|
-
@name = name
|
16
|
-
@factors = assert_array!(options, :factors)
|
17
|
-
@sensors = PulseMeter::Sensor::Configuration.new
|
18
|
-
@configuration_options = options[:configuration]
|
19
|
-
raise ArgumentError, "configuration option missing" unless @configuration_options
|
20
|
-
end
|
21
|
-
|
22
|
-
def sensor(name)
|
23
|
-
raise ArgumentError, 'need a block' unless block_given?
|
24
|
-
sensors.sensor(name){|s| yield(s)}
|
25
|
-
end
|
26
|
-
|
27
|
-
def event(factors_hash, value)
|
28
|
-
ensure_valid_factors!(factors_hash)
|
29
|
-
|
30
|
-
each_factors_combination do |combination|
|
31
|
-
factor_values = factor_values_for_combination(combination, factors_hash)
|
32
|
-
get_or_create_sensor(combination, factor_values) do |s|
|
33
|
-
s.event(value)
|
34
|
-
end
|
35
|
-
end
|
36
|
-
end
|
37
|
-
|
38
|
-
def each
|
39
|
-
sensors.each {|s| yield(s)}
|
40
|
-
end
|
41
|
-
|
42
|
-
def sensor_for_factors(factor_names, factor_values)
|
43
|
-
raise ArgumentError, 'need a block' unless block_given?
|
44
|
-
sensor(get_sensor_name(factor_names, factor_values)){|s| yield(s)}
|
45
|
-
end
|
46
|
-
|
47
|
-
protected
|
48
|
-
|
49
|
-
def is_subsensor?(sensor)
|
50
|
-
sensor.name.start_with?(get_sensor_name([], []).to_s)
|
51
|
-
end
|
52
|
-
|
53
|
-
def get_or_create_sensor(factor_names, factor_values)
|
54
|
-
raise ArgumentError, 'need a block' unless block_given?
|
55
|
-
name = get_sensor_name(factor_names, factor_values)
|
56
|
-
unless sensors.has_sensor?(name)
|
57
|
-
sensors.add_sensor(name, configuration_options)
|
58
|
-
dump!(false)
|
59
|
-
end
|
60
|
-
sensor(name) do |s|
|
61
|
-
yield(s)
|
62
|
-
end
|
63
|
-
end
|
64
|
-
|
65
|
-
def ensure_valid_factors!(factors_hash)
|
66
|
-
factors.each do |factor_name|
|
67
|
-
unless factors_hash.has_key?(factor_name)
|
68
|
-
raise ArgumentError, "Value of factor #{factor_name} missing"
|
69
|
-
end
|
70
|
-
end
|
71
|
-
end
|
72
|
-
|
73
|
-
def each_factors_combination
|
74
|
-
each_subset(factors) do |combination|
|
75
|
-
yield(combination)
|
76
|
-
end
|
77
|
-
end
|
78
|
-
|
79
|
-
def factor_values_for_combination(combination, factors_hash)
|
80
|
-
combination.each_with_object([]) do |k, acc|
|
81
|
-
acc << factors_hash[k]
|
82
|
-
end
|
83
|
-
end
|
84
|
-
|
85
|
-
def get_sensor_name(factor_names, factor_values)
|
86
|
-
sensor_name = name.to_s
|
87
|
-
unless factor_names.empty?
|
88
|
-
factor_names.zip(factor_values).each do |n, v|
|
89
|
-
sensor_name << "_#{n}_#{v}"
|
90
|
-
end
|
91
|
-
end
|
92
|
-
sensor_name.to_sym
|
93
|
-
end
|
94
|
-
|
95
|
-
end
|
96
|
-
end
|
97
|
-
end
|
@@ -1,236 +0,0 @@
|
|
1
|
-
require 'securerandom'
|
2
|
-
|
3
|
-
module PulseMeter
|
4
|
-
module Sensor
|
5
|
-
# @abstract Represents timelined sensor: series of values,
|
6
|
-
# one value for each consequent time interval.
|
7
|
-
class Timeline < Base
|
8
|
-
include PulseMeter::Mixins::Utils
|
9
|
-
include PulseMeter::Sensor::TimelineReduce
|
10
|
-
|
11
|
-
MAX_TIMESPAN_POINTS = 1000
|
12
|
-
|
13
|
-
# @!attribute [r] interval
|
14
|
-
# @return [Fixnum] Rotation interval
|
15
|
-
# @!attribute [r] ttl
|
16
|
-
# @return [Fixnum] How long summarized data will be stored before expiration
|
17
|
-
# @!attribute [r] raw_data_ttl
|
18
|
-
# @return [Fixnum] How long unsummarized raw data will be stored before expiration
|
19
|
-
# @!attribute [r] reduce_delay
|
20
|
-
# @return [Fixnum] Delay between end of interval and summarization
|
21
|
-
attr_reader :interval, :ttl, :raw_data_ttl, :reduce_delay
|
22
|
-
|
23
|
-
# Default values for some sensor parameters
|
24
|
-
DEFAULTS = {
|
25
|
-
:raw_data_ttl => 3600,
|
26
|
-
:reduce_delay => 60,
|
27
|
-
}
|
28
|
-
|
29
|
-
# Initializes sensor with given name and parameters
|
30
|
-
# @param name [String] sensor name
|
31
|
-
# @option options [Fixnum] :interval Rotation interval
|
32
|
-
# @option options [Fixnum] :ttl How long summarized data will be stored before expiration
|
33
|
-
# @option options [Fixnum] :raw_data_ttl How long unsummarized raw data will be stored before expiration
|
34
|
-
# @option options [Fixnum] :reduce_delay Delay between end of interval and summarization
|
35
|
-
def initialize(name, options)
|
36
|
-
@interval = assert_positive_integer!(options, :interval)
|
37
|
-
@ttl = assert_positive_integer!(options, :ttl)
|
38
|
-
@raw_data_ttl = assert_positive_integer!(options, :raw_data_ttl, DEFAULTS[:raw_data_ttl])
|
39
|
-
@reduce_delay = assert_positive_integer!(options, :reduce_delay, DEFAULTS[:reduce_delay])
|
40
|
-
super
|
41
|
-
end
|
42
|
-
|
43
|
-
# Clean up all sensor metadata and data
|
44
|
-
def cleanup
|
45
|
-
keys = redis.keys(raw_data_key('*')) + redis.keys(data_key('*'))
|
46
|
-
multi do
|
47
|
-
keys.each{|key| redis.del(key)}
|
48
|
-
end
|
49
|
-
super
|
50
|
-
end
|
51
|
-
|
52
|
-
# Processes event from the past
|
53
|
-
# @param time [Time] event time
|
54
|
-
# @param value event value
|
55
|
-
def event_at(time, value = nil)
|
56
|
-
multi do
|
57
|
-
interval_id = get_interval_id(time)
|
58
|
-
key = raw_data_key(interval_id)
|
59
|
-
aggregate_event(key, value)
|
60
|
-
command_aggregator.expire(key, raw_data_ttl)
|
61
|
-
end
|
62
|
-
true
|
63
|
-
rescue StandardError => e
|
64
|
-
false
|
65
|
-
end
|
66
|
-
|
67
|
-
# Returts sensor data within some last seconds
|
68
|
-
# @param time_ago [Fixnum] interval length in seconds
|
69
|
-
# @return [Array<SensorData>]
|
70
|
-
# @raise ArgumentError if argumets are not valid time objects
|
71
|
-
def timeline(time_ago)
|
72
|
-
raise ArgumentError unless time_ago.respond_to?(:to_i) && time_ago.to_i > 0
|
73
|
-
now = Time.now
|
74
|
-
timeline_within(now - time_ago.to_i, now)
|
75
|
-
end
|
76
|
-
|
77
|
-
# Returts sensor data within given time
|
78
|
-
# @param from [Time] lower bound
|
79
|
-
# @param till [Time] upper bound
|
80
|
-
# @param skip_optimization [Boolean] must be set to true to skip interval optimization
|
81
|
-
# @return [Array<SensorData>]
|
82
|
-
# @raise ArgumentError if argumets are not valid time objects
|
83
|
-
def timeline_within(from, till, skip_optimization = false)
|
84
|
-
raise ArgumentError unless from.kind_of?(Time) && till.kind_of?(Time)
|
85
|
-
start_time, end_time = from.to_i, till.to_i
|
86
|
-
actual_interval = optimized_interval(start_time, end_time, skip_optimization)
|
87
|
-
start_interval_id = get_interval_id(start_time) + actual_interval
|
88
|
-
ids, values = fetch_reduced_interval_data(start_interval_id, actual_interval, end_time)
|
89
|
-
zip_with_raw_data(ids, values)
|
90
|
-
end
|
91
|
-
|
92
|
-
# Returns sensor data for given interval making in-memory summarization
|
93
|
-
# and returns calculated value
|
94
|
-
# @param interval_id [Fixnum]
|
95
|
-
# @return [SensorData]
|
96
|
-
def get_raw_value(interval_id)
|
97
|
-
interval_raw_data_key = raw_data_key(interval_id)
|
98
|
-
if redis.exists(interval_raw_data_key)
|
99
|
-
sensor_data(interval_id, summarize(interval_raw_data_key))
|
100
|
-
else
|
101
|
-
sensor_data(interval_id, nil)
|
102
|
-
end
|
103
|
-
end
|
104
|
-
|
105
|
-
# Drops sensor data within given time
|
106
|
-
# @param from [Time] lower bound
|
107
|
-
# @param till [Time] upper bound
|
108
|
-
# @raise ArgumentError if argumets are not valid time objects
|
109
|
-
def drop_within(from, till)
|
110
|
-
raise ArgumentError unless from.kind_of?(Time) && till.kind_of?(Time)
|
111
|
-
start_time, end_time = from.to_i, till.to_i
|
112
|
-
current_interval_id = get_interval_id(start_time) + interval
|
113
|
-
keys = []
|
114
|
-
while current_interval_id < end_time
|
115
|
-
keys << data_key(current_interval_id)
|
116
|
-
keys << raw_data_key(current_interval_id)
|
117
|
-
current_interval_id += interval
|
118
|
-
end
|
119
|
-
keys.empty? ? 0 : redis.del(*keys)
|
120
|
-
end
|
121
|
-
|
122
|
-
# Returns Redis key by which raw data for current interval is stored
|
123
|
-
def current_raw_data_key
|
124
|
-
raw_data_key(current_interval_id)
|
125
|
-
end
|
126
|
-
|
127
|
-
# Returns Redis key by which raw data for given interval is stored
|
128
|
-
# @param id [Fixnum] interval id
|
129
|
-
def raw_data_key(id)
|
130
|
-
"pulse_meter:raw:#{name}:#{id}"
|
131
|
-
end
|
132
|
-
|
133
|
-
# Returns Redis key by which summarized data for given interval is stored
|
134
|
-
# @param id [Fixnum] interval id
|
135
|
-
def data_key(id)
|
136
|
-
"pulse_meter:data:#{name}:#{id}"
|
137
|
-
end
|
138
|
-
|
139
|
-
# Returns interval id where given time is
|
140
|
-
# @param time [Time]
|
141
|
-
def get_interval_id(time)
|
142
|
-
(time.to_i / interval) * interval
|
143
|
-
end
|
144
|
-
|
145
|
-
# Returns current interval id
|
146
|
-
# @return [Fixnum]
|
147
|
-
def current_interval_id
|
148
|
-
get_interval_id(Time.now)
|
149
|
-
end
|
150
|
-
|
151
|
-
# @abstract Registeres event for current interval identified by key
|
152
|
-
# @param key [Fixnum] interval id
|
153
|
-
# @param value [Object] value to be aggregated
|
154
|
-
def aggregate_event(key, value)
|
155
|
-
# simple
|
156
|
-
redis.set(key, value)
|
157
|
-
end
|
158
|
-
|
159
|
-
# @abstract Summarizes all event within interval to a single value
|
160
|
-
# @param key [Fixnum] interval_id
|
161
|
-
def summarize(key)
|
162
|
-
# simple
|
163
|
-
redis.get(key)
|
164
|
-
end
|
165
|
-
|
166
|
-
# @abstract Deflates data taken from redis as string preserving nil values
|
167
|
-
# @param value [String] raw data
|
168
|
-
def deflate_safe(value)
|
169
|
-
value.nil? ? nil : deflate(value)
|
170
|
-
rescue
|
171
|
-
nil
|
172
|
-
end
|
173
|
-
|
174
|
-
private
|
175
|
-
|
176
|
-
def deflate(value)
|
177
|
-
# simple
|
178
|
-
value
|
179
|
-
end
|
180
|
-
|
181
|
-
def sensor_data(interval_id, value)
|
182
|
-
value = deflate(value) unless value.nil?
|
183
|
-
SensorData.new(Time.at(interval_id), value)
|
184
|
-
end
|
185
|
-
|
186
|
-
# Processes event
|
187
|
-
# @param value event value
|
188
|
-
def process_event(value = nil)
|
189
|
-
command_aggregator.multi do
|
190
|
-
current_key = current_raw_data_key
|
191
|
-
aggregate_event(current_key, value)
|
192
|
-
command_aggregator.expire(current_key, raw_data_ttl)
|
193
|
-
end
|
194
|
-
end
|
195
|
-
|
196
|
-
# Makes interval optimization so that the requested timespan contains less than MAX_TIMESPAN_POINTS values
|
197
|
-
# @param start_time [Fixnum] unix timestamp of timespan start
|
198
|
-
# @param end_time [Fixnum] unix timestamp of timespan start
|
199
|
-
# @return [Fixnum] optimized interval in seconds.
|
200
|
-
def optimized_interval(start_time, end_time, skip_optimization = false)
|
201
|
-
res_interval = interval
|
202
|
-
return res_interval if skip_optimization
|
203
|
-
timespan = end_time - start_time
|
204
|
-
while timespan / res_interval > MAX_TIMESPAN_POINTS - 1
|
205
|
-
res_interval *= 2
|
206
|
-
end
|
207
|
-
res_interval
|
208
|
-
end
|
209
|
-
|
210
|
-
def fetch_reduced_interval_data(start_interval_id, actual_interval, end_time)
|
211
|
-
keys = []
|
212
|
-
ids = []
|
213
|
-
current_interval_id = start_interval_id
|
214
|
-
while current_interval_id < end_time
|
215
|
-
ids << current_interval_id
|
216
|
-
keys << data_key(current_interval_id)
|
217
|
-
current_interval_id += actual_interval
|
218
|
-
end
|
219
|
-
values = keys.empty? ? [] : redis.mget(*keys)
|
220
|
-
[ids, values]
|
221
|
-
end
|
222
|
-
|
223
|
-
def zip_with_raw_data(ids, values)
|
224
|
-
res = []
|
225
|
-
ids.zip(values) do |(id, val)|
|
226
|
-
res << if val.nil?
|
227
|
-
get_raw_value(id)
|
228
|
-
else
|
229
|
-
sensor_data(id, val)
|
230
|
-
end
|
231
|
-
end
|
232
|
-
res
|
233
|
-
end
|
234
|
-
end
|
235
|
-
end
|
236
|
-
end
|
@@ -1,68 +0,0 @@
|
|
1
|
-
module PulseMeter
|
2
|
-
module Sensor
|
3
|
-
# Methods for reducing raw data to single values
|
4
|
-
module TimelineReduce
|
5
|
-
|
6
|
-
def self.included(base)
|
7
|
-
base.extend(ClassMethods)
|
8
|
-
end
|
9
|
-
|
10
|
-
MAX_INTERVALS = 100
|
11
|
-
|
12
|
-
# @note Interval id is
|
13
|
-
# just unixtime of its lower bound. Ruduction is a process
|
14
|
-
# of 'compressing' all interval's raw data to a single value.
|
15
|
-
# When reduction is done summarized data is saved to Redis
|
16
|
-
# separately with expiration time taken from sensor configuration.
|
17
|
-
# @param interval_id [Fixnum]
|
18
|
-
def reduce(interval_id)
|
19
|
-
interval_raw_data_key = raw_data_key(interval_id)
|
20
|
-
return unless redis.exists(interval_raw_data_key)
|
21
|
-
value = summarize(interval_raw_data_key)
|
22
|
-
interval_data_key = data_key(interval_id)
|
23
|
-
multi do
|
24
|
-
redis.del(interval_raw_data_key)
|
25
|
-
if redis.setnx(interval_data_key, value)
|
26
|
-
redis.expire(interval_data_key, ttl)
|
27
|
-
end
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
|
-
# Reduces data in all raw intervals
|
32
|
-
def reduce_all_raw
|
33
|
-
time = Time.now
|
34
|
-
min_time = time - reduce_delay - interval
|
35
|
-
max_depth = time - reduce_delay - interval * MAX_INTERVALS
|
36
|
-
ids = collect_ids_to_reduce(time, max_depth, min_time)
|
37
|
-
ids.reverse.each {|id| reduce(id)}
|
38
|
-
end
|
39
|
-
|
40
|
-
def collect_ids_to_reduce(time, time_from, time_to)
|
41
|
-
ids = []
|
42
|
-
while (time > time_from) # go backwards
|
43
|
-
time -= interval
|
44
|
-
interval_id = get_interval_id(time)
|
45
|
-
next if Time.at(interval_id) > time_to
|
46
|
-
|
47
|
-
reduced_key = data_key(interval_id)
|
48
|
-
raw_key = raw_data_key(interval_id)
|
49
|
-
break if redis.exists(reduced_key)
|
50
|
-
ids << interval_id
|
51
|
-
end
|
52
|
-
ids
|
53
|
-
end
|
54
|
-
|
55
|
-
module ClassMethods
|
56
|
-
|
57
|
-
def reduce_all_raw
|
58
|
-
list_objects.each do |sensor|
|
59
|
-
sensor.reduce_all_raw if sensor.respond_to? :reduce_all_raw
|
60
|
-
end
|
61
|
-
end
|
62
|
-
|
63
|
-
end
|
64
|
-
|
65
|
-
end
|
66
|
-
end
|
67
|
-
end
|
68
|
-
|