nightfury 0.6.3 → 0.7.0
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.
|
@@ -2,20 +2,26 @@ module Nightfury
|
|
|
2
2
|
module Metric
|
|
3
3
|
class AvgTimeSeries < TimeSeries
|
|
4
4
|
|
|
5
|
-
def default_meta
|
|
6
|
-
{'count' => 0.0, 'total' => 0.0}
|
|
7
|
-
end
|
|
8
|
-
|
|
9
5
|
protected
|
|
10
6
|
|
|
11
|
-
def before_set(value)
|
|
12
|
-
|
|
13
|
-
|
|
7
|
+
def before_set(value, time)
|
|
8
|
+
step_time = get_step_time(time).to_i
|
|
9
|
+
data_point, meta_value = get_exact(step_time, true)
|
|
10
|
+
current_count = current_total = 0.0
|
|
11
|
+
unless data_point.nil?
|
|
12
|
+
current_count = meta_value[:current_count].to_f
|
|
13
|
+
current_total = meta_value[:current_total].to_f
|
|
14
|
+
end
|
|
15
|
+
updated_count = current_count + 1.0
|
|
16
|
+
updated_total = current_total + value
|
|
14
17
|
result = updated_total / updated_count
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
18
|
+
result = "#{updated_count},#{updated_total},#{result}"
|
|
19
|
+
[result, time]
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def decode_data_point(data_point)
|
|
23
|
+
current_count, current_total, data = data_point[0].split(',')
|
|
24
|
+
[data_point[1], data, {current_count: current_count, current_total: current_total}]
|
|
19
25
|
end
|
|
20
26
|
end
|
|
21
27
|
end
|
|
@@ -12,7 +12,7 @@ module Nightfury
|
|
|
12
12
|
end
|
|
13
13
|
|
|
14
14
|
def set(value, time=Time.now, options={})
|
|
15
|
-
value = before_set(value) unless options[:skip_before_set]
|
|
15
|
+
value, time = before_set(value, time) unless options[:skip_before_set]
|
|
16
16
|
# make sure the time_series is initialized.
|
|
17
17
|
# It will not if the metric is removed and
|
|
18
18
|
# set is called on the smae object
|
|
@@ -20,7 +20,7 @@ module Nightfury
|
|
|
20
20
|
add_value_to_timeline(value, time)
|
|
21
21
|
end
|
|
22
22
|
|
|
23
|
-
def get(timestamp=nil)
|
|
23
|
+
def get(timestamp=nil, get_meta=false)
|
|
24
24
|
return nil unless redis.exists(redis_key)
|
|
25
25
|
data_point = ''
|
|
26
26
|
if timestamp
|
|
@@ -32,11 +32,21 @@ module Nightfury
|
|
|
32
32
|
data_point = data_point.each_slice(2).map {|pair| pair }.last
|
|
33
33
|
end
|
|
34
34
|
|
|
35
|
-
return nil if data_point.nil?
|
|
36
|
-
return nil if data_point[1] == "0"
|
|
35
|
+
return get_meta ? [nil, {}] : nil if data_point.nil?
|
|
36
|
+
return get_meta ? [nil, {}] : nil if data_point[1] == "0"
|
|
37
37
|
|
|
38
|
-
time, data = decode_data_point(data_point)
|
|
39
|
-
{time => data}
|
|
38
|
+
time, data, meta_value = decode_data_point(data_point)
|
|
39
|
+
get_meta ? [{time => data}, meta_value] : {time => data}
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def get_exact(timestamp, get_meta=false)
|
|
43
|
+
return nil unless redis.exists(redis_key)
|
|
44
|
+
timestamp = get_step_time(timestamp).to_i
|
|
45
|
+
data_point = redis.zrangebyscore(redis_key, timestamp, timestamp, withscores: true)
|
|
46
|
+
data_point = data_point.each_slice(2).map {|pair| pair }.last
|
|
47
|
+
return get_meta ? [nil, {}] : nil if data_point.nil?
|
|
48
|
+
time, data, meta_value = decode_data_point(data_point)
|
|
49
|
+
result = get_meta ? [{time => data}, meta_value] : {time => data}
|
|
40
50
|
end
|
|
41
51
|
|
|
42
52
|
def get_range(start_time, end_time)
|
|
@@ -72,8 +82,26 @@ module Nightfury
|
|
|
72
82
|
|
|
73
83
|
protected
|
|
74
84
|
|
|
75
|
-
def before_set(value)
|
|
76
|
-
value
|
|
85
|
+
def before_set(value, time)
|
|
86
|
+
[value, time]
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def decode_data_point(data_point)
|
|
90
|
+
[data_point[1], data_point[0], {}]
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def round_time(time, seconds=60)
|
|
94
|
+
self.class.round_time(time, seconds)
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def get_step_time(time)
|
|
98
|
+
case step
|
|
99
|
+
when :minute then round_time(time, 60)
|
|
100
|
+
when :hour then round_time(time, 1.hour)
|
|
101
|
+
when :day then round_time(time, 1.day)
|
|
102
|
+
when :week then round_time(time, 1.week)
|
|
103
|
+
when :month then round_time(time, Time.days_in_month(time.month, time.year))
|
|
104
|
+
end
|
|
77
105
|
end
|
|
78
106
|
|
|
79
107
|
private
|
|
@@ -91,11 +119,7 @@ module Nightfury
|
|
|
91
119
|
result[time] = data
|
|
92
120
|
end
|
|
93
121
|
result
|
|
94
|
-
end
|
|
95
|
-
|
|
96
|
-
def decode_data_point(data_point)
|
|
97
|
-
[data_point[1], data_point[0]]
|
|
98
|
-
end
|
|
122
|
+
end
|
|
99
123
|
|
|
100
124
|
def save_meta
|
|
101
125
|
redis.zremrangebyscore redis_key, 0, 0
|
|
@@ -106,19 +130,6 @@ module Nightfury
|
|
|
106
130
|
redis.zadd redis_key, 0, default_meta.to_json
|
|
107
131
|
end
|
|
108
132
|
|
|
109
|
-
def round_time(time, seconds=60)
|
|
110
|
-
self.class.round_time(time, seconds)
|
|
111
|
-
end
|
|
112
|
-
|
|
113
|
-
def get_step_time(time)
|
|
114
|
-
case step
|
|
115
|
-
when :minute then round_time(time, 60)
|
|
116
|
-
when :hour then round_time(time, 1.hour)
|
|
117
|
-
when :day then round_time(time, 1.day)
|
|
118
|
-
when :week then round_time(time, 1.week)
|
|
119
|
-
when :month then round_time(time, Time.days_in_month(time.month, time.year))
|
|
120
|
-
end
|
|
121
|
-
end
|
|
122
133
|
end
|
|
123
134
|
end
|
|
124
135
|
end
|
data/lib/nightfury/version.rb
CHANGED
|
@@ -1,24 +1,22 @@
|
|
|
1
1
|
require 'spec_helper'
|
|
2
2
|
|
|
3
3
|
describe Nightfury::Metric::AvgTimeSeries do
|
|
4
|
-
it "should
|
|
4
|
+
it "should calculate avg in buckets defined by step" do
|
|
5
5
|
avg_metric = Nightfury::Metric::AvgTimeSeries.new(:avg)
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
first_bucket_time = Time.now
|
|
7
|
+
next_bucket_time = first_bucket_time + 61 # step is 60 seconds by default
|
|
8
|
+
|
|
9
|
+
# Add to first bucket
|
|
10
|
+
avg_metric.set(3, first_bucket_time)
|
|
11
|
+
avg_metric.set(2, first_bucket_time)
|
|
12
|
+
avg_metric.set(4, first_bucket_time)
|
|
13
|
+
avg_metric.set(11, first_bucket_time)
|
|
8
14
|
|
|
9
|
-
|
|
10
|
-
avg_metric
|
|
11
|
-
avg_metric.set(
|
|
12
|
-
avg_metric.set(2)
|
|
13
|
-
avg_metric.set(4)
|
|
14
|
-
avg_metric.set(11)
|
|
15
|
-
avg_metric.get.values.first.should == "5.0"
|
|
16
|
-
end
|
|
15
|
+
# Add to next bucket
|
|
16
|
+
avg_metric.set(3, next_bucket_time)
|
|
17
|
+
avg_metric.set(2, next_bucket_time)
|
|
17
18
|
|
|
18
|
-
|
|
19
|
-
avg_metric
|
|
20
|
-
avg_metric.set(1)
|
|
21
|
-
avg_metric.set(2)
|
|
22
|
-
avg_metric.meta['count'].should == 2
|
|
19
|
+
avg_metric.get(first_bucket_time).values.first.should == "5.0"
|
|
20
|
+
avg_metric.get(next_bucket_time).values.first.should == "2.5"
|
|
23
21
|
end
|
|
24
22
|
end
|
|
@@ -27,6 +27,15 @@ describe Nightfury::Metric::TimeSeries do
|
|
|
27
27
|
ts_metric.get.should be_nil
|
|
28
28
|
end
|
|
29
29
|
|
|
30
|
+
context "with meta" do
|
|
31
|
+
it "should also return the meta part of the data point" do
|
|
32
|
+
ts_metric = Nightfury::Metric::TimeSeries.new(:time)
|
|
33
|
+
time_now = Time.now
|
|
34
|
+
ts_metric.set(1, time_now)
|
|
35
|
+
ts_metric.get(time_now, true)[1].should == {}
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
30
39
|
context "without timestamp" do
|
|
31
40
|
it "should get the most recent data point" do
|
|
32
41
|
ts_metric = Nightfury::Metric::TimeSeries.new(:time)
|
|
@@ -72,6 +81,39 @@ describe Nightfury::Metric::TimeSeries do
|
|
|
72
81
|
end
|
|
73
82
|
end
|
|
74
83
|
|
|
84
|
+
describe "#get_exact" do
|
|
85
|
+
it "should get the data_point at the timestamp" do
|
|
86
|
+
ts_metric = Nightfury::Metric::TimeSeries.new(:time)
|
|
87
|
+
time = Time.now
|
|
88
|
+
ts_metric.set(1, time)
|
|
89
|
+
result = ts_metric.get_exact(time)
|
|
90
|
+
result.values.first.should == '1'
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
it "should return data point's meta if specified" do
|
|
94
|
+
ts_metric = Nightfury::Metric::TimeSeries.new(:time)
|
|
95
|
+
time = Time.now
|
|
96
|
+
ts_metric.set(1, time)
|
|
97
|
+
result = ts_metric.get_exact(time, true)
|
|
98
|
+
result[1].should == {}
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
it "should return nil if there is no data_point at the timestamp" do
|
|
102
|
+
ts_metric = Nightfury::Metric::TimeSeries.new(:time)
|
|
103
|
+
time = Time.now
|
|
104
|
+
ts_metric.set(1, time)
|
|
105
|
+
result = ts_metric.get_exact(time+61)
|
|
106
|
+
result.should be_nil
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
it "should retrun nil if metric key on redis is empty" do
|
|
110
|
+
ts_metric = Nightfury::Metric::TimeSeries.new(:time)
|
|
111
|
+
# delete redis key
|
|
112
|
+
ts_metric.redis.del ts_metric.redis_key
|
|
113
|
+
ts_metric.get_exact(Time.now).should be_nil
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
|
|
75
117
|
describe "#get_range" do
|
|
76
118
|
it "should retrun nil if metric key on redis is empty" do
|
|
77
119
|
ts_metric = Nightfury::Metric::TimeSeries.new(:time)
|
|
@@ -136,8 +178,9 @@ describe Nightfury::Metric::TimeSeries do
|
|
|
136
178
|
describe "before set" do
|
|
137
179
|
it "should call before_set, before adding the value to the timeline" do
|
|
138
180
|
ts_metric = Nightfury::Metric::TimeSeries.new(:avg_time)
|
|
139
|
-
|
|
140
|
-
ts_metric.
|
|
181
|
+
time = Time.now
|
|
182
|
+
flexmock(ts_metric).should_receive(:before_set).with(1, time).once
|
|
183
|
+
ts_metric.set(1, time)
|
|
141
184
|
end
|
|
142
185
|
|
|
143
186
|
it "should not call before_set, before adding the value to the timeline if optiond ':skip_before_set' is provided" do
|