scout_apm 2.3.5 → 2.4.0.pre
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/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
|