scout_apm 3.0.0.pre13 → 3.0.0.pre14
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.
- 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
|