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.
Files changed (192) hide show
  1. data/Rakefile +1 -48
  2. data/lib/pulse-meter.rb +1 -68
  3. data/lib/pulse-meter/visualizer.rb +1 -40
  4. data/pulse-meter.gemspec +4 -26
  5. metadata +10 -558
  6. data/Procfile +0 -3
  7. data/bin/pulse +0 -6
  8. data/examples/basic.ru +0 -145
  9. data/examples/basic_sensor_data.rb +0 -96
  10. data/examples/udp_benchmark.rb +0 -29
  11. data/lib/cmd.rb +0 -171
  12. data/lib/pulse-meter/command_aggregator/async.rb +0 -83
  13. data/lib/pulse-meter/command_aggregator/sync.rb +0 -18
  14. data/lib/pulse-meter/command_aggregator/udp.rb +0 -48
  15. data/lib/pulse-meter/extensions/enumerable.rb +0 -24
  16. data/lib/pulse-meter/mixins/cmd.rb +0 -46
  17. data/lib/pulse-meter/mixins/dumper.rb +0 -87
  18. data/lib/pulse-meter/mixins/utils.rb +0 -155
  19. data/lib/pulse-meter/observer.rb +0 -120
  20. data/lib/pulse-meter/observer/extended.rb +0 -34
  21. data/lib/pulse-meter/sensor.rb +0 -61
  22. data/lib/pulse-meter/sensor/base.rb +0 -88
  23. data/lib/pulse-meter/sensor/configuration.rb +0 -106
  24. data/lib/pulse-meter/sensor/counter.rb +0 -39
  25. data/lib/pulse-meter/sensor/hashed_counter.rb +0 -36
  26. data/lib/pulse-meter/sensor/hashed_indicator.rb +0 -24
  27. data/lib/pulse-meter/sensor/indicator.rb +0 -35
  28. data/lib/pulse-meter/sensor/multi.rb +0 -97
  29. data/lib/pulse-meter/sensor/timeline.rb +0 -236
  30. data/lib/pulse-meter/sensor/timeline_reduce.rb +0 -68
  31. data/lib/pulse-meter/sensor/timelined/average.rb +0 -32
  32. data/lib/pulse-meter/sensor/timelined/counter.rb +0 -23
  33. data/lib/pulse-meter/sensor/timelined/hashed_counter.rb +0 -31
  34. data/lib/pulse-meter/sensor/timelined/hashed_indicator.rb +0 -30
  35. data/lib/pulse-meter/sensor/timelined/indicator.rb +0 -23
  36. data/lib/pulse-meter/sensor/timelined/max.rb +0 -19
  37. data/lib/pulse-meter/sensor/timelined/median.rb +0 -14
  38. data/lib/pulse-meter/sensor/timelined/min.rb +0 -19
  39. data/lib/pulse-meter/sensor/timelined/multi_percentile.rb +0 -34
  40. data/lib/pulse-meter/sensor/timelined/percentile.rb +0 -22
  41. data/lib/pulse-meter/sensor/timelined/uniq_counter.rb +0 -22
  42. data/lib/pulse-meter/sensor/timelined/zset_based.rb +0 -38
  43. data/lib/pulse-meter/sensor/uniq_counter.rb +0 -24
  44. data/lib/pulse-meter/server.rb +0 -0
  45. data/lib/pulse-meter/server/command_line_options.rb +0 -0
  46. data/lib/pulse-meter/server/config_options.rb +0 -0
  47. data/lib/pulse-meter/server/sensors.rb +0 -0
  48. data/lib/pulse-meter/udp_server.rb +0 -45
  49. data/lib/pulse-meter/version.rb +0 -3
  50. data/lib/pulse-meter/visualize/app.rb +0 -78
  51. data/lib/pulse-meter/visualize/base.rb +0 -15
  52. data/lib/pulse-meter/visualize/coffee/application.coffee +0 -40
  53. data/lib/pulse-meter/visualize/coffee/collections/page_info_list.coffee +0 -17
  54. data/lib/pulse-meter/visualize/coffee/collections/sensor_info_list.coffee +0 -4
  55. data/lib/pulse-meter/visualize/coffee/collections/widget_list.coffee +0 -14
  56. data/lib/pulse-meter/visualize/coffee/extensions.coffee +0 -26
  57. data/lib/pulse-meter/visualize/coffee/models/dinamic_widget.coffee +0 -34
  58. data/lib/pulse-meter/visualize/coffee/models/page_info.coffee +0 -2
  59. data/lib/pulse-meter/visualize/coffee/models/sensor_info.coffee +0 -2
  60. data/lib/pulse-meter/visualize/coffee/models/widget.coffee +0 -54
  61. data/lib/pulse-meter/visualize/coffee/presenters/area.coffee +0 -2
  62. data/lib/pulse-meter/visualize/coffee/presenters/gauge.coffee +0 -11
  63. data/lib/pulse-meter/visualize/coffee/presenters/line.coffee +0 -2
  64. data/lib/pulse-meter/visualize/coffee/presenters/pie.coffee +0 -20
  65. data/lib/pulse-meter/visualize/coffee/presenters/series.coffee +0 -44
  66. data/lib/pulse-meter/visualize/coffee/presenters/table.coffee +0 -10
  67. data/lib/pulse-meter/visualize/coffee/presenters/timeline.coffee +0 -13
  68. data/lib/pulse-meter/visualize/coffee/presenters/widget.coffee +0 -65
  69. data/lib/pulse-meter/visualize/coffee/router.coffee +0 -21
  70. data/lib/pulse-meter/visualize/coffee/views/dynamic_chart.coffee +0 -91
  71. data/lib/pulse-meter/visualize/coffee/views/dynamic_widget.coffee +0 -58
  72. data/lib/pulse-meter/visualize/coffee/views/page_title.coffee +0 -17
  73. data/lib/pulse-meter/visualize/coffee/views/page_titles.coffee +0 -15
  74. data/lib/pulse-meter/visualize/coffee/views/sensor_info_list.coffee +0 -19
  75. data/lib/pulse-meter/visualize/coffee/views/widget.coffee +0 -99
  76. data/lib/pulse-meter/visualize/coffee/views/widget_chart.coffee +0 -13
  77. data/lib/pulse-meter/visualize/coffee/views/widget_list.coffee +0 -15
  78. data/lib/pulse-meter/visualize/dsl/base.rb +0 -131
  79. data/lib/pulse-meter/visualize/dsl/errors.rb +0 -40
  80. data/lib/pulse-meter/visualize/dsl/layout.rb +0 -27
  81. data/lib/pulse-meter/visualize/dsl/page.rb +0 -33
  82. data/lib/pulse-meter/visualize/dsl/sensor.rb +0 -20
  83. data/lib/pulse-meter/visualize/dsl/widget.rb +0 -37
  84. data/lib/pulse-meter/visualize/dsl/widgets/area.rb +0 -20
  85. data/lib/pulse-meter/visualize/dsl/widgets/gauge.rb +0 -12
  86. data/lib/pulse-meter/visualize/dsl/widgets/line.rb +0 -21
  87. data/lib/pulse-meter/visualize/dsl/widgets/pie.rb +0 -16
  88. data/lib/pulse-meter/visualize/dsl/widgets/table.rb +0 -19
  89. data/lib/pulse-meter/visualize/layout.rb +0 -79
  90. data/lib/pulse-meter/visualize/page.rb +0 -25
  91. data/lib/pulse-meter/visualize/public/css/application.css +0 -56
  92. data/lib/pulse-meter/visualize/public/css/bootstrap.css +0 -4883
  93. data/lib/pulse-meter/visualize/public/css/bootstrap.min.css +0 -729
  94. data/lib/pulse-meter/visualize/public/css/images/ui-bg_flat_0_aaaaaa_40x100.png +0 -0
  95. data/lib/pulse-meter/visualize/public/css/images/ui-bg_glass_55_fbf9ee_1x400.png +0 -0
  96. data/lib/pulse-meter/visualize/public/css/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
  97. data/lib/pulse-meter/visualize/public/css/images/ui-bg_glass_75_dadada_1x400.png +0 -0
  98. data/lib/pulse-meter/visualize/public/css/images/ui-bg_glass_75_e6e6e6_1x400.png +0 -0
  99. data/lib/pulse-meter/visualize/public/css/images/ui-bg_glass_75_ffffff_1x400.png +0 -0
  100. data/lib/pulse-meter/visualize/public/css/images/ui-bg_highlight-soft_75_cccccc_1x100.png +0 -0
  101. data/lib/pulse-meter/visualize/public/css/images/ui-bg_inset-soft_95_fef1ec_1x100.png +0 -0
  102. data/lib/pulse-meter/visualize/public/css/images/ui-icons_222222_256x240.png +0 -0
  103. data/lib/pulse-meter/visualize/public/css/images/ui-icons_2e83ff_256x240.png +0 -0
  104. data/lib/pulse-meter/visualize/public/css/images/ui-icons_454545_256x240.png +0 -0
  105. data/lib/pulse-meter/visualize/public/css/images/ui-icons_888888_256x240.png +0 -0
  106. data/lib/pulse-meter/visualize/public/css/images/ui-icons_cd0a0a_256x240.png +0 -0
  107. data/lib/pulse-meter/visualize/public/css/images/ui-icons_f6cf3b_256x240.png +0 -0
  108. data/lib/pulse-meter/visualize/public/css/jquery-ui-1.8.16.bootstrap.css +0 -1320
  109. data/lib/pulse-meter/visualize/public/favicon.ico +0 -208
  110. data/lib/pulse-meter/visualize/public/img/glyphicons-halflings-white.png +0 -0
  111. data/lib/pulse-meter/visualize/public/img/glyphicons-halflings.png +0 -0
  112. data/lib/pulse-meter/visualize/public/js/application.js +0 -973
  113. data/lib/pulse-meter/visualize/public/js/backbone-min.js +0 -38
  114. data/lib/pulse-meter/visualize/public/js/bootstrap.js +0 -1835
  115. data/lib/pulse-meter/visualize/public/js/jquery-1.7.2.min.js +0 -4
  116. data/lib/pulse-meter/visualize/public/js/jquery-ui-1.8.16.bootstrap.min.js +0 -791
  117. data/lib/pulse-meter/visualize/public/js/jquery-ui-1.8.23.custom.min.js +0 -21
  118. data/lib/pulse-meter/visualize/public/js/jquery-ui-timepicker-addon.js +0 -1687
  119. data/lib/pulse-meter/visualize/public/js/json2.js +0 -487
  120. data/lib/pulse-meter/visualize/public/js/underscore-min.js +0 -32
  121. data/lib/pulse-meter/visualize/sensor.rb +0 -63
  122. data/lib/pulse-meter/visualize/series_extractor.rb +0 -107
  123. data/lib/pulse-meter/visualize/views/main.haml +0 -30
  124. data/lib/pulse-meter/visualize/views/sensors.haml +0 -76
  125. data/lib/pulse-meter/visualize/views/widgets/area.haml +0 -53
  126. data/lib/pulse-meter/visualize/views/widgets/extend_options.haml +0 -11
  127. data/lib/pulse-meter/visualize/views/widgets/gauge.haml +0 -13
  128. data/lib/pulse-meter/visualize/views/widgets/line.haml +0 -54
  129. data/lib/pulse-meter/visualize/views/widgets/pie.haml +0 -13
  130. data/lib/pulse-meter/visualize/views/widgets/table.haml +0 -45
  131. data/lib/pulse-meter/visualize/widget.rb +0 -38
  132. data/lib/pulse-meter/visualize/widgets/gauge.rb +0 -47
  133. data/lib/pulse-meter/visualize/widgets/pie.rb +0 -36
  134. data/lib/pulse-meter/visualize/widgets/timeline.rb +0 -114
  135. data/spec/pulse_meter/command_aggregator/async_spec.rb +0 -53
  136. data/spec/pulse_meter/command_aggregator/sync_spec.rb +0 -25
  137. data/spec/pulse_meter/command_aggregator/udp_spec.rb +0 -45
  138. data/spec/pulse_meter/extensions/enumerable_spec.rb +0 -58
  139. data/spec/pulse_meter/mixins/cmd_spec.rb +0 -117
  140. data/spec/pulse_meter/mixins/dumper_spec.rb +0 -162
  141. data/spec/pulse_meter/mixins/utils_spec.rb +0 -212
  142. data/spec/pulse_meter/observer/extended_spec.rb +0 -92
  143. data/spec/pulse_meter/observer_spec.rb +0 -207
  144. data/spec/pulse_meter/sensor/base_spec.rb +0 -106
  145. data/spec/pulse_meter/sensor/configuration_spec.rb +0 -103
  146. data/spec/pulse_meter/sensor/counter_spec.rb +0 -54
  147. data/spec/pulse_meter/sensor/hashed_counter_spec.rb +0 -43
  148. data/spec/pulse_meter/sensor/hashed_indicator_spec.rb +0 -39
  149. data/spec/pulse_meter/sensor/indicator_spec.rb +0 -43
  150. data/spec/pulse_meter/sensor/multi_spec.rb +0 -137
  151. data/spec/pulse_meter/sensor/timeline_spec.rb +0 -88
  152. data/spec/pulse_meter/sensor/timelined/average_spec.rb +0 -6
  153. data/spec/pulse_meter/sensor/timelined/counter_spec.rb +0 -6
  154. data/spec/pulse_meter/sensor/timelined/hashed_counter_spec.rb +0 -8
  155. data/spec/pulse_meter/sensor/timelined/hashed_indicator_spec.rb +0 -8
  156. data/spec/pulse_meter/sensor/timelined/indicator_spec.rb +0 -6
  157. data/spec/pulse_meter/sensor/timelined/max_spec.rb +0 -7
  158. data/spec/pulse_meter/sensor/timelined/median_spec.rb +0 -7
  159. data/spec/pulse_meter/sensor/timelined/min_spec.rb +0 -7
  160. data/spec/pulse_meter/sensor/timelined/multi_percentile_spec.rb +0 -21
  161. data/spec/pulse_meter/sensor/timelined/percentile_spec.rb +0 -17
  162. data/spec/pulse_meter/sensor/timelined/uniq_counter_spec.rb +0 -9
  163. data/spec/pulse_meter/sensor/uniq_counter_spec.rb +0 -28
  164. data/spec/pulse_meter/udp_server_spec.rb +0 -36
  165. data/spec/pulse_meter/visualize/app_spec.rb +0 -27
  166. data/spec/pulse_meter/visualize/dsl/layout_spec.rb +0 -64
  167. data/spec/pulse_meter/visualize/dsl/page_spec.rb +0 -62
  168. data/spec/pulse_meter/visualize/dsl/sensor_spec.rb +0 -30
  169. data/spec/pulse_meter/visualize/dsl/widget_spec.rb +0 -6
  170. data/spec/pulse_meter/visualize/dsl/widgets/area_spec.rb +0 -44
  171. data/spec/pulse_meter/visualize/dsl/widgets/gauge_spec.rb +0 -22
  172. data/spec/pulse_meter/visualize/dsl/widgets/line_spec.rb +0 -44
  173. data/spec/pulse_meter/visualize/dsl/widgets/pie_spec.rb +0 -35
  174. data/spec/pulse_meter/visualize/dsl/widgets/table_spec.rb +0 -36
  175. data/spec/pulse_meter/visualize/layout_spec.rb +0 -54
  176. data/spec/pulse_meter/visualize/page_spec.rb +0 -153
  177. data/spec/pulse_meter/visualize/sensor_spec.rb +0 -120
  178. data/spec/pulse_meter/visualize/series_extractor_spec.rb +0 -80
  179. data/spec/pulse_meter/visualize/widgets/area_spec.rb +0 -6
  180. data/spec/pulse_meter/visualize/widgets/gauge_spec.rb +0 -63
  181. data/spec/pulse_meter/visualize/widgets/line_spec.rb +0 -6
  182. data/spec/pulse_meter/visualize/widgets/pie_spec.rb +0 -73
  183. data/spec/pulse_meter/visualize/widgets/table_spec.rb +0 -6
  184. data/spec/pulse_meter/visualizer_spec.rb +0 -42
  185. data/spec/pulse_meter_spec.rb +0 -73
  186. data/spec/shared_examples/dsl_widget.rb +0 -106
  187. data/spec/shared_examples/timeline_sensor.rb +0 -439
  188. data/spec/shared_examples/timelined_subclass.rb +0 -23
  189. data/spec/shared_examples/widget.rb +0 -97
  190. data/spec/spec_helper.rb +0 -40
  191. data/spec/support/matchers.rb +0 -34
  192. 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
-