fozzie 0.0.20 → 0.0.21
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/Guardfile +0 -4
- data/README.md +6 -6
- data/fozzie.gemspec +6 -3
- data/lib/core_ext/module/monitor.rb +11 -0
- data/lib/fozzie.rb +5 -1
- data/lib/fozzie/configuration.rb +14 -8
- data/lib/fozzie/mill.rb +50 -0
- data/lib/fozzie/rails/engine.rb +15 -0
- data/lib/fozzie/rails/middleware.rb +7 -4
- data/lib/fozzie/railtie.rb +15 -0
- data/lib/fozzie/sniff.rb +53 -0
- data/lib/fozzie/socket.rb +3 -2
- data/lib/fozzie/version.rb +1 -1
- data/resources/mill.js.example +27 -0
- data/resources/mill.min.js.example +1 -0
- data/spec/lib/fozzie/configuration_spec.rb +34 -0
- data/spec/lib/fozzie/interface_spec.rb +7 -6
- data/spec/lib/fozzie/mill_spec.rb +43 -0
- data/spec/lib/fozzie/rails/middleware_spec.rb +14 -20
- data/spec/lib/fozzie/sniff_spec.rb +107 -0
- metadata +144 -44
- data/doc/lib/core_ext/hash.html +0 -79
- data/doc/lib/fozzie.html +0 -152
- data/doc/lib/fozzie/configuration.html +0 -175
- data/doc/lib/fozzie/interface.html +0 -286
- data/doc/lib/fozzie/rack/middleware.html +0 -97
- data/doc/lib/fozzie/rails/middleware.html +0 -97
- data/doc/lib/fozzie/socket.html +0 -129
- data/doc/lib/fozzie/version.html +0 -36
data/Guardfile
CHANGED
data/README.md
CHANGED
@@ -144,11 +144,7 @@ To time and register the controller actions within your Rails application, Fozzi
|
|
144
144
|
|
145
145
|
Based on the Rack middleware above, but is more involved in it's construction of the bucket value.
|
146
146
|
|
147
|
-
|
148
|
-
|
149
|
-
Rails::Initializer.run do |config|
|
150
|
-
config.middleware.use 'Fozzie::Rails::Middleware'
|
151
|
-
end
|
147
|
+
Fozzie::Rails::Middleware will automatically be invoked on Rails initialization.
|
152
148
|
|
153
149
|
## Bucket name prefixes
|
154
150
|
|
@@ -176,6 +172,10 @@ Fozzie will try to log these errors, but only if a logger has been applied (whic
|
|
176
172
|
|
177
173
|
This may change, depending on feedback and more production experience.
|
178
174
|
|
175
|
+
## Rails User Interface Performance Measuring
|
176
|
+
|
177
|
+
If you also require UI metrics, you can also include the Mill script in the bottom of any page you would like to measure (see `resources/mill.js` and `resources/mill.min.js`) and you start receiving measurements on page performance.
|
178
|
+
|
179
179
|
## Credits
|
180
180
|
|
181
181
|
Currently supported and maintained by [Marc Watts](marc.watts@lonelyplanet.co.uk) @Lonely Planet Online.
|
@@ -186,7 +186,7 @@ Big thanks to:
|
|
186
186
|
|
187
187
|
* [Etsy](http://codeascraft.etsy.com/) who's [Statsd](https://github.com/etsy/statsd) product has enabled us to come such a long way in a very short period of time. We love Etsy.
|
188
188
|
|
189
|
-
* [
|
189
|
+
* [reinh](https://github.com/reinh/statsd) for his [statsd](https://github.com/reinh/statsd) Gem.
|
190
190
|
|
191
191
|
## Comments and Feedback
|
192
192
|
|
data/fozzie.gemspec
CHANGED
@@ -21,19 +21,22 @@ Gem::Specification.new do |s|
|
|
21
21
|
s.require_paths = ["lib"]
|
22
22
|
|
23
23
|
s.add_dependency 'sys-uname'
|
24
|
+
s.add_dependency 'facets'
|
24
25
|
|
25
26
|
s.add_development_dependency 'rake'
|
26
27
|
s.add_development_dependency 'rspec'
|
27
28
|
s.add_development_dependency 'mocha'
|
28
29
|
s.add_development_dependency 'syntax'
|
29
|
-
|
30
|
-
s.add_development_dependency 'rack-test'
|
31
30
|
s.add_development_dependency 'simplecov'
|
31
|
+
|
32
32
|
s.add_development_dependency 'sinatra'
|
33
|
-
s.add_development_dependency '
|
33
|
+
s.add_development_dependency 'rack-test'
|
34
|
+
s.add_development_dependency 'actionpack', '2.3.14'
|
34
35
|
|
35
36
|
s.add_development_dependency 'guard'
|
36
37
|
s.add_development_dependency 'guard-rspec'
|
37
38
|
s.add_development_dependency 'guard-rocco'
|
38
39
|
s.add_development_dependency 'fl-rocco'
|
40
|
+
|
41
|
+
s.add_development_dependency 'ruby_gntp'
|
39
42
|
end
|
data/lib/fozzie.rb
CHANGED
@@ -9,6 +9,8 @@
|
|
9
9
|
#
|
10
10
|
module Fozzie
|
11
11
|
|
12
|
+
require 'core_ext/module/monitor'
|
13
|
+
|
12
14
|
require 'fozzie/configuration'
|
13
15
|
require "fozzie/interface"
|
14
16
|
require "fozzie/version"
|
@@ -16,6 +18,8 @@ module Fozzie
|
|
16
18
|
require "fozzie/rack/middleware"
|
17
19
|
require "fozzie/rails/middleware"
|
18
20
|
|
21
|
+
require 'fozzie/railtie' if defined?(::Rails)
|
22
|
+
|
19
23
|
class << self
|
20
24
|
|
21
25
|
# Shortcut for `Fozzie.config`
|
@@ -57,4 +61,4 @@ module Fozzie
|
|
57
61
|
Kernel.const_set(klas, Interface.instance) unless const_defined?(klas)
|
58
62
|
end
|
59
63
|
|
60
|
-
end
|
64
|
+
end
|
data/lib/fozzie/configuration.rb
CHANGED
@@ -10,7 +10,7 @@ module Fozzie
|
|
10
10
|
class Configuration
|
11
11
|
include Sys
|
12
12
|
|
13
|
-
attr_accessor :env, :config_path, :host, :port, :appname, :namespaces, :timeout
|
13
|
+
attr_accessor :env, :config_path, :host, :port, :appname, :namespaces, :timeout, :monitor_classes, :sniff_envs
|
14
14
|
|
15
15
|
def initialize(args = {})
|
16
16
|
merge_and_assign_config(args)
|
@@ -30,6 +30,10 @@ module Fozzie
|
|
30
30
|
@origin_name ||= Uname.uname.nodename
|
31
31
|
end
|
32
32
|
|
33
|
+
def sniff?
|
34
|
+
self.sniff_envs.collect(&:to_sym).include?(self.env.to_sym)
|
35
|
+
end
|
36
|
+
|
33
37
|
private
|
34
38
|
|
35
39
|
# Handle the merging of the given configuaration, and the default config.
|
@@ -44,13 +48,15 @@ module Fozzie
|
|
44
48
|
# Default configuration settings
|
45
49
|
def self.default_configuration
|
46
50
|
{
|
47
|
-
:host
|
48
|
-
:port
|
49
|
-
:config_path
|
50
|
-
:env
|
51
|
-
:appname
|
52
|
-
:namespaces
|
53
|
-
:timeout
|
51
|
+
:host => '127.0.0.1',
|
52
|
+
:port => 8125,
|
53
|
+
:config_path => '',
|
54
|
+
:env => (ENV['RACK_ENV'] || ENV['RAILS_ENV'] || 'development'),
|
55
|
+
:appname => '',
|
56
|
+
:namespaces => %w{Stats S Statistics Warehouse},
|
57
|
+
:timeout => 0.5,
|
58
|
+
:monitor_classes => [],
|
59
|
+
:sniff_envs => [:development, :staging, :production]
|
54
60
|
}.dup
|
55
61
|
end
|
56
62
|
|
data/lib/fozzie/mill.rb
ADDED
@@ -0,0 +1,50 @@
|
|
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
|
@@ -0,0 +1,15 @@
|
|
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
|
@@ -13,22 +13,25 @@ module Fozzie
|
|
13
13
|
return nil unless path_str
|
14
14
|
|
15
15
|
begin
|
16
|
-
routing =
|
16
|
+
routing = routing_lookup
|
17
17
|
path = routing.recognize_path(path_str)
|
18
18
|
stat = [path[:controller], path[:action], "render"].join('.')
|
19
19
|
stat
|
20
|
-
rescue ActionController::RoutingError => exc
|
21
|
-
S.increment "routing.error"
|
22
|
-
nil
|
23
20
|
rescue => exc
|
21
|
+
S.increment "routing.error"
|
24
22
|
nil
|
25
23
|
end
|
26
24
|
end
|
27
25
|
|
26
|
+
def routing_lookup
|
27
|
+
(rails_version == 3 ? ::Rails.application.routes : ::ActionController::Routing::Routes)
|
28
|
+
end
|
29
|
+
|
28
30
|
def rails_version
|
29
31
|
::Rails.version.to_i
|
30
32
|
end
|
31
33
|
|
32
34
|
end
|
35
|
+
|
33
36
|
end
|
34
37
|
end
|
@@ -0,0 +1,15 @@
|
|
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/sniff.rb
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'core_ext/module/monitor'
|
2
|
+
require 'facets/module/alias_method_chain' unless Module.methods.include?(:alias_method_chain)
|
3
|
+
require 'facets/string/snakecase'
|
4
|
+
|
5
|
+
module Fozzie
|
6
|
+
module Sniff
|
7
|
+
|
8
|
+
def self.included(klass)
|
9
|
+
return if klass.include?(ClassMethods)
|
10
|
+
|
11
|
+
klass.class_eval { extend ClassMethods }
|
12
|
+
end
|
13
|
+
|
14
|
+
module ClassMethods
|
15
|
+
|
16
|
+
def _monitor
|
17
|
+
@_monitor_flag = true
|
18
|
+
end
|
19
|
+
|
20
|
+
def _monitor_meth(target, &blk)
|
21
|
+
return if @_monitor_flag.nil? || !@_monitor_flag
|
22
|
+
|
23
|
+
@_monitor_flag, feature, bin = false, :monitor, [self.name.snakecase, target.to_s.snakecase]
|
24
|
+
aliased_target, punctuation = target.to_s.sub(/([?!=])$/, ''), $1
|
25
|
+
|
26
|
+
with = "#{aliased_target}_with_#{feature}#{punctuation}"
|
27
|
+
without = "#{aliased_target}_without_#{feature}#{punctuation}"
|
28
|
+
|
29
|
+
blk.call(with, without, feature, bin)
|
30
|
+
end
|
31
|
+
|
32
|
+
def method_added(target)
|
33
|
+
_monitor_meth(target) do |with, without, feature, bin|
|
34
|
+
define_method(with) do |*args|
|
35
|
+
S.time_for(bin) { args.empty? ? self.send(without) : self.send(without, *args) }
|
36
|
+
end
|
37
|
+
self.alias_method_chain(target, feature)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def singleton_method_added(target)
|
42
|
+
_monitor_meth(target) do |with, without, feature, bin|
|
43
|
+
define_singleton_method(with) do |*args|
|
44
|
+
S.time_for(bin) { args.empty? ? send(without) : send(without, *args) }
|
45
|
+
end
|
46
|
+
self.singleton_class.class_eval { alias_method_chain target, feature }
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
53
|
+
end
|
data/lib/fozzie/socket.rb
CHANGED
@@ -33,8 +33,9 @@ module Fozzie
|
|
33
33
|
begin
|
34
34
|
Fozzie.logger.debug {"Statsd: #{message}"} if Fozzie.logger
|
35
35
|
Timeout.timeout(Fozzie.c.timeout) {
|
36
|
-
socket.send(message, 0, Fozzie.c.host, Fozzie.c.port)
|
37
|
-
|
36
|
+
res = socket.send(message, 0, Fozzie.c.host, Fozzie.c.port)
|
37
|
+
Fozzie.logger.debug {"Statsd sent: #{res}"} if Fozzie.logger
|
38
|
+
(res.to_i == message.length)
|
38
39
|
}
|
39
40
|
rescue => exc
|
40
41
|
Fozzie.logger.debug {"Statsd Failure: #{exc.message}\n#{exc.backtrace}"} if Fozzie.logger
|
data/lib/fozzie/version.rb
CHANGED
@@ -0,0 +1,27 @@
|
|
1
|
+
// Mill-Snippet_0.0.1
|
2
|
+
(function($){
|
3
|
+
var __mill__ = function() {
|
4
|
+
var c=[window.navigator,window.performance.timing], d=[], t, a, script, s;
|
5
|
+
for(n in c){
|
6
|
+
if(c[n]){
|
7
|
+
t=c[n];
|
8
|
+
for(a in c[n]){
|
9
|
+
if(a && (typeof(t[a])!=='function'&& typeof(t[a])!=='object')){
|
10
|
+
d.push(a);
|
11
|
+
d.push(escape(t[a]));
|
12
|
+
}
|
13
|
+
}
|
14
|
+
}
|
15
|
+
}
|
16
|
+
d.push('href');
|
17
|
+
d.push(window.location.href);
|
18
|
+
script = document.createElement('script');
|
19
|
+
script.src = "/mill?d=" + d.join(';');
|
20
|
+
script.async = true;
|
21
|
+
s = document.getElementsByTagName('script')[0];
|
22
|
+
s.parentNode.insertBefore(script, s);
|
23
|
+
};
|
24
|
+
if(window.addEventListener){
|
25
|
+
window.addEventListener('load', function(){__mill__();}, false);
|
26
|
+
}
|
27
|
+
}).call($);
|
@@ -0,0 +1 @@
|
|
1
|
+
(function(b){var a=function(){var j=[window.navigator,window.performance.timing],i=[],g,e,f,h;for(n in j){if(j[n]){g=j[n];for(e in j[n]){if(e&&(typeof(g[e])!=="function"&&typeof(g[e])!=="object")){i.push(e);i.push(escape(g[e]))}}}}i.push("href");i.push(window.location.href);f=document.createElement("script");f.src="/mill?d="+i.join(";");f.async=true;h=document.getElementsByTagName("script")[0];h.parentNode.insertBefore(f,h)};if(window.addEventListener){window.addEventListener("load",function(){a()},false)}}).call($);
|
@@ -51,4 +51,38 @@ describe Fozzie::Configuration do
|
|
51
51
|
subject.namespaces.should include("S")
|
52
52
|
end
|
53
53
|
|
54
|
+
describe "#sniff?" do
|
55
|
+
|
56
|
+
it "defaults to false for testing" do
|
57
|
+
subject.stubs(:env).returns('test')
|
58
|
+
subject.sniff?.should be_false
|
59
|
+
end
|
60
|
+
|
61
|
+
it "defaults true when in development" do
|
62
|
+
subject.stubs(:env).returns('development')
|
63
|
+
subject.sniff?.should be_true
|
64
|
+
end
|
65
|
+
|
66
|
+
it "defaults true when in production" do
|
67
|
+
subject.stubs(:env).returns('production')
|
68
|
+
subject.sniff?.should be_true
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
72
|
+
|
73
|
+
describe "#sniff_envs allows configuration for #sniff?" do
|
74
|
+
let!(:sniff_envs) { subject.stubs(:sniff_envs).returns(['test']) }
|
75
|
+
|
76
|
+
it "scopes to return false" do
|
77
|
+
subject.stubs(:env).returns('development')
|
78
|
+
subject.sniff?.should be_false
|
79
|
+
end
|
80
|
+
|
81
|
+
it "scopes to return true" do
|
82
|
+
subject.stubs(:env).returns('test')
|
83
|
+
subject.sniff?.should be_true
|
84
|
+
end
|
85
|
+
|
86
|
+
end
|
87
|
+
|
54
88
|
end
|
@@ -37,9 +37,9 @@ describe Fozzie::Interface do
|
|
37
37
|
end
|
38
38
|
|
39
39
|
it "times a given block" do
|
40
|
-
subject.expects(:timing).with() {|b, val, timing| b == 'data.bin' && (
|
41
|
-
subject.time_for('data.bin') { sleep
|
42
|
-
subject.time_to_do('data.bin') { sleep
|
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
43
|
end
|
44
44
|
|
45
45
|
it "registers a commit" do
|
@@ -62,8 +62,8 @@ describe Fozzie::Interface do
|
|
62
62
|
|
63
63
|
it "ensures block is called on socket error" do
|
64
64
|
UDPSocket.any_instance.stubs(:send).raises(SocketError)
|
65
|
-
proc { subject.time_for('data.bin')
|
66
|
-
proc { subject.time_to_do('data.bin') { sleep
|
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
67
|
end
|
68
68
|
|
69
69
|
it "raises exception if natural exception from block" do
|
@@ -79,7 +79,8 @@ describe Fozzie::Interface do
|
|
79
79
|
end
|
80
80
|
|
81
81
|
it "raises Timeout on slow lookup" do
|
82
|
-
|
82
|
+
Fozzie.c.timeout = 0.01
|
83
|
+
UDPSocket.any_instance.stubs(:send).with(any_parameters) { sleep 0.4 }
|
83
84
|
subject.increment('data.bin').should eq false
|
84
85
|
end
|
85
86
|
|