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
data/lib/core_ext/hash.rb
DELETED
@@ -1,16 +0,0 @@
|
|
1
|
-
class Hash
|
2
|
-
|
3
|
-
# Return self as symbolized keys hash
|
4
|
-
def symbolize_keys
|
5
|
-
self.dup.inject({}) do |hsh, (k,v)|
|
6
|
-
hsh[k.to_s.to_sym] = (v.respond_to?(:symbolize_keys) ? v.symbolize_keys : v)
|
7
|
-
hsh
|
8
|
-
end
|
9
|
-
end
|
10
|
-
|
11
|
-
# Replace self with symbolized keys hash
|
12
|
-
def symbolize_keys!
|
13
|
-
self.replace(self.symbolize_keys)
|
14
|
-
end
|
15
|
-
|
16
|
-
end
|
data/lib/fozzie/mill.rb
DELETED
@@ -1,50 +0,0 @@
|
|
1
|
-
require 'uri'
|
2
|
-
|
3
|
-
module Fozzie
|
4
|
-
class Mill
|
5
|
-
|
6
|
-
DELIMETER = ';'
|
7
|
-
METRICS = %w{ttfb load}
|
8
|
-
|
9
|
-
attr_reader :str, :args
|
10
|
-
|
11
|
-
def initialize(str = "")
|
12
|
-
@str = str
|
13
|
-
escaped_split = str.split(DELIMETER).map!{|x| URI.unescape(x) }
|
14
|
-
@args = Hash[*escaped_split]
|
15
|
-
end
|
16
|
-
|
17
|
-
def self.register(str = "")
|
18
|
-
new(str).register
|
19
|
-
end
|
20
|
-
|
21
|
-
def register
|
22
|
-
return self unless self.has_href?
|
23
|
-
METRICS.each do |k|
|
24
|
-
next unless self.respond_to?(k.to_sym)
|
25
|
-
S.timing((namespace << ['page', k]).flatten, self.send(k.to_sym))
|
26
|
-
end
|
27
|
-
|
28
|
-
self
|
29
|
-
end
|
30
|
-
|
31
|
-
def load
|
32
|
-
@load ||= @args['domComplete'].to_i - @args['fetchStart'].to_i
|
33
|
-
end
|
34
|
-
|
35
|
-
def ttfb
|
36
|
-
@ttfb ||= @args['responseStart'].to_i - @args['fetchStart'].to_i
|
37
|
-
end
|
38
|
-
|
39
|
-
def has_href?
|
40
|
-
!@args['href'].nil?
|
41
|
-
end
|
42
|
-
|
43
|
-
def namespace
|
44
|
-
@uri ||= URI(@args['href'])
|
45
|
-
@path ||= @uri.path.strip.split('/').reject(&:empty?)
|
46
|
-
@path.dup
|
47
|
-
end
|
48
|
-
|
49
|
-
end
|
50
|
-
end
|
data/lib/fozzie/rails/engine.rb
DELETED
@@ -1,15 +0,0 @@
|
|
1
|
-
require 'json'
|
2
|
-
require 'fozzie/mill'
|
3
|
-
|
4
|
-
module Fozzie
|
5
|
-
module Rails
|
6
|
-
class Engine < ::Rails::Engine
|
7
|
-
|
8
|
-
endpoint Proc.new { |env|
|
9
|
-
Fozzie::Mill.register(env['QUERY_STRING'].gsub('d=', ''))
|
10
|
-
[201, {"Content-Type" => "text/html"}, [""]]
|
11
|
-
}
|
12
|
-
|
13
|
-
end
|
14
|
-
end
|
15
|
-
end
|
@@ -1,39 +0,0 @@
|
|
1
|
-
require 'fozzie/rack/middleware'
|
2
|
-
|
3
|
-
module Fozzie
|
4
|
-
module Rails
|
5
|
-
|
6
|
-
# Time and record each request through a given Rails app
|
7
|
-
# This middlewware times server processing for a resource, not view render.
|
8
|
-
class Middleware < Fozzie::Rack::Middleware
|
9
|
-
|
10
|
-
# Generates the statistics key for the current path
|
11
|
-
def generate_key(env)
|
12
|
-
path_str = env['PATH_INFO']
|
13
|
-
request_method = env['REQUEST_METHOD']
|
14
|
-
|
15
|
-
return nil unless path_str
|
16
|
-
|
17
|
-
begin
|
18
|
-
routing = routing_lookup
|
19
|
-
path = routing.recognize_path(path_str, :method => request_method)
|
20
|
-
stat = [path[:controller], path[:action], "render"].join('.')
|
21
|
-
stat
|
22
|
-
rescue => exc
|
23
|
-
S.increment "routing.error"
|
24
|
-
nil
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
def routing_lookup
|
29
|
-
(rails_version == 3 ? ::Rails.application.routes : ::ActionController::Routing::Routes)
|
30
|
-
end
|
31
|
-
|
32
|
-
def rails_version
|
33
|
-
::Rails.version.to_i
|
34
|
-
end
|
35
|
-
|
36
|
-
end
|
37
|
-
|
38
|
-
end
|
39
|
-
end
|
data/lib/fozzie/railtie.rb
DELETED
@@ -1,15 +0,0 @@
|
|
1
|
-
require 'fozzie/rails/engine'
|
2
|
-
|
3
|
-
class FozzieRailtie < Rails::Railtie
|
4
|
-
initializer "fozzie_railtie.configure_rails_initialization" do |app|
|
5
|
-
|
6
|
-
# Load up the middleware
|
7
|
-
app.middleware.use Fozzie::Rails::Middleware
|
8
|
-
|
9
|
-
# Add the Mill route
|
10
|
-
app.routes.prepend do
|
11
|
-
mount Fozzie::Rails::Engine => '/mill'
|
12
|
-
end
|
13
|
-
|
14
|
-
end
|
15
|
-
end
|
data/lib/fozzie/socket.rb
DELETED
@@ -1,53 +0,0 @@
|
|
1
|
-
require 'socket'
|
2
|
-
|
3
|
-
module Fozzie
|
4
|
-
module Socket
|
5
|
-
|
6
|
-
RESERVED_CHARS_REGEX = /[\:\|\@\s]/
|
7
|
-
DELIMETER = '.'
|
8
|
-
|
9
|
-
private
|
10
|
-
|
11
|
-
# Send the statistic to the server
|
12
|
-
#
|
13
|
-
# Creates the Statsd key from the given values, and sends to socket (depending on sample rate)
|
14
|
-
#
|
15
|
-
def send(stat, delta, type, sample_rate)
|
16
|
-
stat = [stat].flatten.compact.collect(&:to_s).join(DELIMETER).downcase
|
17
|
-
stat = stat.gsub('::', DELIMETER).gsub(RESERVED_CHARS_REGEX, '_')
|
18
|
-
|
19
|
-
k = [Fozzie.c.data_prefix, stat].compact.join(DELIMETER)
|
20
|
-
k << ":"
|
21
|
-
k << [delta, type].join('|')
|
22
|
-
k << '@%s' % sample_rate.to_s if sample_rate < 1
|
23
|
-
|
24
|
-
sampled(sample_rate) { send_to_socket(k.strip) }
|
25
|
-
end
|
26
|
-
|
27
|
-
# If the statistic is sampled, generate a condition to check if it's good to send
|
28
|
-
def sampled(sample_rate)
|
29
|
-
yield unless sample_rate < 1 and rand > sample_rate
|
30
|
-
end
|
31
|
-
|
32
|
-
# Send data to the server via the socket
|
33
|
-
def send_to_socket(message)
|
34
|
-
begin
|
35
|
-
Fozzie.logger.debug {"Statsd: #{message}"} if Fozzie.logger
|
36
|
-
Timeout.timeout(Fozzie.c.timeout) {
|
37
|
-
res = socket.send(message, 0, Fozzie.c.host, Fozzie.c.port)
|
38
|
-
Fozzie.logger.debug {"Statsd sent: #{res}"} if Fozzie.logger
|
39
|
-
(res.to_i == message.length)
|
40
|
-
}
|
41
|
-
rescue => exc
|
42
|
-
Fozzie.logger.debug {"Statsd Failure: #{exc.message}\n#{exc.backtrace}"} if Fozzie.logger
|
43
|
-
false
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
# The Socket we want to use to send data
|
48
|
-
def socket
|
49
|
-
@socket ||= ::UDPSocket.new
|
50
|
-
end
|
51
|
-
|
52
|
-
end
|
53
|
-
end
|
@@ -1,33 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
require 'core_ext/hash'
|
3
|
-
|
4
|
-
describe Hash do
|
5
|
-
|
6
|
-
it { should respond_to(:symbolize_keys) }
|
7
|
-
it { should respond_to(:symbolize_keys!) }
|
8
|
-
|
9
|
-
it "manipulates keys correctly" do
|
10
|
-
{
|
11
|
-
'1' => 1,
|
12
|
-
'2' => 2,
|
13
|
-
'3' => 3
|
14
|
-
}.symbolize_keys.should == {
|
15
|
-
:"1" => 1,
|
16
|
-
:"2" => 2,
|
17
|
-
:"3" => 3
|
18
|
-
}
|
19
|
-
end
|
20
|
-
|
21
|
-
it "returns copy when bang not provided" do
|
22
|
-
hsh = { '1' => 1, '2' => 2, '3' => 3 }
|
23
|
-
hsh.symbolize_keys
|
24
|
-
hsh.should == { '1' => 1, '2' => 2, '3' => 3 }
|
25
|
-
end
|
26
|
-
|
27
|
-
it "replaces self when bang provided" do
|
28
|
-
hsh = { '1' => 1, '2' => 2, '3' => 3 }
|
29
|
-
hsh.symbolize_keys!
|
30
|
-
hsh.should == { :"1" => 1, :"2" => 2, :"3" => 3 }
|
31
|
-
end
|
32
|
-
|
33
|
-
end
|
@@ -1,180 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
require 'fozzie/interface'
|
3
|
-
|
4
|
-
describe Fozzie::Interface do
|
5
|
-
|
6
|
-
subject { Fozzie::Interface.instance }
|
7
|
-
|
8
|
-
it "acts an a singleton" do
|
9
|
-
Fozzie.c.namespaces.each do |k|
|
10
|
-
Kernel.const_get(k).should eq Fozzie::Interface.instance
|
11
|
-
end
|
12
|
-
end
|
13
|
-
|
14
|
-
it "downcases any stat value" do
|
15
|
-
subject.expects(:send_to_socket)
|
16
|
-
.with {|bin| bin.match /\.foo/ }
|
17
|
-
|
18
|
-
subject.increment("FOO")
|
19
|
-
end
|
20
|
-
|
21
|
-
it "replaces invalid stat value chars" do
|
22
|
-
subject.expects(:send_to_socket)
|
23
|
-
.with {|bin| bin.match /\.foo_/ }
|
24
|
-
.times(4)
|
25
|
-
|
26
|
-
subject.increment("FOO:")
|
27
|
-
subject.increment("FOO@")
|
28
|
-
subject.increment("FOO|")
|
29
|
-
subject.increment(["FOO|"])
|
30
|
-
end
|
31
|
-
|
32
|
-
it "converts any values to strings for stat value, ignoring nil" do
|
33
|
-
subject.expects(:send_to_socket)
|
34
|
-
.with {|bin| bin.match /\.foo.1._.bar/ }
|
35
|
-
|
36
|
-
subject.increment([:foo, 1, nil, "@", "BAR"])
|
37
|
-
end
|
38
|
-
|
39
|
-
it "times a given block" do
|
40
|
-
subject.expects(:timing).with() {|b, val, timing| b == 'data.bin' && (1..11).include?(val) }.twice
|
41
|
-
subject.time_for('data.bin') { sleep 0.01 }
|
42
|
-
subject.time_to_do('data.bin') { sleep 0.01 }
|
43
|
-
end
|
44
|
-
|
45
|
-
it "registers a commit" do
|
46
|
-
subject.expects(:gauge).with(['event', 'commit', nil], anything).twice
|
47
|
-
subject.commit
|
48
|
-
subject.committed
|
49
|
-
end
|
50
|
-
|
51
|
-
it "registers a build" do
|
52
|
-
subject.expects(:gauge).with(['event', 'build', nil], anything).twice
|
53
|
-
subject.build
|
54
|
-
subject.built
|
55
|
-
end
|
56
|
-
|
57
|
-
it "registers a deploy" do
|
58
|
-
subject.expects(:gauge).with(['event', 'deploy', nil], anything).twice
|
59
|
-
subject.deploy
|
60
|
-
subject.deployed
|
61
|
-
end
|
62
|
-
|
63
|
-
it "ensures block is called on socket error" do
|
64
|
-
UDPSocket.any_instance.stubs(:send).raises(SocketError)
|
65
|
-
proc { subject.time_for('data.bin') { sleep 0.01 } }.should_not raise_error
|
66
|
-
proc { subject.time_to_do('data.bin') { sleep 0.01 } }.should_not raise_error
|
67
|
-
end
|
68
|
-
|
69
|
-
it "raises exception if natural exception from block" do
|
70
|
-
proc { subject.time_for('data.bin') { raise ArgumentError, "testing" } }.should raise_error(ArgumentError)
|
71
|
-
end
|
72
|
-
|
73
|
-
it "only calls the block once on SocketError" do
|
74
|
-
UDPSocket.any_instance.stubs(:send).raises(SocketError)
|
75
|
-
i = 0
|
76
|
-
p = proc {|n| (n + 1) }
|
77
|
-
val = subject.time_for('data.bin') { i+= p.call(i) }
|
78
|
-
val.should == 1
|
79
|
-
end
|
80
|
-
|
81
|
-
it "raises Timeout on slow lookup" do
|
82
|
-
Fozzie.c.timeout = 0.01
|
83
|
-
UDPSocket.any_instance.stubs(:send).with(any_parameters) { sleep 0.4 }
|
84
|
-
subject.increment('data.bin').should eq false
|
85
|
-
end
|
86
|
-
|
87
|
-
describe "#increment_on" do
|
88
|
-
|
89
|
-
it "registers success" do
|
90
|
-
subject.expects(:increment).with(["event.increment", "success"], 1)
|
91
|
-
subject.increment_on('event.increment', true).should == true
|
92
|
-
end
|
93
|
-
|
94
|
-
it "registers failure" do
|
95
|
-
subject.expects(:increment).with(["event.increment", "fail"], 1)
|
96
|
-
subject.increment_on('event.increment', false).should == false
|
97
|
-
end
|
98
|
-
|
99
|
-
it "simply questions the passed val with if" do
|
100
|
-
a = mock()
|
101
|
-
a.expects(:save).returns({})
|
102
|
-
subject.expects(:increment).with(["event.increment", "success"], 1)
|
103
|
-
subject.increment_on('event.increment', a.save).should == {}
|
104
|
-
end
|
105
|
-
|
106
|
-
it "registers fail on nil return" do
|
107
|
-
a = mock()
|
108
|
-
a.expects(:save).returns(nil)
|
109
|
-
subject.expects(:increment).with(["event.increment", "fail"], 1)
|
110
|
-
subject.increment_on('event.increment', a.save).should == nil
|
111
|
-
end
|
112
|
-
|
113
|
-
describe "performing actions" do
|
114
|
-
|
115
|
-
it "registers success" do
|
116
|
-
a = mock()
|
117
|
-
a.expects(:save).returns(true)
|
118
|
-
subject.expects(:increment).with(["event.increment", "success"], 1)
|
119
|
-
subject.increment_on('event.increment', a.save).should == true
|
120
|
-
end
|
121
|
-
|
122
|
-
it "registers failure" do
|
123
|
-
a = mock()
|
124
|
-
a.expects(:save).returns(false)
|
125
|
-
subject.expects(:increment).with(["event.increment", "fail"], 1)
|
126
|
-
subject.increment_on('event.increment', a.save).should == false
|
127
|
-
end
|
128
|
-
|
129
|
-
it "registers positive even when nested" do
|
130
|
-
a = mock()
|
131
|
-
a.expects(:save).returns(true)
|
132
|
-
subject.expects(:timing).with('event.run', any_parameters)
|
133
|
-
subject.expects(:increment).with(["event.increment", "success"], 1)
|
134
|
-
|
135
|
-
res = subject.time_to_do "event.run" do
|
136
|
-
subject.increment_on('event.increment', a.save)
|
137
|
-
end
|
138
|
-
res.should == true
|
139
|
-
end
|
140
|
-
|
141
|
-
it "registers negative even when nested" do
|
142
|
-
a = mock()
|
143
|
-
a.expects(:save).returns(false)
|
144
|
-
subject.expects(:timing).with('event.run', any_parameters)
|
145
|
-
subject.expects(:increment).with(["event.increment", "fail"], 1)
|
146
|
-
|
147
|
-
res = subject.time_to_do "event.run" do
|
148
|
-
subject.increment_on('event.increment', a.save)
|
149
|
-
end
|
150
|
-
res.should == false
|
151
|
-
end
|
152
|
-
|
153
|
-
it "allows passing of arrays for stat key" do
|
154
|
-
subject.expects(:timing).with(['event', 'commit'], any_parameters)
|
155
|
-
subject.time_to_do %w{event commit} do; end
|
156
|
-
end
|
157
|
-
|
158
|
-
end
|
159
|
-
|
160
|
-
end
|
161
|
-
|
162
|
-
describe "#gauge" do
|
163
|
-
it "registers a gauge measurement" do
|
164
|
-
subject.expects(:send).with("mystat", 99, "g", 1)
|
165
|
-
subject.gauge("mystat", 99)
|
166
|
-
end
|
167
|
-
end
|
168
|
-
|
169
|
-
describe "without prefix" do
|
170
|
-
|
171
|
-
it "registers stats without app, etc" do
|
172
|
-
Fozzie.c.disable_prefix
|
173
|
-
subject.expects(:send_to_socket).with {|bin| bin.match(/^mystat/) }
|
174
|
-
|
175
|
-
subject.gauge("mystat", 99)
|
176
|
-
end
|
177
|
-
|
178
|
-
end
|
179
|
-
|
180
|
-
end
|
@@ -1,43 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
require 'fozzie/mill'
|
3
|
-
|
4
|
-
module Fozzie
|
5
|
-
describe Mill do
|
6
|
-
let(:str) { "userAgent;Mozilla/5.0%20%28Macintosh%3B%20Intel%20Mac%20OS%20X%2010_7_3%29%20AppleWebKit/535.19%20%28KHTML%2C%20like%20Gecko%29%20Chrome/18.0.1025.165%20Safari/535.19;vendorSub;;vendor;Google%20Inc.;onLine;true;appCodeName;Mozilla;cookieEnabled;true;product;Gecko;language;en-US;appVersion;5.0%20%28Macintosh%3B%20Intel%20Mac%20OS%20X%2010_7_3%29%20AppleWebKit/535.19%20%28KHTML%2C%20like%20Gecko%29%20Chrome/18.0.1025.165%20Safari/535.19;appName;Netscape;productSub;20030107;platform;MacIntel;domainLookupStart;1335538507546;domInteractive;1335538508237;domComplete;1335538508323;loadEventEnd;0;requestStart;1335538507546;connectEnd;1335538507546;domContentLoadedEventEnd;1335538508237;unloadEventStart;1335538508050;domainLookupEnd;1335538507546;fetchStart;1335538507545;unloadEventEnd;1335538508050;connectStart;1335538507546;secureConnectionStart;0;redirectEnd;0;domContentLoadedEventStart;1335538508237;loadEventStart;1335538508323;responseStart;1335538508049;redirectStart;0;domLoading;1335538508182;responseEnd;1335538508050;navigationStart;1335538507545;href;http://localhost:8080/" }
|
7
|
-
subject { Mill }
|
8
|
-
|
9
|
-
describe "with environment arguments" do
|
10
|
-
|
11
|
-
it "creates args hash from string" do
|
12
|
-
inst = subject.register(str)
|
13
|
-
inst.args['appCodeName'].should eq 'Mozilla'
|
14
|
-
inst.args['cookieEnabled'].should eq 'true'
|
15
|
-
end
|
16
|
-
|
17
|
-
it "handles escaped values" do
|
18
|
-
inst = subject.register(str)
|
19
|
-
inst.args['userAgent'].should eq 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_3) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.165 Safari/535.19'
|
20
|
-
inst.args['appVersion'].should eq '5.0 (Macintosh; Intel Mac OS X 10_7_3) AppleWebKit/535.19 (KHTML, like Gecko) Chrome/18.0.1025.165 Safari/535.19'
|
21
|
-
end
|
22
|
-
|
23
|
-
it "skips if not passed" do
|
24
|
-
S.expects(:timing).never
|
25
|
-
subject.register("")
|
26
|
-
end
|
27
|
-
|
28
|
-
describe "registers all mapped metrics" do
|
29
|
-
let!(:expects) {
|
30
|
-
S.expects(:timing).with(["page", "ttfb"], 504)
|
31
|
-
S.expects(:timing).with(["page", "load"], 778)
|
32
|
-
}
|
33
|
-
|
34
|
-
it "dom complete" do
|
35
|
-
subject.register(str)
|
36
|
-
end
|
37
|
-
|
38
|
-
end
|
39
|
-
|
40
|
-
end
|
41
|
-
|
42
|
-
end
|
43
|
-
end
|