rhcf-timeseries 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 146cc9e889b48ba83a1dde00fea45287a95f25e9
4
+ data.tar.gz: 93d923a9fc1bf50c114e1029ad6e4f5080c17dbc
5
+ SHA512:
6
+ metadata.gz: e38c432a2dc566fbd5796e5786090143d7b615059cc126e29fbd0d5d15dd879396c68daabc5459d52db46123d67643b4fef312ddd33ad26899bcbaa2b2bbeb04
7
+ data.tar.gz: c54b9df5b03bb47b6bd5f5c1a51288ed0e264c14c7e3c52eb3086d5369a791479eaa05ef488798947ef5df2e416eea94b4f9dc77d8c9719db279395e6b65ac94
data/.gitignore ADDED
@@ -0,0 +1,18 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ .idea
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format progress
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+ gem 'pry-debugger'
3
+ # Specify your gem's dependencies in rhcf-timeseries.gemspec
4
+ gemspec
data/Guardfile ADDED
@@ -0,0 +1,30 @@
1
+ # A sample Guardfile
2
+ # More info at https://github.com/guard/guard#readme
3
+
4
+ guard :rspec do
5
+ watch(%r{^spec/.+_spec\.rb$})
6
+ watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
7
+ watch('spec/spec_helper.rb') { "spec" }
8
+
9
+ # Rails example
10
+ watch(%r{^app/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
11
+ watch(%r{^app/(.*)(\.erb|\.haml|\.slim)$}) { |m| "spec/#{m[1]}#{m[2]}_spec.rb" }
12
+ watch(%r{^app/controllers/(.+)_(controller)\.rb$}) { |m| ["spec/routing/#{m[1]}_routing_spec.rb", "spec/#{m[2]}s/#{m[1]}_#{m[2]}_spec.rb", "spec/acceptance/#{m[1]}_spec.rb"] }
13
+ watch(%r{^spec/support/(.+)\.rb$}) { "spec" }
14
+ watch('config/routes.rb') { "spec/routing" }
15
+ watch('app/controllers/application_controller.rb') { "spec/controllers" }
16
+
17
+ # Capybara features specs
18
+ watch(%r{^app/views/(.+)/.*\.(erb|haml|slim)$}) { |m| "spec/features/#{m[1]}_spec.rb" }
19
+
20
+ # Turnip features and steps
21
+ watch(%r{^spec/acceptance/(.+)\.feature$})
22
+ watch(%r{^spec/acceptance/steps/(.+)_steps\.rb$}) { |m| Dir[File.join("**/#{m[1]}.feature")][0] || 'spec/acceptance' }
23
+ end
24
+
25
+
26
+ guard :bundler do
27
+ watch('Gemfile')
28
+ # Uncomment next line if your Gemfile contains the `gemspec' command.
29
+ # watch(/^.+\.gemspec/)
30
+ end
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2014 Romeu Fonseca
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,29 @@
1
+ # Rhcf::Timeseries
2
+
3
+ TODO: Write a gem description
4
+
5
+ ## Installation
6
+
7
+ Add this line to your application's Gemfile:
8
+
9
+ gem 'rhcf-timeseries'
10
+
11
+ And then execute:
12
+
13
+ $ bundle
14
+
15
+ Or install it yourself as:
16
+
17
+ $ gem install rhcf-timeseries
18
+
19
+ ## Usage
20
+
21
+ TODO: Write usage instructions here
22
+
23
+ ## Contributing
24
+
25
+ 1. Fork it ( http://github.com/<my-github-username>/redis-timeseries/fork )
26
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
27
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
28
+ 4. Push to the branch (`git push origin my-new-feature`)
29
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,7 @@
1
+ require "rhcf-timeseries/version"
2
+
3
+ module Rhcf
4
+ class Timeseries
5
+ # Your code goes here...
6
+ end
7
+ end
@@ -0,0 +1,293 @@
1
+ #!/usr/local/rvm/rubies/ruby-1.9.3-p194/bin/ruby
2
+ require 'active_support/core_ext/numeric/time'
3
+
4
+ #require 'observer'
5
+
6
+ require 'micon'
7
+ require 'date'
8
+
9
+ class Rhcf::Timeseries::Result
10
+ def initialize(subject, from, to, series)
11
+ if from > to
12
+ raise ArgumentError, "Argument 'from' can not be bigger then 'to'"
13
+ end
14
+ @series = series
15
+ @subject = subject
16
+ @from = from
17
+ @to = to
18
+ end
19
+
20
+
21
+ def total(resolution_id=nil)
22
+ accumulator={}
23
+ points(resolution_id || better_resolution[:id]) do |data|
24
+ data[:values].each do |key, value|
25
+ accumulator[key]||=0
26
+ accumulator[key]+=value
27
+ end
28
+ end
29
+ accumulator
30
+ end
31
+
32
+ def points(resolution_id)
33
+ list =[]
34
+
35
+ point_range(resolution_id) do |point|
36
+ values = {}
37
+
38
+ @series.events_for_subject_on(@subject, point, resolution_id).each do |event|
39
+ value = @series.get('point', @subject, event, resolution_id, point)
40
+ values[event] = value.to_i
41
+ end
42
+
43
+ next if values.empty?
44
+ data = {moment: point, values: values }
45
+ if block_given?
46
+ yield data
47
+ else
48
+ list << data
49
+ end
50
+ end
51
+ list unless block_given?
52
+ end
53
+
54
+ def point_range(resolution_id)
55
+ #require 'pry-debugger';binding.pry
56
+ resolution = @series.resolution(resolution_id)
57
+ span = resolution[:span]
58
+ ptr = @from.dup
59
+ while ptr < @to
60
+ point = @series.resolution_value_at(ptr, resolution_id)
61
+ yield point
62
+ ptr += span.to_i
63
+ end
64
+ rescue FloatDomainError
65
+ # OK
66
+ end
67
+
68
+ def better_resolution
69
+ span = @to - @from
70
+ resolutions = @series.resolutions.sort_by{|h| h[:span]}.reverse
71
+ better = resolutions.find{|r| r[:span] < span / 5} || resolutions.last
72
+ end
73
+ end
74
+
75
+
76
+ class Rhcf::Timeseries::Redis
77
+ inject :logger
78
+ inject :redis_connection
79
+
80
+ RESOLUTIONS_MAP={
81
+ :ever => {span:Float::INFINITY, formatter: "ever"},
82
+ :year => {span: 365.days,formatter: "%Y"},
83
+ :week => {span: 1.week, formatter: "%Y-CW%w"},
84
+ :month => {span: 30.days, formatter: "%Y-%m"},
85
+ :day => {span: 1.day, formatter: "%Y-%m-%d"},
86
+ :hour => {span: 1.hour, formatter: "%Y-%m-%dT%H"},
87
+ :minute => {span: 1.minute, formatter: "%Y-%m-%dT%H:%M"},
88
+ :second => {span: 1, formatter: "%Y-%m-%dT%H:%M:%S"},
89
+ :"5seconds" => {span: 5.seconds, formatter: ->(time){ [time.strftime("%Y-%m-%dT%H:%M:") , time.to_i % 60/5, '*',5].join('') }},
90
+ :"5minutes" => {span: 5.minutes, formatter: ->(time){ [time.strftime("%Y-%m-%dT%H:") , (time.to_i/60) % 60/5, '*',5].join('') }},
91
+ :"15minutes" => {span: 15.minutes, formatter: ->(time){ [time.strftime("%Y-%m-%dT%H:") , (time.to_i/60) % 60/15, '*',15].join('') }}
92
+
93
+ }
94
+ DEFAULT_RESOLUTIONS = RESOLUTIONS_MAP.keys
95
+ DEFAULT_MAX_POINTS = 1_024
96
+ NAMESPACE_SEPARATOR = '|'
97
+
98
+
99
+ def initialize(options = {})
100
+ @resolution_ids = options[:resolutions] || DEFAULT_RESOLUTIONS
101
+ @max_points = options[:max_points] || DEFAULT_MAX_POINTS
102
+ @prefix=self.class.name
103
+ end
104
+
105
+ def store(subject, event_point_hash, moment = Time.now)
106
+ descend(subject) do |subject_path|
107
+ event_point_hash.each do |event, point_value|
108
+ descend(event) do |event_path|
109
+ resolutions_of(moment) do |resolution_name, resolution_value|
110
+ store_point_value(subject_path, event_path, resolution_name, resolution_value, point_value)
111
+ end
112
+ end
113
+ end
114
+ end
115
+ end
116
+
117
+
118
+ def resolutions_of(moment)
119
+ @resolution_ids.each do |res_id|
120
+ yield res_id, resolution_value_at(moment, res_id)
121
+ end
122
+ end
123
+
124
+ def resolution_value_at(moment, res_id)
125
+ time_resolution_formater = RESOLUTIONS_MAP[res_id][:formatter]
126
+ case time_resolution_formater
127
+ when String
128
+ moment.strftime(time_resolution_formater)
129
+ when Proc
130
+ time_resolution_formater.call(moment)
131
+ else
132
+ raise ArgumentError, "Unexpected moment formater type #{time_resolution_formater.class}"
133
+ end
134
+ end
135
+
136
+
137
+ def descend(path, &block)
138
+ return if path.empty? or path == "."
139
+ block.call(path)
140
+ descend(File.dirname(path), &block)
141
+ end
142
+
143
+ def store_point_event( resolution_name, resolution_value, subject_path, event_path)
144
+ key = [@prefix, 'event_set', resolution_name, resolution_value, subject_path].join(NAMESPACE_SEPARATOR)
145
+ logger.debug("EVENTSET SADD #{key} -> #{event_path}")
146
+ redis_connection.sadd(key, event_path)
147
+ end
148
+
149
+ def store_point_value( subject_path, event_path, resolution_name, resolution_value, point_value)
150
+ store_point_event(resolution_name, resolution_value, subject_path, event_path)
151
+
152
+ key = [@prefix, 'point' ,subject_path, event_path, resolution_name, resolution_value].join(NAMESPACE_SEPARATOR)
153
+ logger.debug("SETTING KEY #{key}")
154
+ redis_connection.incrby(key, point_value)
155
+ end
156
+
157
+ def find(subject, from, to = Time.now)
158
+ Rhcf::Timeseries::Result.new(subject, from, to, self)
159
+ end
160
+
161
+ def flush!
162
+ every_key{|a_key| delete_key(a_key)}
163
+ end
164
+
165
+ def every_key(pattern=nil, &block)
166
+ pattern = [@prefix, pattern,'*'].compact.join(NAMESPACE_SEPARATOR)
167
+ redis_connection.keys(pattern).each do |key|
168
+ yield key
169
+ end
170
+ end
171
+
172
+ def delete_key(a_key)
173
+ logger.debug("DELETING KEY #{a_key}")
174
+ redis_connection.del(a_key)
175
+ end
176
+
177
+ def keys(*a_key)
178
+ raise "GIVEUP"
179
+ a_key = [@prefix, a_key].flatten.join(NAMESPACE_SEPARATOR)
180
+ logger.debug("FINDING KEY #{a_key}")
181
+ redis_connection.keys(a_key).collect{|k| k.split(NAMESPACE_SEPARATOR)[1,1000].join(NAMESPACE_SEPARATOR) }
182
+ end
183
+
184
+ def get(*a_key)
185
+ a_key = [@prefix, a_key].flatten.join(NAMESPACE_SEPARATOR)
186
+ logger.debug("GETTING KEY #{a_key}")
187
+ redis_connection.get(a_key)
188
+ end
189
+
190
+
191
+ def resolution(id)
192
+ res = RESOLUTIONS_MAP[id]
193
+ raise ArgumentError, "Invalid resolution name #{id} for this time series" if res.nil?
194
+ res.merge(:id => id)
195
+ end
196
+ def resolutions
197
+ @resolution_ids.collect do |id|
198
+ resolution(id)
199
+ end
200
+ end
201
+
202
+
203
+ def events_for_subject_on(subject, point, resolution_id)
204
+ key = [@prefix, 'event_set', resolution_id, point, subject].join(NAMESPACE_SEPARATOR)
205
+ logger.debug("EVENTSET SMEMBERS #{key}")
206
+ redis_connection.smembers(key)
207
+ end
208
+ end
209
+
210
+ #require 'json'
211
+ #$:.unshift File.dirname(__FILE__)
212
+ #require 'hash_storer'
213
+
214
+ =begin
215
+ class Redis
216
+ # include Observable
217
+ attr_reader :prefix, :scales, :max_points
218
+
219
+
220
+ def initialize(prefix, scales, max_points, store = HashStorer.new)
221
+ @lasts = {}
222
+ @prefix = prefix
223
+ @scales = {}
224
+ @store = store
225
+ scales.each do |s|
226
+ @scales[s] = eval(s)
227
+ end
228
+ @max_point = max_points
229
+ end
230
+
231
+ def persist
232
+ @store.persist if @store.respond_to?( 'persist' )
233
+ end
234
+
235
+
236
+ def add(dimension, value, time = Time.now)
237
+ @scales.each do |name, v|
238
+ add_to_scale(name, dimension, value, time)
239
+ end
240
+ end
241
+
242
+ def add_to_scale(scale_name, dimension, value, time = Time.now)
243
+ scale = @scales[scale_name]
244
+ time = time.to_i
245
+ scale_time = time - (time % scale)
246
+ scale_key = [@prefix, dimension, scale_name].join('-')
247
+ last = @store.increment(scale_key, scale_time, value, time, @lasts["#{scale_name}-#{dimension}"])
248
+ @lasts["#{scale_name}-#{dimension}"] = last['last']
249
+ changed
250
+ notify_observers(scale_key, last)
251
+ end
252
+ end
253
+
254
+
255
+ class RedisTimeSeriesUpdater
256
+ def initialize(channel_prefix, observable, redis)
257
+ @channel_prefix = channel_prefix
258
+ @observable = observable
259
+ @redis = redis
260
+ observable.add_observer(self)
261
+ end
262
+
263
+ def update(key, data)
264
+ key += '-realtime'
265
+ # puts ['broadcasting', data, 'on', key].join(' ')
266
+ @redis.publish(key, data.to_json)
267
+ end
268
+ end
269
+
270
+ redis = Redis.new
271
+
272
+ ts1 = TimeSeries.new('mymachine', ['1.hour', '15.minutes', '1.minute', '1.second', '10.seconds'], 1000)
273
+ #ts1 = TimeSeries.new('mymachine', [ '1.second'], 1000)
274
+ pub = RedisTimeSeriesUpdater.new('realtime', ts1, redis)
275
+
276
+
277
+ alive = true
278
+ Signal.trap('INT'){
279
+ alive = false
280
+ }
281
+
282
+ Signal.trap('USR1'){
283
+ pub.refresh
284
+ }
285
+ while alive
286
+ sleep 1
287
+ ts1.add('cpu_load', %x{uptime | sed 's/.*: //;s/,.*//'}.strip.to_f, Time.now)
288
+ ts1.add('rx', %x{ifconfig eth0| grep 'RX bytes' | sed 's/ (.*//;s/.*://'}.strip.to_f,Time.now)
289
+ ts1.add('tx', %x{ifconfig eth0| grep 'TX bytes' | sed 's/.*TX.*://;s/ .*//'}.strip.to_f,Time.now)
290
+ end
291
+
292
+ ts1.persist
293
+ =end
@@ -0,0 +1,5 @@
1
+ module Rhcf
2
+ module Timeseries
3
+ VERSION = "0.0.1"
4
+ end
5
+ end
@@ -0,0 +1,32 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'rhcf/timeseries/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "rhcf-timeseries"
8
+ spec.version = Rhcf::Timeseries::VERSION
9
+ spec.authors = ["Romeu Fonseca"]
10
+ spec.email = ["romeu.hcf@gmail.com"]
11
+ spec.summary = %q{Redistat inspired redis time series.}
12
+ spec.description = %q{Gem to allow your system to keep record of time series on rhcf}
13
+ spec.homepage = ""
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.5"
22
+ spec.add_development_dependency "rake"
23
+ spec.add_development_dependency "redis"
24
+ spec.add_development_dependency "rspec"
25
+ spec.add_development_dependency "guard"
26
+ spec.add_development_dependency "guard-rspec"
27
+ spec.add_development_dependency "guard-bundler"
28
+ spec.add_development_dependency "simplecov"
29
+ spec.add_development_dependency "timecop"
30
+ spec.add_dependency "activesupport"
31
+ spec.add_dependency "micon"
32
+ end
@@ -0,0 +1 @@
1
+ # TODO prune date set
@@ -0,0 +1,146 @@
1
+ require 'spec_helper'
2
+ require 'timecop'
3
+ require 'redis'
4
+ require 'micon'
5
+ require 'rhcf/timeseries/redis'
6
+ require 'benchmark'
7
+ require 'logger'
8
+ micon.register(:logger){Logger.new('/dev/null')}
9
+ #micon.register(:logger){Logger.new(STDOUT)}
10
+ micon.register(:redis_connection){Redis.new}
11
+
12
+
13
+ describe Rhcf::Timeseries::Redis do
14
+
15
+ before(:each) do
16
+ Timecop.return
17
+ subject.flush!
18
+ end
19
+
20
+ it "should be fast to store and read" do
21
+ subject.flush!
22
+ total = 0
23
+ start_time = Time.now
24
+
25
+ bench = Benchmark.measure {
26
+ 10000.times do
27
+ total +=1
28
+ subject.store("a", {"b" => 1} ) #, time)
29
+ end
30
+ }
31
+
32
+
33
+ #pp subject.find("a", start_time - 11100, Time.now + 11100).points(:second)
34
+ qbench = Benchmark.measure {
35
+ subject.find("a", start_time - 11100, Time.now + 11100).total['b'].to_i.should == total
36
+ }
37
+
38
+ qbench_year = Benchmark.measure {
39
+ subject.find("a", start_time - 100000, Time.now + 100000).total(:year)['b'].to_i.should == total
40
+ }
41
+
42
+ puts "Write speed %d points/seg | points:%d, duration:%0.3fs | query_time %0.3fs" % [speed = (1.0 * total / (bench.total + 0.00000001)), total, bench.total, qbench.total]
43
+ speed.should > 400
44
+ end
45
+
46
+
47
+ it "should be similar to redistat" do
48
+ start_time = Time.parse("2000-01-01 00:00:00")
49
+ Timecop.travel(start_time)
50
+ subject.store("views/product/15", {"web/firefox/3" => 1})
51
+
52
+ Timecop.travel(15.minutes) #00:00:15
53
+ subject.store("views/product/13", {"web/firefox/3" => 1}, Time.now)
54
+ subject.store("views/product/13", {"web/firefox/3" => 1}, Time.now)
55
+ subject.store("views/product/13", {"web/firefox/3" => 0}, Time.now)
56
+
57
+ Timecop.travel(15.minutes) #00:00:30
58
+ subject.store("views/product/15", {"web/ie/6" => 3})
59
+
60
+ Timecop.travel(15.minutes) #00:00:45
61
+ subject.store("views/product/15", {"web/ie/6" => 2})
62
+
63
+ Timecop.travel(15.minutes) #00:00:00
64
+ subject.store("views/product/11", {"web/ie/5" => 2})
65
+
66
+ Timecop.travel(15.minutes) #00:00:15
67
+ subject.store("views/product/11", {"web/chrome/11"=> 4})
68
+
69
+ Timecop.travel(15.minutes) #00:00:30
70
+ subject.store("views/product/11", {"web/chrome/11"=> 2})
71
+
72
+ subject.find("views/product", start_time, start_time + 55.minutes).total(:ever).should == {
73
+ "web" => 16.0,
74
+ "web/chrome" => 6.0,
75
+ "web/chrome/11" => 6.0,
76
+ "web/firefox" => 3.0,
77
+ "web/firefox/3" => 3.0,
78
+ "web/ie" => 7.0,
79
+ "web/ie/5" => 2.0,
80
+ "web/ie/6" => 5.0
81
+ }
82
+
83
+ subject.find("views/product", start_time, start_time + 55.minutes).total(:year).should == {
84
+ "web" => 16.0,
85
+ "web/chrome" => 6.0,
86
+ "web/chrome/11" => 6.0,
87
+ "web/firefox" => 3.0,
88
+ "web/firefox/3" => 3.0,
89
+ "web/ie" => 7.0,
90
+ "web/ie/5" => 2.0,
91
+ "web/ie/6" => 5.0
92
+ }
93
+
94
+ subject.find("views/product", start_time, start_time + 55.minutes).total.should == {
95
+ 'web' => 8,
96
+ 'web/firefox' => 3,
97
+ 'web/firefox/3' => 3,
98
+ 'web/ie' => 5,
99
+ 'web/ie/6' => 5,
100
+ }
101
+
102
+ subject.find("views/product/15", start_time, start_time + 55.minutes).points(:minute).should == [
103
+ {:moment=>"2000-01-01T00:00", :values=>{"web/firefox"=>1, "web/firefox/3"=>1, "web"=>1}},
104
+ {:moment=>"2000-01-01T00:30", :values=>{"web"=>3, "web/ie/6"=>3, "web/ie"=>3}},
105
+ {:moment=>"2000-01-01T00:45", :values=>{"web"=>2, "web/ie/6"=>2, "web/ie"=>2}}
106
+ ]
107
+
108
+ subject.find("views/product/13", start_time, start_time + 55.minutes).points(:minute).should == [
109
+ {:moment=>"2000-01-01T00:15", :values=>{"web/firefox"=>2, "web/firefox/3"=>2, "web"=>2}},
110
+ ]
111
+
112
+
113
+
114
+
115
+ subject.find("views/product", start_time, start_time + 55.minutes).points(:minute).should == [
116
+ {:moment=>"2000-01-01T00:00", :values=>{"web/firefox"=>1, "web/firefox/3"=>1, "web"=>1}},
117
+ {:moment=>"2000-01-01T00:15", :values=>{"web/firefox"=>2, "web/firefox/3"=>2, "web"=>2}},
118
+ {:moment=>"2000-01-01T00:30", :values=>{"web"=>3, "web/ie/6"=>3, "web/ie"=>3}},
119
+ {:moment=>"2000-01-01T00:45", :values=>{"web"=>2, "web/ie/6"=>2, "web/ie"=>2}}
120
+ ]
121
+
122
+ subject.find("views", start_time, start_time + 55.minutes).points(:minute).should == [
123
+ {:moment=>"2000-01-01T00:00", :values=>{"web/firefox"=>1, "web/firefox/3"=>1, "web"=>1}},
124
+ {:moment=>"2000-01-01T00:15", :values=>{"web/firefox"=>2, "web/firefox/3"=>2, "web"=>2}},
125
+ {:moment=>"2000-01-01T00:30", :values=>{"web"=>3, "web/ie/6"=>3, "web/ie"=>3}},
126
+ {:moment=>"2000-01-01T00:45", :values=>{"web"=>2, "web/ie/6"=>2, "web/ie"=>2}}
127
+ ]
128
+
129
+ subject.find("views", start_time).points(:hour).should == [{:moment=>"2000-01-01T00",
130
+ :values=>
131
+ {"web/ie"=>5.0,
132
+ "web"=>8.0,
133
+ "web/firefox"=>3.0,
134
+ "web/ie/6"=>5.0,
135
+ "web/firefox/3"=>3.0}},
136
+ {:moment=>"2000-01-01T01",
137
+ :values=>
138
+ {"web/ie"=>2.0,
139
+ "web/chrome"=>6.0,
140
+ "web/chrome/11"=>6.0,
141
+ "web"=>8.0,
142
+ "web/ie/5"=>2.0}}]
143
+
144
+
145
+ end
146
+ end
@@ -0,0 +1,20 @@
1
+ # This file was generated by the `rspec --init` command. Conventionally, all
2
+ # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
3
+ # Require this file using `require "spec_helper"` to ensure that it is only
4
+ # loaded once.
5
+ #
6
+ # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
7
+ require 'simplecov'
8
+ SimpleCov.start
9
+ RSpec.configure do |config|
10
+ config.treat_symbols_as_metadata_keys_with_true_values = true
11
+ config.run_all_when_everything_filtered = true
12
+ config.filter_run :focus
13
+
14
+ # Run specs in random order to surface order dependencies. If you find an
15
+ # order dependency and want to debug it, you can fix the order by providing
16
+ # the seed, which is printed after each run.
17
+ # --seed 1234
18
+ config.order = 'random'
19
+
20
+ end
metadata ADDED
@@ -0,0 +1,217 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: rhcf-timeseries
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Romeu Fonseca
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-04-04 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.5'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.5'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: redis
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: guard
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: guard-rspec
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: guard-bundler
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: '0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: simplecov
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: timecop
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
139
+ - !ruby/object:Gem::Dependency
140
+ name: activesupport
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - ">="
144
+ - !ruby/object:Gem::Version
145
+ version: '0'
146
+ type: :runtime
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - ">="
151
+ - !ruby/object:Gem::Version
152
+ version: '0'
153
+ - !ruby/object:Gem::Dependency
154
+ name: micon
155
+ requirement: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - ">="
158
+ - !ruby/object:Gem::Version
159
+ version: '0'
160
+ type: :runtime
161
+ prerelease: false
162
+ version_requirements: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - ">="
165
+ - !ruby/object:Gem::Version
166
+ version: '0'
167
+ description: Gem to allow your system to keep record of time series on rhcf
168
+ email:
169
+ - romeu.hcf@gmail.com
170
+ executables: []
171
+ extensions: []
172
+ extra_rdoc_files: []
173
+ files:
174
+ - ".gitignore"
175
+ - ".rspec"
176
+ - Gemfile
177
+ - Guardfile
178
+ - LICENSE.txt
179
+ - README.md
180
+ - Rakefile
181
+ - lib/rhcf/timeseries.rb
182
+ - lib/rhcf/timeseries/redis.rb
183
+ - lib/rhcf/timeseries/version.rb
184
+ - rhcf-timeseries.gemspec
185
+ - spec/lib/rhcf/timeseries/.timeseries_spec.rb.swp
186
+ - spec/lib/rhcf/timeseries/TODO
187
+ - spec/lib/rhcf/timeseries/redis_spec.rb
188
+ - spec/spec_helper.rb
189
+ homepage: ''
190
+ licenses:
191
+ - MIT
192
+ metadata: {}
193
+ post_install_message:
194
+ rdoc_options: []
195
+ require_paths:
196
+ - lib
197
+ required_ruby_version: !ruby/object:Gem::Requirement
198
+ requirements:
199
+ - - ">="
200
+ - !ruby/object:Gem::Version
201
+ version: '0'
202
+ required_rubygems_version: !ruby/object:Gem::Requirement
203
+ requirements:
204
+ - - ">="
205
+ - !ruby/object:Gem::Version
206
+ version: '0'
207
+ requirements: []
208
+ rubyforge_project:
209
+ rubygems_version: 2.2.2
210
+ signing_key:
211
+ specification_version: 4
212
+ summary: Redistat inspired redis time series.
213
+ test_files:
214
+ - spec/lib/rhcf/timeseries/.timeseries_spec.rb.swp
215
+ - spec/lib/rhcf/timeseries/TODO
216
+ - spec/lib/rhcf/timeseries/redis_spec.rb
217
+ - spec/spec_helper.rb