pulse_meter_core 0.4.13 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -38,3 +38,4 @@ Or install it yourself as:
38
38
  3. Commit your changes (`git commit -am 'Added some feature'`)
39
39
  4. Push to the branch (`git push origin my-new-feature`)
40
40
  5. Create new Pull Request
41
+
@@ -1,4 +1,5 @@
1
1
  require 'securerandom'
2
+ require 'pulse_meter/time_converter'
2
3
 
3
4
  module PulseMeter
4
5
  module Sensor
@@ -18,7 +19,9 @@ module PulseMeter
18
19
  # @return [Fixnum] How long unsummarized raw data will be stored before expiration
19
20
  # @!attribute [r] reduce_delay
20
21
  # @return [Fixnum] Delay between end of interval and summarization
21
- attr_reader :interval, :ttl, :raw_data_ttl, :reduce_delay
22
+ # @!attribute [r] timezone
23
+ # @return [String] TimeZone to which sensor data is related
24
+ attr_reader :interval, :ttl, :raw_data_ttl, :reduce_delay, :timezone
22
25
 
23
26
  # Default values for some sensor parameters
24
27
  DEFAULTS = {
@@ -32,11 +35,13 @@ module PulseMeter
32
35
  # @option options [Fixnum] :ttl How long summarized data will be stored before expiration
33
36
  # @option options [Fixnum] :raw_data_ttl How long unsummarized raw data will be stored before expiration
34
37
  # @option options [Fixnum] :reduce_delay Delay between end of interval and summarization
38
+ # @option options [String] :timezone TimeZone to which sensor data is related
35
39
  def initialize(name, options)
36
40
  @interval = assert_positive_integer!(options, :interval)
37
41
  @ttl = assert_positive_integer!(options, :ttl)
38
42
  @raw_data_ttl = assert_positive_integer!(options, :raw_data_ttl, DEFAULTS[:raw_data_ttl])
39
43
  @reduce_delay = assert_positive_integer!(options, :reduce_delay, DEFAULTS[:reduce_delay])
44
+ @timezone = options[:timezone]
40
45
  super
41
46
  end
42
47
 
@@ -54,7 +59,7 @@ module PulseMeter
54
59
  # @param value event value
55
60
  def event_at(time, value = nil)
56
61
  multi do
57
- interval_id = get_interval_id(time)
62
+ interval_id = get_interval_id(time_to_redis(time))
58
63
  key = raw_data_key(interval_id)
59
64
  aggregate_event(key, value)
60
65
  command_aggregator.expire(key, raw_data_ttl)
@@ -82,7 +87,7 @@ module PulseMeter
82
87
  # @raise ArgumentError if argumets are not valid time objects
83
88
  def timeline_within(from, till, skip_optimization = false)
84
89
  raise ArgumentError unless from.kind_of?(Time) && till.kind_of?(Time)
85
- start_time, end_time = from.to_i, till.to_i
90
+ start_time, end_time = time_to_redis(from.to_i), time_to_redis(till.to_i)
86
91
  actual_interval = optimized_interval(start_time, end_time, skip_optimization)
87
92
  start_interval_id = get_interval_id(start_time) + actual_interval
88
93
  ids, values = fetch_reduced_interval_data(start_interval_id, actual_interval, end_time)
@@ -108,7 +113,7 @@ module PulseMeter
108
113
  # @raise ArgumentError if argumets are not valid time objects
109
114
  def drop_within(from, till)
110
115
  raise ArgumentError unless from.kind_of?(Time) && till.kind_of?(Time)
111
- start_time, end_time = from.to_i, till.to_i
116
+ start_time, end_time = time_to_redis(from.to_i), time_to_redis(till.to_i)
112
117
  current_interval_id = get_interval_id(start_time) + interval
113
118
  keys = []
114
119
  while current_interval_id < end_time
@@ -145,7 +150,7 @@ module PulseMeter
145
150
  # Returns current interval id
146
151
  # @return [Fixnum]
147
152
  def current_interval_id
148
- get_interval_id(Time.now)
153
+ get_interval_id(time_to_redis(Time.now))
149
154
  end
150
155
 
151
156
  # @abstract Registeres event for current interval identified by key
@@ -180,7 +185,7 @@ module PulseMeter
180
185
 
181
186
  def sensor_data(interval_id, value)
182
187
  value = deflate(value) unless value.nil?
183
- SensorData.new(Time.at(interval_id), value)
188
+ SensorData.new(Time.at(time_from_redis(interval_id)), value)
184
189
  end
185
190
 
186
191
  # Processes event
@@ -231,6 +236,18 @@ module PulseMeter
231
236
  end
232
237
  res
233
238
  end
239
+
240
+ def time_converter
241
+ @time_converter ||= PulseMeter::TimeConverter.new(@timezone)
242
+ end
243
+
244
+ def time_to_redis(time)
245
+ time_converter.to_redis(time)
246
+ end
247
+
248
+ def time_from_redis(time)
249
+ time_converter.from_redis(time)
250
+ end
234
251
  end
235
252
  end
236
253
  end
@@ -30,7 +30,7 @@ module PulseMeter
30
30
 
31
31
  # Reduces data in all raw intervals
32
32
  def reduce_all_raw
33
- time = Time.now
33
+ time = time_to_redis(Time.now)
34
34
  min_time = time - reduce_delay - interval
35
35
  max_depth = time - reduce_delay - interval * MAX_INTERVALS
36
36
  ids = collect_ids_to_reduce(time, max_depth, min_time)
@@ -42,7 +42,7 @@ module PulseMeter
42
42
  while (time > time_from) # go backwards
43
43
  time -= interval
44
44
  interval_id = get_interval_id(time)
45
- next if Time.at(interval_id) > time_to
45
+ next if interval_id > time_to
46
46
 
47
47
  reduced_key = data_key(interval_id)
48
48
  raw_key = raw_data_key(interval_id)
@@ -0,0 +1,26 @@
1
+ require 'tzinfo'
2
+
3
+ module PulseMeter
4
+ class TimeConverter
5
+ def initialize(timezone_name)
6
+ @tz = TZInfo::Timezone.get(timezone_name)
7
+ rescue TZInfo::InvalidTimezoneIdentifier
8
+ @tz = TZInfo::Timezone.get('UTC')
9
+ end
10
+
11
+ def to_redis(time)
12
+ tz_period.to_local(time.to_i).to_i
13
+ end
14
+
15
+ def from_redis(time)
16
+ tz_period.to_utc(time.to_i).to_i
17
+ end
18
+
19
+ private
20
+
21
+ def tz_period
22
+ @tz.period_for_utc(Time.now.utc)
23
+ end
24
+
25
+ end
26
+ end
@@ -15,10 +15,11 @@ Gem::Specification.new do |gem|
15
15
  gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
16
16
  gem.name = "pulse_meter_core"
17
17
  gem.require_paths = ["lib"]
18
- gem.version = "0.4.13"
18
+ gem.version = "0.5.0"
19
19
 
20
- gem.add_runtime_dependency('redis')
21
20
  gem.add_runtime_dependency('json')
21
+ gem.add_runtime_dependency('redis')
22
+ gem.add_runtime_dependency('tzinfo')
22
23
 
23
24
  gem.add_development_dependency('aquarium')
24
25
  gem.add_development_dependency('hashie')
@@ -10,7 +10,8 @@ shared_examples_for "timeline sensor" do |extra_init_values, default_event|
10
10
  let(:raw_data_ttl){ 3000 }
11
11
  let(:interval){ 5 }
12
12
  let(:reduce_delay){ 3 }
13
- let(:good_init_values){ {:ttl => ttl, :raw_data_ttl => raw_data_ttl, :interval => interval, :reduce_delay => reduce_delay}.merge(extra_init_values || {}) }
13
+ let(:timezone){'Europe/Moscow'}
14
+ let(:good_init_values){ {:timezone => timezone, :ttl => ttl, :raw_data_ttl => raw_data_ttl, :interval => interval, :reduce_delay => reduce_delay}.merge(extra_init_values || {}) }
14
15
  let!(:sensor){ described_class.new(name, good_init_values) }
15
16
  let(:dummy) {Dummy.new}
16
17
  let(:base_class){ PulseMeter::Sensor::Base }
@@ -18,16 +19,22 @@ shared_examples_for "timeline sensor" do |extra_init_values, default_event|
18
19
  let(:sample_event) {default_event || 123}
19
20
 
20
21
  before(:each) do
21
- @interval_id = (Time.now.to_i / interval) * interval
22
- @prev_interval_id = (Time.now.to_i / interval) * interval - interval
22
+ @now = Time.now
23
+ tc = PulseMeter::TimeConverter.new(timezone)
24
+
25
+ @redis_now = tc.to_redis(@now).to_i
26
+
27
+ @interval_id = (@redis_now / interval) * interval
28
+ @prev_interval_id = (@redis_now / interval) * interval - interval
23
29
 
24
30
  @raw_data_key = sensor.raw_data_key(@interval_id)
31
+
25
32
  @prev_raw_data_key = sensor.raw_data_key(@prev_interval_id)
26
33
 
27
34
  @next_raw_data_key = sensor.raw_data_key(@interval_id + interval)
28
35
 
29
- @start_of_interval = Time.at(@interval_id)
30
- @start_of_prev_interval = Time.at(@prev_interval_id)
36
+ @start_of_interval = Time.at(tc.from_redis(@interval_id))
37
+ @start_of_prev_interval = Time.at(tc.from_redis(@prev_interval_id))
31
38
  end
32
39
 
33
40
  describe "#dump" do
@@ -66,7 +73,7 @@ shared_examples_for "timeline sensor" do |extra_init_values, default_event|
66
73
  it "should write data so that it totally expires after :raw_data_ttl" do
67
74
  key_count = redis.keys('*').count
68
75
  sensor.event(sample_event)
69
- Timecop.freeze(Time.now + raw_data_ttl + 1) do
76
+ Timecop.freeze(@now + raw_data_ttl + 1) do
70
77
  redis.keys('*').count.should == key_count
71
78
  end
72
79
  end
@@ -90,7 +97,7 @@ shared_examples_for "timeline sensor" do |extra_init_values, default_event|
90
97
  end
91
98
 
92
99
  describe "#event_at" do
93
- let(:now) {Time.now}
100
+ let(:now) {@now}
94
101
  it "should write events to redis" do
95
102
  expect{
96
103
  sensor.event_at(now, sample_event)
@@ -230,14 +237,14 @@ shared_examples_for "timeline sensor" do |extra_init_values, default_event|
230
237
  describe "#timeline_within" do
231
238
  it "should raise exception unless both arguments are Time objects" do
232
239
  [:q, nil, -1].each do |bad_value|
233
- expect{ sensor.timeline_within(Time.now, bad_value) }.to raise_exception(ArgumentError)
234
- expect{ sensor.timeline_within(bad_value, Time.now) }.to raise_exception(ArgumentError)
240
+ expect{ sensor.timeline_within(@now, bad_value) }.to raise_exception(ArgumentError)
241
+ expect{ sensor.timeline_within(bad_value, @now) }.to raise_exception(ArgumentError)
235
242
  end
236
243
  end
237
244
 
238
245
  it "should return an array of SensorData objects corresponding to stored data for passed interval" do
239
246
  sensor.event(sample_event)
240
- now = Time.now
247
+ now = @now
241
248
  timeline = sensor.timeline_within(now - 1, now)
242
249
  timeline.should be_kind_of(Array)
243
250
  timeline.each{|i| i.should be_kind_of(SensorData) }
@@ -306,8 +313,8 @@ shared_examples_for "timeline sensor" do |extra_init_values, default_event|
306
313
  end
307
314
 
308
315
  it "should request timeline within interval from given number of seconds ago till now" do
309
- Timecop.freeze do
310
- now = Time.now
316
+ Timecop.freeze(@now) do
317
+ now = @now
311
318
  ago = interval * 100
312
319
  sensor.timeline(ago).should == sensor.timeline_within(now - ago, now)
313
320
  end
@@ -332,8 +339,8 @@ shared_examples_for "timeline sensor" do |extra_init_values, default_event|
332
339
  describe "#drop_within" do
333
340
  it "should raise exception unless both arguments are Time objects" do
334
341
  [:q, nil, -1].each do |bad_value|
335
- expect{ sensor.drop_within(Time.now, bad_value) }.to raise_exception(ArgumentError)
336
- expect{ sensor.drop_within(bad_value, Time.now) }.to raise_exception(ArgumentError)
342
+ expect{ sensor.drop_within(@now, bad_value) }.to raise_exception(ArgumentError)
343
+ expect{ sensor.drop_within(bad_value, @now) }.to raise_exception(ArgumentError)
337
344
  end
338
345
  end
339
346
 
@@ -399,7 +406,7 @@ shared_examples_for "timeline sensor" do |extra_init_values, default_event|
399
406
  def check_sensor_data(sensor, value)
400
407
  data = sensor.timeline(2).first
401
408
  data.value.should be_generally_equal(sensor.deflate_safe(value))
402
- data.start_time.to_i.should == @interval_id
409
+ data.start_time.to_i.should == @start_of_interval.to_i
403
410
  end
404
411
 
405
412
  it "should contain summarized value stored by data_key for reduced intervals" do
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pulse_meter_core
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.13
4
+ version: 0.5.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -10,8 +10,24 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2013-06-16 00:00:00.000000000 Z
13
+ date: 2014-02-09 00:00:00.000000000 Z
14
14
  dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: json
17
+ requirement: !ruby/object:Gem::Requirement
18
+ none: false
19
+ requirements:
20
+ - - ! '>='
21
+ - !ruby/object:Gem::Version
22
+ version: '0'
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ none: false
27
+ requirements:
28
+ - - ! '>='
29
+ - !ruby/object:Gem::Version
30
+ version: '0'
15
31
  - !ruby/object:Gem::Dependency
16
32
  name: redis
17
33
  requirement: !ruby/object:Gem::Requirement
@@ -29,7 +45,7 @@ dependencies:
29
45
  - !ruby/object:Gem::Version
30
46
  version: '0'
31
47
  - !ruby/object:Gem::Dependency
32
- name: json
48
+ name: tzinfo
33
49
  requirement: !ruby/object:Gem::Requirement
34
50
  none: false
35
51
  requirements:
@@ -239,6 +255,7 @@ files:
239
255
  - lib/pulse_meter/server/command_line_options.rb
240
256
  - lib/pulse_meter/server/config_options.rb
241
257
  - lib/pulse_meter/server/sensors.rb
258
+ - lib/pulse_meter/time_converter.rb
242
259
  - lib/pulse_meter/udp_server.rb
243
260
  - lib/pulse_meter_core.rb
244
261
  - pulse_meter_core.gemspec
@@ -294,9 +311,6 @@ required_rubygems_version: !ruby/object:Gem::Requirement
294
311
  - - ! '>='
295
312
  - !ruby/object:Gem::Version
296
313
  version: '0'
297
- segments:
298
- - 0
299
- hash: 887814886917484037
300
314
  requirements: []
301
315
  rubyforge_project:
302
316
  rubygems_version: 1.8.23