camayoc 0.1.0 → 0.2.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/HISTORY.md +9 -0
- data/README.md +77 -18
- data/lib/camayoc.rb +9 -5
- data/lib/camayoc/handlers/filter.rb +15 -20
- data/lib/camayoc/handlers/io.rb +7 -7
- data/lib/camayoc/handlers/logger.rb +21 -26
- data/lib/camayoc/handlers/memory.rb +39 -13
- data/lib/camayoc/handlers/redis.rb +21 -13
- data/lib/camayoc/handlers/statsd.rb +22 -10
- data/lib/camayoc/stat_event.rb +10 -3
- data/lib/camayoc/stats.rb +58 -20
- data/lib/camayoc/timer.rb +41 -0
- data/lib/camayoc/version.rb +1 -1
- data/test/handlers/filter_test.rb +39 -35
- data/test/handlers/io_test.rb +25 -11
- data/test/handlers/logger_test.rb +14 -9
- data/test/handlers/memory_test.rb +63 -12
- data/test/handlers/redis_test.rb +10 -5
- data/test/handlers/statsd_test.rb +29 -5
- data/test/registration_test.rb +12 -0
- data/test/stat_event_test.rb +2 -2
- data/test/stats_test.rb +44 -49
- data/test/test_helper.rb +39 -1
- metadata +9 -5
@@ -1,6 +1,6 @@
|
|
1
1
|
require 'socket'
|
2
2
|
|
3
|
-
# This class is a port of the code in https://github.com/reinh/statsd to fit
|
3
|
+
# This class is a port of the code in https://github.com/reinh/statsd to fit
|
4
4
|
# with the Camayoc handler interface.
|
5
5
|
module Camayoc
|
6
6
|
module Handlers
|
@@ -9,7 +9,7 @@ module Camayoc
|
|
9
9
|
include ThreadSafety
|
10
10
|
|
11
11
|
attr_accessor :namespace
|
12
|
-
|
12
|
+
|
13
13
|
def initialize(options={})
|
14
14
|
self.namespace = options[:namespace]
|
15
15
|
@host = options[:host]
|
@@ -18,15 +18,28 @@ module Camayoc
|
|
18
18
|
self.thread_safe = Camayoc.thread_safe?
|
19
19
|
end
|
20
20
|
|
21
|
-
def
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
21
|
+
def event(ev)
|
22
|
+
case ev.type
|
23
|
+
when :timing then timing(ev)
|
24
|
+
when :count then count(ev)
|
25
|
+
else other(ev)
|
26
|
+
end
|
27
27
|
end
|
28
28
|
|
29
29
|
private
|
30
|
+
def other(ev)
|
31
|
+
value = Integer(ev.value) rescue 1
|
32
|
+
send(ev.ns_stat,value,'c',ev.options[:sample_rate]||1)
|
33
|
+
end
|
34
|
+
|
35
|
+
def count(ev)
|
36
|
+
send(ev.ns_stat,ev.value,'c',ev.options[:sample_rate]||1)
|
37
|
+
end
|
38
|
+
|
39
|
+
def timing(ev)
|
40
|
+
send(ev.ns_stat,ev.value,'ms',ev.options[:sample_rate]||1)
|
41
|
+
end
|
42
|
+
|
30
43
|
def sampled(sample_rate)
|
31
44
|
yield unless sample_rate < 1 and rand > sample_rate
|
32
45
|
end
|
@@ -41,7 +54,6 @@ module Camayoc
|
|
41
54
|
end
|
42
55
|
end
|
43
56
|
end
|
44
|
-
|
45
57
|
end
|
46
58
|
end
|
47
|
-
end
|
59
|
+
end
|
data/lib/camayoc/stat_event.rb
CHANGED
@@ -1,9 +1,16 @@
|
|
1
1
|
module Camayoc
|
2
2
|
class StatEvent
|
3
3
|
|
4
|
-
attr_accessor :source, :stat, :value, :options
|
4
|
+
attr_accessor :type, :source, :stat, :value, :options
|
5
5
|
|
6
|
-
|
6
|
+
# Constructor
|
7
|
+
# * +type+ :: Symbol of stat type: count, timing, or generic
|
8
|
+
# * +source+ :: Source of stat
|
9
|
+
# * +stat+ :: Name of stat
|
10
|
+
# * +value+ :: Value of stat
|
11
|
+
# * +options+ :: Optionals options
|
12
|
+
def initialize(type,source,stat,value,options={})
|
13
|
+
self.type = type
|
7
14
|
self.source = source
|
8
15
|
self.stat = stat
|
9
16
|
self.value = value
|
@@ -15,4 +22,4 @@ module Camayoc
|
|
15
22
|
end
|
16
23
|
|
17
24
|
end
|
18
|
-
end
|
25
|
+
end
|
data/lib/camayoc/stats.rb
CHANGED
@@ -3,12 +3,23 @@ module Camayoc
|
|
3
3
|
|
4
4
|
attr_accessor :name, :parent, :handlers
|
5
5
|
|
6
|
+
# Constructor
|
7
|
+
# * +name+ :: Name of stat
|
8
|
+
# * +parent+ :: Optional parent stat (default: nil)
|
6
9
|
def initialize(name,parent=nil)
|
7
10
|
self.name = name
|
8
11
|
self.parent = parent
|
9
12
|
self.handlers = []
|
10
13
|
end
|
11
|
-
|
14
|
+
|
15
|
+
def [](descendant_name)
|
16
|
+
Camayoc[Camayoc.join(name,descendant_name)]
|
17
|
+
end
|
18
|
+
|
19
|
+
# Add handler with filter options
|
20
|
+
# * +handler+ :: Handler instance
|
21
|
+
# * +filter_opts+ :: Options for a new Handlers::Filter
|
22
|
+
# instance (optional)
|
12
23
|
def add(handler,filter_opts={})
|
13
24
|
if !filter_opts.empty?
|
14
25
|
handler = Handlers::Filter.new(handler,filter_opts)
|
@@ -17,49 +28,76 @@ module Camayoc
|
|
17
28
|
self
|
18
29
|
end
|
19
30
|
|
31
|
+
# Quick alias for adding a handler
|
20
32
|
def <<(handler)
|
21
33
|
self.add(handler)
|
22
34
|
end
|
23
35
|
|
36
|
+
# Timing stat
|
37
|
+
def timing(stat,value,options={})
|
38
|
+
propagate(:timing,stat,value,options)
|
39
|
+
end
|
40
|
+
|
41
|
+
# Generic event
|
42
|
+
def event(stat,value,options={})
|
43
|
+
propagate(:generic,stat,value,options)
|
44
|
+
end
|
45
|
+
|
46
|
+
# Count and incr/decr convenience methods
|
47
|
+
def count(stat,value,options={})
|
48
|
+
propagate(:count,stat,value,options)
|
49
|
+
end
|
50
|
+
|
24
51
|
def increment(stat,options={})
|
25
|
-
count(stat,1,options)
|
52
|
+
count(stat,1,options)
|
26
53
|
end
|
27
54
|
|
28
55
|
def decrement(stat,options={})
|
29
56
|
count(stat,-1,options)
|
30
57
|
end
|
31
58
|
|
32
|
-
|
33
|
-
|
59
|
+
# Executes a block, stores the timing information in the specified stat
|
60
|
+
# and returns the value of the block. Use this to wrap existing code with
|
61
|
+
# timing information without worrying about return values.
|
62
|
+
def benchmark(stat,options={})
|
63
|
+
result = nil
|
64
|
+
realtime(stat,options) do
|
65
|
+
result = yield
|
66
|
+
end
|
67
|
+
result
|
34
68
|
end
|
35
69
|
|
36
|
-
|
37
|
-
|
70
|
+
# Executes a block, stores the timing information in the specified stat
|
71
|
+
# and returns the time **in seconds** that the execution took. This is
|
72
|
+
# basically a drop-in replacement for calls to Benchmark.realtime
|
73
|
+
def realtime(stat,options={})
|
74
|
+
start_time = Time.now
|
75
|
+
yield
|
76
|
+
duration = (Time.now.to_f - start_time.to_f)
|
77
|
+
# Convert to ms for timing call
|
78
|
+
timing(stat,(duration*1000).round,options)
|
79
|
+
duration
|
38
80
|
end
|
39
|
-
|
81
|
+
|
40
82
|
protected
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
end
|
45
|
-
if parent
|
46
|
-
parent.count_event(event)
|
47
|
-
end
|
48
|
-
self
|
83
|
+
# Creates new StatEvent and passes to +#propagate_event+
|
84
|
+
def propagate(type,stat,value,options)
|
85
|
+
propagate_event(StatEvent.new(type,name,stat,value,options))
|
49
86
|
end
|
50
87
|
|
51
|
-
|
88
|
+
# Propagates event to all handlers and parent Stat
|
89
|
+
def propagate_event(ev)
|
52
90
|
each_handler do |handler|
|
53
|
-
handler.
|
91
|
+
handler.event(ev)
|
54
92
|
end
|
55
93
|
if parent
|
56
|
-
parent.
|
94
|
+
parent.propagate_event(ev)
|
57
95
|
end
|
58
96
|
self
|
59
97
|
end
|
60
98
|
|
61
99
|
private
|
62
|
-
def each_handler
|
100
|
+
def each_handler
|
63
101
|
handlers.each do |handler|
|
64
102
|
begin
|
65
103
|
yield(handler)
|
@@ -74,4 +112,4 @@ module Camayoc
|
|
74
112
|
end
|
75
113
|
|
76
114
|
end
|
77
|
-
end
|
115
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module Camayoc
|
2
|
+
class Timer
|
3
|
+
|
4
|
+
attr_accessor :stats, :name, :start_time, :stop_time
|
5
|
+
|
6
|
+
def initialize(stats,name)
|
7
|
+
self.stats = stats
|
8
|
+
self.name = name
|
9
|
+
end
|
10
|
+
|
11
|
+
def start
|
12
|
+
self.start_time = Time.now.to_f
|
13
|
+
end
|
14
|
+
|
15
|
+
def stop
|
16
|
+
self.stop_time = Time.now.to_f
|
17
|
+
duration
|
18
|
+
end
|
19
|
+
|
20
|
+
def duration
|
21
|
+
(duration_seconds*1000).round
|
22
|
+
end
|
23
|
+
|
24
|
+
def duration_seconds
|
25
|
+
stop_time - start_time
|
26
|
+
end
|
27
|
+
|
28
|
+
def save(options={})
|
29
|
+
stats.timing(name,duration,options)
|
30
|
+
end
|
31
|
+
|
32
|
+
def realtime
|
33
|
+
start
|
34
|
+
yield
|
35
|
+
stop
|
36
|
+
save
|
37
|
+
duration_seconds
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
end
|
data/lib/camayoc/version.rb
CHANGED
@@ -1,53 +1,57 @@
|
|
1
1
|
class FilterTest < Test::Unit::TestCase
|
2
|
-
|
2
|
+
|
3
|
+
include EventTestHelper
|
4
|
+
|
3
5
|
def setup
|
4
6
|
@handler = mock("handler")
|
5
7
|
end
|
6
8
|
|
7
|
-
|
8
|
-
filter = Camayoc::Handlers::Filter.new(@handler) do |
|
9
|
+
with_event_types("test_constructor_block_used_as_filter") do
|
10
|
+
filter = Camayoc::Handlers::Filter.new(@handler) do |event|
|
9
11
|
event.stat.length > 5
|
10
12
|
end
|
11
|
-
|
12
|
-
@handler.expects(:
|
13
|
-
filter.
|
14
|
-
filter.
|
15
|
-
filter.timing(Camayoc::StatEvent.new("foo:bar","short",500))
|
16
|
-
filter.timing(Camayoc::StatEvent.new("foo:bar","very_long",500))
|
13
|
+
|
14
|
+
@handler.expects(:event).once
|
15
|
+
filter.event(Camayoc::StatEvent.new(@event_type,"foo:bar","short",500))
|
16
|
+
filter.event(Camayoc::StatEvent.new(@event_type,"foo:bar","very_long",500))
|
17
17
|
end
|
18
18
|
|
19
|
-
|
19
|
+
with_event_types("test_with_filters_on_namespaced_stat") do
|
20
20
|
filter = Camayoc::Handlers::Filter.new(@handler,:with=>/a{2}/)
|
21
|
-
|
22
|
-
@
|
23
|
-
|
24
|
-
filter.
|
25
|
-
filter.
|
26
|
-
filter.timing(Camayoc::StatEvent.new("foo:bar","bb_blah",500))
|
21
|
+
|
22
|
+
evt = stat_event_match(@event_type,"foo:bar","aa_blah",500)
|
23
|
+
@handler.expects(:event).with(&evt).once
|
24
|
+
filter.event(Camayoc::StatEvent.new(@event_type,"foo:bar","aa_blah",500))
|
25
|
+
filter.event(Camayoc::StatEvent.new(@event_type,"foo:bar","bb_blah",500))
|
27
26
|
end
|
28
27
|
|
29
|
-
def
|
28
|
+
def test_constructor_block_used_as_filter_with_if_condition
|
30
29
|
filter = Camayoc::Handlers::Filter.new(@handler,
|
31
|
-
:if=>Proc.new{|
|
32
|
-
|
33
|
-
|
34
|
-
@handler.expects(:
|
35
|
-
filter.
|
36
|
-
filter.
|
37
|
-
filter.
|
30
|
+
:if=>Proc.new{|event| event.type == :timing && event.value > 1000 })
|
31
|
+
|
32
|
+
evt = stat_event_match(:timing,"foo:bar","very_long",1500)
|
33
|
+
@handler.expects(:event).with(&evt).once
|
34
|
+
filter.event(Camayoc::StatEvent.new(:count,"foo:bar","short",500))
|
35
|
+
filter.event(Camayoc::StatEvent.new(:timing,"foo:bar","short",500))
|
36
|
+
filter.event(Camayoc::StatEvent.new(:timing,"foo:bar","very_long",1500))
|
38
37
|
end
|
39
38
|
|
40
|
-
def
|
39
|
+
def test_constructor_block_used_as_filter_with_unless_condition
|
41
40
|
filter = Camayoc::Handlers::Filter.new(@handler,
|
42
|
-
:unless=>Proc.new{|
|
43
|
-
|
44
|
-
|
45
|
-
@handler.expects(:
|
46
|
-
filter.
|
47
|
-
filter.
|
48
|
-
filter.
|
49
|
-
|
41
|
+
:unless=>Proc.new{|event| event.type == :count })
|
42
|
+
|
43
|
+
evt = stat_event_match(:timing,"foo:bar","short",500)
|
44
|
+
@handler.expects(:event).with(&evt).once
|
45
|
+
filter.event(Camayoc::StatEvent.new(:timing,"foo:bar","short",500))
|
46
|
+
filter.event(Camayoc::StatEvent.new(:count,"foo:bar","short",500))
|
47
|
+
filter.event(Camayoc::StatEvent.new(:count,"foo:bar","very_long",500))
|
48
|
+
end
|
49
|
+
|
50
|
+
def test_default_filter_is_always_true
|
51
|
+
filter = Camayoc::Handlers::Filter.new(@handler)
|
52
|
+
|
53
|
+
@handler.expects(:event).once
|
54
|
+
filter.event(Camayoc::StatEvent.new(:counting,"foo:bar","short",500))
|
50
55
|
end
|
51
56
|
|
52
|
-
|
53
|
-
end
|
57
|
+
end
|
data/test/handlers/io_test.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
class IOTest < Test::Unit::TestCase
|
2
|
-
|
2
|
+
|
3
3
|
def setup
|
4
4
|
# Hack to get around weird Mocha issue with expecting :puts
|
5
5
|
@io = []
|
@@ -10,24 +10,38 @@ class IOTest < Test::Unit::TestCase
|
|
10
10
|
end
|
11
11
|
|
12
12
|
def test_count_sends_correct_log_message
|
13
|
-
|
14
|
-
|
13
|
+
@handler.event(Camayoc::StatEvent.new(:count,"foo:bar","baz",500))
|
14
|
+
assert_message(/count foo:bar:baz 500/)
|
15
15
|
end
|
16
16
|
|
17
17
|
def test_timing_sends_correct_log_message
|
18
|
-
|
19
|
-
|
18
|
+
@handler.event(Camayoc::StatEvent.new(:timing,"foo:bar","time",100))
|
19
|
+
assert_message(/timing foo:bar:time 100/)
|
20
20
|
end
|
21
21
|
|
22
22
|
def test_formatter_changes_format_of_message
|
23
|
-
@handler.formatter = Proc.new{|
|
24
|
-
|
25
|
-
|
23
|
+
@handler.formatter = Proc.new{|event| "#{event.type}: #{event.ns_stat}"}
|
24
|
+
@handler.event(Camayoc::StatEvent.new(:timing,"foo:bar","time",100))
|
25
|
+
assert_message(/timing: foo:bar:time/)
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_formatter_can_be_set_with_constructor_block
|
29
|
+
@handler = Camayoc::Handlers::IO.new(@io) do |event|
|
30
|
+
"#{event.type}: #{event.ns_stat} #{event.value}"
|
31
|
+
end
|
32
|
+
@handler.event(Camayoc::StatEvent.new(:timing,"foo:bar","time",100))
|
33
|
+
assert_message(/timing: foo:bar:time 100/)
|
34
|
+
end
|
35
|
+
|
36
|
+
def test_logs_any_event_type
|
37
|
+
@handler.event(Camayoc::StatEvent.new(:baz,"foo:bar","time",500))
|
38
|
+
assert_message(/baz foo:bar:time 500/)
|
26
39
|
end
|
27
40
|
|
28
41
|
private
|
29
|
-
def
|
30
|
-
|
42
|
+
def assert_message(*messages)
|
43
|
+
pairs = messages.zip(@io)
|
44
|
+
assert(pairs.all?{ |actual,patt| actual =~ patt },pairs.join("\n"))
|
31
45
|
end
|
32
46
|
|
33
|
-
end
|
47
|
+
end
|
@@ -1,32 +1,37 @@
|
|
1
1
|
class LoggerTest < Test::Unit::TestCase
|
2
|
-
|
2
|
+
|
3
3
|
def setup
|
4
4
|
@dest_logger = mock("logger")
|
5
5
|
@handler = Camayoc::Handlers::Logger.new(@dest_logger)
|
6
6
|
end
|
7
|
-
|
7
|
+
|
8
8
|
def test_count_sends_correct_log_message
|
9
9
|
expect_message(:debug, /count foo:bar:baz 500/)
|
10
|
-
@handler.
|
10
|
+
@handler.event(Camayoc::StatEvent.new(:count,"foo:bar","baz",500))
|
11
11
|
end
|
12
12
|
|
13
13
|
def test_timing_sends_correct_log_message
|
14
14
|
expect_message(:debug,/timing foo:bar:time 100/)
|
15
|
-
@handler.
|
15
|
+
@handler.event(Camayoc::StatEvent.new(:timing,"foo:bar","time",100))
|
16
16
|
end
|
17
17
|
|
18
18
|
def test_method_option_changes_method_called_on_logger
|
19
19
|
@handler.method = :info
|
20
20
|
expect_message(:info,/timing foo:bar:time 100/)
|
21
|
-
@handler.
|
21
|
+
@handler.event(Camayoc::StatEvent.new(:timing,"foo:bar","time",100))
|
22
22
|
expect_message(:info, /count foo:bar:baz 5000/)
|
23
|
-
@handler.
|
23
|
+
@handler.event(Camayoc::StatEvent.new(:count,"foo:bar","baz",5000))
|
24
24
|
end
|
25
25
|
|
26
26
|
def test_formatter_changes_format_of_message
|
27
|
-
@handler.formatter = Proc.new{|
|
27
|
+
@handler.formatter = Proc.new{|event| "#{event.type}: #{event.ns_stat}"}
|
28
28
|
expect_message(:debug,/timing: foo:bar:time/)
|
29
|
-
@handler.
|
29
|
+
@handler.event(Camayoc::StatEvent.new(:timing,"foo:bar","time",100))
|
30
|
+
end
|
31
|
+
|
32
|
+
def test_logs_unknown_event_type
|
33
|
+
expect_message(:debug,/throwaway foo:bar:time 500/)
|
34
|
+
@handler.event(Camayoc::StatEvent.new(:throwaway,"foo:bar","time",500))
|
30
35
|
end
|
31
36
|
|
32
37
|
private
|
@@ -34,4 +39,4 @@ class LoggerTest < Test::Unit::TestCase
|
|
34
39
|
@dest_logger.expects(method).with(regexp_matches(message))
|
35
40
|
end
|
36
41
|
|
37
|
-
end
|
42
|
+
end
|