scout_rails_proxy 1.0.4 → 1.0.6
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/Gemfile +1 -1
- data/README.markdown +3 -3
- data/lib/scout_rails_proxy.rb +32 -0
- data/lib/{scout_rails → scout_rails_proxy}/agent.rb +13 -13
- data/lib/scout_rails_proxy/config.rb +34 -0
- data/lib/{scout_rails → scout_rails_proxy}/environment.rb +1 -1
- data/lib/{scout_rails → scout_rails_proxy}/instruments/active_record_instruments.rb +7 -7
- data/lib/{scout_rails → scout_rails_proxy}/instruments/net_http.rb +2 -2
- data/lib/{scout_rails → scout_rails_proxy}/instruments/process/process_cpu.rb +1 -1
- data/lib/{scout_rails → scout_rails_proxy}/instruments/process/process_memory.rb +1 -1
- data/lib/{scout_rails → scout_rails_proxy}/instruments/rails/action_controller_instruments.rb +8 -8
- data/lib/{scout_rails → scout_rails_proxy}/instruments/rails3/action_controller_instruments.rb +8 -8
- data/lib/{scout_rails → scout_rails_proxy}/instruments/sinatra_instruments.rb +5 -5
- data/lib/{scout_rails → scout_rails_proxy}/layaway.rb +12 -12
- data/lib/{scout_rails → scout_rails_proxy}/layaway_file.rb +7 -7
- data/lib/{scout_rails → scout_rails_proxy}/metric_meta.rb +1 -1
- data/lib/{scout_rails → scout_rails_proxy}/metric_stats.rb +1 -1
- data/lib/{scout_rails → scout_rails_proxy}/stack_item.rb +1 -1
- data/lib/{scout_rails → scout_rails_proxy}/store.rb +11 -11
- data/lib/{scout_rails → scout_rails_proxy}/tracer.rb +8 -8
- data/lib/{scout_rails → scout_rails_proxy}/transaction_sample.rb +1 -1
- data/lib/scout_rails_proxy/version.rb +3 -0
- data/{scout_rails.gemspec → scout_rails_proxy.gemspec} +4 -4
- metadata +23 -23
- data/lib/scout_rails.rb +0 -32
- data/lib/scout_rails/config.rb +0 -34
- data/lib/scout_rails/version.rb +0 -3
data/Gemfile
CHANGED
data/README.markdown
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
#
|
1
|
+
# ScoutRailsProxy
|
2
2
|
|
3
3
|
A Ruby gem for detailed Rails application performance analysis. Metrics are reported to [Scout](https://scoutapp.com), a hosted server and application monitoring service. For general server monitoring, see our [server monitoring agent](https://github.com/scoutapp/scout-client).
|
4
4
|
|
@@ -8,9 +8,9 @@ A Ruby gem for detailed Rails application performance analysis. Metrics are repo
|
|
8
8
|
|
9
9
|
Install the gem:
|
10
10
|
|
11
|
-
gem install
|
11
|
+
gem install scout_rails_proxy
|
12
12
|
|
13
|
-
Signup for a [Scout](https://scoutapp.com) account and copy the config file to `RAILS_ROOT/config/
|
13
|
+
Signup for a [Scout](https://scoutapp.com) account and copy the config file to `RAILS_ROOT/config/scout_rails_proxy.yml`.
|
14
14
|
|
15
15
|
Your config file should look like:
|
16
16
|
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module ScoutRailsProxy
|
2
|
+
end
|
3
|
+
require 'socket'
|
4
|
+
require 'set'
|
5
|
+
require 'net/http'
|
6
|
+
require File.expand_path('../scout_rails_proxy/version.rb', __FILE__)
|
7
|
+
require File.expand_path('../scout_rails_proxy/agent.rb', __FILE__)
|
8
|
+
require File.expand_path('../scout_rails_proxy/layaway.rb', __FILE__)
|
9
|
+
require File.expand_path('../scout_rails_proxy/layaway_file.rb', __FILE__)
|
10
|
+
require File.expand_path('../scout_rails_proxy/config.rb', __FILE__)
|
11
|
+
require File.expand_path('../scout_rails_proxy/environment.rb', __FILE__)
|
12
|
+
require File.expand_path('../scout_rails_proxy/metric_meta.rb', __FILE__)
|
13
|
+
require File.expand_path('../scout_rails_proxy/metric_stats.rb', __FILE__)
|
14
|
+
require File.expand_path('../scout_rails_proxy/stack_item.rb', __FILE__)
|
15
|
+
require File.expand_path('../scout_rails_proxy/store.rb', __FILE__)
|
16
|
+
require File.expand_path('../scout_rails_proxy/tracer.rb', __FILE__)
|
17
|
+
require File.expand_path('../scout_rails_proxy/transaction_sample.rb', __FILE__)
|
18
|
+
require File.expand_path('../scout_rails_proxy/instruments/process/process_cpu.rb', __FILE__)
|
19
|
+
require File.expand_path('../scout_rails_proxy/instruments/process/process_memory.rb', __FILE__)
|
20
|
+
|
21
|
+
if defined?(Rails) and Rails.respond_to?(:version) and Rails.version =~ /^3/
|
22
|
+
module ScoutRailsProxy
|
23
|
+
class Railtie < Rails::Railtie
|
24
|
+
initializer "scout_rails_proxy.start" do |app|
|
25
|
+
ScoutRailsProxy::Agent.instance.start
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
else
|
30
|
+
ScoutRailsProxy::Agent.instance.start
|
31
|
+
end
|
32
|
+
|
@@ -1,4 +1,4 @@
|
|
1
|
-
module
|
1
|
+
module ScoutRailsProxy
|
2
2
|
# The agent gathers performance data from a Ruby application. One Agent instance is created per-Ruby process.
|
3
3
|
#
|
4
4
|
# Each Agent object creates a worker thread (unless monitoring is disabled or we're forking).
|
@@ -33,24 +33,24 @@ module ScoutRails
|
|
33
33
|
def initialize(options = {})
|
34
34
|
@started = false
|
35
35
|
@options ||= options
|
36
|
-
@store =
|
37
|
-
@layaway =
|
38
|
-
@config =
|
36
|
+
@store = ScoutRailsProxy::Store.new
|
37
|
+
@layaway = ScoutRailsProxy::Layaway.new
|
38
|
+
@config = ScoutRailsProxy::Config.new(options[:config_path])
|
39
39
|
@metric_lookup = Hash.new
|
40
|
-
@process_cpu=
|
41
|
-
@process_memory=
|
40
|
+
@process_cpu=ScoutRailsProxy::Instruments::Process::ProcessCpu.new(environment.processors)
|
41
|
+
@process_memory=ScoutRailsProxy::Instruments::Process::ProcessMemory.new
|
42
42
|
end
|
43
43
|
|
44
44
|
def environment
|
45
|
-
@environment ||=
|
45
|
+
@environment ||= ScoutRailsProxy::Environment.new
|
46
46
|
end
|
47
47
|
|
48
|
-
# This is called via +
|
48
|
+
# This is called via +ScoutRailsProxy::Agent.instance.start+ when ScoutRailsProxy is required in a Ruby application.
|
49
49
|
# It initializes the agent and starts the worker thread (if appropiate).
|
50
50
|
def start(options = {})
|
51
51
|
@options.merge!(options)
|
52
52
|
init_logger
|
53
|
-
logger.info "Attempting to start Scout Agent [#{
|
53
|
+
logger.info "Attempting to start Scout Agent [#{ScoutRailsProxy::VERSION}] on [#{Socket.gethostname}]"
|
54
54
|
if !config.settings['monitor'] and !@options[:force]
|
55
55
|
logger.warn "Monitoring isn't enabled for the [#{environment.env}] environment."
|
56
56
|
return false
|
@@ -72,7 +72,7 @@ module ScoutRails
|
|
72
72
|
end
|
73
73
|
start_worker_thread
|
74
74
|
handle_exit
|
75
|
-
logger.info "Scout Agent [#{
|
75
|
+
logger.info "Scout Agent [#{ScoutRailsProxy::VERSION}] Initialized"
|
76
76
|
end
|
77
77
|
|
78
78
|
# Placeholder: store metrics locally on exit so those in memory aren't lost. Need to decide
|
@@ -94,7 +94,7 @@ module ScoutRails
|
|
94
94
|
end
|
95
95
|
|
96
96
|
def init_logger
|
97
|
-
@log_file = "#{log_path}/
|
97
|
+
@log_file = "#{log_path}/scout_rails_proxy.log"
|
98
98
|
@logger = Logger.new(@log_file)
|
99
99
|
@logger.level = Logger::DEBUG
|
100
100
|
def logger.format_message(severity, timestamp, progname, msg)
|
@@ -123,7 +123,7 @@ module ScoutRails
|
|
123
123
|
Unicorn::HttpServer.class_eval do
|
124
124
|
old = instance_method(:worker_loop)
|
125
125
|
define_method(:worker_loop) do |worker|
|
126
|
-
|
126
|
+
ScoutRailsProxy::Agent.instance.start_worker_thread
|
127
127
|
old.bind(self).call(worker)
|
128
128
|
end
|
129
129
|
end
|
@@ -316,4 +316,4 @@ module ScoutRails
|
|
316
316
|
end
|
317
317
|
|
318
318
|
end # class Agent
|
319
|
-
end # module
|
319
|
+
end # module ScoutRailsProxy
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module ScoutRailsProxy
|
2
|
+
class Config
|
3
|
+
def initialize(config_path = nil)
|
4
|
+
@config_path = config_path
|
5
|
+
end
|
6
|
+
|
7
|
+
def settings
|
8
|
+
return @settings if @settings
|
9
|
+
load_file
|
10
|
+
end
|
11
|
+
|
12
|
+
def config_path
|
13
|
+
@config_path || File.join(ScoutRailsProxy::Agent.instance.environment.root,"config","scout_rails_proxy.yml")
|
14
|
+
end
|
15
|
+
|
16
|
+
def config_file
|
17
|
+
File.expand_path(config_path)
|
18
|
+
end
|
19
|
+
|
20
|
+
def load_file
|
21
|
+
if !File.exist?(config_file)
|
22
|
+
ScoutRailsProxy::Agent.instance.logger.warn "No config file found at [#{config_file}]."
|
23
|
+
@settings = {}
|
24
|
+
else
|
25
|
+
@settings = YAML.load(ERB.new(File.read(config_file)).result(binding))[ScoutRailsProxy::Agent.instance.environment.env] || {}
|
26
|
+
end
|
27
|
+
rescue Exception => e
|
28
|
+
ScoutRailsProxy::Agent.instance.logger.warn "Unable to load the config file."
|
29
|
+
ScoutRailsProxy::Agent.instance.logger.warn e.message
|
30
|
+
ScoutRailsProxy::Agent.instance.logger.warn e.backtrace
|
31
|
+
@settings = {}
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -1,9 +1,9 @@
|
|
1
|
-
module
|
1
|
+
module ScoutRailsProxy::Instruments
|
2
2
|
# Contains ActiveRecord instrument, aliasing +ActiveRecord::ConnectionAdapters::AbstractAdapter#log+ calls
|
3
3
|
# to trace calls to the database.
|
4
4
|
module ActiveRecordInstruments
|
5
5
|
def self.included(instrumented_class)
|
6
|
-
|
6
|
+
ScoutRailsProxy::Agent.instance.logger.debug "Instrumenting #{instrumented_class.inspect}"
|
7
7
|
instrumented_class.class_eval do
|
8
8
|
unless instrumented_class.method_defined?(:log_without_scout_instruments)
|
9
9
|
alias_method :log_without_scout_instruments, :log
|
@@ -62,20 +62,20 @@ end # module Instruments
|
|
62
62
|
def add_instruments
|
63
63
|
if defined?(ActiveRecord) && defined?(ActiveRecord::Base)
|
64
64
|
ActiveRecord::ConnectionAdapters::AbstractAdapter.module_eval do
|
65
|
-
include ::
|
66
|
-
include ::
|
65
|
+
include ::ScoutRailsProxy::Instruments::ActiveRecordInstruments
|
66
|
+
include ::ScoutRailsProxy::Tracer
|
67
67
|
end
|
68
68
|
ActiveRecord::Base.class_eval do
|
69
|
-
include ::
|
69
|
+
include ::ScoutRailsProxy::Tracer
|
70
70
|
end
|
71
71
|
end
|
72
72
|
rescue
|
73
|
-
|
73
|
+
ScoutRailsProxy::Agent.instance.logger.warn "ActiveRecord instrumentation exception: #{$!.message}"
|
74
74
|
end
|
75
75
|
|
76
76
|
if defined?(::Rails) && ::Rails::VERSION::MAJOR.to_i == 3
|
77
77
|
Rails.configuration.after_initialize do
|
78
|
-
|
78
|
+
ScoutRailsProxy::Agent.instance.logger.debug "Adding ActiveRecord instrumentation to a Rails 3 app"
|
79
79
|
add_instruments
|
80
80
|
end
|
81
81
|
else
|
@@ -1,7 +1,7 @@
|
|
1
1
|
if defined?(::Net) && defined?(Net::HTTP)
|
2
|
-
|
2
|
+
ScoutRailsProxy::Agent.instance.logger.debug "Instrumenting Net::HTTP"
|
3
3
|
Net::HTTP.class_eval do
|
4
|
-
include
|
4
|
+
include ScoutRailsProxy::Tracer
|
5
5
|
|
6
6
|
def request_with_scout_instruments(*args,&block)
|
7
7
|
self.class.instrument("HTTP/request", :desc => "#{(@address+args.first.path.split('?').first)[0..99]}") do
|
data/lib/{scout_rails → scout_rails_proxy}/instruments/rails/action_controller_instruments.rb
RENAMED
@@ -1,7 +1,7 @@
|
|
1
|
-
module
|
1
|
+
module ScoutRailsProxy::Instruments
|
2
2
|
module ActionControllerInstruments
|
3
3
|
def self.included(instrumented_class)
|
4
|
-
|
4
|
+
ScoutRailsProxy::Agent.instance.logger.debug "Instrumenting #{instrumented_class.inspect}"
|
5
5
|
instrumented_class.class_eval do
|
6
6
|
unless instrumented_class.method_defined?(:perform_action_without_scout_instruments)
|
7
7
|
alias_method :perform_action_without_scout_instruments, :perform_action
|
@@ -25,12 +25,12 @@ end
|
|
25
25
|
|
26
26
|
if defined?(ActionController) && defined?(ActionController::Base)
|
27
27
|
ActionController::Base.class_eval do
|
28
|
-
include
|
29
|
-
include ::
|
28
|
+
include ScoutRailsProxy::Tracer
|
29
|
+
include ::ScoutRailsProxy::Instruments::ActionControllerInstruments
|
30
30
|
|
31
31
|
def rescue_action_with_scout(exception)
|
32
|
-
|
33
|
-
|
32
|
+
ScoutRailsProxy::Agent.instance.store.track!("Errors/Request",1, :scope => nil)
|
33
|
+
ScoutRailsProxy::Agent.instance.store.ignore_transaction!
|
34
34
|
rescue_action_without_scout exception
|
35
35
|
end
|
36
36
|
|
@@ -38,9 +38,9 @@ if defined?(ActionController) && defined?(ActionController::Base)
|
|
38
38
|
alias_method :rescue_action, :rescue_action_with_scout
|
39
39
|
protected :rescue_action
|
40
40
|
end
|
41
|
-
|
41
|
+
ScoutRailsProxy::Agent.instance.logger.debug "Instrumenting ActionView::Template"
|
42
42
|
ActionView::Template.class_eval do
|
43
|
-
include ::
|
43
|
+
include ::ScoutRailsProxy::Tracer
|
44
44
|
instrument_method :render, :metric_name => 'View/#{path[%r{^(/.*/)?(.*)$},2]}/Rendering', :scope => true
|
45
45
|
end
|
46
46
|
end
|
data/lib/{scout_rails → scout_rails_proxy}/instruments/rails3/action_controller_instruments.rb
RENAMED
@@ -1,15 +1,15 @@
|
|
1
1
|
# Rails 3
|
2
|
-
module
|
2
|
+
module ScoutRailsProxy::Instruments
|
3
3
|
module ActionControllerInstruments
|
4
4
|
# Instruments the action and tracks errors.
|
5
5
|
def process_action(*args)
|
6
6
|
scout_controller_action = "Controller/#{controller_path}/#{action_name}"
|
7
|
-
#
|
7
|
+
#ScoutRailsProxy::Agent.instance.logger.debug "Processing #{scout_controller_action}"
|
8
8
|
self.class.trace(scout_controller_action, :uri => request.fullpath) do
|
9
9
|
begin
|
10
10
|
super
|
11
11
|
rescue Exception => e
|
12
|
-
|
12
|
+
ScoutRailsProxy::Agent.instance.store.track!("Errors/Request",1, :scope => nil)
|
13
13
|
raise
|
14
14
|
ensure
|
15
15
|
Thread::current[:scout_scope_name] = nil
|
@@ -22,17 +22,17 @@ end
|
|
22
22
|
# ActionController::Base is a subclass of ActionController::Metal, so this instruments both
|
23
23
|
# standard Rails requests + Metal.
|
24
24
|
if defined?(ActionController) && defined?(ActionController::Metal)
|
25
|
-
|
25
|
+
ScoutRailsProxy::Agent.instance.logger.debug "Instrumenting ActionController::Metal"
|
26
26
|
ActionController::Metal.class_eval do
|
27
|
-
include
|
28
|
-
include ::
|
27
|
+
include ScoutRailsProxy::Tracer
|
28
|
+
include ::ScoutRailsProxy::Instruments::ActionControllerInstruments
|
29
29
|
end
|
30
30
|
end
|
31
31
|
|
32
32
|
if defined?(ActionView) && defined?(ActionView::PartialRenderer)
|
33
|
-
|
33
|
+
ScoutRailsProxy::Agent.instance.logger.debug "Instrumenting ActionView::PartialRenderer"
|
34
34
|
ActionView::PartialRenderer.class_eval do
|
35
|
-
include
|
35
|
+
include ScoutRailsProxy::Tracer
|
36
36
|
instrument_method :render_partial, :metric_name => 'View/#{@template.virtual_path}/Rendering', :scope => true
|
37
37
|
end
|
38
38
|
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
module
|
1
|
+
module ScoutRailsProxy::Instruments
|
2
2
|
module SinatraInstruments
|
3
3
|
def route_eval_with_scout_instruments(&blockarg)
|
4
4
|
path = unescape(@request.path_info)
|
@@ -20,13 +20,13 @@ module ScoutRails::Instruments
|
|
20
20
|
end
|
21
21
|
end # route_eval_with_scout_instrumentss
|
22
22
|
end # SinatraInstruments
|
23
|
-
end #
|
23
|
+
end # ScoutRailsProxy::Instruments
|
24
24
|
|
25
25
|
if defined?(::Sinatra) && defined?(::Sinatra::Base)
|
26
|
-
|
26
|
+
ScoutRailsProxy::Agent.instance.logger.debug "Instrumenting Sinatra"
|
27
27
|
::Sinatra::Base.class_eval do
|
28
|
-
include
|
29
|
-
include ::
|
28
|
+
include ScoutRailsProxy::Tracer
|
29
|
+
include ::ScoutRailsProxy::Instruments::SinatraInstruments
|
30
30
|
alias route_eval_without_scout_instruments route_eval
|
31
31
|
alias route_eval route_eval_with_scout_instruments
|
32
32
|
end
|
@@ -4,21 +4,21 @@
|
|
4
4
|
#
|
5
5
|
# Metrics are stored in a Hash, where the keys are Time.to_i on the minute. When depositing data,
|
6
6
|
# metrics are either merged with an existing time or placed in a new key.
|
7
|
-
class
|
7
|
+
class ScoutRailsProxy::Layaway
|
8
8
|
attr_accessor :file
|
9
9
|
def initialize
|
10
|
-
@file =
|
10
|
+
@file = ScoutRailsProxy::LayawayFile.new
|
11
11
|
end
|
12
12
|
|
13
13
|
def deposit_and_deliver
|
14
|
-
new_data =
|
14
|
+
new_data = ScoutRailsProxy::Agent.instance.store.metric_hash
|
15
15
|
controller_count = 0
|
16
16
|
new_data.each do |meta,stats|
|
17
17
|
if meta.metric_name =~ /\AController/
|
18
18
|
controller_count += stats.call_count
|
19
19
|
end
|
20
20
|
end
|
21
|
-
|
21
|
+
ScoutRailsProxy::Agent.instance.logger.debug "Depositing #{controller_count} requests into #{Time.at(slot).strftime("%m/%d/%y %H:%M:%S %z")} slot."
|
22
22
|
|
23
23
|
to_deliver = {}
|
24
24
|
file.read_and_write do |old_data|
|
@@ -29,12 +29,12 @@ class ScoutRails::Layaway
|
|
29
29
|
to_deliver = old_data
|
30
30
|
old_data = Hash.new
|
31
31
|
elsif old_data.any?
|
32
|
-
|
32
|
+
ScoutRailsProxy::Agent.instance.logger.debug "Not yet time to deliver metrics for slot [#{Time.at(old_data.keys.sort.last).strftime("%m/%d/%y %H:%M:%S %z")}]"
|
33
33
|
else
|
34
|
-
|
34
|
+
ScoutRailsProxy::Agent.instance.logger.debug "There is no data in the layaway file to deliver."
|
35
35
|
end
|
36
|
-
old_data[slot]=
|
37
|
-
|
36
|
+
old_data[slot]=ScoutRailsProxy::Agent.instance.store.merge_data_and_clear(old_data[slot] || Hash.new)
|
37
|
+
ScoutRailsProxy::Agent.instance.logger.debug "Saving the following #{old_data.size} time slots locally:"
|
38
38
|
old_data.each do |k,v|
|
39
39
|
controller_count = 0
|
40
40
|
new_data.each do |meta,stats|
|
@@ -42,7 +42,7 @@ class ScoutRails::Layaway
|
|
42
42
|
controller_count += stats.call_count
|
43
43
|
end
|
44
44
|
end
|
45
|
-
|
45
|
+
ScoutRailsProxy::Agent.instance.logger.debug "#{Time.at(k).strftime("%m/%d/%y %H:%M:%S %z")} => #{controller_count} requests"
|
46
46
|
end
|
47
47
|
old_data
|
48
48
|
end
|
@@ -58,14 +58,14 @@ class ScoutRails::Layaway
|
|
58
58
|
data = data.to_a.sort
|
59
59
|
now = Time.now
|
60
60
|
if (most_recent = data.first.first) < now.to_i - 2*60
|
61
|
-
|
61
|
+
ScoutRailsProxy::Agent.instance.logger.debug "Local Storage is stale (#{Time.at(most_recent).strftime("%m/%d/%y %H:%M:%S %z")}). Not sending data."
|
62
62
|
{}
|
63
63
|
else
|
64
64
|
data.first.last
|
65
65
|
end
|
66
66
|
rescue
|
67
|
-
|
68
|
-
|
67
|
+
ScoutRailsProxy::Agent.instance.logger.debug $!.message
|
68
|
+
ScoutRailsProxy::Agent.instance.logger.debug $!.backtrace
|
69
69
|
end
|
70
70
|
|
71
71
|
def slot
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# Logic for the serialized file access
|
2
|
-
class
|
2
|
+
class ScoutRailsProxy::LayawayFile
|
3
3
|
def path
|
4
|
-
"#{
|
4
|
+
"#{ScoutRailsProxy::Agent.instance.log_path}/scout_rails_proxy.db"
|
5
5
|
end
|
6
6
|
|
7
7
|
def dump(object)
|
@@ -10,13 +10,13 @@ class ScoutRails::LayawayFile
|
|
10
10
|
|
11
11
|
def load(dump)
|
12
12
|
if dump.size == 0
|
13
|
-
|
13
|
+
ScoutRailsProxy::Agent.instance.logger.debug("No data in layaway file.")
|
14
14
|
return nil
|
15
15
|
end
|
16
16
|
Marshal.load(dump)
|
17
17
|
rescue ArgumentError, TypeError => e
|
18
|
-
|
19
|
-
|
18
|
+
ScoutRailsProxy::Agent.instance.logger.debug("Error loading data from layaway file: #{e.inspect}")
|
19
|
+
ScoutRailsProxy::Agent.instance.logger.debug(e.backtrace.inspect)
|
20
20
|
nil
|
21
21
|
end
|
22
22
|
|
@@ -35,8 +35,8 @@ class ScoutRails::LayawayFile
|
|
35
35
|
end
|
36
36
|
end
|
37
37
|
rescue Errno::ENOENT, Exception => e
|
38
|
-
|
39
|
-
|
38
|
+
ScoutRailsProxy::Agent.instance.logger.error(e.message)
|
39
|
+
ScoutRailsProxy::Agent.instance.logger.debug(e.backtrace.split("\n"))
|
40
40
|
end
|
41
41
|
|
42
42
|
def get_data(f)
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# The store encapsolutes the logic that (1) saves instrumented data by Metric name to memory and (2) maintains a stack (just an Array)
|
2
|
-
# of instrumented methods that are being called. It's accessed via +
|
3
|
-
class
|
2
|
+
# of instrumented methods that are being called. It's accessed via +ScoutRailsProxy::Agent.instance.store+.
|
3
|
+
class ScoutRailsProxy::Store
|
4
4
|
attr_accessor :metric_hash
|
5
5
|
attr_accessor :transaction_hash
|
6
6
|
attr_accessor :stack
|
@@ -36,7 +36,7 @@ class ScoutRails::Store
|
|
36
36
|
# (2) Adds a StackItem to the stack. This StackItem is returned and later used to validate the item popped off the stack
|
37
37
|
# when an instrumented code block completes.
|
38
38
|
def record(metric_name)
|
39
|
-
item =
|
39
|
+
item = ScoutRailsProxy::StackItem.new(metric_name)
|
40
40
|
stack << item
|
41
41
|
item
|
42
42
|
end
|
@@ -51,7 +51,7 @@ class ScoutRails::Store
|
|
51
51
|
# unbalanced stack check - unreproducable cases have seen this occur. when it does, sets a Thread variable
|
52
52
|
# so we ignore further recordings. +Store#reset_transaction!+ resets this.
|
53
53
|
if item != sanity_check_item
|
54
|
-
|
54
|
+
ScoutRailsProxy::Agent.instance.logger.warn "Scope [#{Thread::current[:scout_scope_name]}] Popped off stack: #{item.inspect} Expected: #{sanity_check_item.inspect}. Aborting."
|
55
55
|
ignore_transaction!
|
56
56
|
return
|
57
57
|
end
|
@@ -59,14 +59,14 @@ class ScoutRails::Store
|
|
59
59
|
if last=stack.last
|
60
60
|
last.children_time += duration
|
61
61
|
end
|
62
|
-
meta =
|
62
|
+
meta = ScoutRailsProxy::MetricMeta.new(item.metric_name, :desc => options[:desc])
|
63
63
|
meta.scope = nil if stack_empty
|
64
64
|
|
65
65
|
# add backtrace for slow calls ... how is exclusive time handled?
|
66
66
|
if duration > 0.5 and !stack_empty
|
67
67
|
meta.extra = {:backtrace => caller.find_all { |c| c =~ /\/app\//}}
|
68
68
|
end
|
69
|
-
stat = transaction_hash[meta] ||
|
69
|
+
stat = transaction_hash[meta] || ScoutRailsProxy::MetricStats.new(!stack_empty)
|
70
70
|
|
71
71
|
stat.update!(duration,duration-item.children_time)
|
72
72
|
transaction_hash[meta] = stat
|
@@ -101,9 +101,9 @@ class ScoutRails::Store
|
|
101
101
|
categories = categories(metrics)
|
102
102
|
aggregates = {}
|
103
103
|
categories.each do |cat|
|
104
|
-
agg_meta=
|
104
|
+
agg_meta=ScoutRailsProxy::MetricMeta.new("#{cat}/all")
|
105
105
|
agg_meta.scope = parent_meta.metric_name
|
106
|
-
agg_stats =
|
106
|
+
agg_stats = ScoutRailsProxy::MetricStats.new
|
107
107
|
metrics.each do |meta,stats|
|
108
108
|
if meta.metric_name =~ /\A#{cat}\//
|
109
109
|
agg_stats.combine!(stats)
|
@@ -118,7 +118,7 @@ class ScoutRails::Store
|
|
118
118
|
def store_sample(uri,transaction_hash,parent_meta,parent_stat,options = {})
|
119
119
|
@transaction_sample_lock.synchronize do
|
120
120
|
if parent_stat.total_call_time >= 2 and (@sample.nil? or (@sample and parent_stat.total_call_time > @sample.total_call_time))
|
121
|
-
@sample =
|
121
|
+
@sample = ScoutRailsProxy::TransactionSample.new(uri,parent_meta.metric_name,parent_stat.total_call_time,transaction_hash.dup)
|
122
122
|
end
|
123
123
|
end
|
124
124
|
end
|
@@ -130,9 +130,9 @@ class ScoutRails::Store
|
|
130
130
|
# :scope => If provided, overrides the default scope.
|
131
131
|
# :exclusive_time => Sets the exclusive time for the method. If not provided, uses +call_time+.
|
132
132
|
def track!(metric_name,call_time,options = {})
|
133
|
-
meta =
|
133
|
+
meta = ScoutRailsProxy::MetricMeta.new(metric_name)
|
134
134
|
meta.scope = options[:scope] if options.has_key?(:scope)
|
135
|
-
stat = metric_hash[meta] ||
|
135
|
+
stat = metric_hash[meta] || ScoutRailsProxy::MetricStats.new
|
136
136
|
stat.update!(call_time,options[:exclusive_time] || call_time)
|
137
137
|
metric_hash[meta] = stat
|
138
138
|
end
|
@@ -6,7 +6,7 @@
|
|
6
6
|
# we created earlier.
|
7
7
|
# * Once verified, the metrics for the recording session are merged into the in-memory Store#metric_hash. The current scope
|
8
8
|
# is also set for the metric (if Thread::current[:scout_scope_name] isn't nil).
|
9
|
-
module
|
9
|
+
module ScoutRailsProxy::Tracer
|
10
10
|
def self.included(klass)
|
11
11
|
klass.extend ClassMethods
|
12
12
|
end
|
@@ -15,7 +15,7 @@ module ScoutRails::Tracer
|
|
15
15
|
|
16
16
|
# Use to trace a method call, possibly reporting slow transaction traces to Scout.
|
17
17
|
def trace(metric_name, options = {}, &block)
|
18
|
-
|
18
|
+
ScoutRailsProxy::Agent.instance.store.reset_transaction!
|
19
19
|
instrument(metric_name, options) do
|
20
20
|
Thread::current[:scout_scope_name] = metric_name
|
21
21
|
yield
|
@@ -29,23 +29,23 @@ module ScoutRails::Tracer
|
|
29
29
|
def instrument(metric_name, options={}, &block)
|
30
30
|
# don't instrument if (1) NOT inside a transaction and (2) NOT a Controller metric.
|
31
31
|
if !Thread::current[:scout_scope_name] and metric_name !~ /\AController\//
|
32
|
-
|
32
|
+
ScoutRailsProxy::Agent.instance.logger.debug "Not instrumenting [#{metric_name}] - no scope."
|
33
33
|
return yield
|
34
34
|
end
|
35
35
|
if options.delete(:scope)
|
36
36
|
Thread::current[:scout_sub_scope] = metric_name
|
37
37
|
end
|
38
|
-
stack_item =
|
38
|
+
stack_item = ScoutRailsProxy::Agent.instance.store.record(metric_name)
|
39
39
|
begin
|
40
40
|
yield
|
41
41
|
ensure
|
42
42
|
Thread::current[:scout_sub_scope] = nil if Thread::current[:scout_sub_scope] == metric_name
|
43
|
-
|
43
|
+
ScoutRailsProxy::Agent.instance.store.stop_recording(stack_item,options)
|
44
44
|
end
|
45
45
|
end
|
46
46
|
|
47
47
|
def instrument_method(method,options = {})
|
48
|
-
|
48
|
+
ScoutRailsProxy::Agent.instance.logger.info "Instrumenting #{method}"
|
49
49
|
metric_name = options[:metric_name] || default_metric_name(method)
|
50
50
|
return if !instrumentable?(method) or instrumented?(method,metric_name)
|
51
51
|
class_eval instrumented_method_string(method, {:metric_name => metric_name, :scope => options[:scope]}), __FILE__, __LINE__
|
@@ -69,14 +69,14 @@ module ScoutRails::Tracer
|
|
69
69
|
# The method must exist to be instrumented.
|
70
70
|
def instrumentable?(method)
|
71
71
|
exists = method_defined?(method) || private_method_defined?(method)
|
72
|
-
|
72
|
+
ScoutRailsProxy::Agent.instance.logger.warn "The method [#{self.name}##{method}] does not exist and will not be instrumented" unless exists
|
73
73
|
exists
|
74
74
|
end
|
75
75
|
|
76
76
|
# +True+ if the method is already instrumented.
|
77
77
|
def instrumented?(method,metric_name)
|
78
78
|
instrumented = method_defined?(_instrumented_method_name(method, metric_name))
|
79
|
-
|
79
|
+
ScoutRailsProxy::Agent.instance.logger.warn "The method [#{self.name}##{method}] has already been instrumented" if instrumented
|
80
80
|
instrumented
|
81
81
|
end
|
82
82
|
|
@@ -1,17 +1,17 @@
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
2
2
|
$:.push File.expand_path("../lib", __FILE__)
|
3
|
-
require "
|
3
|
+
require "scout_rails_proxy/version"
|
4
4
|
|
5
5
|
Gem::Specification.new do |s|
|
6
6
|
s.name = "scout_rails_proxy"
|
7
|
-
s.version =
|
7
|
+
s.version = ScoutRailsProxy::VERSION
|
8
8
|
s.authors = ["Derek Haynes",'Andre Lewis','Bastian Schumacher']
|
9
9
|
s.email = ["support@scoutapp.com"]
|
10
|
-
s.homepage = "https://github.com/scoutapp/
|
10
|
+
s.homepage = "https://github.com/scoutapp/scout_rails_proxy"
|
11
11
|
s.summary = "Rails application performance monitoring with proxy support"
|
12
12
|
s.description = "Monitors a Ruby on Rails application and reports detailed metrics on performance to Scout, a hosted monitoring service."
|
13
13
|
|
14
|
-
# s.rubyforge_project = "
|
14
|
+
# s.rubyforge_project = "scout_rails_proxy"
|
15
15
|
|
16
16
|
s.files = `git ls-files`.split("\n")
|
17
17
|
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: scout_rails_proxy
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.6
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -27,28 +27,28 @@ files:
|
|
27
27
|
- Gemfile
|
28
28
|
- README.markdown
|
29
29
|
- Rakefile
|
30
|
-
- lib/
|
31
|
-
- lib/
|
32
|
-
- lib/
|
33
|
-
- lib/
|
34
|
-
- lib/
|
35
|
-
- lib/
|
36
|
-
- lib/
|
37
|
-
- lib/
|
38
|
-
- lib/
|
39
|
-
- lib/
|
40
|
-
- lib/
|
41
|
-
- lib/
|
42
|
-
- lib/
|
43
|
-
- lib/
|
44
|
-
- lib/
|
45
|
-
- lib/
|
46
|
-
- lib/
|
47
|
-
- lib/
|
48
|
-
- lib/
|
49
|
-
- lib/
|
50
|
-
-
|
51
|
-
homepage: https://github.com/scoutapp/
|
30
|
+
- lib/scout_rails_proxy.rb
|
31
|
+
- lib/scout_rails_proxy/agent.rb
|
32
|
+
- lib/scout_rails_proxy/config.rb
|
33
|
+
- lib/scout_rails_proxy/environment.rb
|
34
|
+
- lib/scout_rails_proxy/instruments/active_record_instruments.rb
|
35
|
+
- lib/scout_rails_proxy/instruments/net_http.rb
|
36
|
+
- lib/scout_rails_proxy/instruments/process/process_cpu.rb
|
37
|
+
- lib/scout_rails_proxy/instruments/process/process_memory.rb
|
38
|
+
- lib/scout_rails_proxy/instruments/rails/action_controller_instruments.rb
|
39
|
+
- lib/scout_rails_proxy/instruments/rails3/action_controller_instruments.rb
|
40
|
+
- lib/scout_rails_proxy/instruments/sinatra_instruments.rb
|
41
|
+
- lib/scout_rails_proxy/layaway.rb
|
42
|
+
- lib/scout_rails_proxy/layaway_file.rb
|
43
|
+
- lib/scout_rails_proxy/metric_meta.rb
|
44
|
+
- lib/scout_rails_proxy/metric_stats.rb
|
45
|
+
- lib/scout_rails_proxy/stack_item.rb
|
46
|
+
- lib/scout_rails_proxy/store.rb
|
47
|
+
- lib/scout_rails_proxy/tracer.rb
|
48
|
+
- lib/scout_rails_proxy/transaction_sample.rb
|
49
|
+
- lib/scout_rails_proxy/version.rb
|
50
|
+
- scout_rails_proxy.gemspec
|
51
|
+
homepage: https://github.com/scoutapp/scout_rails_proxy
|
52
52
|
licenses: []
|
53
53
|
post_install_message:
|
54
54
|
rdoc_options: []
|
data/lib/scout_rails.rb
DELETED
@@ -1,32 +0,0 @@
|
|
1
|
-
module ScoutRails
|
2
|
-
end
|
3
|
-
require 'socket'
|
4
|
-
require 'set'
|
5
|
-
require 'net/http'
|
6
|
-
require File.expand_path('../scout_rails/version.rb', __FILE__)
|
7
|
-
require File.expand_path('../scout_rails/agent.rb', __FILE__)
|
8
|
-
require File.expand_path('../scout_rails/layaway.rb', __FILE__)
|
9
|
-
require File.expand_path('../scout_rails/layaway_file.rb', __FILE__)
|
10
|
-
require File.expand_path('../scout_rails/config.rb', __FILE__)
|
11
|
-
require File.expand_path('../scout_rails/environment.rb', __FILE__)
|
12
|
-
require File.expand_path('../scout_rails/metric_meta.rb', __FILE__)
|
13
|
-
require File.expand_path('../scout_rails/metric_stats.rb', __FILE__)
|
14
|
-
require File.expand_path('../scout_rails/stack_item.rb', __FILE__)
|
15
|
-
require File.expand_path('../scout_rails/store.rb', __FILE__)
|
16
|
-
require File.expand_path('../scout_rails/tracer.rb', __FILE__)
|
17
|
-
require File.expand_path('../scout_rails/transaction_sample.rb', __FILE__)
|
18
|
-
require File.expand_path('../scout_rails/instruments/process/process_cpu.rb', __FILE__)
|
19
|
-
require File.expand_path('../scout_rails/instruments/process/process_memory.rb', __FILE__)
|
20
|
-
|
21
|
-
if defined?(Rails) and Rails.respond_to?(:version) and Rails.version =~ /^3/
|
22
|
-
module ScoutRails
|
23
|
-
class Railtie < Rails::Railtie
|
24
|
-
initializer "scout_rails.start" do |app|
|
25
|
-
ScoutRails::Agent.instance.start
|
26
|
-
end
|
27
|
-
end
|
28
|
-
end
|
29
|
-
else
|
30
|
-
ScoutRails::Agent.instance.start
|
31
|
-
end
|
32
|
-
|
data/lib/scout_rails/config.rb
DELETED
@@ -1,34 +0,0 @@
|
|
1
|
-
module ScoutRails
|
2
|
-
class Config
|
3
|
-
def initialize(config_path = nil)
|
4
|
-
@config_path = config_path
|
5
|
-
end
|
6
|
-
|
7
|
-
def settings
|
8
|
-
return @settings if @settings
|
9
|
-
load_file
|
10
|
-
end
|
11
|
-
|
12
|
-
def config_path
|
13
|
-
@config_path || File.join(ScoutRails::Agent.instance.environment.root,"config","scout_rails.yml")
|
14
|
-
end
|
15
|
-
|
16
|
-
def config_file
|
17
|
-
File.expand_path(config_path)
|
18
|
-
end
|
19
|
-
|
20
|
-
def load_file
|
21
|
-
if !File.exist?(config_file)
|
22
|
-
ScoutRails::Agent.instance.logger.warn "No config file found at [#{config_file}]."
|
23
|
-
@settings = {}
|
24
|
-
else
|
25
|
-
@settings = YAML.load(ERB.new(File.read(config_file)).result(binding))[ScoutRails::Agent.instance.environment.env] || {}
|
26
|
-
end
|
27
|
-
rescue Exception => e
|
28
|
-
ScoutRails::Agent.instance.logger.warn "Unable to load the config file."
|
29
|
-
ScoutRails::Agent.instance.logger.warn e.message
|
30
|
-
ScoutRails::Agent.instance.logger.warn e.backtrace
|
31
|
-
@settings = {}
|
32
|
-
end
|
33
|
-
end
|
34
|
-
end
|
data/lib/scout_rails/version.rb
DELETED