scout_apm 2.1.29 → 2.1.30
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/CHANGELOG.markdown +4 -0
- data/Guardfile +42 -0
- data/lib/scout_apm/agent/logging.rb +6 -1
- data/lib/scout_apm/agent.rb +52 -2
- data/lib/scout_apm/background_job_integrations/resque.rb +85 -0
- data/lib/scout_apm/background_recorder.rb +43 -0
- data/lib/scout_apm/config.rb +11 -3
- data/lib/scout_apm/environment.rb +1 -0
- data/lib/scout_apm/instruments/resque.rb +30 -0
- data/lib/scout_apm/layer_children_set.rb +7 -2
- data/lib/scout_apm/remote/message.rb +23 -0
- data/lib/scout_apm/remote/recorder.rb +57 -0
- data/lib/scout_apm/remote/router.rb +49 -0
- data/lib/scout_apm/remote/server.rb +58 -0
- data/lib/scout_apm/request_manager.rb +1 -1
- data/lib/scout_apm/synchronous_recorder.rb +26 -0
- data/lib/scout_apm/tracked_request.rb +51 -4
- data/lib/scout_apm/version.rb +1 -1
- data/lib/scout_apm.rb +10 -0
- data/scout_apm.gemspec +2 -0
- data/test/unit/remote/test_message.rb +13 -0
- data/test/unit/remote/test_router.rb +33 -0
- data/test/unit/remote/test_server.rb +15 -0
- data/test/unit/test_tracked_request.rb +87 -0
- metadata +76 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 94cee593281d02b80d99aa3bf55a66fb4ef1adf9
|
4
|
+
data.tar.gz: a5aff2d47256429910ff7eb2e4f0c145bdca69f7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4a38d11380c58574636bf7ed6e086f890989edd7e7ef5a395e4d9cfecd11dc12c30206a85ea4f25324b28c4d92e49cad7be3e2e0ccd332a75f93497cc03b96d8
|
7
|
+
data.tar.gz: dd758e13ce68396da594a7d6bc8a04dc9f3f300d7bda905cb3676ca36a74b347ea9ace9f818b652b92150dfdb85d23656ad802c713660098f095b14d8ab88c11
|
data/.gitignore
CHANGED
data/CHANGELOG.markdown
CHANGED
data/Guardfile
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
# A sample Guardfile
|
2
|
+
# More info at https://github.com/guard/guard#readme
|
3
|
+
|
4
|
+
## Uncomment and set this to only include directories you want to watch
|
5
|
+
# directories %w(app lib config test spec features) \
|
6
|
+
# .select{|d| Dir.exists?(d) ? d : UI.warning("Directory #{d} does not exist")}
|
7
|
+
|
8
|
+
## Note: if you are using the `directories` clause above and you are not
|
9
|
+
## watching the project directory ('.'), then you will want to move
|
10
|
+
## the Guardfile to a watched dir and symlink it back, e.g.
|
11
|
+
#
|
12
|
+
# $ mkdir config
|
13
|
+
# $ mv Guardfile config/
|
14
|
+
# $ ln -s config/Guardfile .
|
15
|
+
#
|
16
|
+
# and, you'll have to watch "config/Guardfile" instead of "Guardfile"
|
17
|
+
|
18
|
+
guard :minitest do
|
19
|
+
# with Minitest::Unit
|
20
|
+
watch(%r{^test/(.*)\/?test_(.*)\.rb$})
|
21
|
+
watch(%r{^lib/(.*/)?([^/]+)\.rb$}) { |m| "test/#{m[1]}test_#{m[2]}.rb" }
|
22
|
+
watch(%r{^test/test_helper\.rb$}) { 'test' }
|
23
|
+
|
24
|
+
# with Minitest::Spec
|
25
|
+
# watch(%r{^spec/(.*)_spec\.rb$})
|
26
|
+
# watch(%r{^lib/(.+)\.rb$}) { |m| "spec/#{m[1]}_spec.rb" }
|
27
|
+
# watch(%r{^spec/spec_helper\.rb$}) { 'spec' }
|
28
|
+
|
29
|
+
# Rails 4
|
30
|
+
# watch(%r{^app/(.+)\.rb$}) { |m| "test/#{m[1]}_test.rb" }
|
31
|
+
# watch(%r{^app/controllers/application_controller\.rb$}) { 'test/controllers' }
|
32
|
+
# watch(%r{^app/controllers/(.+)_controller\.rb$}) { |m| "test/integration/#{m[1]}_test.rb" }
|
33
|
+
# watch(%r{^app/views/(.+)_mailer/.+}) { |m| "test/mailers/#{m[1]}_mailer_test.rb" }
|
34
|
+
# watch(%r{^lib/(.+)\.rb$}) { |m| "test/lib/#{m[1]}_test.rb" }
|
35
|
+
# watch(%r{^test/.+_test\.rb$})
|
36
|
+
# watch(%r{^test/test_helper\.rb$}) { 'test' }
|
37
|
+
|
38
|
+
# Rails < 4
|
39
|
+
# watch(%r{^app/controllers/(.*)\.rb$}) { |m| "test/functional/#{m[1]}_test.rb" }
|
40
|
+
# watch(%r{^app/helpers/(.*)\.rb$}) { |m| "test/helpers/#{m[1]}_test.rb" }
|
41
|
+
# watch(%r{^app/models/(.*)\.rb$}) { |m| "test/unit/#{m[1]}_test.rb" }
|
42
|
+
end
|
data/lib/scout_apm/agent.rb
CHANGED
@@ -10,6 +10,7 @@ module ScoutApm
|
|
10
10
|
|
11
11
|
# Accessors below are for associated classes
|
12
12
|
attr_accessor :store
|
13
|
+
attr_reader :recorder
|
13
14
|
attr_accessor :layaway
|
14
15
|
attr_accessor :config
|
15
16
|
attr_accessor :logger
|
@@ -41,6 +42,9 @@ module ScoutApm
|
|
41
42
|
@process_start_time = Time.now
|
42
43
|
@options ||= options
|
43
44
|
|
45
|
+
# until the agent is started, there's no recorder
|
46
|
+
@recorder = nil
|
47
|
+
|
44
48
|
# Start up without attempting to load a configuration file. We need to be
|
45
49
|
# able to lookup configuration options like "application_root" which would
|
46
50
|
# then in turn influence where the configuration file came from.
|
@@ -54,6 +58,7 @@ module ScoutApm
|
|
54
58
|
@request_histograms_by_time = Hash.new { |h, k| h[k] = ScoutApm::RequestHistograms.new }
|
55
59
|
|
56
60
|
@store = ScoutApm::Store.new
|
61
|
+
|
57
62
|
@layaway = ScoutApm::Layaway.new(config, environment)
|
58
63
|
@metric_lookup = Hash.new
|
59
64
|
|
@@ -111,13 +116,14 @@ module ScoutApm
|
|
111
116
|
def start(options = {})
|
112
117
|
@options.merge!(options)
|
113
118
|
|
114
|
-
|
115
119
|
@config = ScoutApm::Config.with_file(@config.value("config_file"))
|
116
120
|
layaway.config = config
|
117
121
|
|
118
122
|
init_logger
|
119
123
|
logger.info "Attempting to start Scout Agent [#{ScoutApm::VERSION}] on [#{environment.hostname}]"
|
120
124
|
|
125
|
+
@recorder = create_recorder
|
126
|
+
|
121
127
|
@config.log_settings
|
122
128
|
|
123
129
|
@ignored_uris = ScoutApm::IgnoredUris.new(config.value('ignore'))
|
@@ -134,7 +140,6 @@ module ScoutApm
|
|
134
140
|
@started = true
|
135
141
|
logger.info "Starting monitoring for [#{environment.application_name}]. Framework [#{environment.framework}] App Server [#{environment.app_server}] Background Job Framework [#{environment.background_job_name}]."
|
136
142
|
|
137
|
-
|
138
143
|
[ ScoutApm::Instruments::Process::ProcessCpu.new(environment.processors, logger),
|
139
144
|
ScoutApm::Instruments::Process::ProcessMemory.new(logger),
|
140
145
|
ScoutApm::Instruments::PercentileSampler.new(logger, request_histograms_by_time),
|
@@ -256,6 +261,9 @@ module ScoutApm
|
|
256
261
|
|
257
262
|
install_exit_handler
|
258
263
|
|
264
|
+
@recorder = create_recorder
|
265
|
+
logger.info("recorder is now: #{@recorder.class}")
|
266
|
+
|
259
267
|
@background_worker = ScoutApm::BackgroundWorker.new
|
260
268
|
@background_worker_thread = Thread.new do
|
261
269
|
@background_worker.start {
|
@@ -336,5 +344,47 @@ module ScoutApm
|
|
336
344
|
def background_job_missing?(options = {})
|
337
345
|
environment.background_job_integration.nil? && !options[:skip_background_job_check]
|
338
346
|
end
|
347
|
+
|
348
|
+
def clear_recorder
|
349
|
+
@recorder = nil
|
350
|
+
end
|
351
|
+
|
352
|
+
def create_recorder
|
353
|
+
if @recorder
|
354
|
+
return @recorder
|
355
|
+
end
|
356
|
+
|
357
|
+
if config.value("async_recording")
|
358
|
+
logger.debug("Using asynchronous recording")
|
359
|
+
ScoutApm::BackgroundRecorder.new(logger).start
|
360
|
+
else
|
361
|
+
logger.debug("Using synchronous recording")
|
362
|
+
ScoutApm::SynchronousRecorder.new(logger).start
|
363
|
+
end
|
364
|
+
end
|
365
|
+
|
366
|
+
def start_remote_server(bind, port)
|
367
|
+
return if @remote_server && @remote_server.running?
|
368
|
+
|
369
|
+
logger.info("Starting Remote Agent Server")
|
370
|
+
|
371
|
+
# Start the listening web server only in parent process.
|
372
|
+
@remote_server = ScoutApm::Remote::Server.new(
|
373
|
+
bind,
|
374
|
+
port,
|
375
|
+
ScoutApm::Remote::Router.new(ScoutApm::SynchronousRecorder.new(logger), logger),
|
376
|
+
logger
|
377
|
+
)
|
378
|
+
|
379
|
+
@remote_server.start
|
380
|
+
end
|
381
|
+
|
382
|
+
# Execute this in the child process of a remote agent. The parent is
|
383
|
+
# expected to have its accepting webserver up and running
|
384
|
+
def use_remote_recorder(host, port)
|
385
|
+
logger.debug("Becoming Remote Agent (reporting to: #{host}:#{port})")
|
386
|
+
@recorder = ScoutApm::Remote::Recorder.new(host, port, logger)
|
387
|
+
@store = ScoutApm::FakeStore.new
|
388
|
+
end
|
339
389
|
end
|
340
390
|
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
module ScoutApm
|
2
|
+
module BackgroundJobIntegrations
|
3
|
+
class Resque
|
4
|
+
def name
|
5
|
+
:resque
|
6
|
+
end
|
7
|
+
|
8
|
+
def present?
|
9
|
+
defined?(::Resque) &&
|
10
|
+
::Resque.respond_to?(:before_first_fork) &&
|
11
|
+
::Resque.respond_to?(:after_fork)
|
12
|
+
end
|
13
|
+
|
14
|
+
# Lies. This forks really aggressively, but we have to do handling
|
15
|
+
# of it manually here, rather than via any sort of automatic
|
16
|
+
# background worker starting
|
17
|
+
def forking?
|
18
|
+
false
|
19
|
+
end
|
20
|
+
|
21
|
+
def install
|
22
|
+
install_before_fork
|
23
|
+
install_after_fork
|
24
|
+
end
|
25
|
+
|
26
|
+
def install_before_fork
|
27
|
+
::Resque.before_first_fork do
|
28
|
+
begin
|
29
|
+
ScoutApm::Agent.instance.start(:skip_app_server_check => true)
|
30
|
+
ScoutApm::Agent.instance.start_background_worker
|
31
|
+
ScoutApm::Agent.instance.start_remote_server(bind, port)
|
32
|
+
rescue Errno::EADDRINUSE
|
33
|
+
ScoutApm::Agent.instance.logger.warn "Error while Installing Resque Instruments, Port #{port} already in use. Set via the `remote_agent_port` configuration option"
|
34
|
+
rescue => e
|
35
|
+
ScoutApm::Agent.instance.logger.warn "Error while Installing Resque before_first_fork: #{e.inspect}"
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def install_after_fork
|
41
|
+
::Resque.after_fork do
|
42
|
+
begin
|
43
|
+
ScoutApm::Agent.instance.use_remote_recorder(bind, port)
|
44
|
+
inject_job_instrument
|
45
|
+
rescue => e
|
46
|
+
ScoutApm::Agent.instance.logger.warn "Error while Installing Resque after_fork: #{e.inspect}"
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
# Insert ourselves into the point when resque turns a string "TestJob"
|
52
|
+
# into the class constant TestJob, and insert our instrumentation plugin
|
53
|
+
# into that constantized class
|
54
|
+
#
|
55
|
+
# This automates away any need for the user to insert our instrumentation into
|
56
|
+
# each of their jobs
|
57
|
+
def inject_job_instrument
|
58
|
+
::Resque::Job.class_eval do
|
59
|
+
def payload_class_with_scout_instruments
|
60
|
+
klass = payload_class_without_scout_instruments
|
61
|
+
klass.extend(ScoutApm::Instruments::Resque)
|
62
|
+
klass
|
63
|
+
end
|
64
|
+
alias_method :payload_class_without_scout_instruments, :payload_class
|
65
|
+
alias_method :payload_class, :payload_class_with_scout_instruments
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
private
|
70
|
+
|
71
|
+
def bind
|
72
|
+
config.value("remote_agent_host")
|
73
|
+
end
|
74
|
+
|
75
|
+
def port
|
76
|
+
config.value("remote_agent_port")
|
77
|
+
end
|
78
|
+
|
79
|
+
def config
|
80
|
+
@config || ScoutApm::Agent.instance.config
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# Provide a background thread queue to do the processing of
|
2
|
+
# TrackedRequest objects, to remove it from the hot-path of returning a
|
3
|
+
# web response
|
4
|
+
|
5
|
+
module ScoutApm
|
6
|
+
class BackgroundRecorder
|
7
|
+
attr_reader :queue
|
8
|
+
attr_reader :thread
|
9
|
+
attr_reader :logger
|
10
|
+
|
11
|
+
def initialize(logger)
|
12
|
+
@logger = logger
|
13
|
+
@queue = Queue.new
|
14
|
+
end
|
15
|
+
|
16
|
+
def start
|
17
|
+
logger.info("Starting BackgroundRecorder")
|
18
|
+
@thread = Thread.new(&method(:thread_func))
|
19
|
+
self
|
20
|
+
end
|
21
|
+
|
22
|
+
def stop
|
23
|
+
@thread.kill
|
24
|
+
end
|
25
|
+
|
26
|
+
def record!(request)
|
27
|
+
start unless @thread.alive?
|
28
|
+
@queue.push(request)
|
29
|
+
end
|
30
|
+
|
31
|
+
def thread_func
|
32
|
+
while req = queue.pop
|
33
|
+
begin
|
34
|
+
logger.debug("recording in thread. Queue size: #{queue.size}")
|
35
|
+
# For now, just proxy right back into the TrackedRequest object's record function
|
36
|
+
req.record!
|
37
|
+
rescue => e
|
38
|
+
logger.warn("Error in BackgroundRecorder - #{e.message} : #{e.backtrace}")
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
data/lib/scout_apm/config.rb
CHANGED
@@ -27,6 +27,8 @@ require 'scout_apm/environment'
|
|
27
27
|
# report_format - 'json' or 'marshal'. Marshal is legacy and will be removed.
|
28
28
|
# scm_subdirectory - if the app root lives in source management in a subdirectory. E.g. #{SCM_ROOT}/src
|
29
29
|
# uri_reporting - 'path' or 'full_path' default is 'full_path', which reports URL params as well as the path.
|
30
|
+
# remote_agent_host - Internal: What host to bind to, and also send messages to for remote. Default: 127.0.0.1.
|
31
|
+
# remote_agent_port - What port to bind the remote webserver to
|
30
32
|
#
|
31
33
|
# Any of these config settings can be set with an environment variable prefixed
|
32
34
|
# by SCOUT_ and uppercasing the key: SCOUT_LOG_LEVEL for instance.
|
@@ -35,6 +37,7 @@ module ScoutApm
|
|
35
37
|
class Config
|
36
38
|
KNOWN_CONFIG_OPTIONS = [
|
37
39
|
'application_root',
|
40
|
+
'async_recording',
|
38
41
|
'compress_payload',
|
39
42
|
'config_file',
|
40
43
|
'data_file',
|
@@ -53,6 +56,8 @@ module ScoutApm
|
|
53
56
|
'name',
|
54
57
|
'profile',
|
55
58
|
'proxy',
|
59
|
+
'remote_agent_host',
|
60
|
+
'remote_agent_port',
|
56
61
|
'report_format',
|
57
62
|
'scm_subdirectory',
|
58
63
|
'uri_reporting',
|
@@ -129,11 +134,12 @@ module ScoutApm
|
|
129
134
|
|
130
135
|
|
131
136
|
SETTING_COERCIONS = {
|
132
|
-
"
|
133
|
-
"enable_background_jobs" => BooleanCoercion.new,
|
134
|
-
"dev_trace" => BooleanCoercion.new,
|
137
|
+
"async_recording" => BooleanCoercion.new,
|
135
138
|
"detailed_middleware" => BooleanCoercion.new,
|
139
|
+
"dev_trace" => BooleanCoercion.new,
|
140
|
+
"enable_background_jobs" => BooleanCoercion.new,
|
136
141
|
"ignore" => JsonCoercion.new,
|
142
|
+
"monitor" => BooleanCoercion.new,
|
137
143
|
}
|
138
144
|
|
139
145
|
|
@@ -219,6 +225,8 @@ module ScoutApm
|
|
219
225
|
'report_format' => 'json',
|
220
226
|
'scm_subdirectory' => '',
|
221
227
|
'uri_reporting' => 'full_path',
|
228
|
+
'remote_agent_host' => '127.0.0.1',
|
229
|
+
'remote_agent_port' => 7721, # picked at random
|
222
230
|
}.freeze
|
223
231
|
|
224
232
|
def value(key)
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module ScoutApm
|
2
|
+
module Instruments
|
3
|
+
module Resque
|
4
|
+
def around_perform_with_scout_instruments(*args)
|
5
|
+
job_name = self.to_s
|
6
|
+
queue = @queue
|
7
|
+
|
8
|
+
req = ScoutApm::RequestManager.lookup
|
9
|
+
req.job!
|
10
|
+
# req.annotate_request(:queue_latency => latency(msg))
|
11
|
+
|
12
|
+
begin
|
13
|
+
req.start_layer(ScoutApm::Layer.new('Queue', queue))
|
14
|
+
started_queue = true
|
15
|
+
req.start_layer(ScoutApm::Layer.new('Job', job_name))
|
16
|
+
started_job = true
|
17
|
+
|
18
|
+
yield
|
19
|
+
rescue => e
|
20
|
+
req.error!
|
21
|
+
raise
|
22
|
+
ensure
|
23
|
+
req.stop_layer if started_job
|
24
|
+
req.stop_layer if started_queue
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
@@ -27,18 +27,23 @@ module ScoutApm
|
|
27
27
|
private :children
|
28
28
|
|
29
29
|
def initialize(unique_cutoff = DEFAULT_UNIQUE_CUTOFF)
|
30
|
-
@children = Hash.new
|
30
|
+
@children = Hash.new
|
31
31
|
@limited_layers = nil # populated when needed
|
32
32
|
@unique_cutoff = unique_cutoff
|
33
33
|
end
|
34
34
|
|
35
|
+
def child_set(metric_type)
|
36
|
+
children[metric_type] = Set.new if !children.has_key?(metric_type)
|
37
|
+
children[metric_type]
|
38
|
+
end
|
39
|
+
|
35
40
|
# Add a new layer into this set
|
36
41
|
# Only add completed layers - otherwise this will collect up incorrect info
|
37
42
|
# into the created LimitedLayer, since it will "freeze" any current data for
|
38
43
|
# total_call_time and similar methods.
|
39
44
|
def <<(child)
|
40
45
|
metric_type = child.type
|
41
|
-
set =
|
46
|
+
set = child_set(metric_type)
|
42
47
|
|
43
48
|
if set.size >= unique_cutoff
|
44
49
|
# find limited_layer
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module ScoutApm
|
2
|
+
module Remote
|
3
|
+
class Message
|
4
|
+
attr_reader :type
|
5
|
+
attr_reader :command
|
6
|
+
attr_reader :args
|
7
|
+
|
8
|
+
def initialize(type, command, *args)
|
9
|
+
@type = type
|
10
|
+
@command = command
|
11
|
+
@args = args
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.decode(msg)
|
15
|
+
Marshal.load(msg)
|
16
|
+
end
|
17
|
+
|
18
|
+
def encode
|
19
|
+
Marshal.dump(self)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
module ScoutApm
|
2
|
+
module Remote
|
3
|
+
class Recorder
|
4
|
+
attr_reader :logger
|
5
|
+
attr_reader :remote_agent_host
|
6
|
+
attr_reader :remote_agent_port
|
7
|
+
|
8
|
+
def initialize(remote_agent_host, remote_agent_port, logger)
|
9
|
+
@remote_agent_host = remote_agent_host
|
10
|
+
@remote_agent_port = remote_agent_port
|
11
|
+
@logger = logger
|
12
|
+
end
|
13
|
+
|
14
|
+
def start
|
15
|
+
# nothing to do
|
16
|
+
self
|
17
|
+
end
|
18
|
+
|
19
|
+
def stop
|
20
|
+
# nothing to do
|
21
|
+
end
|
22
|
+
|
23
|
+
def record!(request)
|
24
|
+
begin
|
25
|
+
t1 = Time.now
|
26
|
+
# Mark this request as recorded, so the next lookup on this thread, it
|
27
|
+
# can be recreated
|
28
|
+
request.recorded!
|
29
|
+
|
30
|
+
# Only send requests that we actually want. Incidental http &
|
31
|
+
# background thread stuff can just be dropped
|
32
|
+
unless request.job? || request.web?
|
33
|
+
return
|
34
|
+
end
|
35
|
+
|
36
|
+
request.prepare_to_dump!
|
37
|
+
message = ScoutApm::Remote::Message.new('record', 'record!', request)
|
38
|
+
encoded = message.encode
|
39
|
+
logger.debug "Remote Agent: Posting a message of length: #{encoded.length}"
|
40
|
+
post(encoded)
|
41
|
+
t2 = Time.now
|
42
|
+
|
43
|
+
logger.debug("Remote Recording took: #{t2.to_f - t1.to_f} seconds")
|
44
|
+
rescue => e
|
45
|
+
logger.debug "Remote: Error while sending to collector: #{e.inspect}, #{e.backtrace.join("\n")}"
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def post(encoded_message)
|
50
|
+
http = Net::HTTP.new(remote_agent_host, remote_agent_port)
|
51
|
+
request = Net::HTTP::Post.new("/users")
|
52
|
+
request.body = encoded_message
|
53
|
+
response = http.request(request)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module ScoutApm
|
2
|
+
module Remote
|
3
|
+
class Router
|
4
|
+
attr_reader :logger
|
5
|
+
attr_reader :routes
|
6
|
+
|
7
|
+
# If/When we add different types, this signature should change to a hash
|
8
|
+
# of {type => Object}, rather than building it in the initializer here.
|
9
|
+
#
|
10
|
+
# Keys of routes should be strings
|
11
|
+
def initialize(recorder, logger)
|
12
|
+
@routes = {
|
13
|
+
'record' => recorder
|
14
|
+
}
|
15
|
+
|
16
|
+
@logger = logger
|
17
|
+
end
|
18
|
+
|
19
|
+
# A message is a 2 element array [:type, :command, [args]].
|
20
|
+
# For this first creation, this should be ['record', 'record', [TrackedRequest]] (the args arg should always be an array, even w/ only 1 item)
|
21
|
+
#
|
22
|
+
# Where
|
23
|
+
# type: ['recorder']
|
24
|
+
# command: any function supported on that type of object
|
25
|
+
# args: any array of arguments
|
26
|
+
#
|
27
|
+
# Raises on unknown message
|
28
|
+
#
|
29
|
+
# Returns whatever the recipient object returns
|
30
|
+
def handle(msg)
|
31
|
+
message = Remote::Message.decode(msg)
|
32
|
+
assert_type(message)
|
33
|
+
call_route(message)
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def assert_type(message)
|
39
|
+
if ! routes.keys.include?(message.type.to_s)
|
40
|
+
raise "Unknown type: #{message.type.to_s}"
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def call_route(message)
|
45
|
+
routes[message.type].send(message.command, *message.args)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
# Web Server bound to localhost that listens for remote agent reports. Forwards
|
2
|
+
# onto the router
|
3
|
+
module ScoutApm
|
4
|
+
module Remote
|
5
|
+
class Server
|
6
|
+
attr_reader :router
|
7
|
+
attr_reader :bind
|
8
|
+
attr_reader :port
|
9
|
+
attr_reader :logger
|
10
|
+
|
11
|
+
def initialize(bind, port, router, logger)
|
12
|
+
@router = router
|
13
|
+
@logger = logger
|
14
|
+
@bind = bind
|
15
|
+
@port = port
|
16
|
+
@server = nil
|
17
|
+
end
|
18
|
+
|
19
|
+
def start
|
20
|
+
@server = WEBrick::HTTPServer.new(
|
21
|
+
:BindAddress => bind,
|
22
|
+
:Port => port,
|
23
|
+
:AccessLog => [],
|
24
|
+
:Logger => @logger
|
25
|
+
)
|
26
|
+
|
27
|
+
@server.mount_proc '/' do |request, response|
|
28
|
+
router.handle(request.body)
|
29
|
+
|
30
|
+
# arbitrary response, client doesn't expect anything in particular
|
31
|
+
response.body = 'Ok'
|
32
|
+
end
|
33
|
+
|
34
|
+
@thread = Thread.new do
|
35
|
+
begin
|
36
|
+
logger.debug("Remote: Starting Server on #{bind}:#{port}")
|
37
|
+
|
38
|
+
@server.start
|
39
|
+
|
40
|
+
logger.debug("Remote: Server returned after #start call, thread exiting")
|
41
|
+
rescue => e
|
42
|
+
logger.debug("Remote: Server Exception, #{e}")
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def running?
|
48
|
+
@thread.alive?
|
49
|
+
@server && @server.status == :Running
|
50
|
+
end
|
51
|
+
|
52
|
+
def stop
|
53
|
+
@server.stop
|
54
|
+
@thread.kill
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# Provide a synchronous approach to recording TrackedRequests
|
2
|
+
# Doesn't attempt to background the work, or do it elsewhere. It happens
|
3
|
+
# inline, in the caller thread right when record! is called
|
4
|
+
|
5
|
+
module ScoutApm
|
6
|
+
class SynchronousRecorder
|
7
|
+
attr_reader :logger
|
8
|
+
|
9
|
+
def initialize(logger)
|
10
|
+
@logger = logger
|
11
|
+
end
|
12
|
+
|
13
|
+
def start
|
14
|
+
# nothing to do
|
15
|
+
self
|
16
|
+
end
|
17
|
+
|
18
|
+
def stop
|
19
|
+
# nothing to do
|
20
|
+
end
|
21
|
+
|
22
|
+
def record!(request)
|
23
|
+
request.record!
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -42,6 +42,9 @@ module ScoutApm
|
|
42
42
|
# Whereas the instant_key gets set per-request in reponse to a URL param, dev_trace is set in the config file
|
43
43
|
attr_accessor :dev_trace
|
44
44
|
|
45
|
+
# An object that responds to `record!(TrackedRequest)` to store this tracked request
|
46
|
+
attr_reader :recorder
|
47
|
+
|
45
48
|
def initialize(store)
|
46
49
|
@store = store #this is passed in so we can use a real store (normal operation) or fake store (instant mode only)
|
47
50
|
@layers = []
|
@@ -51,12 +54,19 @@ module ScoutApm
|
|
51
54
|
@context = Context.new
|
52
55
|
@root_layer = nil
|
53
56
|
@error = false
|
57
|
+
@stopping = false
|
54
58
|
@instant_key = nil
|
55
59
|
@mem_start = mem_usage
|
56
60
|
@dev_trace = ScoutApm::Agent.instance.config.value('dev_trace') && ScoutApm::Agent.instance.environment.env == "development"
|
61
|
+
@recorder = ScoutApm::Agent.instance.recorder
|
62
|
+
|
63
|
+
ignore_request! if @recorder.nil?
|
57
64
|
end
|
58
65
|
|
59
66
|
def start_layer(layer)
|
67
|
+
# If we're already stopping, don't do additional layers
|
68
|
+
return if stopping?
|
69
|
+
|
60
70
|
return if ignoring_children?
|
61
71
|
|
62
72
|
return ignoring_start_layer if ignoring_request?
|
@@ -66,6 +76,9 @@ module ScoutApm
|
|
66
76
|
end
|
67
77
|
|
68
78
|
def stop_layer
|
79
|
+
# If we're already stopping, don't do additional layers
|
80
|
+
return if stopping?
|
81
|
+
|
69
82
|
return if ignoring_children?
|
70
83
|
|
71
84
|
return ignoring_stop_layer if ignoring_request?
|
@@ -77,7 +90,7 @@ module ScoutApm
|
|
77
90
|
# lined up correctly. If stop_layer gets called twice, when it should
|
78
91
|
# only have been called once you'll end up with this error.
|
79
92
|
if layer.nil?
|
80
|
-
|
93
|
+
logger.warn("Error stopping layer, was nil. Root Layer: #{@root_layer.inspect}")
|
81
94
|
stop_request
|
82
95
|
return
|
83
96
|
end
|
@@ -169,7 +182,15 @@ module ScoutApm
|
|
169
182
|
#
|
170
183
|
# * Send the request off to be stored
|
171
184
|
def stop_request
|
172
|
-
|
185
|
+
@stopping = true
|
186
|
+
|
187
|
+
if recorder
|
188
|
+
recorder.record!(self)
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
def stopping?
|
193
|
+
@stopping
|
173
194
|
end
|
174
195
|
|
175
196
|
###################################
|
@@ -224,13 +245,21 @@ module ScoutApm
|
|
224
245
|
# Persist the Request
|
225
246
|
###################################
|
226
247
|
|
248
|
+
def recorded!
|
249
|
+
@recorded = true
|
250
|
+
end
|
251
|
+
|
227
252
|
# Convert this request to the appropriate structure, then report it into
|
228
253
|
# the peristent Store object
|
229
254
|
def record!
|
230
|
-
|
255
|
+
recorded!
|
231
256
|
|
232
257
|
return if ignoring_request?
|
233
258
|
|
259
|
+
# If we didn't have store, but we're trying to record anyway, go
|
260
|
+
# figure that out. (this happens in Remote Agent scenarios)
|
261
|
+
restore_store if @store.nil?
|
262
|
+
|
234
263
|
# Bail out early if the user asked us to ignore this uri
|
235
264
|
return if ScoutApm::Agent.instance.ignored_uris.ignore?(annotations[:uri])
|
236
265
|
|
@@ -275,7 +304,6 @@ module ScoutApm
|
|
275
304
|
|
276
305
|
allocation_metrics = LayerConverters::AllocationMetricConverter.new(self).call
|
277
306
|
@store.track!(allocation_metrics)
|
278
|
-
|
279
307
|
end
|
280
308
|
|
281
309
|
# Only call this after the request is complete
|
@@ -389,5 +417,24 @@ module ScoutApm
|
|
389
417
|
def ignoring_recorded?
|
390
418
|
@ignoring_depth <= 0
|
391
419
|
end
|
420
|
+
|
421
|
+
def logger
|
422
|
+
ScoutApm::Agent.instance.logger
|
423
|
+
end
|
424
|
+
|
425
|
+
# Actually go fetch & make-real any lazily created data.
|
426
|
+
# Clean up any cleverness in objects.
|
427
|
+
# Makes this object ready to be Marshal Dumped (or otherwise serialized)
|
428
|
+
def prepare_to_dump!
|
429
|
+
@call_set = nil
|
430
|
+
@store = nil
|
431
|
+
@recorder = nil
|
432
|
+
end
|
433
|
+
|
434
|
+
# Go re-fetch the store based on what the Agent's official one is. Used
|
435
|
+
# after hydrating a dumped TrackedRequest
|
436
|
+
def restore_store
|
437
|
+
@store = ScoutApm::Agent.instance.store
|
438
|
+
end
|
392
439
|
end
|
393
440
|
end
|
data/lib/scout_apm/version.rb
CHANGED
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
|
@@ -53,6 +54,7 @@ require 'scout_apm/server_integrations/null'
|
|
53
54
|
|
54
55
|
require 'scout_apm/background_job_integrations/sidekiq'
|
55
56
|
require 'scout_apm/background_job_integrations/delayed_job'
|
57
|
+
require 'scout_apm/background_job_integrations/resque'
|
56
58
|
|
57
59
|
require 'scout_apm/framework_integrations/rails_2'
|
58
60
|
require 'scout_apm/framework_integrations/rails_3_or_4'
|
@@ -118,6 +120,8 @@ require 'scout_apm/fake_store'
|
|
118
120
|
require 'scout_apm/tracer'
|
119
121
|
require 'scout_apm/context'
|
120
122
|
require 'scout_apm/instant_reporting'
|
123
|
+
require 'scout_apm/background_recorder'
|
124
|
+
require 'scout_apm/synchronous_recorder'
|
121
125
|
|
122
126
|
require 'scout_apm/metric_meta'
|
123
127
|
require 'scout_apm/metric_stats'
|
@@ -147,6 +151,12 @@ require 'scout_apm/instant/middleware'
|
|
147
151
|
|
148
152
|
require 'scout_apm/rack'
|
149
153
|
|
154
|
+
require 'scout_apm/remote/server'
|
155
|
+
require 'scout_apm/remote/router'
|
156
|
+
require 'scout_apm/remote/message'
|
157
|
+
require 'scout_apm/remote/recorder'
|
158
|
+
require 'scout_apm/instruments/resque'
|
159
|
+
|
150
160
|
if defined?(Rails) && defined?(Rails::VERSION) && defined?(Rails::VERSION::MAJOR) && Rails::VERSION::MAJOR >= 3 && defined?(Rails::Railtie)
|
151
161
|
module ScoutApm
|
152
162
|
class Railtie < Rails::Railtie
|
data/scout_apm.gemspec
CHANGED
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class MessageTest < Minitest::Test
|
4
|
+
def test_message_encode_decode_roundtrip
|
5
|
+
message = ScoutApm::Remote::Message.new('type', 'command', ['arg'])
|
6
|
+
encoded = message.encode
|
7
|
+
decoded = ScoutApm::Remote::Message.decode(encoded)
|
8
|
+
assert_equal message.type, decoded.type
|
9
|
+
assert_equal message.command, decoded.command
|
10
|
+
assert_equal message.args, decoded.args
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class RouterTest < Minitest::Test
|
4
|
+
def test_router_handles_record
|
5
|
+
recorder = stub
|
6
|
+
router = ScoutApm::Remote::Router.new(recorder, logger)
|
7
|
+
message = ScoutApm::Remote::Message.new("record", "foo", 1, 2).encode
|
8
|
+
|
9
|
+
recorder.expects(:foo).with(1, 2)
|
10
|
+
|
11
|
+
router.handle(message)
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_router_raises_on_unknown_types
|
15
|
+
recorder = stub
|
16
|
+
router = ScoutApm::Remote::Router.new(recorder, logger)
|
17
|
+
message = ScoutApm::Remote::Message.new("something_else", "foo", 1, 2).encode
|
18
|
+
|
19
|
+
recorder.expects(:foo).never
|
20
|
+
assert_raises do
|
21
|
+
router.handle(message)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def logger
|
26
|
+
@logger ||= Logger.new(logger_io)
|
27
|
+
end
|
28
|
+
|
29
|
+
def logger_io
|
30
|
+
@logger_io ||= StringIO.new
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class TestRemoteServer < Minitest::Test
|
4
|
+
def test_start_and_bind
|
5
|
+
bind = "127.0.0.1"
|
6
|
+
port = 8938
|
7
|
+
router = stub(:router)
|
8
|
+
logger_io = StringIO.new
|
9
|
+
server = ScoutApm::Remote::Server.new(bind, port, router, Logger.new(logger_io))
|
10
|
+
|
11
|
+
server.start
|
12
|
+
sleep 0.01 # Let the server finish starting. The assert should instead allow a time
|
13
|
+
assert server.running?
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class TrackedRequestDumpAndLoadTest < Minitest::Test
|
4
|
+
# TrackedRequest must be marshalable
|
5
|
+
def test_marshal_dump_load
|
6
|
+
tr = ScoutApm::TrackedRequest.new(ScoutApm::FakeStore.new)
|
7
|
+
tr.prepare_to_dump!
|
8
|
+
|
9
|
+
dumped = Marshal.dump(tr)
|
10
|
+
loaded = Marshal.load(dumped)
|
11
|
+
assert_false loaded.nil?
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_restore_store
|
15
|
+
faux = ScoutApm::FakeStore.new
|
16
|
+
tr = ScoutApm::TrackedRequest.new(faux)
|
17
|
+
assert_equal faux, tr.instance_variable_get("@store")
|
18
|
+
|
19
|
+
tr.prepare_to_dump!
|
20
|
+
assert_nil tr.instance_variable_get("@store")
|
21
|
+
|
22
|
+
tr.restore_store
|
23
|
+
assert_equal ScoutApm::Agent.instance.store, tr.instance_variable_get("@store")
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
class TrackedRequestFlagsTest < Minitest::Test
|
28
|
+
def test_set_web
|
29
|
+
tr = ScoutApm::TrackedRequest.new(ScoutApm::FakeStore.new)
|
30
|
+
assert_false tr.web?
|
31
|
+
tr.web!
|
32
|
+
assert tr.web?
|
33
|
+
end
|
34
|
+
|
35
|
+
def test_set_job
|
36
|
+
tr = ScoutApm::TrackedRequest.new(ScoutApm::FakeStore.new)
|
37
|
+
assert ! tr.job?
|
38
|
+
tr.job!
|
39
|
+
assert tr.job?
|
40
|
+
end
|
41
|
+
|
42
|
+
def test_set_error
|
43
|
+
tr = ScoutApm::TrackedRequest.new(ScoutApm::FakeStore.new)
|
44
|
+
assert_false tr.error?
|
45
|
+
tr.error!
|
46
|
+
assert tr.error?
|
47
|
+
end
|
48
|
+
|
49
|
+
def test_set_error_and_web
|
50
|
+
tr = ScoutApm::TrackedRequest.new(ScoutApm::FakeStore.new)
|
51
|
+
assert_false tr.error?
|
52
|
+
assert_false tr.web?
|
53
|
+
|
54
|
+
tr.web!
|
55
|
+
assert_false tr.error?
|
56
|
+
assert tr.web?
|
57
|
+
|
58
|
+
tr.error!
|
59
|
+
assert tr.error?
|
60
|
+
assert tr.web?
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
class TrackedRequestLayerManipulationTest < Minitest::Test
|
65
|
+
def test_start_layer
|
66
|
+
tr = ScoutApm::TrackedRequest.new(ScoutApm::FakeStore.new)
|
67
|
+
tr.start_layer(ScoutApm::Layer.new("Foo", "Bar"))
|
68
|
+
|
69
|
+
assert_equal "Foo", tr.current_layer.type
|
70
|
+
end
|
71
|
+
|
72
|
+
def test_start_several_layers
|
73
|
+
# layers are Controller -> ActiveRecord
|
74
|
+
controller_layer = ScoutApm::Layer.new("Controller", "users/index")
|
75
|
+
ar_layer = ScoutApm::Layer.new("ActiveRecord", "Users#find")
|
76
|
+
|
77
|
+
tr = ScoutApm::TrackedRequest.new(ScoutApm::FakeStore.new)
|
78
|
+
tr.start_layer(controller_layer)
|
79
|
+
tr.start_layer(ar_layer)
|
80
|
+
|
81
|
+
assert_equal "ActiveRecord", tr.current_layer.type
|
82
|
+
|
83
|
+
tr.stop_layer
|
84
|
+
|
85
|
+
assert_equal "Controller", tr.current_layer.type
|
86
|
+
end
|
87
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: scout_apm
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.1.
|
4
|
+
version: 2.1.30
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Derek Haynes
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2017-08-
|
12
|
+
date: 2017-08-15 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: minitest
|
@@ -109,6 +109,34 @@ dependencies:
|
|
109
109
|
- - ">="
|
110
110
|
- !ruby/object:Gem::Version
|
111
111
|
version: '0'
|
112
|
+
- !ruby/object:Gem::Dependency
|
113
|
+
name: guard
|
114
|
+
requirement: !ruby/object:Gem::Requirement
|
115
|
+
requirements:
|
116
|
+
- - ">="
|
117
|
+
- !ruby/object:Gem::Version
|
118
|
+
version: '0'
|
119
|
+
type: :development
|
120
|
+
prerelease: false
|
121
|
+
version_requirements: !ruby/object:Gem::Requirement
|
122
|
+
requirements:
|
123
|
+
- - ">="
|
124
|
+
- !ruby/object:Gem::Version
|
125
|
+
version: '0'
|
126
|
+
- !ruby/object:Gem::Dependency
|
127
|
+
name: guard-minitest
|
128
|
+
requirement: !ruby/object:Gem::Requirement
|
129
|
+
requirements:
|
130
|
+
- - ">="
|
131
|
+
- !ruby/object:Gem::Version
|
132
|
+
version: '0'
|
133
|
+
type: :development
|
134
|
+
prerelease: false
|
135
|
+
version_requirements: !ruby/object:Gem::Requirement
|
136
|
+
requirements:
|
137
|
+
- - ">="
|
138
|
+
- !ruby/object:Gem::Version
|
139
|
+
version: '0'
|
112
140
|
description: Monitors Ruby apps and reports detailed metrics on performance to Scout.
|
113
141
|
email:
|
114
142
|
- support@scoutapp.com
|
@@ -122,6 +150,7 @@ files:
|
|
122
150
|
- ".rubocop.yml"
|
123
151
|
- CHANGELOG.markdown
|
124
152
|
- Gemfile
|
153
|
+
- Guardfile
|
125
154
|
- LICENSE.md
|
126
155
|
- README.markdown
|
127
156
|
- Rakefile
|
@@ -138,7 +167,9 @@ files:
|
|
138
167
|
- lib/scout_apm/app_server_load.rb
|
139
168
|
- lib/scout_apm/attribute_arranger.rb
|
140
169
|
- lib/scout_apm/background_job_integrations/delayed_job.rb
|
170
|
+
- lib/scout_apm/background_job_integrations/resque.rb
|
141
171
|
- lib/scout_apm/background_job_integrations/sidekiq.rb
|
172
|
+
- lib/scout_apm/background_recorder.rb
|
142
173
|
- lib/scout_apm/background_worker.rb
|
143
174
|
- lib/scout_apm/bucket_name_splitter.rb
|
144
175
|
- lib/scout_apm/call_set.rb
|
@@ -176,6 +207,7 @@ files:
|
|
176
207
|
- lib/scout_apm/instruments/process/process_memory.rb
|
177
208
|
- lib/scout_apm/instruments/rails_router.rb
|
178
209
|
- lib/scout_apm/instruments/redis.rb
|
210
|
+
- lib/scout_apm/instruments/resque.rb
|
179
211
|
- lib/scout_apm/instruments/sinatra.rb
|
180
212
|
- lib/scout_apm/job_record.rb
|
181
213
|
- lib/scout_apm/layaway.rb
|
@@ -200,6 +232,10 @@ files:
|
|
200
232
|
- lib/scout_apm/platform_integrations/heroku.rb
|
201
233
|
- lib/scout_apm/platform_integrations/server.rb
|
202
234
|
- lib/scout_apm/rack.rb
|
235
|
+
- lib/scout_apm/remote/message.rb
|
236
|
+
- lib/scout_apm/remote/recorder.rb
|
237
|
+
- lib/scout_apm/remote/router.rb
|
238
|
+
- lib/scout_apm/remote/server.rb
|
203
239
|
- lib/scout_apm/reporter.rb
|
204
240
|
- lib/scout_apm/request_histograms.rb
|
205
241
|
- lib/scout_apm/request_manager.rb
|
@@ -225,6 +261,7 @@ files:
|
|
225
261
|
- lib/scout_apm/slow_transaction.rb
|
226
262
|
- lib/scout_apm/stack_item.rb
|
227
263
|
- lib/scout_apm/store.rb
|
264
|
+
- lib/scout_apm/synchronous_recorder.rb
|
228
265
|
- lib/scout_apm/tracer.rb
|
229
266
|
- lib/scout_apm/tracked_request.rb
|
230
267
|
- lib/scout_apm/utils/active_record_metric_name.rb
|
@@ -259,12 +296,16 @@ files:
|
|
259
296
|
- test/unit/layer_children_set_test.rb
|
260
297
|
- test/unit/limited_layer_test.rb
|
261
298
|
- test/unit/metric_set_test.rb
|
299
|
+
- test/unit/remote/test_message.rb
|
300
|
+
- test/unit/remote/test_router.rb
|
301
|
+
- test/unit/remote/test_server.rb
|
262
302
|
- test/unit/scored_item_set_test.rb
|
263
303
|
- test/unit/serializers/payload_serializer_test.rb
|
264
304
|
- test/unit/slow_job_policy_test.rb
|
265
305
|
- test/unit/slow_request_policy_test.rb
|
266
306
|
- test/unit/sql_sanitizer_test.rb
|
267
307
|
- test/unit/store_test.rb
|
308
|
+
- test/unit/test_tracked_request.rb
|
268
309
|
- test/unit/utils/active_record_metric_name_test.rb
|
269
310
|
- test/unit/utils/backtrace_parser_test.rb
|
270
311
|
- test/unit/utils/numbers_test.rb
|
@@ -290,8 +331,39 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
290
331
|
version: '0'
|
291
332
|
requirements: []
|
292
333
|
rubyforge_project: scout_apm
|
293
|
-
rubygems_version: 2.
|
334
|
+
rubygems_version: 2.4.5.2
|
294
335
|
signing_key:
|
295
336
|
specification_version: 4
|
296
337
|
summary: Ruby application performance monitoring
|
297
|
-
test_files:
|
338
|
+
test_files:
|
339
|
+
- test/data/config_test_1.yml
|
340
|
+
- test/test_helper.rb
|
341
|
+
- test/unit/agent_test.rb
|
342
|
+
- test/unit/background_job_integrations/sidekiq_test.rb
|
343
|
+
- test/unit/config_test.rb
|
344
|
+
- test/unit/context_test.rb
|
345
|
+
- test/unit/environment_test.rb
|
346
|
+
- test/unit/git_revision_test.rb
|
347
|
+
- test/unit/histogram_test.rb
|
348
|
+
- test/unit/ignored_uris_test.rb
|
349
|
+
- test/unit/instruments/active_record_instruments_test.rb
|
350
|
+
- test/unit/instruments/net_http_test.rb
|
351
|
+
- test/unit/instruments/percentile_sampler_test.rb
|
352
|
+
- test/unit/layaway_test.rb
|
353
|
+
- test/unit/layer_children_set_test.rb
|
354
|
+
- test/unit/limited_layer_test.rb
|
355
|
+
- test/unit/metric_set_test.rb
|
356
|
+
- test/unit/remote/test_message.rb
|
357
|
+
- test/unit/remote/test_router.rb
|
358
|
+
- test/unit/remote/test_server.rb
|
359
|
+
- test/unit/scored_item_set_test.rb
|
360
|
+
- test/unit/serializers/payload_serializer_test.rb
|
361
|
+
- test/unit/slow_job_policy_test.rb
|
362
|
+
- test/unit/slow_request_policy_test.rb
|
363
|
+
- test/unit/sql_sanitizer_test.rb
|
364
|
+
- test/unit/store_test.rb
|
365
|
+
- test/unit/test_tracked_request.rb
|
366
|
+
- test/unit/utils/active_record_metric_name_test.rb
|
367
|
+
- test/unit/utils/backtrace_parser_test.rb
|
368
|
+
- test/unit/utils/numbers_test.rb
|
369
|
+
- test/unit/utils/scm.rb
|