fozzie 0.0.27 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +2 -1
- data/Guardfile +2 -2
- data/README.md +22 -11
- data/Rakefile +1 -1
- data/fozzie.gemspec +8 -14
- data/lib/core_ext/module/monitor.rb +4 -3
- data/lib/fozzie.rb +6 -7
- data/lib/fozzie/adapter.rb +1 -0
- data/lib/fozzie/adapter/statsd.rb +86 -0
- data/lib/fozzie/bulk_dsl.rb +28 -0
- data/lib/fozzie/configuration.rb +32 -13
- data/lib/fozzie/dsl.rb +19 -0
- data/lib/fozzie/exception.rb +5 -0
- data/lib/fozzie/interface.rb +30 -15
- data/lib/fozzie/rack/middleware.rb +3 -1
- data/lib/fozzie/sniff.rb +28 -33
- data/lib/fozzie/version.rb +1 -1
- data/spec/config/fozzie.yml +2 -1
- data/spec/lib/core_ext/module/monitor_spec.rb +9 -0
- data/spec/lib/fozzie/adapter/statsd_spec.rb +82 -0
- data/spec/lib/fozzie/bulk_dsl_spec.rb +47 -0
- data/spec/lib/fozzie/configuration_spec.rb +34 -20
- data/spec/lib/fozzie/dsl_spec.rb +16 -0
- data/spec/lib/fozzie/rack/middleware_spec.rb +6 -36
- data/spec/lib/fozzie/rack/sinatra_spec.rb +31 -0
- data/spec/lib/fozzie/sniff_spec.rb +37 -37
- data/spec/lib/fozzie/version_spec.rb +1 -1
- data/spec/lib/fozzie_spec.rb +19 -3
- data/spec/shared_examples/fozzie_adapter.rb +7 -0
- data/spec/shared_examples/interface.rb +160 -0
- data/spec/spec_helper.rb +20 -10
- metadata +31 -74
- data/lib/core_ext/hash.rb +0 -16
- data/lib/fozzie/mill.rb +0 -50
- data/lib/fozzie/rails/engine.rb +0 -15
- data/lib/fozzie/rails/middleware.rb +0 -39
- data/lib/fozzie/railtie.rb +0 -15
- data/lib/fozzie/socket.rb +0 -53
- data/spec/lib/core_ext/hash_spec.rb +0 -33
- data/spec/lib/fozzie/interface_spec.rb +0 -180
- data/spec/lib/fozzie/mill_spec.rb +0 -43
- data/spec/lib/fozzie/rails/middleware_spec.rb +0 -125
@@ -1,8 +1,10 @@
|
|
1
|
+
require 'fozzie'
|
2
|
+
|
1
3
|
module Fozzie
|
2
4
|
module Rack
|
3
5
|
|
4
6
|
# Time and record each request through a given Rack app
|
5
|
-
# This
|
7
|
+
# This middleware times server processing for a resource, not view render.
|
6
8
|
class Middleware
|
7
9
|
|
8
10
|
attr_reader :app
|
data/lib/fozzie/sniff.rb
CHANGED
@@ -5,53 +5,48 @@ require 'facets/string/snakecase'
|
|
5
5
|
module Fozzie
|
6
6
|
module Sniff
|
7
7
|
|
8
|
-
def
|
9
|
-
|
10
|
-
|
11
|
-
klass.class_eval { extend ClassMethods }
|
8
|
+
def _monitor(bucket_name = nil)
|
9
|
+
@_monitor_flag = true
|
10
|
+
@_bucket_name = bucket_name
|
12
11
|
end
|
13
12
|
|
14
|
-
|
15
|
-
|
16
|
-
def _monitor
|
17
|
-
@_monitor_flag = true
|
18
|
-
end
|
13
|
+
def _monitor_meth(target, &blk)
|
14
|
+
return if @_monitor_flag.nil? || !@_monitor_flag
|
19
15
|
|
20
|
-
|
21
|
-
|
16
|
+
@_monitor_flag = false
|
17
|
+
bin = @_bucket_name || [self.name.snakecase, target.to_s.snakecase]
|
18
|
+
feature = :monitor
|
19
|
+
aliased_target = target.to_s.sub(/([?!=])$/, '')
|
20
|
+
punctuation = $1
|
22
21
|
|
23
|
-
|
24
|
-
|
22
|
+
with = "#{aliased_target}_with_#{feature}#{punctuation}"
|
23
|
+
without = "#{aliased_target}_without_#{feature}#{punctuation}"
|
25
24
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
blk.call(with, without, feature, bin)
|
30
|
-
end
|
25
|
+
blk.call(with, without, feature, bin)
|
26
|
+
end
|
31
27
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
end
|
28
|
+
def method_added(target)
|
29
|
+
_monitor_meth(target) do |with, without, feature, bin|
|
30
|
+
define_method(with) do |*args, &blk|
|
31
|
+
S.time_for(bin) do
|
32
|
+
args.empty? ? self.send(without, &blk) : self.send(without, *args, &blk)
|
38
33
|
end
|
39
|
-
self.alias_method_chain(target, feature)
|
40
34
|
end
|
35
|
+
self.alias_method_chain(target, feature)
|
41
36
|
end
|
37
|
+
end
|
42
38
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
end
|
39
|
+
def singleton_method_added(target)
|
40
|
+
_monitor_meth(target) do |with, without, feature, bin|
|
41
|
+
define_singleton_method(with) do |*args, &blk|
|
42
|
+
S.time_for(bin) do
|
43
|
+
args.empty? ? send(without, &blk) : send(without, *args, &blk)
|
49
44
|
end
|
50
|
-
self.singleton_class.class_eval { alias_method_chain target, feature }
|
51
45
|
end
|
46
|
+
self.singleton_class.class_eval { alias_method_chain target, feature }
|
52
47
|
end
|
53
|
-
|
54
48
|
end
|
55
49
|
|
56
50
|
end
|
51
|
+
|
57
52
|
end
|
data/lib/fozzie/version.rb
CHANGED
data/spec/config/fozzie.yml
CHANGED
@@ -0,0 +1,82 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'fozzie/adapter/statsd'
|
3
|
+
|
4
|
+
module Fozzie::Adapter
|
5
|
+
describe Statsd do
|
6
|
+
it_behaves_like "fozzie adapter"
|
7
|
+
|
8
|
+
# Switch to Statsd adapter for the duration of this test
|
9
|
+
before(:all) do
|
10
|
+
Fozzie.c.adapter = :Statsd
|
11
|
+
end
|
12
|
+
|
13
|
+
after(:all) do
|
14
|
+
Fozzie.c.adapter = :TestAdapter
|
15
|
+
end
|
16
|
+
|
17
|
+
it "downcases any stat value" do
|
18
|
+
subject.should_receive(:send_to_socket).with {|bin| bin.match /\.foo/ }
|
19
|
+
|
20
|
+
subject.register(:bin => "FOO", :value => 1, :type => :gauge, :sample_rate => 1)
|
21
|
+
end
|
22
|
+
|
23
|
+
describe "#format_bucket" do
|
24
|
+
it "accepts arrays" do
|
25
|
+
subject.format_bucket([:foo, '2']).should match /foo.2$/
|
26
|
+
subject.format_bucket([:foo, '2']).should match /foo.2$/
|
27
|
+
subject.format_bucket(%w{foo bar}).should match /foo.bar$/
|
28
|
+
end
|
29
|
+
|
30
|
+
it "converts any values to strings for stat value, ignoring nil" do
|
31
|
+
subject.format_bucket([:foo, 1, nil, "@", "BAR"]).should =~ /foo.1._.bar/
|
32
|
+
end
|
33
|
+
|
34
|
+
it "replaces invalid chracters" do
|
35
|
+
subject.format_bucket([:foo, ':']).should match /foo.#{subject.class::RESERVED_CHARS_REPLACEMENT}$/
|
36
|
+
subject.format_bucket([:foo, '@']).should match /foo.#{subject.class::RESERVED_CHARS_REPLACEMENT}$/
|
37
|
+
subject.format_bucket('foo.bar.|').should match /foo.bar.#{subject.class::RESERVED_CHARS_REPLACEMENT}$/
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
describe "#format_value" do
|
42
|
+
it "defaults type to gauge when type is not mapped" do
|
43
|
+
subject.format_value(1, :foo, 1).should eq '1|g'
|
44
|
+
end
|
45
|
+
|
46
|
+
it "converts basic values to string" do
|
47
|
+
subject.format_value(1, :count, 1).should eq '1|c'
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
it "ensures block is called on socket error" do
|
52
|
+
subject.socket.stub(:send) { raise SocketError }
|
53
|
+
|
54
|
+
proc { subject.register(:bin => 'data.bin', :value => 1, :type => :gauge, :sample_rate => 1) { sleep 0.01 } }.should_not raise_error
|
55
|
+
proc { subject.register(:bin => 'data.bin', :value => 1, :type => :gauge, :sample_rate => 1) { sleep 0.01 } }.should_not raise_error
|
56
|
+
end
|
57
|
+
|
58
|
+
it "raises Timeout on slow lookup" do
|
59
|
+
Fozzie.c.timeout = 0.01
|
60
|
+
subject.socket.stub(:send).with(any_args) { sleep 0.4 }
|
61
|
+
|
62
|
+
subject.register(:bin => 'data.bin', :value => 1, :type => :gauge, :sample_rate => 1).should eq false
|
63
|
+
end
|
64
|
+
|
65
|
+
describe "multiple stats in a single call" do
|
66
|
+
|
67
|
+
it "collects stats together with delimeter" do
|
68
|
+
Fozzie.c.disable_prefix
|
69
|
+
|
70
|
+
stats = [
|
71
|
+
{ :bin => 'foo', :value => 1, :type => :count, :sample_rate => 1 },
|
72
|
+
{ :bin => 'bar', :value => 1, :type => :gauge, :sample_rate => 1 },
|
73
|
+
{ :bin => %w{foo bar}, :value => 100, :type => :timing, :sample_rate => 1 }
|
74
|
+
]
|
75
|
+
|
76
|
+
subject.should_receive(:send_to_socket).with "foo:1|c\nbar:1|g\nfoo.bar:100|ms"
|
77
|
+
|
78
|
+
subject.register(stats)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module Fozzie
|
4
|
+
describe BulkDsl do
|
5
|
+
|
6
|
+
it_behaves_like "interface"
|
7
|
+
|
8
|
+
describe "#initialize" do
|
9
|
+
|
10
|
+
it "accepts and performs block" do
|
11
|
+
BulkDsl.any_instance.should_receive(:foo)
|
12
|
+
|
13
|
+
BulkDsl.new { foo }
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
|
18
|
+
it "sends statistics in one call" do
|
19
|
+
Fozzie.c.adapter.should_receive(:register).once
|
20
|
+
|
21
|
+
BulkDsl.new do
|
22
|
+
increment :foo
|
23
|
+
decrement :bar
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
it "scopes given block when arity provided" do
|
28
|
+
Fozzie.c.adapter.should_receive(:register).once
|
29
|
+
|
30
|
+
class Foo
|
31
|
+
|
32
|
+
def send_stats
|
33
|
+
BulkDsl.new do |s|
|
34
|
+
s.increment random_value
|
35
|
+
s.decrement random_value
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def random_value; rand end
|
40
|
+
|
41
|
+
end
|
42
|
+
|
43
|
+
Foo.new.send_stats
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
end
|
@@ -2,7 +2,6 @@ require 'spec_helper'
|
|
2
2
|
require 'resolv'
|
3
3
|
|
4
4
|
describe Fozzie::Configuration do
|
5
|
-
|
6
5
|
it "#host" do
|
7
6
|
subject.host.should be_kind_of(String)
|
8
7
|
end
|
@@ -12,27 +11,47 @@ describe Fozzie::Configuration do
|
|
12
11
|
end
|
13
12
|
|
14
13
|
it "attempts to load configuration from yaml" do
|
15
|
-
c = Fozzie::Configuration.new({
|
16
|
-
|
14
|
+
c = Fozzie::Configuration.new({
|
15
|
+
env: 'test',
|
16
|
+
config_path: 'spec/',
|
17
|
+
adapter: :TestAdapter
|
18
|
+
})
|
19
|
+
c.stub(:origin_name => "")
|
17
20
|
c.host.should eq '1.1.1.1'
|
18
21
|
c.port.should eq 9876
|
19
22
|
c.appname.should eq 'fozzie'
|
20
|
-
c.data_prefix.should eq
|
23
|
+
c.data_prefix.should eq "fozzie#{c.safe_separator}test"
|
21
24
|
end
|
22
25
|
|
23
26
|
it "defaults env" do
|
24
27
|
subject.env.should eq 'test'
|
25
28
|
end
|
26
29
|
|
27
|
-
describe "#
|
30
|
+
describe "#adapter" do
|
31
|
+
it "throw error on incorrect assignment" do
|
32
|
+
-> { Fozzie::Configuration.new({:env => 'test', :adapter => 'foo'}) }.should raise_error(Fozzie::AdapterMissing)
|
33
|
+
end
|
34
|
+
|
35
|
+
it "defaults adapter to Statsd" do
|
36
|
+
subject.adapter.should be_kind_of(Fozzie::Adapter::Statsd)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
describe "#disable_prefix" do
|
41
|
+
it "sets the data_prefix to nil" do
|
42
|
+
subject.disable_prefix
|
43
|
+
subject.data_prefix.should be_nil
|
44
|
+
end
|
45
|
+
end
|
28
46
|
|
47
|
+
describe "#prefix and #data_prefix" do
|
29
48
|
it "creates a #data_prefix" do
|
30
|
-
subject.
|
49
|
+
subject.stub(:origin_name => "")
|
31
50
|
subject.data_prefix.should eq 'test'
|
32
51
|
end
|
33
52
|
|
34
53
|
it "creates a #data_prefix with appname when set" do
|
35
|
-
subject.
|
54
|
+
subject.stub(:origin_name => "")
|
36
55
|
subject.appname = 'astoria'
|
37
56
|
subject.data_prefix.should eq 'astoria.test'
|
38
57
|
end
|
@@ -48,11 +67,10 @@ describe Fozzie::Configuration do
|
|
48
67
|
end
|
49
68
|
|
50
69
|
it "allows dynamic injection of value to prefix" do
|
51
|
-
subject.
|
70
|
+
subject.stub(:origin_name => "")
|
52
71
|
subject.prefix << 'git-sha-1234'
|
53
72
|
subject.data_prefix.should eq 'test.git-sha-1234'
|
54
73
|
end
|
55
|
-
|
56
74
|
end
|
57
75
|
|
58
76
|
it "handles missing configuration namespace" do
|
@@ -66,46 +84,42 @@ describe Fozzie::Configuration do
|
|
66
84
|
end
|
67
85
|
|
68
86
|
describe "#sniff?" do
|
69
|
-
|
70
87
|
it "defaults to false for testing" do
|
71
|
-
subject.
|
88
|
+
subject.stub(:env => "test")
|
72
89
|
subject.sniff?.should be_false
|
73
90
|
end
|
74
91
|
|
75
92
|
it "defaults true when in development" do
|
76
|
-
subject.
|
93
|
+
subject.stub(:env => "development")
|
77
94
|
subject.sniff?.should be_true
|
78
95
|
end
|
79
96
|
|
80
97
|
it "defaults true when in production" do
|
81
|
-
subject.
|
98
|
+
subject.stub(:env => "production")
|
82
99
|
subject.sniff?.should be_true
|
83
100
|
end
|
84
|
-
|
85
101
|
end
|
86
102
|
|
87
103
|
describe "#sniff_envs allows configuration for #sniff?" do
|
88
|
-
let!(:sniff_envs) { subject.
|
104
|
+
let!(:sniff_envs) { subject.stub(:sniff_envs => ['test']) }
|
89
105
|
|
90
106
|
it "scopes to return false" do
|
91
|
-
subject.
|
107
|
+
subject.stub(:env => "development")
|
92
108
|
subject.sniff?.should be_false
|
93
109
|
end
|
94
110
|
|
95
111
|
it "scopes to return true" do
|
96
|
-
subject.
|
112
|
+
subject.stub(:env => "test")
|
97
113
|
subject.sniff?.should be_true
|
98
114
|
end
|
99
115
|
|
100
116
|
end
|
101
117
|
|
102
118
|
describe "ignoring prefix" do
|
103
|
-
|
104
119
|
it "does not use prefix when set to ignore" do
|
105
120
|
subject.disable_prefix
|
106
121
|
subject.ignore_prefix.should eq(true)
|
107
122
|
end
|
108
|
-
|
109
123
|
end
|
110
124
|
|
111
|
-
end
|
125
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'fozzie/interface'
|
3
|
+
|
4
|
+
describe Fozzie::Dsl do
|
5
|
+
|
6
|
+
subject { Fozzie::Dsl.instance }
|
7
|
+
|
8
|
+
it_behaves_like "interface"
|
9
|
+
|
10
|
+
it "acts an a singleton" do
|
11
|
+
Fozzie.c.namespaces.each do |k|
|
12
|
+
Kernel.const_get(k).should eq Fozzie::Dsl.instance
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
@@ -1,12 +1,11 @@
|
|
1
1
|
require 'spec_helper'
|
2
|
-
require '
|
3
|
-
require 'rack/test'
|
2
|
+
require 'fozzie/rack/middleware'
|
4
3
|
|
5
4
|
describe Fozzie::Rack::Middleware do
|
6
5
|
|
7
6
|
subject do
|
8
7
|
unless defined?(RackApp)
|
9
|
-
RackApp = Class.new { def call(env); env end }
|
8
|
+
RackApp = Class.new { def call(env); env end }
|
10
9
|
end
|
11
10
|
Fozzie::Rack::Middleware.new RackApp.new
|
12
11
|
end
|
@@ -24,30 +23,29 @@ describe Fozzie::Rack::Middleware do
|
|
24
23
|
|
25
24
|
it "ignored stats request when path not valid" do
|
26
25
|
fake_env = { 'PATH_INFO' => '' }
|
27
|
-
subject.
|
26
|
+
subject.should_receive(:call_without_timer).with(fake_env)
|
28
27
|
subject.call(fake_env)
|
29
28
|
end
|
30
29
|
|
31
30
|
it "passes request with timer on index" do
|
32
31
|
fake_env = { 'PATH_INFO' => '/' }
|
33
|
-
subject.
|
32
|
+
subject.should_receive(:call_with_timer).with('index.render', fake_env)
|
34
33
|
subject.call(fake_env)
|
35
34
|
end
|
36
35
|
|
37
36
|
it "passes request with timer on full path" do
|
38
37
|
fake_env = { 'PATH_INFO' => '/somewhere/nice' }
|
39
|
-
subject.
|
38
|
+
subject.should_receive(:call_with_timer).with('somewhere.nice.render', fake_env)
|
40
39
|
subject.call(fake_env)
|
41
40
|
end
|
42
41
|
|
43
42
|
it "passes request onto app" do
|
44
43
|
envs = ['', '/', '/somewhere/nice'].each do |p|
|
45
44
|
fake_env = { 'PATH_INFO' => p }
|
46
|
-
subject.app.
|
45
|
+
subject.app.should_receive(:call).with(fake_env)
|
47
46
|
subject.call(fake_env)
|
48
47
|
end
|
49
48
|
end
|
50
|
-
|
51
49
|
end
|
52
50
|
|
53
51
|
describe "#generate_key" do
|
@@ -69,32 +67,4 @@ describe Fozzie::Rack::Middleware do
|
|
69
67
|
|
70
68
|
end
|
71
69
|
|
72
|
-
end
|
73
|
-
|
74
|
-
describe "Sinatra Server with Middleware" do
|
75
|
-
include Rack::Test::Methods
|
76
|
-
|
77
|
-
def app
|
78
|
-
Sinatra.new do
|
79
|
-
set :environment, :test
|
80
|
-
use Fozzie::Rack::Middleware
|
81
|
-
get('/') { "echo" }
|
82
|
-
get('/somewhere/nice') { "echo" }
|
83
|
-
end
|
84
|
-
end
|
85
|
-
|
86
|
-
it "sends stats request on root" do
|
87
|
-
S.expects(:timing).with('index.render', any_parameters)
|
88
|
-
get '/'
|
89
|
-
last_response.should be_ok
|
90
|
-
last_response.body.should == 'echo'
|
91
|
-
end
|
92
|
-
|
93
|
-
it "sends stats request on nested path" do
|
94
|
-
S.expects(:timing).with('somewhere.nice.render', any_parameters)
|
95
|
-
get '/somewhere/nice'
|
96
|
-
last_response.should be_ok
|
97
|
-
last_response.body.should == 'echo'
|
98
|
-
end
|
99
|
-
|
100
70
|
end
|