Allow for configurable group separator

This commit is contained in:
David Czarnecki
2012-04-18 14:44:36 -04:00
parent a9cf3938cf
commit fa182e618d
7 changed files with 71 additions and 8 deletions

View File

@@ -149,7 +149,12 @@ is the label that you're storing to, or fetching from.
Labels support multiple grouping levels by splitting the label string with `/` Labels support multiple grouping levels by splitting the label string with `/`
and storing the same stats for each level. For example, when storing data to a and storing the same stats for each level. For example, when storing data to a
label called `views/product/44`, the data is stored for the label you specify, label called `views/product/44`, the data is stored for the label you specify,
and also for `views/product` and `views`. and also for `views/product` and `views`. You may also configure a different
group separator using the `Redistat.group_separator` option. For example:
```ruby
Redistat.group_separator = '|'
```
A word of caution: Don't use a crazy number of group levels. As two levels A word of caution: Don't use a crazy number of group levels. As two levels
causes twice as many `hincrby` calls to Redis as not using the grouping causes twice as many `hincrby` calls to Redis as not using the grouping

View File

@@ -52,6 +52,8 @@ module Redistat
class << self class << self
attr_writer :group_separator
def buffer def buffer
Buffer.instance Buffer.instance
end end
@@ -91,6 +93,10 @@ module Redistat
connection.flushdb connection.flushdb
end end
def group_separator
@group_separator ||= GROUP_SEPARATOR
end
end end
end end

View File

@@ -56,7 +56,7 @@ module Redistat
members = db.smembers("#{scope}#{LABEL_INDEX}#{@label}") || [] # older versions of Redis returns nil members = db.smembers("#{scope}#{LABEL_INDEX}#{@label}") || [] # older versions of Redis returns nil
members.map { |member| members.map { |member|
child_label = [@label, member].reject { |i| i.nil? } child_label = [@label, member].reject { |i| i.nil? }
self.class.new(self.scope, child_label.join(GROUP_SEPARATOR), self.date, @options) self.class.new(self.scope, child_label.join(Redistat.group_separator), self.date, @options)
} }
end end

View File

@@ -13,7 +13,7 @@ module Redistat
def self.join(*args) def self.join(*args)
args = args.map {|i| i.to_s} args = args.map {|i| i.to_s}
self.new(args.reject {|i| i.blank? }.join(GROUP_SEPARATOR)) self.new(args.reject {|i| i.blank? }.join(Redistat.group_separator))
end end
def initialize(str, opts = {}) def initialize(str, opts = {})
@@ -48,16 +48,16 @@ module Redistat
end end
def me def me
self.to_s.split(GROUP_SEPARATOR).last self.to_s.split(Redistat.group_separator).last
end end
def groups def groups
return @groups unless @groups.nil? return @groups unless @groups.nil?
@groups = [] @groups = []
parent = "" parent = ""
self.to_s.split(GROUP_SEPARATOR).each do |part| self.to_s.split(Redistat.group_separator).each do |part|
if !part.blank? if !part.blank?
group = ((parent.blank?) ? "" : "#{parent}#{GROUP_SEPARATOR}") + part group = ((parent.blank?) ? "" : "#{parent}#{Redistat.group_separator}") + part
@groups << Label.new(group) @groups << Label.new(group)
parent = group parent = group
end end

View File

@@ -66,13 +66,13 @@ module Redistat
def inject_group_summaries!(stats) def inject_group_summaries!(stats)
summaries = {} summaries = {}
stats.each do |key, value| stats.each do |key, value|
parts = key.to_s.split(GROUP_SEPARATOR) parts = key.to_s.split(Redistat.group_separator)
parts.pop parts.pop
if parts.size > 0 if parts.size > 0
sum_parts = [] sum_parts = []
parts.each do |part| parts.each do |part|
sum_parts << part sum_parts << part
sum_key = sum_parts.join(GROUP_SEPARATOR) sum_key = sum_parts.join(Redistat.group_separator)
(summaries.has_key?(sum_key)) ? summaries[sum_key] += value : summaries[sum_key] = value (summaries.has_key?(sum_key)) ? summaries[sum_key] += value : summaries[sum_key] = value
end end
end end

View File

@@ -38,6 +38,21 @@ describe Redistat::Label do
label.to_s.should == 'email/message/public' label.to_s.should == 'email/message/public'
end end
it "should allow you to use a different group separator" do
include Redistat
Redistat.group_separator = '|'
label = Label.join('email', 'message', 'public')
label.should be_a(Label)
label.to_s.should == 'email|message|public'
label = Label.join(Label.new('email'), Label.new('message'), Label.new('public'))
label.should be_a(Label)
label.to_s.should == 'email|message|public'
label = Label.join('email', '', 'message', nil, 'public')
label.should be_a(Label)
label.to_s.should == 'email|message|public'
Redistat.group_separator = Redistat::GROUP_SEPARATOR
end
describe "Grouping" do describe "Grouping" do
before(:each) do before(:each) do
@name = "message/public/offensive" @name = "message/public/offensive"

View File

@@ -136,4 +136,41 @@ describe Redistat::Summary do
summary["visitors/us"].should == "8" summary["visitors/us"].should == "8"
end end
it "should store label-based grouping enabled stats using a different group separator" do
Redistat.group_separator = '|'
stats = {"views" => 3, "visitors|eu" => 2, "visitors|us" => 4}
label = "views|about_us"
key = Redistat::Key.new(@scope, label, @date)
Redistat::Summary.update_all(key, stats, :hour)
key.groups[0].label.to_s.should == "views|about_us"
key.groups[1].label.to_s.should == "views"
child1 = key.groups[0]
parent = key.groups[1]
label = "views|contact"
key = Redistat::Key.new(@scope, label, @date)
Redistat::Summary.update_all(key, stats, :hour)
key.groups[0].label.to_s.should == "views|contact"
key.groups[1].label.to_s.should == "views"
child2 = key.groups[0]
summary = db.hgetall(child1.to_s(:hour))
summary["views"].should == "3"
summary["visitors|eu"].should == "2"
summary["visitors|us"].should == "4"
summary = db.hgetall(child2.to_s(:hour))
summary["views"].should == "3"
summary["visitors|eu"].should == "2"
summary["visitors|us"].should == "4"
summary = db.hgetall(parent.to_s(:hour))
summary["views"].should == "6"
summary["visitors|eu"].should == "4"
summary["visitors|us"].should == "8"
Redistat.group_separator = Redistat::GROUP_SEPARATOR
end
end end