redistat 0.0.9 → 0.1.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.
- data/.gitignore +1 -0
- data/README.md +1 -1
- data/Rakefile +1 -0
- data/lib/redistat.rb +1 -0
- data/lib/redistat/event.rb +5 -2
- data/lib/redistat/key.rb +10 -0
- data/lib/redistat/label.rb +16 -2
- data/lib/redistat/summary.rb +38 -4
- data/lib/redistat/version.rb +1 -1
- data/redistat.gemspec +1 -0
- data/spec/key_spec.rb +13 -0
- data/spec/label_spec.rb +20 -0
- data/spec/summary_spec.rb +74 -0
- metadata +22 -6
data/.gitignore
CHANGED
data/README.md
CHANGED
|
@@ -14,7 +14,7 @@ Redis fits perfectly with all of these requirements. It has atomic operations li
|
|
|
14
14
|
|
|
15
15
|
gem install redistat
|
|
16
16
|
|
|
17
|
-
If you are using Ruby 1.8.x, it's recommended you also install the `
|
|
17
|
+
If you are using Ruby 1.8.x, it's recommended you also install the `SystemTimer` gem, as the Redis gem will otherwise complain.
|
|
18
18
|
|
|
19
19
|
## Usage
|
|
20
20
|
|
data/Rakefile
CHANGED
data/lib/redistat.rb
CHANGED
data/lib/redistat/event.rb
CHANGED
|
@@ -31,7 +31,10 @@ module Redistat
|
|
|
31
31
|
end
|
|
32
32
|
|
|
33
33
|
def default_options
|
|
34
|
-
{ :depth => :hour,
|
|
34
|
+
{ :depth => :hour,
|
|
35
|
+
:store_event => false,
|
|
36
|
+
:connection_ref => nil,
|
|
37
|
+
:enable_grouping => true }
|
|
35
38
|
end
|
|
36
39
|
|
|
37
40
|
def new?
|
|
@@ -72,7 +75,7 @@ module Redistat
|
|
|
72
75
|
|
|
73
76
|
def save
|
|
74
77
|
return false if !self.new?
|
|
75
|
-
Summary.update_all(@key, @stats, depth_limit, @connection_ref)
|
|
78
|
+
Summary.update_all(@key, @stats, depth_limit, @connection_ref, @options[:enable_grouping])
|
|
76
79
|
if @options[:store_event]
|
|
77
80
|
@id = self.next_id
|
|
78
81
|
db.hmset("#{self.scope}#{KEY_EVENT}#{@id}",
|
data/lib/redistat/key.rb
CHANGED
|
@@ -39,10 +39,20 @@ module Redistat
|
|
|
39
39
|
@label.hash
|
|
40
40
|
end
|
|
41
41
|
|
|
42
|
+
def label_groups
|
|
43
|
+
@label.groups
|
|
44
|
+
end
|
|
45
|
+
|
|
42
46
|
def label=(input)
|
|
43
47
|
@label = (input.instance_of?(Redistat::Label)) ? input : Label.create(input, @options)
|
|
44
48
|
end
|
|
45
49
|
|
|
50
|
+
def groups
|
|
51
|
+
@groups ||= label_groups.map do |label_name|
|
|
52
|
+
self.class.new(@scope, label_name, self.date, @options)
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
46
56
|
def to_s(depth = nil)
|
|
47
57
|
depth ||= @options[:depth]
|
|
48
58
|
key = self.prefix
|
data/lib/redistat/label.rb
CHANGED
|
@@ -5,6 +5,10 @@ module Redistat
|
|
|
5
5
|
attr_reader :raw
|
|
6
6
|
attr_reader :connection_ref
|
|
7
7
|
|
|
8
|
+
def self.create(name, options = {})
|
|
9
|
+
self.new(name, options).save
|
|
10
|
+
end
|
|
11
|
+
|
|
8
12
|
def initialize(str, options = {})
|
|
9
13
|
@options = options
|
|
10
14
|
@raw = str.to_s
|
|
@@ -31,8 +35,18 @@ module Redistat
|
|
|
31
35
|
@saved ||= false
|
|
32
36
|
end
|
|
33
37
|
|
|
34
|
-
def
|
|
35
|
-
|
|
38
|
+
def groups
|
|
39
|
+
return @groups if @groups
|
|
40
|
+
@groups = []
|
|
41
|
+
parent = ""
|
|
42
|
+
@raw.split(GROUP_SEPARATOR).each do |part|
|
|
43
|
+
if !part.blank?
|
|
44
|
+
group = ((parent.blank?) ? "" : "#{parent}/") + part
|
|
45
|
+
@groups << group
|
|
46
|
+
parent = group
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
@groups.reverse!
|
|
36
50
|
end
|
|
37
51
|
|
|
38
52
|
end
|
data/lib/redistat/summary.rb
CHANGED
|
@@ -2,23 +2,57 @@ module Redistat
|
|
|
2
2
|
class Summary
|
|
3
3
|
include Database
|
|
4
4
|
|
|
5
|
-
def self.update_all(key, stats = {}, depth_limit = nil, connection_ref = nil)
|
|
5
|
+
def self.update_all(key, stats = {}, depth_limit = nil, connection_ref = nil, enable_grouping = nil)
|
|
6
6
|
stats ||= {}
|
|
7
|
-
depth_limit ||= key.depth
|
|
8
7
|
return nil if stats.size == 0
|
|
8
|
+
|
|
9
|
+
depth_limit ||= key.depth
|
|
10
|
+
enable_grouping = true if enable_grouping.nil?
|
|
11
|
+
|
|
12
|
+
if enable_grouping
|
|
13
|
+
stats = inject_group_summaries(stats)
|
|
14
|
+
key.groups.each { |k|
|
|
15
|
+
update_key(k, stats, depth_limit, connection_ref)
|
|
16
|
+
}
|
|
17
|
+
else
|
|
18
|
+
update_key(key, stats, depth_limit, connection_ref)
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
private
|
|
23
|
+
|
|
24
|
+
def self.update_key(key, stats, depth_limit, connection_ref)
|
|
9
25
|
Date::DEPTHS.each do |depth|
|
|
10
26
|
update(key, stats, depth, connection_ref)
|
|
11
27
|
break if depth == depth_limit
|
|
12
28
|
end
|
|
13
29
|
end
|
|
14
30
|
|
|
15
|
-
private
|
|
16
|
-
|
|
17
31
|
def self.update(key, stats, depth, connection_ref = nil)
|
|
18
32
|
stats.each do |field, value|
|
|
19
33
|
db(connection_ref).hincrby key.to_s(depth), field, value
|
|
20
34
|
end
|
|
21
35
|
end
|
|
22
36
|
|
|
37
|
+
def self.inject_group_summaries!(stats)
|
|
38
|
+
stats.each do |key, value|
|
|
39
|
+
parts = key.to_s.split(GROUP_SEPARATOR)
|
|
40
|
+
parts.pop
|
|
41
|
+
if parts.size > 0
|
|
42
|
+
sum_parts = []
|
|
43
|
+
parts.each do |part|
|
|
44
|
+
sum_parts << part
|
|
45
|
+
sum_key = sum_parts.join(GROUP_SEPARATOR)
|
|
46
|
+
(stats.has_key?(sum_key)) ? stats[sum_key] += value : stats[sum_key] = value
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
stats
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def self.inject_group_summaries(stats)
|
|
54
|
+
inject_group_summaries!(stats.clone)
|
|
55
|
+
end
|
|
56
|
+
|
|
23
57
|
end
|
|
24
58
|
end
|
data/lib/redistat/version.rb
CHANGED
data/redistat.gemspec
CHANGED
data/spec/key_spec.rb
CHANGED
|
@@ -14,6 +14,7 @@ describe Redistat::Key do
|
|
|
14
14
|
@key.scope.should == @scope
|
|
15
15
|
@key.label.should == @label
|
|
16
16
|
@key.label_hash.should == @label_hash
|
|
17
|
+
@key.label_groups.should == @key.instance_variable_get("@label").groups
|
|
17
18
|
@key.date.should be_instance_of(Redistat::Date)
|
|
18
19
|
@key.date.to_time.to_s.should == @date.to_s
|
|
19
20
|
end
|
|
@@ -60,4 +61,16 @@ describe Redistat::Key do
|
|
|
60
61
|
@key.label_hash == @label_hash
|
|
61
62
|
end
|
|
62
63
|
|
|
64
|
+
it "should create a group of keys from label group" do
|
|
65
|
+
label = 'message/public/offensive'
|
|
66
|
+
result = [ "message/public/offensive",
|
|
67
|
+
"message/public",
|
|
68
|
+
"message" ]
|
|
69
|
+
|
|
70
|
+
key = Redistat::Key.new(@scope, label, @date, {:depth => :hour})
|
|
71
|
+
|
|
72
|
+
key.label_groups.should == result
|
|
73
|
+
key.groups.map { |k| k.label }.should == result
|
|
74
|
+
end
|
|
75
|
+
|
|
63
76
|
end
|
data/spec/label_spec.rb
CHANGED
|
@@ -25,4 +25,24 @@ describe Redistat::Label do
|
|
|
25
25
|
db.get("#{Redistat::KEY_LEBELS}#{label.hash}").should == name
|
|
26
26
|
end
|
|
27
27
|
|
|
28
|
+
it "should separate label names into groups" do
|
|
29
|
+
name = "message/public/offensive"
|
|
30
|
+
label = Redistat::Label.new(name)
|
|
31
|
+
label.name.should == name
|
|
32
|
+
label.groups.should == [ "message/public/offensive",
|
|
33
|
+
"message/public",
|
|
34
|
+
"message" ]
|
|
35
|
+
|
|
36
|
+
name = "/message/public/"
|
|
37
|
+
label = Redistat::Label.new(name)
|
|
38
|
+
label.name.should == name
|
|
39
|
+
label.groups.should == [ "message/public",
|
|
40
|
+
"message" ]
|
|
41
|
+
|
|
42
|
+
name = "message"
|
|
43
|
+
label = Redistat::Label.new(name)
|
|
44
|
+
label.name.should == name
|
|
45
|
+
label.groups.should == [ "message" ]
|
|
46
|
+
end
|
|
47
|
+
|
|
28
48
|
end
|
data/spec/summary_spec.rb
CHANGED
|
@@ -46,4 +46,78 @@ describe Redistat::Summary do
|
|
|
46
46
|
end
|
|
47
47
|
end
|
|
48
48
|
|
|
49
|
+
it "should inject stats key grouping summaries" do
|
|
50
|
+
hash = { "count/hello" => 3, "count/world" => 7,
|
|
51
|
+
"death/bomb" => 4, "death/unicorn" => 3,
|
|
52
|
+
:"od/sugar" => 7, :"od/meth" => 8 }
|
|
53
|
+
res = Redistat::Summary.send(:inject_group_summaries, hash)
|
|
54
|
+
res.should == { "count" => 10, "count/hello" => 3, "count/world" => 7,
|
|
55
|
+
"death" => 7, "death/bomb" => 4, "death/unicorn" => 3,
|
|
56
|
+
"od" => 15, :"od/sugar" => 7, :"od/meth" => 8 }
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
it "should properly store key group summaries" do
|
|
60
|
+
stats = {"views" => 3, "visitors/eu" => 2, "visitors/us" => 4}
|
|
61
|
+
Redistat::Summary.update_all(@key, stats, :hour)
|
|
62
|
+
summary = db.hgetall(@key.to_s(:hour))
|
|
63
|
+
summary.should have(4).items
|
|
64
|
+
summary["views"].should == "3"
|
|
65
|
+
summary["visitors"].should == "6"
|
|
66
|
+
summary["visitors/eu"].should == "2"
|
|
67
|
+
summary["visitors/us"].should == "4"
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
it "should not store key group summaries when option is disabled" do
|
|
71
|
+
stats = {"views" => 3, "visitors/eu" => 2, "visitors/us" => 4}
|
|
72
|
+
Redistat::Summary.update_all(@key, stats, :hour, nil, false)
|
|
73
|
+
summary = db.hgetall(@key.to_s(:hour))
|
|
74
|
+
summary.should have(3).items
|
|
75
|
+
summary["views"].should == "3"
|
|
76
|
+
summary["visitors/eu"].should == "2"
|
|
77
|
+
summary["visitors/us"].should == "4"
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
it "should store label-based grouping enabled stats" do
|
|
81
|
+
stats = {"views" => 3, "visitors/eu" => 2, "visitors/us" => 4}
|
|
82
|
+
label = "views/about_us"
|
|
83
|
+
key = Redistat::Key.new(@scope, label, @date)
|
|
84
|
+
Redistat::Summary.update_all(key, stats, :hour)
|
|
85
|
+
|
|
86
|
+
key.groups[0].label.should == "views/about_us"
|
|
87
|
+
key.groups[1].label.should == "views"
|
|
88
|
+
child1 = key.groups[0]
|
|
89
|
+
parent = key.groups[1]
|
|
90
|
+
|
|
91
|
+
label = "views/contact"
|
|
92
|
+
key = Redistat::Key.new(@scope, label, @date)
|
|
93
|
+
Redistat::Summary.update_all(key, stats, :hour)
|
|
94
|
+
|
|
95
|
+
key.groups[0].label.should == "views/contact"
|
|
96
|
+
key.groups[1].label.should == "views"
|
|
97
|
+
child2 = key.groups[0]
|
|
98
|
+
|
|
99
|
+
summary = db.hgetall(child1.to_s(:hour))
|
|
100
|
+
summary["views"].should == "3"
|
|
101
|
+
summary["visitors/eu"].should == "2"
|
|
102
|
+
summary["visitors/us"].should == "4"
|
|
103
|
+
|
|
104
|
+
summary = db.hgetall(child2.to_s(:hour))
|
|
105
|
+
summary["views"].should == "3"
|
|
106
|
+
summary["visitors/eu"].should == "2"
|
|
107
|
+
summary["visitors/us"].should == "4"
|
|
108
|
+
|
|
109
|
+
summary = db.hgetall(parent.to_s(:hour))
|
|
110
|
+
summary["views"].should == "6"
|
|
111
|
+
summary["visitors/eu"].should == "4"
|
|
112
|
+
summary["visitors/us"].should == "8"
|
|
113
|
+
end
|
|
114
|
+
|
|
49
115
|
end
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
|
metadata
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: redistat
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
hash:
|
|
4
|
+
hash: 27
|
|
5
5
|
prerelease:
|
|
6
6
|
segments:
|
|
7
7
|
- 0
|
|
8
|
+
- 1
|
|
8
9
|
- 0
|
|
9
|
-
|
|
10
|
-
version: 0.0.9
|
|
10
|
+
version: 0.1.0
|
|
11
11
|
platform: ruby
|
|
12
12
|
authors:
|
|
13
13
|
- Jim Myhrberg
|
|
@@ -15,7 +15,7 @@ autorequire:
|
|
|
15
15
|
bindir: bin
|
|
16
16
|
cert_chain: []
|
|
17
17
|
|
|
18
|
-
date: 2011-
|
|
18
|
+
date: 2011-03-04 00:00:00 +00:00
|
|
19
19
|
default_executable:
|
|
20
20
|
dependencies:
|
|
21
21
|
- !ruby/object:Gem::Dependency
|
|
@@ -99,9 +99,25 @@ dependencies:
|
|
|
99
99
|
type: :development
|
|
100
100
|
version_requirements: *id005
|
|
101
101
|
- !ruby/object:Gem::Dependency
|
|
102
|
-
name:
|
|
102
|
+
name: rcov
|
|
103
103
|
prerelease: false
|
|
104
104
|
requirement: &id006 !ruby/object:Gem::Requirement
|
|
105
|
+
none: false
|
|
106
|
+
requirements:
|
|
107
|
+
- - ">="
|
|
108
|
+
- !ruby/object:Gem::Version
|
|
109
|
+
hash: 41
|
|
110
|
+
segments:
|
|
111
|
+
- 0
|
|
112
|
+
- 9
|
|
113
|
+
- 9
|
|
114
|
+
version: 0.9.9
|
|
115
|
+
type: :development
|
|
116
|
+
version_requirements: *id006
|
|
117
|
+
- !ruby/object:Gem::Dependency
|
|
118
|
+
name: yard
|
|
119
|
+
prerelease: false
|
|
120
|
+
requirement: &id007 !ruby/object:Gem::Requirement
|
|
105
121
|
none: false
|
|
106
122
|
requirements:
|
|
107
123
|
- - ">="
|
|
@@ -113,7 +129,7 @@ dependencies:
|
|
|
113
129
|
- 3
|
|
114
130
|
version: 0.6.3
|
|
115
131
|
type: :development
|
|
116
|
-
version_requirements: *
|
|
132
|
+
version_requirements: *id007
|
|
117
133
|
description: A Redis-backed statistics storage and querying library written in Ruby.
|
|
118
134
|
email:
|
|
119
135
|
- contact@jimeh.me
|