trashed 2.0.5 → 3.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/trashed/instruments/object_space_counter.rb +11 -0
- data/lib/trashed/instruments/ree_gc.rb +28 -0
- data/lib/trashed/instruments/ruby19_gc.rb +16 -0
- data/lib/trashed/instruments/ruby20_gc.rb +24 -0
- data/lib/trashed/instruments/ruby21_gc.rb +28 -0
- data/lib/trashed/instruments/ruby_gc_profiler.rb +27 -0
- data/lib/trashed/instruments/stopwatch.rb +44 -0
- data/lib/trashed/meter.rb +42 -24
- data/lib/trashed/rack.rb +27 -54
- data/lib/trashed/railtie.rb +7 -50
- data/lib/trashed/reporter.rb +48 -0
- data/lib/trashed/resource_usage.rb +34 -36
- data/lib/trashed.rb +2 -5
- metadata +43 -16
- data/MIT-LICENSE +0 -20
- data/README.md +0 -34
- data/Rakefile +0 -22
- data/lib/trashed/new_relic.rb +0 -47
- data/test/lib/trashed/test_helper.rb +0 -3
- data/test/meter_test.rb +0 -15
- data/test/rack_test.rb +0 -18
- data/trashed.gemspec +0 -12
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
!binary "U0hBMQ==":
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8a76c1137b987b5c2e00ce832d90a32ed952d72b
|
4
|
+
data.tar.gz: 0530e17d53650ef1da7787f8f658b2eb93ecbaf0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1e39ad89bdd197f0fffaf9367778d32c48fe2bfa55e70fc11c648837979eadccc94014d5bc0a237ed97b68bc7901460bad8d166caf915a84880638d47b28e1a3
|
7
|
+
data.tar.gz: b1d891fe71584f900ba80adcd3d0a4a73472b1b3a46173341a10c678fa546eb21c314ed4581c8574000ffb621cfff5c096181f5594a12d9ac9436b4799eb5ed1
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Trashed
|
2
|
+
module Instruments
|
3
|
+
class Ruby18GC
|
4
|
+
def initialize
|
5
|
+
GC.enable_stats
|
6
|
+
end
|
7
|
+
|
8
|
+
def start(state)
|
9
|
+
state.update \
|
10
|
+
:'Objects.total' => ObjectSpace.allocated_objects,
|
11
|
+
:'GC.count' => GC.collections,
|
12
|
+
:'GC.elapsed' => GC.time,
|
13
|
+
:'GC.memory' => GC.allocated_size
|
14
|
+
end
|
15
|
+
|
16
|
+
def measure(state, timings, gauges)
|
17
|
+
timings.update \
|
18
|
+
:'Objects.total' => ObjectSpace.allocated_objects - state[:'Objects.total'],
|
19
|
+
:'GC.count' => GC.collections - state[:'GC.count'],
|
20
|
+
:'GC.elapsed' => GC.time - state[:'GC.elapsed'],
|
21
|
+
:'GC.memory' => GC.allocated_size - state[:'GC.memory']
|
22
|
+
|
23
|
+
gauges << [ :'Objects.live', ObjectSpace.live_objects ]
|
24
|
+
gauges << [ :'GC.growth', GC.growth ]
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Trashed
|
2
|
+
module Instruments
|
3
|
+
class Ruby19GC
|
4
|
+
def start(state)
|
5
|
+
gc = GC.stat
|
6
|
+
state[:'GC.count'] = gc[:count]
|
7
|
+
end
|
8
|
+
|
9
|
+
def measure(state, timings, gauges)
|
10
|
+
gc = GC.stat
|
11
|
+
timings[:'GC.count'] = gc[:count] - state.delete(:'GC.count')
|
12
|
+
gauges.concat gc.map { |k, v| [ :"GC.#{k}", v ] }
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Trashed
|
2
|
+
module Instruments
|
3
|
+
class Ruby20GC
|
4
|
+
def start(state)
|
5
|
+
gc = GC.stat
|
6
|
+
state.update \
|
7
|
+
:'GC.count' => gc[:count],
|
8
|
+
:'GC.allocated_objects' => gc[:total_allocated_object],
|
9
|
+
:'GC.freed_objects' => gc[:total_freed_object]
|
10
|
+
end
|
11
|
+
|
12
|
+
def measure(state, timings, gauges)
|
13
|
+
gc = GC.stat
|
14
|
+
|
15
|
+
timings.update \
|
16
|
+
:'GC.count' => gc[:count] - state.delete(:'GC.count'),
|
17
|
+
:'GC.allocated_objects' => gc[:total_allocated_object] - state.delete(:'GC.allocated_objects'),
|
18
|
+
:'GC.freed_objects' => gc[:total_freed_object] - state.delete(:'GC.freed_objects')
|
19
|
+
|
20
|
+
gauges.concat gc.map { |k, v| [ :"GC.#{k}", v ] }
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Trashed
|
2
|
+
module Instruments
|
3
|
+
class Ruby21GC
|
4
|
+
def start(state)
|
5
|
+
gc = GC.stat
|
6
|
+
state.update \
|
7
|
+
:'GC.count' => gc[:count],
|
8
|
+
:'GC.major_count' => gc[:major_gc_count],
|
9
|
+
:'GC.minor_count' => gc[:minor_gc_count],
|
10
|
+
:'GC.allocated_objects' => gc[:total_allocated_object],
|
11
|
+
:'GC.freed_objects' => gc[:total_freed_object]
|
12
|
+
end
|
13
|
+
|
14
|
+
def measure(state, timings, gauges)
|
15
|
+
gc = GC.stat
|
16
|
+
|
17
|
+
timings.update \
|
18
|
+
:'GC.count' => gc[:count] - state.delete(:'GC.count'),
|
19
|
+
:'GC.major_count' => gc[:major_gc_count] - state.delete(:'GC.major_count'),
|
20
|
+
:'GC.minor_count' => gc[:minor_gc_count] - state.delete(:'GC.minor_count'),
|
21
|
+
:'GC.allocated_objects' => gc[:total_allocated_object] - state.delete(:'GC.allocated_objects'),
|
22
|
+
:'GC.freed_objects' => gc[:total_freed_object] - state.delete(:'GC.freed_objects')
|
23
|
+
|
24
|
+
gauges.concat gc.map { |k, v| [ :"GC.#{k}", v ] }
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Trashed
|
2
|
+
module Instruments
|
3
|
+
class RubyGCProfiler
|
4
|
+
def initialize
|
5
|
+
@has_raw_data = GC::Profiler.respond_to?(:raw_data)
|
6
|
+
end
|
7
|
+
|
8
|
+
def start(state)
|
9
|
+
GC::Profiler.enable
|
10
|
+
GC::Profiler.clear
|
11
|
+
end
|
12
|
+
|
13
|
+
def measure(state, timings, gauges)
|
14
|
+
timings[:'GC.time'] = GC::Profiler.total_time
|
15
|
+
|
16
|
+
if @has_raw_data
|
17
|
+
GC::Profiler.raw_data.each do |data|
|
18
|
+
gauges.concat data.map { |k, v| [ :"GC.Profiler.#{k}", v ] }
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
GC::Profiler.disable
|
23
|
+
GC::Profiler.clear
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module Trashed
|
2
|
+
module Instruments
|
3
|
+
class Stopwatch
|
4
|
+
def initialize(timepiece = Timepiece)
|
5
|
+
@timepiece = timepiece
|
6
|
+
@has_cpu_time = timepiece.respond_to?(:cpu)
|
7
|
+
end
|
8
|
+
|
9
|
+
def start(state)
|
10
|
+
state[:'Time.wall'] = @timepiece.wall
|
11
|
+
state[:'Time.cpu'] = @timepiece.cpu if @has_cpu_time
|
12
|
+
end
|
13
|
+
|
14
|
+
def measure(state, timings, gauges)
|
15
|
+
wall_elapsed = @timepiece.wall - state.delete(:'Time.wall')
|
16
|
+
timings[:'Time.wall'] = wall_elapsed
|
17
|
+
if @has_cpu_time
|
18
|
+
cpu_elapsed = @timepiece.cpu - state.delete(:'Time.cpu')
|
19
|
+
timings[:'Time.cpu'] = cpu_elapsed
|
20
|
+
timings[:'Time.idle'] = wall_elapsed - cpu_elapsed
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
module Timepiece
|
26
|
+
def self.wall
|
27
|
+
(::Time.now.to_f * 1000).to_i
|
28
|
+
end
|
29
|
+
|
30
|
+
# Ruby 2.1+
|
31
|
+
if Process.respond_to?(:clock_gettime)
|
32
|
+
def self.cpu
|
33
|
+
Process.clock_gettime Process::CLOCK_PROCESS_CPUTIME_ID, :millisecond
|
34
|
+
end
|
35
|
+
|
36
|
+
# ruby-prof installed
|
37
|
+
elsif defined? RubyProf::Measure::ProcessTime
|
38
|
+
def self.cpu
|
39
|
+
(RubyProf::Measure::Process.measure * 1000).to_i
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
data/lib/trashed/meter.rb
CHANGED
@@ -1,40 +1,58 @@
|
|
1
1
|
module Trashed
|
2
2
|
class Meter
|
3
|
-
attr_reader :
|
3
|
+
attr_reader :instruments
|
4
4
|
|
5
|
-
def initialize
|
6
|
-
@
|
7
|
-
|
5
|
+
def initialize
|
6
|
+
@instruments = []
|
7
|
+
@needs_start = []
|
8
8
|
end
|
9
9
|
|
10
|
-
|
11
|
-
|
10
|
+
# Counters increase, so we measure before/after differences.
|
11
|
+
# Time elapsed, memory growth, objects allocated, etc.
|
12
|
+
def counts(name, &block)
|
13
|
+
instrument ChangeInstrument.new(name, block)
|
14
|
+
end
|
15
|
+
|
16
|
+
# Gauges measure point-in-time values.
|
17
|
+
# Heap size, live objects, GC count, etc.
|
18
|
+
def gauges(name, &block)
|
19
|
+
instrument GaugeInstrument.new(name, block)
|
20
|
+
end
|
12
21
|
|
13
|
-
def
|
14
|
-
|
22
|
+
def instrument(instrument)
|
23
|
+
@instruments << instrument
|
24
|
+
@needs_start << instrument if instrument.respond_to?(:start)
|
25
|
+
end
|
15
26
|
|
16
|
-
def instrument
|
17
|
-
|
18
|
-
yield
|
19
|
-
|
27
|
+
def instrument!(state, timings, gauges)
|
28
|
+
@needs_start.each { |i| i.start state }
|
29
|
+
yield.tap do
|
30
|
+
@instruments.reverse_each { |i| i.measure state, timings, gauges }
|
31
|
+
end
|
20
32
|
end
|
21
33
|
|
22
|
-
|
34
|
+
class ChangeInstrument
|
35
|
+
def initialize(name, probe)
|
36
|
+
@name, @probe = name, probe
|
37
|
+
end
|
23
38
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
39
|
+
def start(state)
|
40
|
+
state[@name] = @probe.call
|
41
|
+
end
|
42
|
+
|
43
|
+
def measure(state, timings, gauges)
|
44
|
+
timings[@name] = @probe.call - state[@name]
|
45
|
+
end
|
28
46
|
end
|
29
47
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
48
|
+
class GaugeInstrument
|
49
|
+
def initialize(name, probe)
|
50
|
+
@name, @probe = name, probe
|
51
|
+
end
|
52
|
+
|
53
|
+
def measure(state, timings, gauges)
|
54
|
+
gauges << [ @name, @probe.call ]
|
36
55
|
end
|
37
|
-
data
|
38
56
|
end
|
39
57
|
end
|
40
58
|
end
|
data/lib/trashed/rack.rb
CHANGED
@@ -1,64 +1,37 @@
|
|
1
|
-
|
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
|
1
|
+
require 'trashed/resource_usage'
|
29
2
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
end
|
3
|
+
module Trashed
|
4
|
+
class Rack
|
5
|
+
STATE, TIMINGS, GAUGES = 'trashed.state', 'trashed.timings', 'trashed.gauges'
|
34
6
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
7
|
+
def initialize(app, reporter, options = {})
|
8
|
+
@reporter = reporter
|
9
|
+
@meters = Array(options.fetch(:meters, [ResourceUsage]))
|
10
|
+
@logger, @statsd, @sample_rate = options.values_at(:logger, :statsd_instance, :sample_rate)
|
11
|
+
@sample_rate ||= 1.0
|
39
12
|
|
40
|
-
|
41
|
-
|
42
|
-
@logger.debug "Usage: #{usage.to_yaml}"
|
43
|
-
end
|
13
|
+
@request_namespaces = options[:statsd_request_namespaces]
|
14
|
+
@sampler_namespaces = options[:statsd_sampler_namespaces]
|
44
15
|
|
45
|
-
|
46
|
-
|
47
|
-
|
16
|
+
# Wrap the app up in the meters.
|
17
|
+
@app = build_instrumented_app(app, @meters)
|
18
|
+
end
|
48
19
|
|
49
|
-
|
50
|
-
|
51
|
-
|
20
|
+
def call(env)
|
21
|
+
env[STATE] = {}
|
22
|
+
env[TIMINGS] = {}
|
23
|
+
env[GAUGES] = []
|
52
24
|
|
53
|
-
|
54
|
-
|
55
|
-
end if @sampler_namespaces
|
56
|
-
end
|
25
|
+
@app.call(env).tap { @reporter.report env }
|
26
|
+
end
|
57
27
|
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
28
|
+
private
|
29
|
+
def build_instrumented_app(app, meters)
|
30
|
+
meters.inject app do |wrapped, meter|
|
31
|
+
lambda do |env|
|
32
|
+
meter.instrument! env[STATE], env[TIMINGS], env[GAUGES] do
|
33
|
+
wrapped.call env
|
34
|
+
end
|
62
35
|
end
|
63
36
|
end
|
64
37
|
end
|
data/lib/trashed/railtie.rb
CHANGED
@@ -1,61 +1,18 @@
|
|
1
|
-
require 'trashed'
|
2
1
|
require 'rails/railtie'
|
3
|
-
require '
|
2
|
+
require 'trashed/rack'
|
3
|
+
require 'trashed/reporter'
|
4
4
|
|
5
5
|
module Trashed
|
6
6
|
class Railtie < ::Rails::Railtie
|
7
|
-
config.trashed =
|
8
|
-
config.trashed.statsd = ActiveSupport::OrderedOptions.new
|
7
|
+
config.trashed = Trashed::Reporter.new
|
9
8
|
|
10
9
|
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
10
|
require 'statsd'
|
50
11
|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
Statsd.new(options[:host], options[:port]).tap do |statsd|
|
56
|
-
statsd.namespace = options[:namespace]
|
57
|
-
end
|
58
|
-
end
|
12
|
+
app.config.trashed.sample_rate ||= 1.0
|
13
|
+
app.config.trashed.logger ||= Rails.logger
|
14
|
+
|
15
|
+
app.middleware.insert_after 'Rack::Runtime', Trashed::Rack, app.config.trashed
|
59
16
|
end
|
60
17
|
end
|
61
18
|
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'trashed/rack'
|
2
|
+
|
3
|
+
module Trashed
|
4
|
+
class Reporter
|
5
|
+
attr_accessor :logger, :statsd, :sample_rate
|
6
|
+
attr_accessor :timing_dimensions, :gauge_dimensions
|
7
|
+
|
8
|
+
DEFAULT_DIMENSIONS = [ :All ]
|
9
|
+
|
10
|
+
def initialize
|
11
|
+
@logger = nil
|
12
|
+
@statsd = nil
|
13
|
+
@sample_rate = 1.0
|
14
|
+
@timing_dimensions = ->(env) { DEFAULT_DIMENSIONS }
|
15
|
+
@gauge_dimensions = ->(env) { DEFAULT_DIMENSIONS }
|
16
|
+
end
|
17
|
+
|
18
|
+
def report(env)
|
19
|
+
report_logger env if @logger
|
20
|
+
report_statsd env if @statsd
|
21
|
+
end
|
22
|
+
|
23
|
+
def report_logger(env)
|
24
|
+
elapsed = env[Trashed::Rack::TIMINGS].assoc(:'Time.wall')
|
25
|
+
gc_runs = env[Trashed::Rack::TIMINGS].assoc(:'GC.count')
|
26
|
+
if elapsed && gc_runs
|
27
|
+
@logger.info "Rack handled in %dms (GC runs: %d)" % [elapsed[1], gc_runs[1]]
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def report_statsd(env)
|
32
|
+
@statsd.batch do |statsd|
|
33
|
+
send_to_statsd statsd, :timing, env[Trashed::Rack::TIMINGS], :'Rack.Request', @timing_dimensions.call(env)
|
34
|
+
send_to_statsd statsd, :gauge, env[Trashed::Rack::GAUGES], :'Rack.Server', @gauge_dimensions.call(env)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def send_to_statsd(statsd, method, measurements, namespace, dimensions)
|
39
|
+
measurements.each do |metric, value|
|
40
|
+
if value.is_a? Numeric
|
41
|
+
Array(dimensions || :All).each do |dimension|
|
42
|
+
statsd.send method, :"#{namespace}.#{dimension}.#{metric}", value, @sample_rate
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -1,48 +1,46 @@
|
|
1
|
-
|
2
|
-
ResourceUsage = Meter.new do
|
1
|
+
require 'trashed/meter'
|
3
2
|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
3
|
+
module Trashed
|
4
|
+
ResourceUsage = Meter.new.tap do |meter|
|
5
|
+
# Wall clock time in milliseconds since epoch.
|
6
|
+
# Includes CPU and idle time on Ruby 2.1+.
|
7
|
+
require 'trashed/instruments/stopwatch'
|
8
|
+
meter.instrument Trashed::Instruments::Stopwatch.new
|
8
9
|
|
9
10
|
# RailsBench GC patch / REE 1.8
|
10
11
|
if GC.respond_to? :enable_stats
|
11
|
-
|
12
|
-
|
13
|
-
|
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
|
12
|
+
require 'trashed/instruments/ree_gc'
|
13
|
+
meter.instrument Trashed::Instruments::Ruby18GC.new
|
14
|
+
end
|
28
15
|
|
29
16
|
# Ruby 1.9+
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
gauges :Objects do
|
36
|
-
ObjectSpace.count_objects
|
37
|
-
end
|
17
|
+
if ObjectSpace.respond_to? :count_objects
|
18
|
+
require 'trashed/instruments/object_space_counter'
|
19
|
+
meter.instrument Trashed::Instruments::ObjectSpaceCounter.new
|
20
|
+
end
|
38
21
|
|
39
|
-
|
40
|
-
|
22
|
+
# Ruby 1.9+
|
23
|
+
if GC.respond_to?(:stat)
|
24
|
+
case
|
25
|
+
# Ruby 2.1+
|
26
|
+
when GC.stat[:major_gc_count]
|
27
|
+
require 'trashed/instruments/ruby21_gc'
|
28
|
+
meter.instrument Trashed::Instruments::Ruby21GC.new
|
29
|
+
# Ruby 2.0+
|
30
|
+
when GC.stat[:total_allocated_object]
|
31
|
+
require 'trashed/instruments/ruby20_gc'
|
32
|
+
meter.instrument Trashed::Instruments::Ruby20GC.new
|
33
|
+
# Ruby 1.9
|
34
|
+
else
|
35
|
+
require 'trashed/instruments/ruby19_gc'
|
36
|
+
meter.instrument Trashed::Instruments::Ruby19GC.new
|
41
37
|
end
|
38
|
+
end
|
42
39
|
|
43
|
-
|
44
|
-
|
45
|
-
|
40
|
+
# Ruby 1.9+
|
41
|
+
if defined? GC::Profiler
|
42
|
+
require 'trashed/instruments/ruby_gc_profiler'
|
43
|
+
meter.instrument Trashed::Instruments::RubyGCProfiler.new
|
46
44
|
end
|
47
45
|
end
|
48
46
|
end
|
data/lib/trashed.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: trashed
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 3.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jeremy Kemper
|
@@ -14,37 +14,65 @@ dependencies:
|
|
14
14
|
name: statsd-ruby
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- -
|
17
|
+
- - ~>
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '
|
19
|
+
version: '1.1'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ~>
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.1'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ! '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
22
36
|
version_requirements: !ruby/object:Gem::Requirement
|
23
37
|
requirements:
|
24
38
|
- - ! '>='
|
25
39
|
- !ruby/object:Gem::Version
|
26
|
-
version: '0
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: minitest
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ~>
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '5.3'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ~>
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '5.3'
|
27
55
|
description:
|
28
|
-
email:
|
56
|
+
email: jeremykemper@gmail.com
|
29
57
|
executables: []
|
30
58
|
extensions: []
|
31
59
|
extra_rdoc_files: []
|
32
60
|
files:
|
33
|
-
- ./MIT-LICENSE
|
34
|
-
- ./README.md
|
35
|
-
- ./Rakefile
|
36
61
|
- ./init.rb
|
37
62
|
- ./lib/trashed.rb
|
63
|
+
- ./lib/trashed/instruments/object_space_counter.rb
|
64
|
+
- ./lib/trashed/instruments/ree_gc.rb
|
65
|
+
- ./lib/trashed/instruments/ruby19_gc.rb
|
66
|
+
- ./lib/trashed/instruments/ruby20_gc.rb
|
67
|
+
- ./lib/trashed/instruments/ruby21_gc.rb
|
68
|
+
- ./lib/trashed/instruments/ruby_gc_profiler.rb
|
69
|
+
- ./lib/trashed/instruments/stopwatch.rb
|
38
70
|
- ./lib/trashed/meter.rb
|
39
|
-
- ./lib/trashed/new_relic.rb
|
40
71
|
- ./lib/trashed/rack.rb
|
41
72
|
- ./lib/trashed/railtie.rb
|
73
|
+
- ./lib/trashed/reporter.rb
|
42
74
|
- ./lib/trashed/resource_usage.rb
|
43
|
-
|
44
|
-
- ./test/meter_test.rb
|
45
|
-
- ./test/rack_test.rb
|
46
|
-
- ./trashed.gemspec
|
47
|
-
homepage: https://github.com/37signals/trashed
|
75
|
+
homepage: https://github.com/basecamp/trashed
|
48
76
|
licenses: []
|
49
77
|
metadata: {}
|
50
78
|
post_install_message:
|
@@ -66,6 +94,5 @@ rubyforge_project:
|
|
66
94
|
rubygems_version: 2.2.2
|
67
95
|
signing_key:
|
68
96
|
specification_version: 4
|
69
|
-
summary:
|
70
|
-
GC time.'
|
97
|
+
summary: Report per-request object allocations, GC time, and more to StatsD
|
71
98
|
test_files: []
|
data/MIT-LICENSE
DELETED
@@ -1,20 +0,0 @@
|
|
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
DELETED
@@ -1,34 +0,0 @@
|
|
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
DELETED
@@ -1,22 +0,0 @@
|
|
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/lib/trashed/new_relic.rb
DELETED
@@ -1,47 +0,0 @@
|
|
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
|
data/test/meter_test.rb
DELETED
@@ -1,15 +0,0 @@
|
|
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
DELETED
@@ -1,18 +0,0 @@
|
|
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
DELETED
@@ -1,12 +0,0 @@
|
|
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
|