Skip to content
Browse files

base Monitor#summaries off the current time as buckets

  • Loading branch information...
1 parent 4d9be85 commit d0b3135da447d46d4f327b5d4fe975ee186f1be6 @qrush qrush committed
View
4 lib/daikon/client.rb
@@ -13,7 +13,7 @@ def setup(config, logger = nil)
self.config = config
self.logger = logger
self.redis = connect
- self.monitor = Monitor.new(connect, logger)
+ self.monitor = Monitor.new
self.http = Excon.new(config.server_prefix)
log "Started Daikon v#{VERSION}"
@@ -24,7 +24,7 @@ def connect
end
def start_monitor
- monitor.start
+ Monitor.start
end
def log(message)
View
43 lib/daikon/monitor.rb
@@ -1,7 +1,5 @@
module Daikon
class Monitor
- attr_accessor :summaries
-
NO_ARG_COMMANDS = ["BGREWRITEAOF", "BGSAVE", "CONFIG RESETSTAT", "DBSIZE", "DEBUG SEGFAULT", "DISCARD", "EXEC", "FLUSHALL", "FLUSHDB", "INFO", "LASTSAVE", "MONITOR", "MULTI", "PING", "QUIT", "RANDOMKEY", "SAVE", "SHUTDOWN", "SYNC", "UNWATCH"]
READ_COMMANDS = ["EXISTS", "GET", "GETBIT", "GETRANGE", "HEXISTS", "HGET", "HGETALL", "HKEYS", "HLEN", "HMGET", "HVALS", "KEYS", "LINDEX", "LLEN", "LRANGE", "MGET", "SCARD", "SDIFF", "SINTER", "SISMEMBER", "SMEMBERS", "SORT", "SRANDMEMBER", "STRLEN", "SUNION", "TTL", "TYPE", "ZCARD", "ZCOUNT", "ZRANGE", "ZRANGEBYSCORE", "ZRANK", "ZREVRANGE", "ZREVRANGEBYSCORE", "ZREVRANK", "ZSCORE"].to_set
WRITE_COMMANDS = ["APPEND", "BLPOP", "BRPOP", "BRPOPLPUSH", "DECR", "DECRBY", "DEL", "GETSET", "EXPIRE", "EXPIREAT", "HDEL", "HINCRBY", "HMSET", "HSET", "HSETNX", "INCR", "INCRBY", "LINSERT", "LPOP", "LPUSH", "LPUSHX", "LREM", "LSET", "LTRIM", "MOVE", "MSET", "MSETNX", "PERSIST", "RENAME", "RENAMENX", "RPOP", "RPOPLPUSH", "RPUSH", "RPUSHX", "SADD", "SDIFFSTORE", "SET", "SETBIT", "SETEX", "SETNX", "SETRANGE", "SINTERSTORE", "SMOVE", "SPOP", "SREM", "SUNIONSTORE", "ZADD", "ZINCRBY", "ZINTERSTORE", "ZREM", "ZREMRANGEBYRANK", "ZREMRANGEBYSCORE", "ZUNIONSTORE"].to_set
@@ -18,29 +16,40 @@ def self.parse(line)
def self.reset
summaries.clear
- summaries.replace(summaries_hash)
end
def self.pop
- summary = self.summaries.dup
+ time, summary = self.summaries.first
+ if summary.nil?
+ summary = summary_hash
+ end
+ summary["start"] = summary["stop"] = Time.now
summary["keys"] = Hash[*summary["keys"].sort_by(&:last).reverse[0..99].flatten]
yield(summary)
- reset
+ summaries.delete(time) if time
end
def self.summaries
- @@summaries ||= summaries_hash
+ @@summaries ||= {}
+ end
+
+ def self.current_summary(time)
+ summaries[time] ||= summary_hash
end
- def self.summaries_hash
+ def self.summary_hash
{"commands" => Hash.new(0),
"keys" => Hash.new(0),
"namespaces" => Hash.new(0),
"totals" => Hash.new(0)}
end
- def summaries
- self.class.summaries
+ def initialize
+ @now = Time.now.utc.strftime("%Y-%m-%d %H:%M:00 %Z")
+ end
+
+ def current_summary
+ self.class.current_summary(@now)
end
def self.start(redis)
@@ -80,33 +89,33 @@ def push(split_command)
def incr_namespace(key)
if marker = key =~ /:|-/
- summaries["namespaces"][key[0...marker]] += 1
+ current_summary["namespaces"][key[0...marker]] += 1
else
incr_global_namespace
end
end
def incr_global_namespace
- summaries["namespaces"]["global"] += 1
+ current_summary["namespaces"]["global"] += 1
end
def incr_command(command)
- summaries["commands"][command] += 1
+ current_summary["commands"][command] += 1
end
def incr_key(key)
- summaries["keys"][key] += 1
+ current_summary["keys"][key] += 1
end
def incr_total(command)
- summaries["totals"]["all"] += 1
+ current_summary["totals"]["all"] += 1
if READ_COMMANDS.member?(command)
- summaries["totals"]["read"] += 1
+ current_summary["totals"]["read"] += 1
elsif WRITE_COMMANDS.member?(command)
- summaries["totals"]["write"] += 1
+ current_summary["totals"]["write"] += 1
elsif OTHER_COMMANDS.member?(command)
- summaries["totals"]["other"] += 1
+ current_summary["totals"]["other"] += 1
end
end
end
View
4 spec/client_spec.rb
@@ -19,7 +19,7 @@
end
it "sets redis to listen on the given port" do
- Redis.should have_received(:connect).with(:url => url).twice
+ Redis.should have_received(:connect).with(:url => url).once
subject.should have_received(:redis=).with(redis)
end
end
@@ -32,7 +32,7 @@
end
it "sets redis to listen on the given port" do
- Redis.should have_received(:connect).with(:url => "redis://0.0.0.0:6379").twice
+ Redis.should have_received(:connect).with(:url => "redis://0.0.0.0:6379").once
subject.should have_received(:redis=).with(redis)
end
end
View
1 spec/daemon_spec.rb
@@ -4,6 +4,7 @@
let(:client) { stub("client") }
before do
+ Timecop.return
Daikon::Client.stubs(:new => client)
Daikon::Daemon.sleep_time = 0.05
client.stubs(:setup => true,
View
63 spec/monitor_spec.rb
@@ -103,14 +103,14 @@
it "parses logs" do
Daikon::Monitor.pop do |summary|
- subject.summaries["commands"]["DECR"].should == 1
- subject.summaries["commands"]["INCR"].should == 1
- subject.summaries["commands"]["SISMEMBER"].should == 1
- subject.summaries["keys"]["foo"].should == 2
- subject.summaries["keys"]["project-13897-global-error-classes"].should == 1
- subject.summaries["totals"]["all"].should == 3
- subject.summaries["totals"]["write"].should == 2
- subject.summaries["totals"]["read"].should == 1
+ summary["commands"]["DECR"].should == 1
+ summary["commands"]["INCR"].should == 1
+ summary["commands"]["SISMEMBER"].should == 1
+ summary["keys"]["foo"].should == 2
+ summary["keys"]["project-13897-global-error-classes"].should == 1
+ summary["totals"]["all"].should == 3
+ summary["totals"]["write"].should == 2
+ summary["totals"]["read"].should == 1
end
end
end
@@ -119,13 +119,13 @@
shared_examples_for "a valid parser" do
it "parses the given commands properly" do
Daikon::Monitor.pop do |summary|
- subject.summaries["commands"]["DECR"].should == 1
- subject.summaries["commands"]["INCR"].should == 1
- subject.summaries["commands"]["SET"].should == 1
- subject.summaries["keys"]["foo"].should == 2
- subject.summaries["keys"]["g:2470920:mrn"].should == 1
- subject.summaries["totals"]["all"].should == 3
- subject.summaries["totals"]["write"].should == 3
+ summary["commands"]["DECR"].should == 1
+ summary["commands"]["INCR"].should == 1
+ summary["commands"]["SET"].should == 1
+ summary["keys"]["foo"].should == 2
+ summary["keys"]["g:2470920:mrn"].should == 1
+ summary["totals"]["all"].should == 3
+ summary["totals"]["write"].should == 3
end
end
end
@@ -193,3 +193,36 @@
end
end
end
+
+describe Daikon::Monitor, "#parse over several minutes keeps several minutes of data" do
+ before do
+ Timecop.freeze(Time.at(Time.now - 179)) do
+ parse("INCR foo")
+ end
+
+ Timecop.freeze(Time.at(Time.now - 119)) do
+ parse("DECR foo")
+ end
+
+ Timecop.freeze(Time.at(Time.now - 60)) do
+ parse("INCR foo")
+ end
+ end
+
+ it "separates each into a separate minute" do
+ Daikon::Monitor.pop do |summary|
+ summary["commands"].should == {"INCR" => 1}
+ summary["keys"].should == {"foo" => 1}
+ end
+
+ Daikon::Monitor.pop do |summary|
+ summary["commands"].should == {"DECR" => 1}
+ summary["keys"].should == {"foo" => 1}
+ end
+
+ Daikon::Monitor.pop do |summary|
+ summary["commands"].should == {"INCR" => 1}
+ summary["keys"].should == {"foo" => 1}
+ end
+ end
+end
View
5 spec/spec_helper.rb
@@ -20,6 +20,11 @@
config.include ParseHelper
config.before do
+ Timecop.freeze(DateTime.now)
Daikon::Monitor.reset
end
+
+ config.after do
+ Timecop.return
+ end
end
View
11 spec/support/capture_helper.rb
@@ -0,0 +1,11 @@
+module CaptureHelper
+ # http://pivotallabs.com/users/alex/blog/articles/853-capturing-standard-out-in-unit-tests
+ def capture
+ output = StringIO.new
+ $stderr = output
+ yield
+ output.string
+ ensure
+ $stderr = STDERR
+ end
+end
View
5 spec/support/parse_helper.rb
@@ -0,0 +1,5 @@
+module ParseHelper
+ def parse(line)
+ Daikon::Monitor.parse(line)
+ end
+end

0 comments on commit d0b3135

Please sign in to comment.
Something went wrong with that request. Please try again.