scout_apm 2.3.5 → 2.4.0.pre
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.markdown +0 -23
- data/lib/scout_apm.rb +21 -10
- data/lib/scout_apm/agent.rb +98 -336
- data/lib/scout_apm/agent/exit_handler.rb +64 -0
- data/lib/scout_apm/agent/preconditions.rb +69 -0
- data/lib/scout_apm/agent_context.rb +226 -0
- data/lib/scout_apm/app_server_load.rb +20 -18
- data/lib/scout_apm/background_job_integrations/resque.rb +7 -8
- data/lib/scout_apm/background_job_integrations/sidekiq.rb +2 -8
- 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 -29
- 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 +16 -11
- data/lib/scout_apm/instruments/action_view.rb +11 -7
- data/lib/scout_apm/instruments/active_record.rb +28 -51
- 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 +11 -10
- 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 +11 -9
- 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 +26 -39
- data/lib/scout_apm/layaway_file.rb +8 -3
- data/lib/scout_apm/layer.rb +1 -1
- data/lib/scout_apm/layer_converters/converter_base.rb +4 -2
- 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/remote/server.rb +0 -2
- data/lib/scout_apm/reporter.rb +14 -8
- data/lib/scout_apm/reporting.rb +135 -0
- data/lib/scout_apm/request_manager.rb +4 -7
- 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 +23 -35
- 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 +4 -6
- data/lib/scout_apm/version.rb +1 -1
- data/lib/tasks/doctor.rake +11 -0
- data/test/test_helper.rb +15 -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
- metadata +15 -7
- 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: cd45ad6c823f8163081d1a4083f1740823351551
|
4
|
+
data.tar.gz: 822bdbc9113c78762a31258b166fe71786bb3448
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6c041d9e89c7dd58588755d805ff88dce9d55ddc38733143e92b32cb1cc8c2d53f577540f69dcc6af8aabb217903ef11c8dc8fe8981e191edc5239c42a1e9317
|
7
|
+
data.tar.gz: 4d70647935de5bcd27fbaa04f3b4a5e657cb01f13e7384ea17f57ee6bbcf5c73b30bfeb7c37c66bda2688069c4b7c5af61e29098a61c293ba06e1f2a3c1358aa
|
data/CHANGELOG.markdown
CHANGED
@@ -1,26 +1,3 @@
|
|
1
|
-
# 2.3.5
|
2
|
-
|
3
|
-
* More robust recovery from stale layaway files
|
4
|
-
* Quiet logging when hitting unusual layaway file limits
|
5
|
-
* Better naming for Sidekiq delayed method jobs
|
6
|
-
* Webrick is only required if actually needed
|
7
|
-
|
8
|
-
# 2.3.4
|
9
|
-
|
10
|
-
* Capture 300 characters of a url from net/http and httpclient instruments (up from 100).
|
11
|
-
|
12
|
-
# 2.3.3
|
13
|
-
|
14
|
-
* Capture ActiveRecord calls that generate more complex queries
|
15
|
-
* More aggressively determine names of complex queries (to determine "User/find", "Account/create" and similar)
|
16
|
-
* Increases the maximum size of SQL queries that are sanitized to 16KB from 4 KB
|
17
|
-
* Captures all SQL individual queries generated in a given AR call (previous only a single query was captured)
|
18
|
-
|
19
|
-
# 2.3.2
|
20
|
-
|
21
|
-
* More robust startup sequence when using `rails server` vs. directly launching an app server
|
22
|
-
* Avoid incompatibility with 3rd party gems that aggressively obtain database connections
|
23
|
-
|
24
1
|
# 2.3.1
|
25
2
|
|
26
3
|
* Fix DevTrace bug
|
data/lib/scout_apm.rb
CHANGED
@@ -14,6 +14,7 @@ require 'socket'
|
|
14
14
|
require 'thread'
|
15
15
|
require 'time'
|
16
16
|
require 'yaml'
|
17
|
+
require 'webrick'
|
17
18
|
|
18
19
|
#####################################
|
19
20
|
# Gem Requires
|
@@ -79,16 +80,18 @@ require 'scout_apm/instruments/elasticsearch'
|
|
79
80
|
require 'scout_apm/instruments/active_record'
|
80
81
|
require 'scout_apm/instruments/action_controller_rails_2'
|
81
82
|
require 'scout_apm/instruments/action_controller_rails_3_rails4'
|
83
|
+
require 'scout_apm/instruments/action_view'
|
82
84
|
require 'scout_apm/instruments/middleware_summary'
|
83
85
|
require 'scout_apm/instruments/middleware_detailed' # Disabled by default, see the file for more details
|
84
86
|
require 'scout_apm/instruments/rails_router'
|
85
87
|
require 'scout_apm/instruments/grape'
|
86
88
|
require 'scout_apm/instruments/sinatra'
|
89
|
+
require 'allocations'
|
90
|
+
|
87
91
|
require 'scout_apm/instruments/process/process_cpu'
|
88
92
|
require 'scout_apm/instruments/process/process_memory'
|
89
93
|
require 'scout_apm/instruments/percentile_sampler'
|
90
|
-
require 'scout_apm/instruments/
|
91
|
-
require 'allocations'
|
94
|
+
require 'scout_apm/instruments/samplers'
|
92
95
|
|
93
96
|
require 'scout_apm/app_server_load'
|
94
97
|
|
@@ -97,7 +100,6 @@ require 'scout_apm/utils/active_record_metric_name'
|
|
97
100
|
require 'scout_apm/utils/backtrace_parser'
|
98
101
|
require 'scout_apm/utils/installed_gems'
|
99
102
|
require 'scout_apm/utils/klass_helper'
|
100
|
-
require 'scout_apm/utils/null_logger'
|
101
103
|
require 'scout_apm/utils/scm'
|
102
104
|
require 'scout_apm/utils/sql_sanitizer'
|
103
105
|
require 'scout_apm/utils/time'
|
@@ -108,8 +110,8 @@ require 'scout_apm/utils/gzip_helper'
|
|
108
110
|
require 'scout_apm/config'
|
109
111
|
require 'scout_apm/environment'
|
110
112
|
require 'scout_apm/agent'
|
111
|
-
require 'scout_apm/
|
112
|
-
require 'scout_apm/
|
113
|
+
require 'scout_apm/logger'
|
114
|
+
require 'scout_apm/reporting'
|
113
115
|
require 'scout_apm/layaway'
|
114
116
|
require 'scout_apm/layaway_file'
|
115
117
|
require 'scout_apm/reporter'
|
@@ -162,6 +164,14 @@ require 'scout_apm/remote/message'
|
|
162
164
|
require 'scout_apm/remote/recorder'
|
163
165
|
require 'scout_apm/instruments/resque'
|
164
166
|
|
167
|
+
require 'scout_apm/agent_context'
|
168
|
+
require 'scout_apm/instrument_manager'
|
169
|
+
require 'scout_apm/periodic_work'
|
170
|
+
require 'scout_apm/agent/preconditions'
|
171
|
+
require 'scout_apm/agent/exit_handler'
|
172
|
+
require 'scout_apm/tasks/doctor'
|
173
|
+
require 'scout_apm/tasks/support'
|
174
|
+
|
165
175
|
if defined?(Rails) && defined?(Rails::VERSION) && defined?(Rails::VERSION::MAJOR) && Rails::VERSION::MAJOR >= 3 && defined?(Rails::Railtie)
|
166
176
|
module ScoutApm
|
167
177
|
class Railtie < Rails::Railtie
|
@@ -172,17 +182,18 @@ if defined?(Rails) && defined?(Rails::VERSION) && defined?(Rails::VERSION::MAJOR
|
|
172
182
|
app.middleware.use ScoutApm::Middleware
|
173
183
|
|
174
184
|
# Attempt to start right away, this will work best for preloading apps, Unicorn & Puma & similar
|
175
|
-
ScoutApm::Agent.instance.
|
176
|
-
|
177
|
-
end
|
178
|
-
class Railtie < Rails::Railtie
|
179
|
-
initializer 'scout_apm.start' do |app|
|
185
|
+
ScoutApm::Agent.instance.install
|
186
|
+
|
180
187
|
# Install the middleware every time in development mode.
|
181
188
|
# The middleware is a noop if dev_trace is not enabled in config
|
182
189
|
if Rails.env.development?
|
183
190
|
app.middleware.use ScoutApm::Instant::Middleware
|
184
191
|
end
|
185
192
|
end
|
193
|
+
|
194
|
+
rake_tasks do
|
195
|
+
load "tasks/doctor.rake"
|
196
|
+
end
|
186
197
|
end
|
187
198
|
end
|
188
199
|
else
|
data/lib/scout_apm/agent.rb
CHANGED
@@ -1,244 +1,110 @@
|
|
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
|
-
@process_start_time = Time.now
|
44
|
-
@options ||= options
|
45
|
-
|
46
|
-
# until the agent is started, there's no recorder
|
47
|
-
@recorder = nil
|
48
|
-
|
49
|
-
# Start up without attempting to load a configuration file. We need to be
|
50
|
-
# able to lookup configuration options like "application_root" which would
|
51
|
-
# then in turn influence where the configuration file came from.
|
52
|
-
#
|
53
|
-
# Later in initialization, we reset @config to include the file.
|
54
|
-
@config = ScoutApm::Config.without_file
|
55
|
-
|
56
|
-
@slow_request_policy = ScoutApm::SlowRequestPolicy.new
|
57
|
-
@slow_job_policy = ScoutApm::SlowJobPolicy.new
|
58
|
-
@request_histograms = ScoutApm::RequestHistograms.new
|
59
|
-
@request_histograms_by_time = Hash.new { |h, k| h[k] = ScoutApm::RequestHistograms.new }
|
60
|
-
|
61
|
-
@store = ScoutApm::Store.new
|
62
|
-
|
63
|
-
@layaway = ScoutApm::Layaway.new(config, environment)
|
64
|
-
@metric_lookup = Hash.new
|
65
|
-
|
66
|
-
@installed_instruments = []
|
26
|
+
@options = options
|
27
|
+
@context = ScoutApm::AgentContext.new
|
67
28
|
end
|
68
29
|
|
69
|
-
def
|
70
|
-
|
30
|
+
def logger
|
31
|
+
context.logger
|
71
32
|
end
|
72
33
|
|
73
|
-
|
74
|
-
|
75
|
-
|
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"))
|
76
37
|
|
77
|
-
|
78
|
-
def force?
|
79
|
-
@options[:force]
|
80
|
-
end
|
38
|
+
context.logger.info "Scout Agent [#{ScoutApm::VERSION}] Initialized"
|
81
39
|
|
82
|
-
|
83
|
-
if
|
84
|
-
logger.warn "Monitoring isn't enabled for the [#{environment.env}] environment. #{force? ? 'Forcing agent to start' : 'Not starting agent'}"
|
85
|
-
return false unless force?
|
86
|
-
end
|
40
|
+
@instrument_manager = ScoutApm::InstrumentManager.new(context)
|
41
|
+
@instrument_manager.install! if should_load_instruments? || force
|
87
42
|
|
88
|
-
|
89
|
-
|
90
|
-
return false unless force?
|
91
|
-
end
|
43
|
+
install_background_job_integrations
|
44
|
+
install_app_server_integration
|
92
45
|
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
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
|
+
AppServerLoad.new(context).run
|
97
50
|
|
98
|
-
|
99
|
-
if force?
|
100
|
-
logger.warn "Agent starting (forced)"
|
101
|
-
else
|
102
|
-
logger.warn "Deferring agent start. Standing by for first request"
|
103
|
-
end
|
104
|
-
return false unless force?
|
105
|
-
end
|
51
|
+
logger.info "Scout Agent [#{ScoutApm::VERSION}] installed"
|
106
52
|
|
107
|
-
|
108
|
-
logger.warn "Already started agent."
|
109
|
-
return false
|
110
|
-
end
|
53
|
+
context.installed!
|
111
54
|
|
112
|
-
if
|
113
|
-
|
114
|
-
return false unless force?
|
55
|
+
if ScoutApm::Agent::Preconditions.check?(context) || force
|
56
|
+
start
|
115
57
|
end
|
116
|
-
|
117
|
-
true
|
118
58
|
end
|
119
59
|
|
120
|
-
#
|
121
|
-
#
|
122
|
-
|
123
|
-
|
60
|
+
# Unconditionally starts the agent. This includes verifying instruments are
|
61
|
+
# installed, and starting the background worker.
|
62
|
+
#
|
63
|
+
# Does not attempt to start twice.
|
64
|
+
def start
|
65
|
+
return if context.started?
|
66
|
+
install unless context.installed?
|
124
67
|
|
125
|
-
|
126
|
-
layaway.config = config
|
68
|
+
context.started!
|
127
69
|
|
128
|
-
|
129
|
-
logger.info "Attempting to start Scout Agent [#{ScoutApm::VERSION}] on [#{environment.hostname}]"
|
130
|
-
|
131
|
-
@recorder = create_recorder
|
132
|
-
|
133
|
-
@config.log_settings
|
134
|
-
|
135
|
-
@ignored_uris = ScoutApm::IgnoredUris.new(config.value('ignore'))
|
136
|
-
|
137
|
-
load_instruments if should_load_instruments?(options)
|
138
|
-
|
139
|
-
if !@config.any_keys_found?
|
140
|
-
logger.info("No configuration file loaded, and no configuration found in ENV. " +
|
141
|
-
"For assistance configuring Scout, visit " +
|
142
|
-
"http://help.apm.scoutapp.com/#configuration-options")
|
143
|
-
end
|
70
|
+
log_environment
|
144
71
|
|
145
|
-
|
146
|
-
@started = true
|
147
|
-
logger.info "Starting monitoring for [#{environment.application_name}]. Framework [#{environment.framework}] App Server [#{environment.app_server}] Background Job Framework [#{environment.background_job_name}]."
|
148
|
-
|
149
|
-
[ ScoutApm::Instruments::Process::ProcessCpu.new(environment.processors, logger),
|
150
|
-
ScoutApm::Instruments::Process::ProcessMemory.new(logger),
|
151
|
-
ScoutApm::Instruments::PercentileSampler.new(logger, request_histograms_by_time),
|
152
|
-
].each { |s| store.add_sampler(s) }
|
153
|
-
|
154
|
-
app_server_load_hook
|
155
|
-
|
156
|
-
if environment.background_job_integration
|
157
|
-
environment.background_job_integration.install
|
158
|
-
logger.info "Installed Background Job Integration [#{environment.background_job_name}]"
|
159
|
-
end
|
160
|
-
|
161
|
-
# start_background_worker? is true on non-forking servers, and directly
|
162
|
-
# starts the background worker. On forking servers, a server-specific
|
163
|
-
# hook is inserted to start the background worker after forking.
|
164
|
-
if start_background_worker?
|
165
|
-
start_background_worker
|
166
|
-
logger.info "Scout Agent [#{ScoutApm::VERSION}] Initialized"
|
167
|
-
else
|
168
|
-
environment.app_server_integration.install
|
169
|
-
logger.info "Scout Agent [#{ScoutApm::VERSION}] loaded in [#{environment.app_server}] master process. Monitoring will start after server forks its workers."
|
170
|
-
end
|
72
|
+
start_background_worker
|
171
73
|
end
|
172
74
|
|
173
|
-
|
174
|
-
|
175
|
-
def app_server_load_hook
|
176
|
-
@app_server_load ||= AppServerLoad.new.run
|
177
|
-
end
|
75
|
+
def log_environment
|
76
|
+
bg_names = context.environment.background_job_integrations.map{|bg| bg.name }.join(", ")
|
178
77
|
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
elsif environment.rubinius?
|
187
|
-
logger.debug "Exit handler not supported for Rubinius"
|
188
|
-
false
|
189
|
-
else
|
190
|
-
true
|
191
|
-
end
|
78
|
+
logger.info(
|
79
|
+
"Scout Agent [#{ScoutApm::VERSION}] starting for [#{context.environment.application_name}] " +
|
80
|
+
"Framework [#{context.environment.framework}] " +
|
81
|
+
"App Server [#{context.environment.app_server}] " +
|
82
|
+
"Background Job Framework [#{bg_names}] " +
|
83
|
+
"Hostname [#{context.environment.hostname}]"
|
84
|
+
)
|
192
85
|
end
|
193
86
|
|
194
|
-
#
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
logger.info "
|
201
|
-
# MRI 1.9 bug drops exit codes.
|
202
|
-
# http://bugs.ruby-lang.org/issues/5218
|
203
|
-
if environment.ruby_19?
|
204
|
-
status = $!.status if $!.is_a?(SystemExit)
|
205
|
-
shutdown
|
206
|
-
exit status if status
|
207
|
-
else
|
208
|
-
shutdown
|
209
|
-
end
|
87
|
+
# Attempts to install all background job integrations. This can come up if
|
88
|
+
# an app has both Resque and Sidekiq - we want both to be installed if
|
89
|
+
# possible, it's no harm to have the "wrong" one also installed while running.
|
90
|
+
def install_background_job_integrations
|
91
|
+
context.environment.background_job_integrations.each do |int|
|
92
|
+
int.install
|
93
|
+
logger.info "Installed Background Job Integration [#{int.name}]"
|
210
94
|
end
|
211
95
|
end
|
212
96
|
|
213
|
-
#
|
214
|
-
#
|
215
|
-
#
|
216
|
-
|
217
|
-
|
218
|
-
logger.info "
|
219
|
-
|
220
|
-
return if !started?
|
221
|
-
|
222
|
-
return if @shutdown
|
223
|
-
@shutdown = true
|
224
|
-
|
225
|
-
if @background_worker
|
226
|
-
logger.info("Stopping background worker")
|
227
|
-
@background_worker.stop
|
228
|
-
store.write_to_layaway(layaway, :force)
|
229
|
-
if @background_worker_thread.alive?
|
230
|
-
@background_worker_thread.wakeup
|
231
|
-
@background_worker_thread.join
|
232
|
-
end
|
233
|
-
end
|
234
|
-
end
|
235
|
-
|
236
|
-
def started?
|
237
|
-
@started
|
97
|
+
# This sets up the background worker thread to run at the correct time,
|
98
|
+
# either immediately, or after a fork into the actual unicorn/puma/etc
|
99
|
+
# worker
|
100
|
+
def install_app_server_integration
|
101
|
+
context.environment.app_server_integration.install
|
102
|
+
logger.info "Installed Application Server Integration [#{context.environment.app_server}]."
|
238
103
|
end
|
239
104
|
|
240
|
-
|
241
|
-
|
105
|
+
# If true, the agent will start regardless of safety checks.
|
106
|
+
def force?
|
107
|
+
@options[:force]
|
242
108
|
end
|
243
109
|
|
244
110
|
# The worker thread will automatically start UNLESS:
|
@@ -246,167 +112,63 @@ module ScoutApm
|
|
246
112
|
# * A supported application server is detected, but it forks. In this case,
|
247
113
|
# the agent is started in the forked process.
|
248
114
|
def start_background_worker?
|
249
|
-
return true if environment.app_server == :thin
|
250
|
-
return true if environment.app_server == :webrick
|
251
115
|
return true if force?
|
252
|
-
return !environment.forking?
|
116
|
+
return !context.environment.forking?
|
253
117
|
end
|
254
118
|
|
255
|
-
def
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
119
|
+
def should_load_instruments?
|
120
|
+
return true if context.config.value('dev_trace')
|
121
|
+
# XXX: If monitor is true, we want to install, right?
|
122
|
+
# return false if context.config.value('monitor')
|
123
|
+
context.environment.app_server_integration.found? || context.environment.background_job_integration
|
260
124
|
end
|
261
125
|
|
262
|
-
|
263
|
-
#
|
264
|
-
|
265
|
-
|
266
|
-
def start_background_worker
|
267
|
-
if !
|
268
|
-
logger.debug "Not starting background worker as monitoring isn't enabled."
|
126
|
+
#################################
|
127
|
+
# Background Worker Lifecycle #
|
128
|
+
#################################
|
129
|
+
|
130
|
+
def start_background_worker
|
131
|
+
if !context.config.value('monitor')
|
132
|
+
logger.debug "Not starting background worker as monitoring isn't enabled."
|
269
133
|
return false
|
270
134
|
end
|
135
|
+
|
271
136
|
if background_worker_running?
|
272
|
-
logger.info "Not starting background worker, already started"
|
273
|
-
return
|
274
|
-
end
|
275
|
-
if shutting_down?
|
276
|
-
logger.info "Not starting background worker, already in process of shutting down" unless quiet
|
277
|
-
return false
|
137
|
+
logger.info "Not starting background worker, already started"
|
138
|
+
return
|
278
139
|
end
|
279
140
|
|
280
141
|
logger.info "Initializing worker thread."
|
281
142
|
|
282
|
-
|
143
|
+
ScoutApm::Agent::ExitHandler.new(context).install
|
283
144
|
|
284
|
-
|
285
|
-
logger.info("Recorder is now: #{@recorder.class}")
|
145
|
+
periodic_work = ScoutApm::PeriodicWork.new(context)
|
286
146
|
|
287
|
-
@background_worker = ScoutApm::BackgroundWorker.new
|
147
|
+
@background_worker = ScoutApm::BackgroundWorker.new(context)
|
288
148
|
@background_worker_thread = Thread.new do
|
289
149
|
@background_worker.start {
|
290
|
-
|
291
|
-
ScoutApm::Agent.instance.process_metrics
|
292
|
-
clean_old_percentiles
|
150
|
+
periodic_work.run
|
293
151
|
}
|
294
152
|
end
|
295
|
-
|
296
|
-
return true
|
297
|
-
end
|
298
|
-
|
299
|
-
def clean_old_percentiles
|
300
|
-
request_histograms_by_time.
|
301
|
-
keys.
|
302
|
-
select {|timestamp| timestamp.age_in_seconds > 60 * 10 }.
|
303
|
-
each {|old_timestamp| request_histograms_by_time.delete(old_timestamp) }
|
304
|
-
end
|
305
|
-
|
306
|
-
# If we want to skip the app_server_check, then we must load it.
|
307
|
-
def should_load_instruments?(options={})
|
308
|
-
return true if options[:skip_app_server_check]
|
309
|
-
return true if config.value('dev_trace')
|
310
|
-
return false if !apm_enabled?
|
311
|
-
environment.app_server_integration.found? || !background_job_missing?
|
312
153
|
end
|
313
154
|
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
if config.value("detailed_middleware")
|
324
|
-
install_instrument(ScoutApm::Instruments::MiddlewareDetailed)
|
325
|
-
else
|
326
|
-
install_instrument(ScoutApm::Instruments::MiddlewareSummary)
|
155
|
+
def stop_background_worker
|
156
|
+
if @background_worker
|
157
|
+
logger.info("Stopping background worker")
|
158
|
+
@background_worker.stop
|
159
|
+
context.store.write_to_layaway(context.layaway, :force)
|
160
|
+
if @background_worker_thread.alive?
|
161
|
+
@background_worker_thread.wakeup
|
162
|
+
@background_worker_thread.join
|
327
163
|
end
|
328
164
|
end
|
329
|
-
|
330
|
-
install_instrument(ScoutApm::Instruments::ActionView)
|
331
|
-
install_instrument(ScoutApm::Instruments::ActiveRecord)
|
332
|
-
install_instrument(ScoutApm::Instruments::Moped)
|
333
|
-
install_instrument(ScoutApm::Instruments::Mongoid)
|
334
|
-
install_instrument(ScoutApm::Instruments::NetHttp)
|
335
|
-
install_instrument(ScoutApm::Instruments::HttpClient)
|
336
|
-
install_instrument(ScoutApm::Instruments::Redis)
|
337
|
-
install_instrument(ScoutApm::Instruments::InfluxDB)
|
338
|
-
install_instrument(ScoutApm::Instruments::Elasticsearch)
|
339
|
-
install_instrument(ScoutApm::Instruments::Grape)
|
340
|
-
rescue
|
341
|
-
logger.warn "Exception loading instruments:"
|
342
|
-
logger.warn $!.message
|
343
|
-
logger.warn $!.backtrace
|
344
165
|
end
|
345
166
|
|
346
|
-
def
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
|
351
|
-
instrument_short_name = instrument_klass.name.split("::").last
|
352
|
-
if (config.value("disabled_instruments") || []).include?(instrument_short_name)
|
353
|
-
logger.info "Skipping Disabled Instrument: #{instrument_short_name} - To re-enable, change `disabled_instruments` key in scout_apm.yml"
|
354
|
-
return
|
355
|
-
end
|
356
|
-
|
357
|
-
instance = instrument_klass.new
|
358
|
-
@installed_instruments << instance
|
359
|
-
instance.install
|
360
|
-
end
|
361
|
-
|
362
|
-
def app_server_missing?(options = {})
|
363
|
-
!environment.app_server_integration(true).found? && !options[:skip_app_server_check]
|
364
|
-
end
|
365
|
-
|
366
|
-
def background_job_missing?(options = {})
|
367
|
-
environment.background_job_integration.nil? && !options[:skip_background_job_check]
|
368
|
-
end
|
369
|
-
|
370
|
-
def clear_recorder
|
371
|
-
@recorder = nil
|
372
|
-
end
|
373
|
-
|
374
|
-
def create_recorder
|
375
|
-
if @recorder
|
376
|
-
return @recorder
|
377
|
-
end
|
378
|
-
|
379
|
-
if config.value("async_recording")
|
380
|
-
logger.debug("Using asynchronous recording")
|
381
|
-
ScoutApm::BackgroundRecorder.new(logger).start
|
382
|
-
else
|
383
|
-
logger.debug("Using synchronous recording")
|
384
|
-
ScoutApm::SynchronousRecorder.new(logger).start
|
385
|
-
end
|
386
|
-
end
|
387
|
-
|
388
|
-
def start_remote_server(bind, port)
|
389
|
-
return if @remote_server && @remote_server.running?
|
390
|
-
|
391
|
-
logger.info("Starting Remote Agent Server")
|
392
|
-
|
393
|
-
# Start the listening web server only in parent process.
|
394
|
-
@remote_server = ScoutApm::Remote::Server.new(
|
395
|
-
bind,
|
396
|
-
port,
|
397
|
-
ScoutApm::Remote::Router.new(ScoutApm::SynchronousRecorder.new(logger), logger),
|
398
|
-
logger
|
399
|
-
)
|
400
|
-
|
401
|
-
@remote_server.start
|
402
|
-
end
|
403
|
-
|
404
|
-
# Execute this in the child process of a remote agent. The parent is
|
405
|
-
# expected to have its accepting webserver up and running
|
406
|
-
def use_remote_recorder(host, port)
|
407
|
-
logger.debug("Becoming Remote Agent (reporting to: #{host}:#{port})")
|
408
|
-
@recorder = ScoutApm::Remote::Recorder.new(host, port, logger)
|
409
|
-
@store = ScoutApm::FakeStore.new
|
167
|
+
def background_worker_running?
|
168
|
+
@background_worker_thread &&
|
169
|
+
@background_worker_thread.alive? &&
|
170
|
+
@background_worker &&
|
171
|
+
@background_worker.running?
|
410
172
|
end
|
411
173
|
end
|
412
174
|
end
|