snappy_stats 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format progress
data/.travis.yml ADDED
@@ -0,0 +1,6 @@
1
+ language: ruby
2
+ rvm:
3
+ - "1.9.2"
4
+ - "1.9.3"
5
+ - "2.0.0"
6
+ script: bundle exec rspec spec
data/README.md CHANGED
@@ -1,4 +1,72 @@
1
- snappy_stats
2
- ============
1
+ # snappy_stats [![Build Status](https://travis-ci.org/timrwilliams/snappy_stats.png?branch=master)](https://travis-ci.org/timrwilliams/snappy_stats)
2
+
3
+ This is a simple Ruby time series statistics gem that uses Redis for storage. Retrieval is optimised for graphing engines by nil filling empty time periods. I graph it with [Rickshaw] (code.shutterstock.com/rickshaw/).
4
+
5
+ ## Installation
6
+ Install the gem:
7
+
8
+ gem install snappy_stats
9
+
10
+ Add it to your Gemfile:
11
+
12
+ gem "snappy_stats"
13
+
14
+ ## Background
15
+ SnappyStats is a Ruby implementation of a simple time series statistics tool based on [ApiAxle's Javascript statistics lib] (http://blog.apiaxle.com/post/storing-near-realtime-stats-in-redis/) which in turn was heavily influenced by [RRDTool] (http://en.wikipedia.org/wiki/RRDtool).
16
+
17
+ It allows you to store and retrieve simple metrics (think hit counters). The metrics are returned in a set optimised for graphing engines as each time period is represented in the results even if no hit was recorded in that period.
18
+
19
+ ## Usage
20
+ # Record a hit now
21
+ SnappyStats.recordHitNow("test:counter1")
22
+ # Get all results between given timestamp range
23
+ results = SnappyStats.get(:day,Time.now.midnight.to_i,(Time.now.midnight + 1.days).to_i,"test:counter1")
24
+
25
+ ## Detailed Example
26
+ require 'snappy_stats'
27
+
28
+ #Using Timecop to simulate changing time, not required in production implementation
29
+ Timecop.freeze
30
+ now = Time.now
31
+
32
+ # Simulate 5 hits for today
33
+ 5.times do
34
+ SnappyStats.recordHitNow("test:counter1")
35
+ end
36
+
37
+ # Simulate 5 hits for 2 days from now
38
+ Timecop.freeze(now + 2.days)
39
+ 2.times do
40
+ SnappyStats.recordHitNow("test:counter1")
41
+ end
42
+
43
+ # Decide what range we want to search for
44
+ from = Time.now.midnight.to_i
45
+ to = (Time.now.midnight + 2.days).to_i
46
+
47
+ # Get daily results between the from and to timestamps for given key, filling missing days with nil
48
+ daily_stats = SnappyStats.get(:day,from,to,"test:counter1")
49
+ p daily_stats # {1382054400=>"5", 1382140800=>nil,1382227200=>"2"}
50
+
51
+ ## Configuration
52
+ By default SnappyStats uses the current vesion of Redis defined in your project. To use a different Redis use a config initializer.
53
+
54
+ # config/initializers/snappy_stats.rb
55
+ SnappyStats.configure do |config|
56
+ # set the Redis connection to a new Redis connection
57
+ config.redis = Redis.new
58
+ # Change Redis key prefix away from default 'stats'
59
+ config.namnespace = "custom_stats"
60
+ end
61
+
62
+ ## Contributing to SnappyStats
63
+
64
+ * Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
65
+ * Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
66
+ * Fork the project
67
+ * Start a feature/bugfix branch
68
+ * Commit and push until you are happy with your contribution
69
+ * Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
70
+ * Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
71
+
3
72
 
4
- Simple Ruby time series statistics backed by Redis gem
@@ -1,3 +1,3 @@
1
1
  module SnappyStats
2
- VERSION = "0.0.1"
2
+ VERSION = "0.0.2"
3
3
  end
data/lib/snappy_stats.rb CHANGED
@@ -71,9 +71,7 @@ module SnappyStats
71
71
  tsround = SnappyStats.getRoundedTimestamp(time, size * factor)
72
72
  redis_key = "#{hash_key}:#{key}:#{gran}:#{tsround}"
73
73
  ts = getFactoredTimestamp time, factor
74
- val = SnappyStats.connection.hincrby redis_key, ts, 1
75
- puts val
76
- puts "#{redis_key}, #{ts},#{SnappyStats.connection.hgetall(redis_key)}"
74
+ SnappyStats.connection.hincrby redis_key, ts, 1
77
75
  SnappyStats.connection.expireat redis_key, tsround + ttl
78
76
  end
79
77
  end
data/snappy_stats.gemspec CHANGED
@@ -10,7 +10,7 @@ Gem::Specification.new do |spec|
10
10
  spec.email = ["tim@teachmatic.com"]
11
11
  spec.description = %q{Metrics storage and retrieval library for time series data.}
12
12
  spec.summary = %q{Redis backed simple time series statistics gem}
13
- spec.homepage = ""
13
+ spec.homepage = "https://github.com/timrwilliams/snappy_stats"
14
14
  spec.license = "MIT"
15
15
 
16
16
  spec.files = `git ls-files`.split($/)
@@ -18,6 +18,8 @@ Gem::Specification.new do |spec|
18
18
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
19
  spec.require_paths = ["lib"]
20
20
 
21
+ spec.add_dependency "active_support"
22
+ spec.add_dependency "redis"
21
23
  spec.add_development_dependency "bundler", "~> 1.3"
22
24
  spec.add_development_dependency "rake"
23
25
  spec.add_development_dependency "rspec"
@@ -0,0 +1,51 @@
1
+ require 'spec_helper'
2
+
3
+ describe SnappyStats do
4
+
5
+ before(:all) do
6
+ #Redis::Connection.drivers.delete_if {|x| Redis::Connection::Memory == x }
7
+ keys = SnappyStats.connection.keys("stats:*")
8
+ keys.each { | key | SnappyStats.connection.del(key) }
9
+ end
10
+
11
+ it "Calculates ts in seconds" do
12
+ Timecop.freeze(Time.local(2013, 01, 01, 01, 01))
13
+ time = SnappyStats.getSecondsTimestamp
14
+ expect(time).to be 1357002060
15
+ default_rounded = SnappyStats.getRoundedTimestamp(nil, 60)
16
+ expect(default_rounded).to be 1357002060
17
+ time = 1364833411
18
+ rounded = SnappyStats.getRoundedTimestamp(time, 60)
19
+ expect(rounded).to be 1364833380
20
+ end
21
+
22
+ it "Records a hit at all granularities" do
23
+ pending("Need updated version of fakeredis with correct hincrby implementation")
24
+ Timecop.freeze
25
+ now = Time.now
26
+ 5.times do
27
+ SnappyStats.recordHitNow("test:counter1")
28
+ end
29
+ 3.times do
30
+ SnappyStats.recordHitNow("test:counter2")
31
+ end
32
+ Timecop.freeze(now + 2.days)
33
+ 2.times do
34
+ SnappyStats.recordHitNow("test:counter1")
35
+ end
36
+ from = now.midnight.to_i
37
+ to = (now.midnight + 2.day).to_i
38
+ daily_user1_stat = SnappyStats.get(:day,from,to,"test:counter1")
39
+ Timecop.freeze(now + 1.day)
40
+ puts daily_user1_stat
41
+ expect(daily_user1_stat[from]).to eq("5")
42
+ hourly_user1_stat = SnappyStats.get(:hour,from,to,"test:counter1")
43
+ expect(hourly_user1_stat[ Time.now.beginning_of_hour.to_i]).to eq("5")
44
+ daily_user2_stat = SnappyStats.get(:day,from,to,"test:counter2")
45
+ expect(daily_user2_stat[from]).to eq("3")
46
+ end
47
+
48
+ after(:each) do
49
+ Timecop.return
50
+ end
51
+ 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 'snappy_stats' # and any other gems you need
8
+ require 'fakeredis'
9
+ require 'timecop'
10
+ RSpec.configure do |config|
11
+ config.treat_symbols_as_metadata_keys_with_true_values = true
12
+ config.run_all_when_everything_filtered = true
13
+ config.filter_run :focus
14
+
15
+ # Run specs in random order to surface order dependencies. If you find an
16
+ # order dependency and want to debug it, you can fix the order by providing
17
+ # the seed, which is printed after each run.
18
+ # --seed 1234
19
+ config.order = 'random'
20
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: snappy_stats
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -11,6 +11,38 @@ bindir: bin
11
11
  cert_chain: []
12
12
  date: 2013-10-18 00:00:00.000000000 Z
13
13
  dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: active_support
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '0'
30
+ - !ruby/object:Gem::Dependency
31
+ name: redis
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :runtime
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
14
46
  - !ruby/object:Gem::Dependency
15
47
  name: bundler
16
48
  requirement: !ruby/object:Gem::Requirement
@@ -99,6 +131,8 @@ extensions: []
99
131
  extra_rdoc_files: []
100
132
  files:
101
133
  - .gitignore
134
+ - .rspec
135
+ - .travis.yml
102
136
  - Gemfile
103
137
  - LICENSE
104
138
  - LICENSE.txt
@@ -108,7 +142,9 @@ files:
108
142
  - lib/snappy_stats/config.rb
109
143
  - lib/snappy_stats/version.rb
110
144
  - snappy_stats.gemspec
111
- homepage: ''
145
+ - spec/snappy_stats_spec.rb
146
+ - spec/spec_helper.rb
147
+ homepage: https://github.com/timrwilliams/snappy_stats
112
148
  licenses:
113
149
  - MIT
114
150
  post_install_message:
@@ -133,4 +169,6 @@ rubygems_version: 1.8.23
133
169
  signing_key:
134
170
  specification_version: 3
135
171
  summary: Redis backed simple time series statistics gem
136
- test_files: []
172
+ test_files:
173
+ - spec/snappy_stats_spec.rb
174
+ - spec/spec_helper.rb