fozzie 0.0.27 → 1.0.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 +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
|