trashed 2.0.5

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: abfbb3ba8576bac0d578d9821479635dda52e57b
4
+ data.tar.gz: b5439fd5e664b3f439860b6fd6dd548248d1594c
5
+ SHA512:
6
+ metadata.gz: 7748860b9937a18abcffb575cb51a2cfb0ed352b9d1ffb824dceafa67a47c22afbfd4bfd1d4e89974f20e5137996cd4ae65cc7285bc3e9c7eef117fb92a8cbf9
7
+ data.tar.gz: 6af120ce83a1048254fc0df2d41f1cef0c32bfd99c9ea81eb5bd1ef063562c447f32bf28e137e23d92f8e712f11536bc4f85b5d49c7d7f9451c86edd2e306349
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 37signals, LLC
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,34 @@
1
+ ## Trashed
2
+ # Keep an eye on resource usage.
3
+
4
+
5
+ - Logs per-request object counts, heap growth, and GC time.
6
+ - Sends periodic resource usage snapshots to StatsD & NewRelic.
7
+ - Requires Ruby 1.9 or REE.
8
+
9
+
10
+ ## Setup
11
+
12
+ ### Rails 3
13
+
14
+ On Rails 3, add this to the top of `config/application.rb`:
15
+
16
+ require 'trashed/railtie'
17
+
18
+ And in the body of your app config:
19
+
20
+ module YourApp
21
+ class Application < Rails::Application
22
+ config.trashed[:statsd] = YourApp.statsd
23
+
24
+
25
+ ### Rails 2
26
+
27
+ On Rails 2, add the middleware to `config/environment.rb`:
28
+
29
+ Rails::Initializer.run do |config|
30
+ config.middleware.use Trashed::Rack::MeasureResourceUsage, :statsd => YourApp.statsd
31
+
32
+ And set up the sampler in `config/initializers/trashed.rb`:
33
+
34
+ Trashed::Newrelic.sample Trashed::ResourceUsage, :statsd => YourApp.statsd
data/Rakefile ADDED
@@ -0,0 +1,22 @@
1
+ require 'rake/testtask'
2
+ require 'rdoc/task'
3
+
4
+ desc 'Default: run unit tests'
5
+ task :default => :test
6
+
7
+ desc 'Run unit tests'
8
+ Rake::TestTask.new :test do |t|
9
+ t.libs << 'test/lib'
10
+ t.pattern = 'test/**/*_test.rb'
11
+ t.verbose = true
12
+ end
13
+
14
+ desc 'Generate RDoc documentation'
15
+ Rake::RDocTask.new :rdoc do |rdoc|
16
+ rdoc.rdoc_dir = 'rdoc'
17
+ rdoc.title = 'Trashed'
18
+ rdoc.options << '--line-numbers' << '--inline-source'
19
+ rdoc.rdoc_files.include('MIT-LICENSE')
20
+ rdoc.rdoc_files.include('README')
21
+ rdoc.rdoc_files.include('lib/**/*.rb')
22
+ end
data/init.rb ADDED
@@ -0,0 +1 @@
1
+ require 'trashed'
data/lib/trashed.rb ADDED
@@ -0,0 +1,5 @@
1
+ module Trashed
2
+ require 'trashed/meter'
3
+ require 'trashed/resource_usage'
4
+ require 'trashed/rack'
5
+ end
@@ -0,0 +1,40 @@
1
+ module Trashed
2
+ class Meter
3
+ attr_reader :counters, :gauges
4
+
5
+ def initialize(&block)
6
+ @counters, @gauges = {}, {}
7
+ instance_eval(&block) if block_given?
8
+ end
9
+
10
+ def counts(name, &block) @counters[name] = block end
11
+ def count; read @counters end
12
+
13
+ def gauges(name, &block) @gauges[name] = block end
14
+ def gauge; read @gauges end
15
+
16
+ def instrument
17
+ before = count
18
+ yield
19
+ delta before, count
20
+ end
21
+
22
+ private
23
+
24
+ def delta(before, after)
25
+ delta = {}
26
+ after.each { |k, v| delta[k] = v - before[k] }
27
+ delta
28
+ end
29
+
30
+ def read(measures)
31
+ data = {}
32
+ measures.each do |name, measure|
33
+ measure.call.each do |key, value|
34
+ data["#{name}.#{key}"] = value
35
+ end
36
+ end
37
+ data
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,47 @@
1
+ module Trashed
2
+ module NewRelic
3
+ def self.sample(meter, options = {})
4
+ ::NewRelic::Agent.instance.stats_engine.add_sampler Sampler.new(meter, options)
5
+ end
6
+
7
+ class Sampler
8
+ attr_accessor :stats_engine
9
+
10
+ def initialize(meter, options = {})
11
+ @meter = meter
12
+ @label = options[:label] || 'Custom/%s'
13
+ @statsd = options[:statsd]
14
+ end
15
+
16
+ def poll
17
+ record @meter.count
18
+ record @meter.gauge
19
+ end
20
+
21
+ def record(data)
22
+ data.each do |name, value|
23
+ record_newrelic name, value
24
+ record_statsd name, value if @statsd
25
+ end
26
+ end
27
+
28
+ private
29
+
30
+ def record_statsd(name, value)
31
+ @statsd.timing name, value
32
+ end
33
+
34
+ def record_newrelic(name, value)
35
+ stats_for(label_for(name)).record_data_point(value)
36
+ end
37
+
38
+ def stats_for(metric)
39
+ stats_engine.get_stats(metric, false)
40
+ end
41
+
42
+ def label_for(name)
43
+ @label % name.gsub('.', '/')
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,66 @@
1
+ module Trashed
2
+ module Rack
3
+ class MeasureResourceUsage
4
+ def initialize(app, options = {})
5
+ @app = app
6
+ @debug, @logger, @statsd, @sample_rate = options.values_at(:debug, :logger, :statsd, :sample_rate)
7
+ @sample_rate ||= 0.1
8
+
9
+ @request_namespaces, @sampler_namespaces = options.values_at(:statsd_request_namespaces, :statsd_sampler_namespaces)
10
+ end
11
+
12
+ def call(env)
13
+ response = nil
14
+ instrument(env) { response = @app.call(env) }
15
+ response
16
+ end
17
+
18
+ def instrument(env, &block)
19
+ change = ResourceUsage.instrument(&block)
20
+ usage = ResourceUsage.gauge
21
+ record env, change, usage
22
+ end
23
+
24
+ def record(env, change, usage)
25
+ record_env env, change, usage
26
+ record_logger env, change, usage if @logger
27
+ record_statsd env, change, usage if @statsd
28
+ end
29
+
30
+ def record_env(env, change, usage)
31
+ env['trashed.change'] = change
32
+ env['trashed.usage'] = usage
33
+ end
34
+
35
+ def record_logger(env, change, usage)
36
+ @logger.info "Rack handled in %dms (GC runs: %d)" % change.values_at('Time.wall', 'GC.count')
37
+ record_debug_logger env, change, usage if @debug
38
+ end
39
+
40
+ def record_debug_logger(env, change, usage)
41
+ @logger.debug "Changes: #{change.to_yaml}"
42
+ @logger.debug "Usage: #{usage.to_yaml}"
43
+ end
44
+
45
+ def record_statsd(env, change, usage)
46
+ record_statsd_timing change, :'Rack.Request.All'
47
+ record_statsd_timing usage, :'Rack.Server.All'
48
+
49
+ Array(@request_namespaces.call(env)).each do |namespace|
50
+ record_statsd_timing change, "Rack.Request.#{namespace}"
51
+ end if @request_namespaces
52
+
53
+ Array(@sampler_namespaces.call(env)).each do |namespace|
54
+ record_statsd_timing usage, "Rack.Server.#{namespace}"
55
+ end if @sampler_namespaces
56
+ end
57
+
58
+ def record_statsd_timing(data, namespace = nil)
59
+ data.each do |name, value|
60
+ name = "#{namespace}.#{name}" if namespace
61
+ @statsd.timing name, value, @sample_rate
62
+ end
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,61 @@
1
+ require 'trashed'
2
+ require 'rails/railtie'
3
+ require 'active_support/ordered_options'
4
+
5
+ module Trashed
6
+ class Railtie < ::Rails::Railtie
7
+ config.trashed = ActiveSupport::OrderedOptions.new
8
+ config.trashed.statsd = ActiveSupport::OrderedOptions.new
9
+
10
+ initializer 'trashed' do |app|
11
+ # Debug data sent to statsd. Class-level config only :/
12
+ Statsd.logger = app.config.trashed.logger if app.config.trashed.debug
13
+
14
+ app.config.trashed.sample_rate ||= 0.1
15
+ app.config.trashed.logger = Rails.logger
16
+ app.config.trashed.statsd = connect_to_statsd(app.config.trashed.statsd)
17
+
18
+ app.config.trashed.statsd_request_namespaces = lambda do |env|
19
+ # Rails 3.2. Record request controller, action, and format.
20
+ if controller = env['action_controller.instance']
21
+ name = controller.controller_name
22
+ action = controller.action_name
23
+ format = controller.request.format.try(:to_sym)
24
+ [ "Controllers.#{name}",
25
+ "Formats.#{format}",
26
+ "Actions.#{name}.#{action}.#{format}" ]
27
+ end
28
+ end
29
+
30
+ hostname = `hostname -s`.chomp
31
+ app.config.trashed.statsd_sampler_namespaces = lambda do |env|
32
+ # Rails 3.2. Record hostname.
33
+ [ "Hosts.#{hostname}" ]
34
+ end
35
+ end
36
+
37
+ initializer 'trashed.middleware', :after => 'trashed', :before => 'trashed.newrelic' do |app|
38
+ app.middleware.insert_after 'Rack::Runtime', Trashed::Rack::MeasureResourceUsage, app.config.trashed
39
+ end
40
+
41
+ initializer 'trashed.newrelic', :after => 'newrelic_rpm.start_plugin' do |app|
42
+ if defined?(NewRelic::Control) && NewRelic::Control.instance.agent_enabled?
43
+ require 'trashed/new_relic'
44
+ Trashed::NewRelic.sample ResourceUsage, app.config.trashed
45
+ end
46
+ end
47
+
48
+ def connect_to_statsd(options)
49
+ require 'statsd'
50
+
51
+ case options
52
+ when Statsd
53
+ options
54
+ when Hash
55
+ Statsd.new(options[:host], options[:port]).tap do |statsd|
56
+ statsd.namespace = options[:namespace]
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,48 @@
1
+ module Trashed
2
+ ResourceUsage = Meter.new do
3
+
4
+ # Wall clock time, in milliseconds since epoch
5
+ counts :Time do
6
+ { :wall => (Time.now.to_f * 1000).to_i }
7
+ end
8
+
9
+ # RailsBench GC patch / REE 1.8
10
+ if GC.respond_to? :enable_stats
11
+ GC.enable_stats
12
+
13
+ counts :Objects do
14
+ { :total => ObjectSpace.allocated_objects }
15
+ end
16
+
17
+ gauges :Objects do
18
+ { :live => ObjectSpace.live_objects }
19
+ end
20
+
21
+ counts :GC do
22
+ { :count => GC.collections, :elapsed => GC.time, :memory => GC.allocated_size }
23
+ end
24
+
25
+ gauges :GC do
26
+ { :growth => GC.growth }
27
+ end
28
+
29
+ # Ruby 1.9+
30
+ elsif ObjectSpace.respond_to? :count_objects
31
+ counts :Objects do
32
+ { :total => ObjectSpace.count_objects[:TOTAL] }
33
+ end
34
+
35
+ gauges :Objects do
36
+ ObjectSpace.count_objects
37
+ end
38
+
39
+ counts :GC do
40
+ { :count => GC.stat[:count] }
41
+ end
42
+
43
+ gauges :GC do
44
+ GC.stat
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,3 @@
1
+ require 'trashed'
2
+ require 'minitest/unit'
3
+ MiniTest::Unit.autorun
@@ -0,0 +1,15 @@
1
+ require 'trashed/test_helper'
2
+
3
+ class MeterTest < MiniTest::Unit::TestCase
4
+ def test_count
5
+ time = Trashed::ResourceUsage.count['Time.wall']
6
+ refute_nil time
7
+ assert_in_delta time, (Time.now.to_f * 1000), 1000
8
+ end
9
+
10
+ def test_instrument
11
+ elapsed = Trashed::ResourceUsage.instrument { nil }['Time.wall']
12
+ refute_nil elapsed
13
+ assert_in_delta elapsed, 0, 1000
14
+ end
15
+ end
data/test/rack_test.rb ADDED
@@ -0,0 +1,18 @@
1
+ require 'trashed/test_helper'
2
+
3
+ class RackTest < MiniTest::Unit::TestCase
4
+ Hello = lambda { |env| [200, {}, %w(hello)] }
5
+
6
+ def test_instruments_app_and_stores_in_env
7
+ env = {}
8
+
9
+ response = Trashed::Rack::MeasureResourceUsage.new(Hello).call(env)
10
+
11
+ refute_nil env['trashed.change']
12
+ refute_nil env['trashed.usage']
13
+
14
+ elapsed = env['trashed.change']['Time.wall']
15
+ refute_nil elapsed
16
+ assert_in_delta elapsed, 0, 1000
17
+ end
18
+ end
data/trashed.gemspec ADDED
@@ -0,0 +1,12 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = 'trashed'
3
+ s.version = '2.0.5'
4
+ s.author = 'Jeremy Kemper'
5
+ s.email = 'jeremy@bitsweat.net'
6
+ s.homepage = 'https://github.com/37signals/trashed'
7
+ s.summary = 'Keep tabs on Ruby garbage collection: object counts, allocated bytes, GC time.'
8
+
9
+ s.add_dependency 'statsd-ruby', '>= 0.4'
10
+
11
+ s.files = Dir["#{File.dirname(__FILE__)}/**/*"]
12
+ end
metadata ADDED
@@ -0,0 +1,71 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: trashed
3
+ version: !ruby/object:Gem::Version
4
+ version: 2.0.5
5
+ platform: ruby
6
+ authors:
7
+ - Jeremy Kemper
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2014-03-30 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: statsd-ruby
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ! '>='
18
+ - !ruby/object:Gem::Version
19
+ version: '0.4'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ! '>='
25
+ - !ruby/object:Gem::Version
26
+ version: '0.4'
27
+ description:
28
+ email: jeremy@bitsweat.net
29
+ executables: []
30
+ extensions: []
31
+ extra_rdoc_files: []
32
+ files:
33
+ - ./MIT-LICENSE
34
+ - ./README.md
35
+ - ./Rakefile
36
+ - ./init.rb
37
+ - ./lib/trashed.rb
38
+ - ./lib/trashed/meter.rb
39
+ - ./lib/trashed/new_relic.rb
40
+ - ./lib/trashed/rack.rb
41
+ - ./lib/trashed/railtie.rb
42
+ - ./lib/trashed/resource_usage.rb
43
+ - ./test/lib/trashed/test_helper.rb
44
+ - ./test/meter_test.rb
45
+ - ./test/rack_test.rb
46
+ - ./trashed.gemspec
47
+ homepage: https://github.com/37signals/trashed
48
+ licenses: []
49
+ metadata: {}
50
+ post_install_message:
51
+ rdoc_options: []
52
+ require_paths:
53
+ - lib
54
+ required_ruby_version: !ruby/object:Gem::Requirement
55
+ requirements:
56
+ - - ! '>='
57
+ - !ruby/object:Gem::Version
58
+ version: '0'
59
+ required_rubygems_version: !ruby/object:Gem::Requirement
60
+ requirements:
61
+ - - ! '>='
62
+ - !ruby/object:Gem::Version
63
+ version: '0'
64
+ requirements: []
65
+ rubyforge_project:
66
+ rubygems_version: 2.2.2
67
+ signing_key:
68
+ specification_version: 4
69
+ summary: ! 'Keep tabs on Ruby garbage collection: object counts, allocated bytes,
70
+ GC time.'
71
+ test_files: []