scout_apm 3.0.0.pre13 → 3.0.0.pre14
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/scout_apm.rb +20 -10
- data/lib/scout_apm/agent.rb +114 -319
- data/lib/scout_apm/agent/exit_handler.rb +66 -0
- data/lib/scout_apm/agent/preconditions.rb +69 -0
- data/lib/scout_apm/agent_context.rb +234 -0
- data/lib/scout_apm/app_server_load.rb +24 -14
- data/lib/scout_apm/background_job_integrations/resque.rb +7 -8
- data/lib/scout_apm/background_job_integrations/sidekiq.rb +2 -2
- data/lib/scout_apm/background_recorder.rb +8 -3
- data/lib/scout_apm/background_worker.rb +14 -7
- data/lib/scout_apm/config.rb +35 -26
- data/lib/scout_apm/context.rb +11 -4
- data/lib/scout_apm/db_query_metric_set.rb +17 -5
- data/lib/scout_apm/debug.rb +1 -1
- data/lib/scout_apm/environment.rb +10 -14
- data/lib/scout_apm/framework_integrations/sinatra.rb +1 -1
- data/lib/scout_apm/git_revision.rb +13 -8
- data/lib/scout_apm/histogram.rb +1 -1
- data/lib/scout_apm/instant/middleware.rb +7 -7
- data/lib/scout_apm/instant_reporting.rb +7 -7
- data/lib/scout_apm/instrument_manager.rb +87 -0
- data/lib/scout_apm/instruments/action_controller_rails_2.rb +12 -7
- data/lib/scout_apm/instruments/action_controller_rails_3_rails4.rb +17 -12
- data/lib/scout_apm/instruments/action_view.rb +11 -7
- data/lib/scout_apm/instruments/active_record.rb +25 -11
- data/lib/scout_apm/instruments/elasticsearch.rb +10 -6
- data/lib/scout_apm/instruments/grape.rb +12 -8
- data/lib/scout_apm/instruments/http_client.rb +10 -6
- data/lib/scout_apm/instruments/influxdb.rb +10 -6
- data/lib/scout_apm/instruments/middleware_detailed.rb +11 -5
- data/lib/scout_apm/instruments/middleware_summary.rb +11 -5
- data/lib/scout_apm/instruments/mongoid.rb +10 -5
- data/lib/scout_apm/instruments/moped.rb +11 -6
- data/lib/scout_apm/instruments/net_http.rb +10 -6
- data/lib/scout_apm/instruments/percentile_sampler.rb +8 -6
- data/lib/scout_apm/instruments/process/process_cpu.rb +8 -4
- data/lib/scout_apm/instruments/process/process_memory.rb +15 -10
- data/lib/scout_apm/instruments/rails_router.rb +12 -6
- data/lib/scout_apm/instruments/redis.rb +10 -6
- data/lib/scout_apm/instruments/samplers.rb +11 -0
- data/lib/scout_apm/instruments/sinatra.rb +5 -4
- data/lib/scout_apm/layaway.rb +21 -20
- data/lib/scout_apm/layaway_file.rb +8 -3
- data/lib/scout_apm/layer.rb +3 -3
- data/lib/scout_apm/layer_converters/converter_base.rb +6 -7
- data/lib/scout_apm/layer_converters/database_converter.rb +1 -1
- data/lib/scout_apm/layer_converters/histograms.rb +2 -2
- data/lib/scout_apm/layer_converters/slow_job_converter.rb +4 -3
- data/lib/scout_apm/layer_converters/slow_request_converter.rb +5 -4
- data/lib/scout_apm/logger.rb +143 -0
- data/lib/scout_apm/middleware.rb +7 -9
- data/lib/scout_apm/periodic_work.rb +28 -0
- data/lib/scout_apm/reporter.rb +14 -8
- data/lib/scout_apm/reporting.rb +135 -0
- data/lib/scout_apm/request_manager.rb +4 -6
- data/lib/scout_apm/serializers/payload_serializer.rb +1 -1
- data/lib/scout_apm/slow_job_policy.rb +6 -2
- data/lib/scout_apm/slow_job_record.rb +5 -5
- data/lib/scout_apm/slow_request_policy.rb +6 -2
- data/lib/scout_apm/slow_transaction.rb +5 -5
- data/lib/scout_apm/store.rb +22 -16
- data/lib/scout_apm/synchronous_recorder.rb +7 -3
- data/lib/scout_apm/tasks/doctor.rb +75 -0
- data/lib/scout_apm/tasks/support.rb +22 -0
- data/lib/scout_apm/tracer.rb +5 -5
- data/lib/scout_apm/tracked_request.rb +43 -19
- data/lib/scout_apm/utils/active_record_metric_name.rb +66 -8
- data/lib/scout_apm/utils/backtrace_parser.rb +1 -1
- data/lib/scout_apm/utils/installed_gems.rb +7 -3
- data/lib/scout_apm/utils/klass_helper.rb +8 -2
- data/lib/scout_apm/utils/scm.rb +1 -1
- data/lib/scout_apm/utils/sql_sanitizer.rb +3 -3
- data/lib/scout_apm/version.rb +1 -1
- data/lib/tasks/doctor.rake +11 -0
- data/scout_apm.gemspec +1 -0
- data/test/test_helper.rb +17 -2
- data/test/unit/agent_test.rb +1 -54
- data/test/unit/config_test.rb +9 -5
- data/test/unit/context_test.rb +4 -4
- data/test/unit/db_query_metric_set_test.rb +11 -4
- data/test/unit/fake_store_test.rb +1 -1
- data/test/unit/git_revision_test.rb +3 -3
- data/test/unit/instruments/net_http_test.rb +2 -1
- data/test/unit/instruments/percentile_sampler_test.rb +5 -9
- data/test/unit/layaway_test.rb +10 -5
- data/test/unit/layer_converters/metric_converter_test.rb +2 -2
- data/test/unit/slow_request_policy_test.rb +7 -3
- data/test/unit/sql_sanitizer_test.rb +0 -6
- data/test/unit/store_test.rb +11 -8
- data/test/unit/utils/active_record_metric_name_test.rb +45 -7
- metadata +27 -5
- data/lib/scout_apm/agent/logging.rb +0 -74
- data/lib/scout_apm/agent/reporting.rb +0 -129
- data/lib/scout_apm/utils/null_logger.rb +0 -13
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5f476cb8dead66959ed3a2e07a102d4d6ee50c79
|
4
|
+
data.tar.gz: 28266d8577a792a8faec963bf01e260360817e81
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: bd5647c9cd02c2fe3e2d670bd71af12cde9d7df06cca03e16561873ee02beab8dda5b5001ec3c397b9dbb1df9b31dde57ef3e7e1ef0ecfdd2755e4ecfae92f69
|
7
|
+
data.tar.gz: 031e7b683fc6ab6cd3c56a52e03a81a3e1a059c1ffbea594e0cc5ca0d3a67120ca7b35a31726becc0acaf39e54f9bd77d09488c3ed4c89bd524d56d07dcf959e
|
data/lib/scout_apm.rb
CHANGED
@@ -81,16 +81,18 @@ require 'scout_apm/instruments/elasticsearch'
|
|
81
81
|
require 'scout_apm/instruments/active_record'
|
82
82
|
require 'scout_apm/instruments/action_controller_rails_2'
|
83
83
|
require 'scout_apm/instruments/action_controller_rails_3_rails4'
|
84
|
+
require 'scout_apm/instruments/action_view'
|
84
85
|
require 'scout_apm/instruments/middleware_summary'
|
85
86
|
require 'scout_apm/instruments/middleware_detailed' # Disabled by default, see the file for more details
|
86
87
|
require 'scout_apm/instruments/rails_router'
|
87
88
|
require 'scout_apm/instruments/grape'
|
88
89
|
require 'scout_apm/instruments/sinatra'
|
90
|
+
require 'allocations'
|
91
|
+
|
89
92
|
require 'scout_apm/instruments/process/process_cpu'
|
90
93
|
require 'scout_apm/instruments/process/process_memory'
|
91
94
|
require 'scout_apm/instruments/percentile_sampler'
|
92
|
-
require 'scout_apm/instruments/
|
93
|
-
require 'allocations'
|
95
|
+
require 'scout_apm/instruments/samplers'
|
94
96
|
|
95
97
|
begin
|
96
98
|
require 'stacks'
|
@@ -105,7 +107,6 @@ require 'scout_apm/utils/active_record_metric_name'
|
|
105
107
|
require 'scout_apm/utils/backtrace_parser'
|
106
108
|
require 'scout_apm/utils/installed_gems'
|
107
109
|
require 'scout_apm/utils/klass_helper'
|
108
|
-
require 'scout_apm/utils/null_logger'
|
109
110
|
require 'scout_apm/utils/scm'
|
110
111
|
require 'scout_apm/utils/sql_sanitizer'
|
111
112
|
require 'scout_apm/utils/time'
|
@@ -116,8 +117,8 @@ require 'scout_apm/utils/gzip_helper'
|
|
116
117
|
require 'scout_apm/config'
|
117
118
|
require 'scout_apm/environment'
|
118
119
|
require 'scout_apm/agent'
|
119
|
-
require 'scout_apm/
|
120
|
-
require 'scout_apm/
|
120
|
+
require 'scout_apm/logger'
|
121
|
+
require 'scout_apm/reporting'
|
121
122
|
require 'scout_apm/layaway'
|
122
123
|
require 'scout_apm/layaway_file'
|
123
124
|
require 'scout_apm/reporter'
|
@@ -171,6 +172,14 @@ require 'scout_apm/remote/message'
|
|
171
172
|
require 'scout_apm/remote/recorder'
|
172
173
|
require 'scout_apm/instruments/resque'
|
173
174
|
|
175
|
+
require 'scout_apm/agent_context'
|
176
|
+
require 'scout_apm/instrument_manager'
|
177
|
+
require 'scout_apm/periodic_work'
|
178
|
+
require 'scout_apm/agent/preconditions'
|
179
|
+
require 'scout_apm/agent/exit_handler'
|
180
|
+
require 'scout_apm/tasks/doctor'
|
181
|
+
require 'scout_apm/tasks/support'
|
182
|
+
|
174
183
|
if defined?(Rails) && defined?(Rails::VERSION) && defined?(Rails::VERSION::MAJOR) && Rails::VERSION::MAJOR >= 3 && defined?(Rails::Railtie)
|
175
184
|
module ScoutApm
|
176
185
|
class Railtie < Rails::Railtie
|
@@ -181,17 +190,18 @@ if defined?(Rails) && defined?(Rails::VERSION) && defined?(Rails::VERSION::MAJOR
|
|
181
190
|
app.middleware.use ScoutApm::Middleware
|
182
191
|
|
183
192
|
# Attempt to start right away, this will work best for preloading apps, Unicorn & Puma & similar
|
184
|
-
ScoutApm::Agent.instance.
|
185
|
-
|
186
|
-
end
|
187
|
-
class Railtie < Rails::Railtie
|
188
|
-
initializer 'scout_apm.start' do |app|
|
193
|
+
ScoutApm::Agent.instance.install
|
194
|
+
|
189
195
|
# Install the middleware every time in development mode.
|
190
196
|
# The middleware is a noop if dev_trace is not enabled in config
|
191
197
|
if Rails.env.development?
|
192
198
|
app.middleware.use ScoutApm::Instant::Middleware
|
193
199
|
end
|
194
200
|
end
|
201
|
+
|
202
|
+
rake_tasks do
|
203
|
+
load "tasks/doctor.rake"
|
204
|
+
end
|
195
205
|
end
|
196
206
|
end
|
197
207
|
else
|
data/lib/scout_apm/agent.rb
CHANGED
@@ -1,240 +1,116 @@
|
|
1
1
|
module ScoutApm
|
2
|
-
# The
|
2
|
+
# The entry-point for the ScoutApm Agent.
|
3
3
|
#
|
4
|
-
#
|
5
|
-
#
|
6
|
-
#
|
4
|
+
# Only one Agent instance is created per-Ruby process, and it coordinates the lifecycle of the monitoring.
|
5
|
+
# - initializes various data stores
|
6
|
+
# - coordinates configuration & logging
|
7
|
+
# - starts background threads, running periodically
|
8
|
+
# - installs shutdown hooks
|
7
9
|
class Agent
|
8
10
|
# see self.instance
|
9
11
|
@@instance = nil
|
10
12
|
|
11
|
-
|
12
|
-
attr_accessor :store
|
13
|
-
attr_reader :recorder
|
14
|
-
attr_accessor :layaway
|
15
|
-
attr_accessor :config
|
16
|
-
attr_accessor :logger
|
17
|
-
attr_accessor :log_file # path to the log file
|
18
|
-
attr_accessor :options # options passed to the agent when +#start+ is called.
|
19
|
-
attr_accessor :metric_lookup # Hash used to lookup metric ids based on their name and scope
|
20
|
-
attr_reader :slow_request_policy
|
21
|
-
attr_reader :slow_job_policy
|
22
|
-
attr_reader :process_start_time # used when creating slow transactions to report how far from startup the transaction was recorded.
|
23
|
-
attr_reader :ignored_uris
|
13
|
+
attr_reader :context
|
24
14
|
|
25
|
-
#
|
26
|
-
attr_reader :request_histograms
|
15
|
+
attr_accessor :options # options passed to the agent when +#start+ is called.
|
27
16
|
|
28
|
-
|
29
|
-
# { StoreReportingPeriodTimestamp => RequestHistograms }
|
30
|
-
attr_reader :request_histograms_by_time
|
17
|
+
attr_reader :instrument_manager
|
31
18
|
|
32
19
|
# All access to the agent is thru this class method to ensure multiple Agent instances are not initialized per-Ruby process.
|
33
20
|
def self.instance(options = {})
|
34
21
|
@@instance ||= self.new(options)
|
35
22
|
end
|
36
23
|
|
37
|
-
#
|
38
|
-
# want to start the worker thread or install instrumentation if (1) disabled for this environment (2) a worker thread shouldn't
|
39
|
-
# be started (when forking).
|
24
|
+
# First call of the agent. Does very little so that the object can be created, and exist.
|
40
25
|
def initialize(options = {})
|
41
|
-
@
|
42
|
-
@
|
43
|
-
@options ||= options
|
44
|
-
|
45
|
-
# until the agent is started, there's no recorder
|
46
|
-
@recorder = nil
|
47
|
-
|
48
|
-
# Start up without attempting to load a configuration file. We need to be
|
49
|
-
# able to lookup configuration options like "application_root" which would
|
50
|
-
# then in turn influence where the configuration file came from.
|
51
|
-
#
|
52
|
-
# Later in initialization, we reset @config to include the file.
|
53
|
-
@config = ScoutApm::Config.without_file
|
54
|
-
|
55
|
-
@slow_request_policy = ScoutApm::SlowRequestPolicy.new
|
56
|
-
@slow_job_policy = ScoutApm::SlowJobPolicy.new
|
57
|
-
@request_histograms = ScoutApm::RequestHistograms.new
|
58
|
-
@request_histograms_by_time = Hash.new { |h, k| h[k] = ScoutApm::RequestHistograms.new }
|
59
|
-
|
60
|
-
@store = ScoutApm::Store.new
|
61
|
-
|
62
|
-
@layaway = ScoutApm::Layaway.new(config, environment)
|
63
|
-
@metric_lookup = Hash.new
|
64
|
-
|
65
|
-
@installed_instruments = []
|
26
|
+
@options = options
|
27
|
+
@context = ScoutApm::AgentContext.new
|
66
28
|
end
|
67
29
|
|
68
|
-
def
|
69
|
-
|
30
|
+
def logger
|
31
|
+
context.logger
|
70
32
|
end
|
71
33
|
|
72
|
-
|
73
|
-
|
74
|
-
|
34
|
+
# Finishes setting up the instrumentation, configuration, and attempts to start the agent.
|
35
|
+
def install(force=false)
|
36
|
+
context.config = ScoutApm::Config.with_file(context, context.config.value("config_file"))
|
75
37
|
|
76
|
-
|
77
|
-
def force?
|
78
|
-
@options[:force]
|
79
|
-
end
|
38
|
+
context.logger.info "Scout Agent [#{ScoutApm::VERSION}] Initialized"
|
80
39
|
|
81
|
-
|
82
|
-
if
|
83
|
-
logger.warn "Monitoring isn't enabled for the [#{environment.env}] environment. #{force? ? 'Forcing agent to start' : 'Not starting agent'}"
|
84
|
-
return false unless force?
|
85
|
-
end
|
40
|
+
@instrument_manager = ScoutApm::InstrumentManager.new(context)
|
41
|
+
@instrument_manager.install! if should_load_instruments? || force
|
86
42
|
|
87
|
-
|
88
|
-
|
89
|
-
return false unless force?
|
90
|
-
end
|
43
|
+
install_background_job_integrations
|
44
|
+
install_app_server_integration
|
91
45
|
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
46
|
+
# XXX: Should this happen at application start?
|
47
|
+
# Should this ever happen after fork?
|
48
|
+
# We start a thread in this, which can screw stuff up when we then fork.
|
49
|
+
#
|
50
|
+
# Save it into a variable to prevent it from ever running twice
|
51
|
+
@app_server_load ||= AppServerLoad.new(context).run
|
96
52
|
|
97
|
-
|
98
|
-
if force?
|
99
|
-
logger.warn "Agent starting (forced)"
|
100
|
-
else
|
101
|
-
logger.warn "Deferring agent start. Standing by for first request"
|
102
|
-
end
|
103
|
-
return false unless force?
|
104
|
-
end
|
53
|
+
logger.info "Scout Agent [#{ScoutApm::VERSION}] installed"
|
105
54
|
|
106
|
-
|
107
|
-
logger.warn "Already started agent."
|
108
|
-
return false
|
109
|
-
end
|
55
|
+
context.installed!
|
110
56
|
|
111
|
-
if
|
112
|
-
|
113
|
-
return false unless force?
|
57
|
+
if ScoutApm::Agent::Preconditions.check?(context) || force
|
58
|
+
start
|
114
59
|
end
|
115
|
-
|
116
|
-
true
|
117
60
|
end
|
118
61
|
|
119
|
-
#
|
120
|
-
#
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
init_logger
|
128
|
-
logger.info "Attempting to start Scout Agent [#{ScoutApm::VERSION}] on [#{environment.hostname}]"
|
129
|
-
|
130
|
-
@recorder = create_recorder
|
131
|
-
|
132
|
-
@config.log_settings
|
133
|
-
|
134
|
-
@ignored_uris = ScoutApm::IgnoredUris.new(config.value('ignore'))
|
135
|
-
|
136
|
-
load_instruments if should_load_instruments?(options)
|
137
|
-
|
138
|
-
if !@config.any_keys_found?
|
139
|
-
logger.info("No configuration file loaded, and no configuration found in ENV. " +
|
140
|
-
"For assistance configuring Scout, visit " +
|
141
|
-
"http://help.apm.scoutapp.com/#configuration-options")
|
62
|
+
# Unconditionally starts the agent. This includes verifying instruments are
|
63
|
+
# installed, and starting the background worker.
|
64
|
+
#
|
65
|
+
# Does not attempt to start twice.
|
66
|
+
def start(_opts={})
|
67
|
+
if context.started?
|
68
|
+
start_background_worker unless background_worker_running?
|
69
|
+
return
|
142
70
|
end
|
143
71
|
|
144
|
-
|
145
|
-
@started = true
|
146
|
-
logger.info "Starting monitoring for [#{environment.application_name}]. Framework [#{environment.framework}] App Server [#{environment.app_server}] Background Job Framework [#{environment.background_job_name}]."
|
72
|
+
install unless context.installed?
|
147
73
|
|
148
|
-
|
149
|
-
ScoutApm::Instruments::Process::ProcessMemory.new(logger),
|
150
|
-
ScoutApm::Instruments::PercentileSampler.new(logger, request_histograms_by_time),
|
151
|
-
].each { |s| store.add_sampler(s) }
|
74
|
+
context.started!
|
152
75
|
|
153
|
-
|
76
|
+
log_environment
|
154
77
|
|
155
|
-
|
156
|
-
environment.background_job_integration.install
|
157
|
-
logger.info "Installed Background Job Integration [#{environment.background_job_name}]"
|
158
|
-
end
|
159
|
-
|
160
|
-
# start_background_worker? is true on non-forking servers, and directly
|
161
|
-
# starts the background worker. On forking servers, a server-specific
|
162
|
-
# hook is inserted to start the background worker after forking.
|
163
|
-
if start_background_worker?
|
164
|
-
start_background_worker
|
165
|
-
logger.info "Scout Agent [#{ScoutApm::VERSION}] Initialized"
|
166
|
-
else
|
167
|
-
environment.app_server_integration.install
|
168
|
-
logger.info "Scout Agent [#{ScoutApm::VERSION}] loaded in [#{environment.app_server}] master process. Monitoring will start after server forks its workers."
|
169
|
-
end
|
78
|
+
start_background_worker
|
170
79
|
end
|
171
80
|
|
172
|
-
|
173
|
-
|
174
|
-
def app_server_load_hook
|
175
|
-
AppServerLoad.new.run
|
176
|
-
end
|
81
|
+
def log_environment
|
82
|
+
bg_names = context.environment.background_job_integrations.map{|bg| bg.name }.join(", ")
|
177
83
|
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
elsif environment.rubinius?
|
186
|
-
logger.debug "Exit handler not supported for Rubinius"
|
187
|
-
false
|
188
|
-
else
|
189
|
-
true
|
190
|
-
end
|
84
|
+
logger.info(
|
85
|
+
"Scout Agent [#{ScoutApm::VERSION}] starting for [#{context.environment.application_name}] " +
|
86
|
+
"Framework [#{context.environment.framework}] " +
|
87
|
+
"App Server [#{context.environment.app_server}] " +
|
88
|
+
"Background Job Framework [#{bg_names}] " +
|
89
|
+
"Hostname [#{context.environment.hostname}]"
|
90
|
+
)
|
191
91
|
end
|
192
92
|
|
193
|
-
#
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
logger.info "
|
200
|
-
# MRI 1.9 bug drops exit codes.
|
201
|
-
# http://bugs.ruby-lang.org/issues/5218
|
202
|
-
if environment.ruby_19?
|
203
|
-
status = $!.status if $!.is_a?(SystemExit)
|
204
|
-
shutdown
|
205
|
-
exit status if status
|
206
|
-
else
|
207
|
-
shutdown
|
208
|
-
end
|
93
|
+
# Attempts to install all background job integrations. This can come up if
|
94
|
+
# an app has both Resque and Sidekiq - we want both to be installed if
|
95
|
+
# possible, it's no harm to have the "wrong" one also installed while running.
|
96
|
+
def install_background_job_integrations
|
97
|
+
context.environment.background_job_integrations.each do |int|
|
98
|
+
int.install
|
99
|
+
logger.info "Installed Background Job Integration [#{int.name}]"
|
209
100
|
end
|
210
101
|
end
|
211
102
|
|
212
|
-
#
|
213
|
-
#
|
214
|
-
#
|
215
|
-
|
216
|
-
|
217
|
-
logger.info "
|
218
|
-
|
219
|
-
return if !started?
|
220
|
-
|
221
|
-
return if @shutdown
|
222
|
-
@shutdown = true
|
223
|
-
|
224
|
-
if @background_worker
|
225
|
-
logger.info("Stopping background worker")
|
226
|
-
@background_worker.stop
|
227
|
-
store.write_to_layaway(layaway, :force)
|
228
|
-
if @background_worker_thread.alive?
|
229
|
-
@background_worker_thread.wakeup
|
230
|
-
@background_worker_thread.join
|
231
|
-
end
|
232
|
-
end
|
233
|
-
ScoutApm::Instruments::Stacks.uninstall
|
103
|
+
# This sets up the background worker thread to run at the correct time,
|
104
|
+
# either immediately, or after a fork into the actual unicorn/puma/etc
|
105
|
+
# worker
|
106
|
+
def install_app_server_integration
|
107
|
+
context.environment.app_server_integration.install
|
108
|
+
logger.info "Installed Application Server Integration [#{context.environment.app_server}]."
|
234
109
|
end
|
235
110
|
|
236
|
-
|
237
|
-
|
111
|
+
# If true, the agent will start regardless of safety checks.
|
112
|
+
def force?
|
113
|
+
@options[:force]
|
238
114
|
end
|
239
115
|
|
240
116
|
# The worker thread will automatically start UNLESS:
|
@@ -242,161 +118,80 @@ module ScoutApm
|
|
242
118
|
# * A supported application server is detected, but it forks. In this case,
|
243
119
|
# the agent is started in the forked process.
|
244
120
|
def start_background_worker?
|
245
|
-
return true if environment.app_server == :thin
|
246
|
-
return true if environment.app_server == :webrick
|
247
121
|
return true if force?
|
248
|
-
return !environment.forking?
|
122
|
+
return !context.environment.forking?
|
249
123
|
end
|
250
124
|
|
251
|
-
def
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
125
|
+
def should_load_instruments?
|
126
|
+
return true if context.config.value('dev_trace')
|
127
|
+
# XXX: If monitor is true, we want to install, right?
|
128
|
+
# return false if context.config.value('monitor')
|
129
|
+
context.environment.app_server_integration.found? || context.environment.background_job_integration
|
256
130
|
end
|
257
131
|
|
132
|
+
#################################
|
133
|
+
# Background Worker Lifecycle #
|
134
|
+
#################################
|
135
|
+
|
258
136
|
# Creates the worker thread. The worker thread is a loop that runs continuously. It sleeps for +Agent#period+ and when it wakes,
|
259
137
|
# processes data, either saving it to disk or reporting to Scout.
|
260
|
-
|
261
|
-
|
262
|
-
|
138
|
+
# => true if thread & worker got started
|
139
|
+
# => false if it wasn't started (either due to already running, or other preconditions)
|
140
|
+
def start_background_worker(quiet=false)
|
141
|
+
if !context.config.value('monitor')
|
142
|
+
logger.debug "Not starting background worker as monitoring isn't enabled." unless quiet
|
263
143
|
return false
|
264
144
|
end
|
265
|
-
|
145
|
+
|
146
|
+
if background_worker_running?
|
147
|
+
logger.info "Not starting background worker, already started" unless quiet
|
148
|
+
return false
|
149
|
+
end
|
150
|
+
|
151
|
+
if context.shutting_down?
|
152
|
+
logger.info "Not starting background worker, already in process of shutting down" unless quiet
|
153
|
+
return false
|
154
|
+
end
|
155
|
+
|
266
156
|
logger.info "Initializing worker thread."
|
267
157
|
|
268
|
-
|
158
|
+
ScoutApm::Agent::ExitHandler.new(context).install
|
269
159
|
|
270
|
-
if
|
160
|
+
if context.config.value('profile')
|
271
161
|
# After we fork, setup the handlers here.
|
272
162
|
ScoutApm::Instruments::Stacks.install
|
273
163
|
ScoutApm::Instruments::Stacks.start
|
274
164
|
end
|
275
165
|
|
276
|
-
|
277
|
-
logger.info("recorder is now: #{@recorder.class}")
|
166
|
+
periodic_work = ScoutApm::PeriodicWork.new(context)
|
278
167
|
|
279
|
-
@background_worker = ScoutApm::BackgroundWorker.new
|
168
|
+
@background_worker = ScoutApm::BackgroundWorker.new(context)
|
280
169
|
@background_worker_thread = Thread.new do
|
281
170
|
@background_worker.start {
|
282
|
-
|
283
|
-
ScoutApm::Agent.instance.process_metrics
|
284
|
-
clean_old_percentiles
|
171
|
+
periodic_work.run
|
285
172
|
}
|
286
173
|
end
|
287
|
-
end
|
288
174
|
|
289
|
-
|
290
|
-
request_histograms_by_time.
|
291
|
-
keys.
|
292
|
-
select {|timestamp| timestamp.age_in_seconds > 60 * 10 }.
|
293
|
-
each {|old_timestamp| request_histograms_by_time.delete(old_timestamp) }
|
175
|
+
return true
|
294
176
|
end
|
295
177
|
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
# Loads the instrumention logic.
|
305
|
-
def load_instruments
|
306
|
-
case environment.framework
|
307
|
-
when :rails then
|
308
|
-
install_instrument(ScoutApm::Instruments::ActionControllerRails2)
|
309
|
-
when :rails3_or_4 then
|
310
|
-
install_instrument(ScoutApm::Instruments::ActionControllerRails3Rails4)
|
311
|
-
install_instrument(ScoutApm::Instruments::RailsRouter)
|
312
|
-
|
313
|
-
if config.value("detailed_middleware")
|
314
|
-
install_instrument(ScoutApm::Instruments::MiddlewareDetailed)
|
315
|
-
else
|
316
|
-
install_instrument(ScoutApm::Instruments::MiddlewareSummary)
|
178
|
+
def stop_background_worker
|
179
|
+
if @background_worker
|
180
|
+
logger.info("Stopping background worker")
|
181
|
+
@background_worker.stop
|
182
|
+
context.store.write_to_layaway(context.layaway, :force)
|
183
|
+
if @background_worker_thread.alive?
|
184
|
+
@background_worker_thread.wakeup
|
185
|
+
@background_worker_thread.join
|
317
186
|
end
|
318
187
|
end
|
319
|
-
|
320
|
-
install_instrument(ScoutApm::Instruments::ActionView)
|
321
|
-
install_instrument(ScoutApm::Instruments::ActiveRecord)
|
322
|
-
install_instrument(ScoutApm::Instruments::Moped)
|
323
|
-
install_instrument(ScoutApm::Instruments::Mongoid)
|
324
|
-
install_instrument(ScoutApm::Instruments::NetHttp)
|
325
|
-
install_instrument(ScoutApm::Instruments::HttpClient)
|
326
|
-
install_instrument(ScoutApm::Instruments::Redis)
|
327
|
-
install_instrument(ScoutApm::Instruments::InfluxDB)
|
328
|
-
install_instrument(ScoutApm::Instruments::Elasticsearch)
|
329
|
-
install_instrument(ScoutApm::Instruments::Grape)
|
330
|
-
rescue
|
331
|
-
logger.warn "Exception loading instruments:"
|
332
|
-
logger.warn $!.message
|
333
|
-
logger.warn $!.backtrace
|
334
|
-
end
|
335
|
-
|
336
|
-
def install_instrument(instrument_klass)
|
337
|
-
# Don't attempt to install the same instrument twice
|
338
|
-
return if @installed_instruments.any? { |already_installed_instrument| instrument_klass === already_installed_instrument }
|
339
|
-
|
340
|
-
# Allow users to skip individual instruments via the config file
|
341
|
-
instrument_short_name = instrument_klass.name.split("::").last
|
342
|
-
if (config.value("disabled_instruments") || []).include?(instrument_short_name)
|
343
|
-
logger.info "Skipping Disabled Instrument: #{instrument_short_name} - To re-enable, change `disabled_instruments` key in scout_apm.yml"
|
344
|
-
return
|
345
|
-
end
|
346
|
-
|
347
|
-
instance = instrument_klass.new
|
348
|
-
@installed_instruments << instance
|
349
|
-
instance.install
|
350
|
-
end
|
351
|
-
|
352
|
-
def app_server_missing?(options = {})
|
353
|
-
!environment.app_server_integration(true).found? && !options[:skip_app_server_check]
|
354
|
-
end
|
355
|
-
|
356
|
-
def background_job_missing?(options = {})
|
357
|
-
environment.background_job_integration.nil? && !options[:skip_background_job_check]
|
358
188
|
end
|
359
189
|
|
360
|
-
def
|
361
|
-
@
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
if @recorder
|
366
|
-
return @recorder
|
367
|
-
end
|
368
|
-
|
369
|
-
if config.value("async_recording")
|
370
|
-
logger.debug("Using asynchronous recording")
|
371
|
-
ScoutApm::BackgroundRecorder.new(logger).start
|
372
|
-
else
|
373
|
-
logger.debug("Using synchronous recording")
|
374
|
-
ScoutApm::SynchronousRecorder.new(logger).start
|
375
|
-
end
|
376
|
-
end
|
377
|
-
|
378
|
-
def start_remote_server(bind, port)
|
379
|
-
return if @remote_server && @remote_server.running?
|
380
|
-
|
381
|
-
logger.info("Starting Remote Agent Server")
|
382
|
-
|
383
|
-
# Start the listening web server only in parent process.
|
384
|
-
@remote_server = ScoutApm::Remote::Server.new(
|
385
|
-
bind,
|
386
|
-
port,
|
387
|
-
ScoutApm::Remote::Router.new(ScoutApm::SynchronousRecorder.new(logger), logger),
|
388
|
-
logger
|
389
|
-
)
|
390
|
-
|
391
|
-
@remote_server.start
|
392
|
-
end
|
393
|
-
|
394
|
-
# Execute this in the child process of a remote agent. The parent is
|
395
|
-
# expected to have its accepting webserver up and running
|
396
|
-
def use_remote_recorder(host, port)
|
397
|
-
logger.debug("Becoming Remote Agent (reporting to: #{host}:#{port})")
|
398
|
-
@recorder = ScoutApm::Remote::Recorder.new(host, port, logger)
|
399
|
-
@store = ScoutApm::FakeStore.new
|
190
|
+
def background_worker_running?
|
191
|
+
@background_worker_thread &&
|
192
|
+
@background_worker_thread.alive? &&
|
193
|
+
@background_worker &&
|
194
|
+
@background_worker.running?
|
400
195
|
end
|
401
196
|
end
|
402
197
|
end
|