scout_apm 3.0.0.pre10 → 3.0.0.pre11
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 +47 -0
- data/Guardfile +42 -0
- data/lib/scout_apm.rb +14 -0
- data/lib/scout_apm/agent.rb +58 -1
- data/lib/scout_apm/agent/logging.rb +6 -1
- data/lib/scout_apm/app_server_load.rb +21 -11
- data/lib/scout_apm/background_job_integrations/resque.rb +85 -0
- data/lib/scout_apm/background_job_integrations/sidekiq.rb +19 -3
- data/lib/scout_apm/background_recorder.rb +43 -0
- data/lib/scout_apm/background_worker.rb +6 -6
- data/lib/scout_apm/config.rb +14 -3
- data/lib/scout_apm/environment.rb +14 -0
- data/lib/scout_apm/instruments/action_controller_rails_3_rails4.rb +112 -70
- data/lib/scout_apm/instruments/action_view.rb +49 -0
- data/lib/scout_apm/instruments/active_record.rb +2 -2
- data/lib/scout_apm/instruments/mongoid.rb +10 -2
- data/lib/scout_apm/instruments/resque.rb +40 -0
- data/lib/scout_apm/layer_children_set.rb +7 -2
- data/lib/scout_apm/rack.rb +26 -0
- 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 +53 -5
- data/lib/scout_apm/utils/backtrace_parser.rb +3 -3
- data/lib/scout_apm/utils/scm.rb +14 -0
- data/lib/scout_apm/version.rb +1 -1
- 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
- data/test/unit/utils/backtrace_parser_test.rb +5 -0
- data/test/unit/utils/scm.rb +17 -0
- metadata +52 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 36bac9cf47e89f5cec6475b574b6cd948339d627
|
4
|
+
data.tar.gz: dd2bc23001811e393950d502f04b2a359dae083d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0d2e5b8270afe767d63890df65b8ea6f1fba96f4a2187cd58537372e13c7555f94875b3884473f210eb6e96f1815240508a53c50638e0ba74ad96075d9364888
|
7
|
+
data.tar.gz: 7b0169e3e311061dc20da5088f7b22247ec3acf66ba145b827a926ef87763bf6e576282a282611c2d5178412de7b8ade5a24a7c50e730399c560e1f846626020
|
data/.gitignore
CHANGED
data/CHANGELOG.markdown
CHANGED
@@ -1,6 +1,52 @@
|
|
1
|
+
<<<<<<< HEAD
|
1
2
|
# 3.0.0
|
2
3
|
|
3
4
|
* ScoutProf BETA
|
5
|
+
=======
|
6
|
+
# 2.1.32
|
7
|
+
|
8
|
+
* Better naming when using Resque + ActiveJob
|
9
|
+
* Better naming when using Sidekiq + DelayedExtension
|
10
|
+
>>>>>>> master
|
11
|
+
|
12
|
+
# 2.1.31
|
13
|
+
|
14
|
+
* Better detection of Resque queue names
|
15
|
+
* Fix passing arguments through Active Record instrumentation. (Thanks to Nick Quaranto for providing the fix)
|
16
|
+
* Stricter checks to prevent agent from starting in Rails console
|
17
|
+
|
18
|
+
# 2.1.30
|
19
|
+
|
20
|
+
* Add Resque support.
|
21
|
+
|
22
|
+
# 2.1.29
|
23
|
+
|
24
|
+
* Add `scm_subdirectory` option. Useful for when your app code does not live in your SCM root directory.
|
25
|
+
|
26
|
+
# 2.1.28
|
27
|
+
|
28
|
+
* Changes to app server load data
|
29
|
+
|
30
|
+
# 2.1.27
|
31
|
+
|
32
|
+
* Don't attempt to call `current_layer.type` on nil
|
33
|
+
|
34
|
+
# 2.1.26
|
35
|
+
|
36
|
+
* Bug fix [4b188d6](https://github.com/scoutapp/scout_apm_ruby/commit/4b188d698852c86b86d8768ea5b37d706ce544fe)
|
37
|
+
|
38
|
+
# 2.1.25
|
39
|
+
|
40
|
+
* Automatically instrument API and Metal controllers.
|
41
|
+
|
42
|
+
# 2.1.24
|
43
|
+
|
44
|
+
* Capture additional layers of application backtrace frames. (From 3 -> 8)
|
45
|
+
|
46
|
+
# 2.1.23
|
47
|
+
|
48
|
+
* Extend Mongoid instrumentation to 6.x
|
49
|
+
>>>>>>> master
|
4
50
|
|
5
51
|
# 2.1.22
|
6
52
|
|
@@ -66,6 +112,7 @@
|
|
66
112
|
# 2.1.9
|
67
113
|
|
68
114
|
* Send raw histograms of response time, enabling more accurate 95th %iles
|
115
|
+
* Raw histograms are used in Apdex calculations
|
69
116
|
* Gzip payloads
|
70
117
|
* Fix Mongoid (5.0) + Mongo (2.1) support
|
71
118
|
* Initial Delayed Job support
|
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.rb
CHANGED
@@ -15,6 +15,7 @@ require 'thread'
|
|
15
15
|
require 'time'
|
16
16
|
require 'yaml'
|
17
17
|
require 'rbconfig'
|
18
|
+
require 'webrick'
|
18
19
|
|
19
20
|
#####################################
|
20
21
|
# Gem Requires
|
@@ -54,6 +55,7 @@ require 'scout_apm/server_integrations/null'
|
|
54
55
|
|
55
56
|
require 'scout_apm/background_job_integrations/sidekiq'
|
56
57
|
require 'scout_apm/background_job_integrations/delayed_job'
|
58
|
+
require 'scout_apm/background_job_integrations/resque'
|
57
59
|
|
58
60
|
require 'scout_apm/framework_integrations/rails_2'
|
59
61
|
require 'scout_apm/framework_integrations/rails_3_or_4'
|
@@ -84,6 +86,7 @@ require 'scout_apm/instruments/sinatra'
|
|
84
86
|
require 'scout_apm/instruments/process/process_cpu'
|
85
87
|
require 'scout_apm/instruments/process/process_memory'
|
86
88
|
require 'scout_apm/instruments/percentile_sampler'
|
89
|
+
require 'scout_apm/instruments/action_view'
|
87
90
|
require 'allocations'
|
88
91
|
|
89
92
|
begin
|
@@ -100,6 +103,7 @@ require 'scout_apm/utils/backtrace_parser'
|
|
100
103
|
require 'scout_apm/utils/installed_gems'
|
101
104
|
require 'scout_apm/utils/klass_helper'
|
102
105
|
require 'scout_apm/utils/null_logger'
|
106
|
+
require 'scout_apm/utils/scm'
|
103
107
|
require 'scout_apm/utils/sql_sanitizer'
|
104
108
|
require 'scout_apm/utils/time'
|
105
109
|
require 'scout_apm/utils/unique_id'
|
@@ -124,6 +128,8 @@ require 'scout_apm/tracer'
|
|
124
128
|
require 'scout_apm/context'
|
125
129
|
require 'scout_apm/instant_reporting'
|
126
130
|
require 'scout_apm/trace_compactor'
|
131
|
+
require 'scout_apm/background_recorder'
|
132
|
+
require 'scout_apm/synchronous_recorder'
|
127
133
|
|
128
134
|
require 'scout_apm/metric_meta'
|
129
135
|
require 'scout_apm/metric_stats'
|
@@ -151,6 +157,14 @@ require 'scout_apm/middleware'
|
|
151
157
|
|
152
158
|
require 'scout_apm/instant/middleware'
|
153
159
|
|
160
|
+
require 'scout_apm/rack'
|
161
|
+
|
162
|
+
require 'scout_apm/remote/server'
|
163
|
+
require 'scout_apm/remote/router'
|
164
|
+
require 'scout_apm/remote/message'
|
165
|
+
require 'scout_apm/remote/recorder'
|
166
|
+
require 'scout_apm/instruments/resque'
|
167
|
+
|
154
168
|
if defined?(Rails) && defined?(Rails::VERSION) && defined?(Rails::VERSION::MAJOR) && Rails::VERSION::MAJOR >= 3 && defined?(Rails::Railtie)
|
155
169
|
module ScoutApm
|
156
170
|
class Railtie < Rails::Railtie
|
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
|
|
@@ -84,6 +89,11 @@ module ScoutApm
|
|
84
89
|
return false unless force?
|
85
90
|
end
|
86
91
|
|
92
|
+
if environment.interactive?
|
93
|
+
logger.warn "Agent attempting to load in interactive mode. #{force? ? 'Forcing agent to start' : 'Not starting agent'}"
|
94
|
+
return false unless force?
|
95
|
+
end
|
96
|
+
|
87
97
|
if app_server_missing?(options) && background_job_missing?
|
88
98
|
if force?
|
89
99
|
logger.warn "Agent starting (forced)"
|
@@ -111,13 +121,14 @@ module ScoutApm
|
|
111
121
|
def start(options = {})
|
112
122
|
@options.merge!(options)
|
113
123
|
|
114
|
-
|
115
124
|
@config = ScoutApm::Config.with_file(@config.value("config_file"))
|
116
125
|
layaway.config = config
|
117
126
|
|
118
127
|
init_logger
|
119
128
|
logger.info "Attempting to start Scout Agent [#{ScoutApm::VERSION}] on [#{environment.hostname}]"
|
120
129
|
|
130
|
+
@recorder = create_recorder
|
131
|
+
|
121
132
|
@config.log_settings
|
122
133
|
|
123
134
|
@ignored_uris = ScoutApm::IgnoredUris.new(config.value('ignore'))
|
@@ -262,6 +273,9 @@ module ScoutApm
|
|
262
273
|
ScoutApm::Instruments::Stacks.start
|
263
274
|
end
|
264
275
|
|
276
|
+
@recorder = create_recorder
|
277
|
+
logger.info("recorder is now: #{@recorder.class}")
|
278
|
+
|
265
279
|
@background_worker = ScoutApm::BackgroundWorker.new
|
266
280
|
@background_worker_thread = Thread.new do
|
267
281
|
@background_worker.start {
|
@@ -303,6 +317,7 @@ module ScoutApm
|
|
303
317
|
end
|
304
318
|
end
|
305
319
|
|
320
|
+
install_instrument(ScoutApm::Instruments::ActionView)
|
306
321
|
install_instrument(ScoutApm::Instruments::ActiveRecord)
|
307
322
|
install_instrument(ScoutApm::Instruments::Moped)
|
308
323
|
install_instrument(ScoutApm::Instruments::Mongoid)
|
@@ -341,5 +356,47 @@ module ScoutApm
|
|
341
356
|
def background_job_missing?(options = {})
|
342
357
|
environment.background_job_integration.nil? && !options[:skip_background_job_check]
|
343
358
|
end
|
359
|
+
|
360
|
+
def clear_recorder
|
361
|
+
@recorder = nil
|
362
|
+
end
|
363
|
+
|
364
|
+
def create_recorder
|
365
|
+
if @recorder
|
366
|
+
return @recorder
|
367
|
+
end
|
368
|
+
|
369
|
+
if config.value("async_recording")
|
370
|
+
logger.debug("Using asynchronous recording")
|
371
|
+
ScoutApm::BackgroundRecorder.new(logger).start
|
372
|
+
else
|
373
|
+
logger.debug("Using synchronous recording")
|
374
|
+
ScoutApm::SynchronousRecorder.new(logger).start
|
375
|
+
end
|
376
|
+
end
|
377
|
+
|
378
|
+
def start_remote_server(bind, port)
|
379
|
+
return if @remote_server && @remote_server.running?
|
380
|
+
|
381
|
+
logger.info("Starting Remote Agent Server")
|
382
|
+
|
383
|
+
# Start the listening web server only in parent process.
|
384
|
+
@remote_server = ScoutApm::Remote::Server.new(
|
385
|
+
bind,
|
386
|
+
port,
|
387
|
+
ScoutApm::Remote::Router.new(ScoutApm::SynchronousRecorder.new(logger), logger),
|
388
|
+
logger
|
389
|
+
)
|
390
|
+
|
391
|
+
@remote_server.start
|
392
|
+
end
|
393
|
+
|
394
|
+
# Execute this in the child process of a remote agent. The parent is
|
395
|
+
# expected to have its accepting webserver up and running
|
396
|
+
def use_remote_recorder(host, port)
|
397
|
+
logger.debug("Becoming Remote Agent (reporting to: #{host}:#{port})")
|
398
|
+
@recorder = ScoutApm::Remote::Recorder.new(host, port, logger)
|
399
|
+
@store = ScoutApm::FakeStore.new
|
400
|
+
end
|
344
401
|
end
|
345
402
|
end
|
@@ -27,20 +27,30 @@ module ScoutApm
|
|
27
27
|
end
|
28
28
|
|
29
29
|
def data
|
30
|
-
{ :server_time => Time.now,
|
31
|
-
:framework => ScoutApm::Environment.instance.framework_integration.human_name,
|
32
|
-
:framework_version => ScoutApm::Environment.instance.framework_integration.version,
|
33
|
-
:environment => ScoutApm::Environment.instance.framework_integration.env,
|
34
|
-
:app_server => ScoutApm::Environment.instance.app_server,
|
30
|
+
{ :server_time => to_s_safe(Time.now),
|
31
|
+
:framework => to_s_safe(ScoutApm::Environment.instance.framework_integration.human_name),
|
32
|
+
:framework_version => to_s_safe(ScoutApm::Environment.instance.framework_integration.version),
|
33
|
+
:environment => to_s_safe(ScoutApm::Environment.instance.framework_integration.env),
|
34
|
+
:app_server => to_s_safe(ScoutApm::Environment.instance.app_server),
|
35
35
|
:ruby_version => RUBY_VERSION,
|
36
|
-
:hostname => ScoutApm::Environment.instance.hostname,
|
37
|
-
:database_engine => ScoutApm::Environment.instance.database_engine, # Detected
|
38
|
-
:database_adapter => ScoutApm::Environment.instance.raw_database_adapter, # Raw
|
39
|
-
:application_name => ScoutApm::Environment.instance.application_name,
|
36
|
+
:hostname => to_s_safe(ScoutApm::Environment.instance.hostname),
|
37
|
+
:database_engine => to_s_safe(ScoutApm::Environment.instance.database_engine), # Detected
|
38
|
+
:database_adapter => to_s_safe(ScoutApm::Environment.instance.raw_database_adapter), # Raw
|
39
|
+
:application_name => to_s_safe(ScoutApm::Environment.instance.application_name),
|
40
40
|
:libraries => ScoutApm::Utils::InstalledGems.new.run,
|
41
|
-
:paas => ScoutApm::Environment.instance.platform_integration.name,
|
42
|
-
:git_sha => ScoutApm::Environment.instance.git_revision.sha
|
41
|
+
:paas => to_s_safe(ScoutApm::Environment.instance.platform_integration.name),
|
42
|
+
:git_sha => to_s_safe(ScoutApm::Environment.instance.git_revision.sha)
|
43
43
|
}
|
44
44
|
end
|
45
|
+
|
46
|
+
# Calls `.to_s` on the object passed in.
|
47
|
+
# Returns literal string 'to_s error' if the object does not respond to .to_s
|
48
|
+
def to_s_safe(obj)
|
49
|
+
if obj.respond_to?(:to_s)
|
50
|
+
obj.to_s
|
51
|
+
else
|
52
|
+
'to_s error'
|
53
|
+
end
|
54
|
+
end
|
45
55
|
end
|
46
56
|
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
|
+
|
@@ -55,8 +55,6 @@ module ScoutApm
|
|
55
55
|
# We insert this middleware into the Sidekiq stack, to capture each job,
|
56
56
|
# and time them.
|
57
57
|
class SidekiqMiddleware
|
58
|
-
ACTIVE_JOB_KLASS = 'ActiveJob::QueueAdapters::SidekiqAdapter::JobWrapper'.freeze
|
59
|
-
|
60
58
|
def call(_worker, msg, queue)
|
61
59
|
req = ScoutApm::RequestManager.lookup
|
62
60
|
req.job!
|
@@ -89,12 +87,30 @@ module ScoutApm
|
|
89
87
|
end
|
90
88
|
|
91
89
|
UNKNOWN_CLASS_PLACEHOLDER = 'UnknownJob'.freeze
|
90
|
+
ACTIVE_JOB_KLASS = 'ActiveJob::QueueAdapters::SidekiqAdapter::JobWrapper'.freeze
|
91
|
+
DELAYED_WRAPPER_KLASS = 'Sidekiq::Extensions::DelayedClass'.freeze
|
92
|
+
|
92
93
|
|
93
94
|
def job_class(msg)
|
94
95
|
job_class = msg.fetch('class', UNKNOWN_CLASS_PLACEHOLDER)
|
96
|
+
|
95
97
|
if job_class == ACTIVE_JOB_KLASS && msg.key?('wrapped')
|
96
|
-
|
98
|
+
begin
|
99
|
+
job_class = msg['wrapped']
|
100
|
+
rescue
|
101
|
+
ACTIVE_JOB_KLASS
|
102
|
+
end
|
103
|
+
elsif job_class == DELAYED_WRAPPER_KLASS
|
104
|
+
begin
|
105
|
+
yml = msg['args'].first
|
106
|
+
deserialized_args = YAML.load(yml)
|
107
|
+
klass, method, *rest = deserialized_args
|
108
|
+
job_class = [klass,method].map(&:to_s).join(".")
|
109
|
+
rescue
|
110
|
+
DELAYED_WRAPPER_KLASS
|
111
|
+
end
|
97
112
|
end
|
113
|
+
|
98
114
|
job_class
|
99
115
|
rescue
|
100
116
|
UNKNOWN_CLASS_PLACEHOLDER
|