scout_apm 3.0.0.pre27 → 4.0.3
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 +5 -5
- data/.github/workflows/test.yml +49 -0
- data/.gitignore +1 -1
- data/.rubocop.yml +5 -5
- data/.travis.yml +19 -14
- data/CHANGELOG.markdown +139 -4
- data/Gemfile +1 -7
- data/README.markdown +13 -4
- data/Rakefile +1 -1
- data/ext/allocations/allocations.c +2 -0
- data/gems/README.md +28 -0
- data/gems/octoshark.gemfile +4 -0
- data/gems/rails3.gemfile +5 -0
- data/gems/rails4.gemfile +4 -0
- data/gems/rails5.gemfile +4 -0
- data/gems/rails6.gemfile +4 -0
- data/lib/scout_apm.rb +38 -9
- data/lib/scout_apm/agent.rb +29 -10
- data/lib/scout_apm/agent/exit_handler.rb +0 -1
- data/lib/scout_apm/agent_context.rb +22 -3
- data/lib/scout_apm/app_server_load.rb +7 -2
- data/lib/scout_apm/attribute_arranger.rb +0 -2
- data/lib/scout_apm/auto_instrument.rb +5 -0
- data/lib/scout_apm/auto_instrument/instruction_sequence.rb +31 -0
- data/lib/scout_apm/auto_instrument/layer.rb +23 -0
- data/lib/scout_apm/auto_instrument/parser.rb +27 -0
- data/lib/scout_apm/auto_instrument/rails.rb +175 -0
- data/lib/scout_apm/background_job_integrations/legacy_sneakers.rb +55 -0
- data/lib/scout_apm/background_job_integrations/que.rb +134 -0
- data/lib/scout_apm/background_job_integrations/resque.rb +6 -2
- data/lib/scout_apm/background_job_integrations/shoryuken.rb +124 -0
- data/lib/scout_apm/background_job_integrations/sidekiq.rb +5 -19
- data/lib/scout_apm/background_job_integrations/sneakers.rb +87 -0
- data/lib/scout_apm/config.rb +45 -8
- data/lib/scout_apm/detailed_trace.rb +217 -0
- data/lib/scout_apm/environment.rb +19 -1
- data/lib/scout_apm/error.rb +27 -0
- data/lib/scout_apm/error_service.rb +32 -0
- data/lib/scout_apm/error_service/error_buffer.rb +39 -0
- data/lib/scout_apm/error_service/error_record.rb +211 -0
- data/lib/scout_apm/error_service/ignored_exceptions.rb +66 -0
- data/lib/scout_apm/error_service/middleware.rb +32 -0
- data/lib/scout_apm/error_service/notifier.rb +33 -0
- data/lib/scout_apm/error_service/payload.rb +47 -0
- data/lib/scout_apm/error_service/periodic_work.rb +17 -0
- data/lib/scout_apm/error_service/railtie.rb +11 -0
- data/lib/scout_apm/error_service/sidekiq.rb +80 -0
- data/lib/scout_apm/extensions/transaction_callback_payload.rb +1 -1
- data/lib/scout_apm/fake_store.rb +3 -0
- data/lib/scout_apm/framework_integrations/rails_2.rb +2 -1
- data/lib/scout_apm/framework_integrations/rails_3_or_4.rb +3 -1
- data/lib/scout_apm/git_revision.rb +6 -3
- data/lib/scout_apm/instant/middleware.rb +2 -1
- data/lib/scout_apm/instrument_manager.rb +9 -7
- data/lib/scout_apm/instruments/action_controller_rails_2.rb +3 -1
- data/lib/scout_apm/instruments/action_controller_rails_3_rails4.rb +56 -55
- data/lib/scout_apm/instruments/action_view.rb +122 -26
- data/lib/scout_apm/instruments/active_record.rb +66 -18
- data/lib/scout_apm/instruments/http.rb +48 -0
- data/lib/scout_apm/instruments/memcached.rb +43 -0
- data/lib/scout_apm/instruments/mongoid.rb +9 -4
- data/lib/scout_apm/instruments/net_http.rb +8 -1
- data/lib/scout_apm/instruments/typhoeus.rb +88 -0
- data/lib/scout_apm/job_record.rb +4 -2
- data/lib/scout_apm/layaway_file.rb +4 -0
- data/lib/scout_apm/layer.rb +6 -57
- data/lib/scout_apm/layer_children_set.rb +9 -8
- data/lib/scout_apm/layer_converters/converter_base.rb +15 -30
- data/lib/scout_apm/layer_converters/slow_job_converter.rb +12 -2
- data/lib/scout_apm/layer_converters/slow_request_converter.rb +14 -4
- data/lib/scout_apm/layer_converters/trace_converter.rb +184 -0
- data/lib/scout_apm/limited_layer.rb +0 -7
- data/lib/scout_apm/metric_stats.rb +0 -8
- data/lib/scout_apm/middleware.rb +1 -1
- data/lib/scout_apm/periodic_work.rb +19 -0
- data/lib/scout_apm/remote/message.rb +4 -0
- data/lib/scout_apm/remote/server.rb +13 -1
- data/lib/scout_apm/reporter.rb +8 -3
- data/lib/scout_apm/reporting.rb +2 -1
- data/lib/scout_apm/request_histograms.rb +8 -0
- data/lib/scout_apm/serializers/app_server_load_serializer.rb +4 -0
- data/lib/scout_apm/serializers/directive_serializer.rb +4 -0
- data/lib/scout_apm/serializers/payload_serializer.rb +2 -2
- data/lib/scout_apm/serializers/payload_serializer_to_json.rb +30 -15
- data/lib/scout_apm/slow_job_record.rb +5 -1
- data/lib/scout_apm/slow_policy/age_policy.rb +33 -0
- data/lib/scout_apm/slow_policy/percent_policy.rb +22 -0
- data/lib/scout_apm/slow_policy/percentile_policy.rb +24 -0
- data/lib/scout_apm/slow_policy/policy.rb +21 -0
- data/lib/scout_apm/slow_policy/speed_policy.rb +16 -0
- data/lib/scout_apm/slow_request_policy.rb +18 -77
- data/lib/scout_apm/slow_transaction.rb +3 -1
- data/lib/scout_apm/store.rb +0 -1
- data/lib/scout_apm/tracked_request.rb +39 -30
- data/lib/scout_apm/utils/backtrace_parser.rb +3 -0
- data/lib/scout_apm/utils/marshal_logging.rb +90 -0
- data/lib/scout_apm/utils/sql_sanitizer.rb +10 -1
- data/lib/scout_apm/utils/sql_sanitizer_regex.rb +8 -1
- data/lib/scout_apm/utils/sql_sanitizer_regex_1_8_7.rb +6 -0
- data/lib/scout_apm/utils/unique_id.rb +27 -0
- data/lib/scout_apm/version.rb +1 -1
- data/scout_apm.gemspec +13 -7
- data/test/test_helper.rb +2 -2
- data/test/unit/agent_context_test.rb +29 -0
- data/test/unit/auto_instrument/assignments-instrumented.rb +31 -0
- data/test/unit/auto_instrument/assignments.rb +31 -0
- data/test/unit/auto_instrument/controller-ast.txt +57 -0
- data/test/unit/auto_instrument/controller-instrumented.rb +49 -0
- data/test/unit/auto_instrument/controller.rb +49 -0
- data/test/unit/auto_instrument/rescue_from-instrumented.rb +13 -0
- data/test/unit/auto_instrument/rescue_from.rb +13 -0
- data/test/unit/auto_instrument_test.rb +54 -0
- data/test/unit/environment_test.rb +2 -2
- data/test/unit/error_service/error_buffer_test.rb +25 -0
- data/test/unit/error_service/ignored_exceptions_test.rb +49 -0
- data/test/unit/instruments/active_record_test.rb +40 -0
- data/test/unit/layer_children_set_test.rb +9 -0
- data/test/unit/request_histograms_test.rb +17 -0
- data/test/unit/serializers/payload_serializer_test.rb +39 -5
- data/test/unit/slow_request_policy_test.rb +41 -13
- data/test/unit/sql_sanitizer_test.rb +78 -0
- metadata +101 -62
- data/ext/stacks/extconf.rb +0 -37
- data/ext/stacks/scout_atomics.h +0 -86
- data/ext/stacks/stacks.c +0 -814
- data/lib/scout_apm/slow_job_policy.rb +0 -111
- data/lib/scout_apm/trace_compactor.rb +0 -312
- data/lib/scout_apm/utils/fake_stacks.rb +0 -88
- data/test/unit/instruments/active_record_instruments_test.rb +0 -5
- data/test/unit/slow_job_policy_test.rb +0 -6
- data/tester.rb +0 -53
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
module ScoutApm
|
|
2
|
+
module BackgroundJobIntegrations
|
|
3
|
+
class Que
|
|
4
|
+
|
|
5
|
+
UNKNOWN_CLASS_PLACEHOLDER = 'UnknownJob'.freeze
|
|
6
|
+
ACTIVE_JOB_KLASS = 'ActiveJob::QueueAdapters::QueAdapter::JobWrapper'.freeze
|
|
7
|
+
UNKNOWN_QUEUE_PLACEHOLDER = 'UnknownQueue'.freeze
|
|
8
|
+
|
|
9
|
+
attr_reader :logger
|
|
10
|
+
|
|
11
|
+
def name
|
|
12
|
+
:que
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def present?
|
|
16
|
+
if defined?(::Que) && File.basename($PROGRAM_NAME).start_with?('que')
|
|
17
|
+
# 0.x releases used "Version" constant.
|
|
18
|
+
# 1.x releases used "VERSION" constant.
|
|
19
|
+
return defined?(::Que::Version)
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def forking?
|
|
24
|
+
false
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def install
|
|
28
|
+
install_tracer
|
|
29
|
+
install_worker
|
|
30
|
+
install_job
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def install_tracer
|
|
34
|
+
::Que::Job.class_eval do
|
|
35
|
+
include ScoutApm::Tracer
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def install_worker
|
|
40
|
+
::Que::Worker.class_eval do
|
|
41
|
+
def initialize_with_scout(*args)
|
|
42
|
+
agent = ::ScoutApm::Agent.instance
|
|
43
|
+
agent.start
|
|
44
|
+
initialize_without_scout(*args)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
alias_method :initialize_without_scout, :initialize
|
|
48
|
+
alias_method :initialize, :initialize_with_scout
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def install_job
|
|
53
|
+
::Que::Job.class_eval do
|
|
54
|
+
# attrs = {
|
|
55
|
+
# "queue"=>"",
|
|
56
|
+
# "priority"=>100,
|
|
57
|
+
# "run_at"=>2018-12-19 15:12:32 -0700,
|
|
58
|
+
# "job_id"=>4,
|
|
59
|
+
# "job_class"=>"ExampleJob",
|
|
60
|
+
# "args"=>[{"key"=>"value"}],
|
|
61
|
+
# "error_count"=>0
|
|
62
|
+
# }
|
|
63
|
+
#
|
|
64
|
+
# With ActiveJob, v0.14.3:
|
|
65
|
+
# attrs = {
|
|
66
|
+
# "queue"=>"",
|
|
67
|
+
# "priority"=>100,
|
|
68
|
+
# "run_at"=>2018-12-19 15:29:18 -0700,
|
|
69
|
+
# "job_id"=>6,
|
|
70
|
+
# "job_class"=>"ActiveJob::QueueAdapters::QueAdapter::JobWrapper",
|
|
71
|
+
# "args"=> [{
|
|
72
|
+
# "job_class"=>"ExampleJob",
|
|
73
|
+
# "job_id"=>"60798b45-4b55-436e-806d-693939266c97",
|
|
74
|
+
# "provider_job_id"=>nil,
|
|
75
|
+
# "queue_name"=>"default",
|
|
76
|
+
# "priority"=>nil,
|
|
77
|
+
# "arguments"=>[],
|
|
78
|
+
# "executions"=>0,
|
|
79
|
+
# "locale"=>"en"
|
|
80
|
+
# }],
|
|
81
|
+
# "error_count"=>0
|
|
82
|
+
# }
|
|
83
|
+
#
|
|
84
|
+
# With ActiveJob, v1.0:
|
|
85
|
+
# There are changes here to make Que more compatible with ActiveJob
|
|
86
|
+
# and this probably needs to be revisited.
|
|
87
|
+
|
|
88
|
+
def _run_with_scout(*args)
|
|
89
|
+
# default queue unless specifed is a blank string
|
|
90
|
+
queue = attrs['queue'] || UNKNOWN_QUEUE_PLACEHOLDER
|
|
91
|
+
|
|
92
|
+
job_class = begin
|
|
93
|
+
if self.class == ActiveJob::QueueAdapters::QueAdapter::JobWrapper
|
|
94
|
+
Array(attrs['args']).first['job_class'] || UNKNOWN_CLASS_PLACEHOLDER
|
|
95
|
+
else
|
|
96
|
+
self.class.name
|
|
97
|
+
end
|
|
98
|
+
rescue => e
|
|
99
|
+
UNKNOWN_CLASS_PLACEHOLDER
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
latency = begin
|
|
103
|
+
Time.now - attrs['run_at']
|
|
104
|
+
rescue
|
|
105
|
+
0
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
req = ScoutApm::RequestManager.lookup
|
|
109
|
+
req.annotate_request(:queue_latency => latency)
|
|
110
|
+
|
|
111
|
+
begin
|
|
112
|
+
req.start_layer(ScoutApm::Layer.new('Queue', queue))
|
|
113
|
+
started_queue = true
|
|
114
|
+
req.start_layer(ScoutApm::Layer.new('Job', job_class))
|
|
115
|
+
started_job = true
|
|
116
|
+
|
|
117
|
+
_run_without_scout(*args)
|
|
118
|
+
rescue Exception => e
|
|
119
|
+
req.error!
|
|
120
|
+
raise
|
|
121
|
+
ensure
|
|
122
|
+
req.stop_layer if started_job
|
|
123
|
+
req.stop_layer if started_queue
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
alias_method :_run_without_scout, :_run
|
|
128
|
+
alias_method :_run, :_run_with_scout
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
end
|
|
134
|
+
end
|
|
@@ -26,8 +26,12 @@ module ScoutApm
|
|
|
26
26
|
def install_before_fork
|
|
27
27
|
::Resque.before_first_fork do
|
|
28
28
|
begin
|
|
29
|
-
ScoutApm::Agent.instance.
|
|
30
|
-
|
|
29
|
+
if ScoutApm::Agent.instance.context.config.value('start_resque_server_instrument')
|
|
30
|
+
ScoutApm::Agent.instance.start
|
|
31
|
+
ScoutApm::Agent.instance.context.start_remote_server!(bind, port)
|
|
32
|
+
else
|
|
33
|
+
logger.info("Not starting remote server due to 'start_resque_server_instrument' setting")
|
|
34
|
+
end
|
|
31
35
|
rescue Errno::EADDRINUSE
|
|
32
36
|
ScoutApm::Agent.instance.context.logger.warn "Error while Installing Resque Instruments, Port #{port} already in use. Set via the `remote_agent_port` configuration option"
|
|
33
37
|
rescue => e
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
module ScoutApm
|
|
2
|
+
module BackgroundJobIntegrations
|
|
3
|
+
class Shoryuken
|
|
4
|
+
attr_reader :logger
|
|
5
|
+
|
|
6
|
+
def name
|
|
7
|
+
:shoryuken
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def present?
|
|
11
|
+
defined?(::Shoryuken) && File.basename($PROGRAM_NAME).start_with?('shoryuken')
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def forking?
|
|
15
|
+
false
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def install
|
|
19
|
+
install_tracer
|
|
20
|
+
add_middleware
|
|
21
|
+
install_processor
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def install_tracer
|
|
25
|
+
# ScoutApm::Tracer is not available when this class is defined
|
|
26
|
+
ShoryukenMiddleware.class_eval do
|
|
27
|
+
include ScoutApm::Tracer
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def add_middleware
|
|
32
|
+
::Shoryuken.configure_server do |config|
|
|
33
|
+
config.server_middleware do |chain|
|
|
34
|
+
chain.add ShoryukenMiddleware
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def install_processor
|
|
40
|
+
require 'shoryuken/processor' # sidekiq v4 has not loaded this file by this point
|
|
41
|
+
|
|
42
|
+
::Shoryuken::Processor.class_eval do
|
|
43
|
+
def initialize_with_scout(*args)
|
|
44
|
+
agent = ::ScoutApm::Agent.instance
|
|
45
|
+
agent.start
|
|
46
|
+
initialize_without_scout(*args)
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
alias_method :initialize_without_scout, :initialize
|
|
50
|
+
alias_method :initialize, :initialize_with_scout
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# We insert this middleware into the Shoryuken stack, to capture each job,
|
|
56
|
+
# and time them.
|
|
57
|
+
class ShoryukenMiddleware
|
|
58
|
+
def call(worker_instance, queue, msg, body)
|
|
59
|
+
job_class =
|
|
60
|
+
begin
|
|
61
|
+
if worker_instance.class.to_s == ACTIVE_JOB_KLASS
|
|
62
|
+
body["job_class"]
|
|
63
|
+
else
|
|
64
|
+
worker_instance.class.to_s
|
|
65
|
+
end
|
|
66
|
+
rescue
|
|
67
|
+
UNKNOWN_CLASS_PLACEHOLDER
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
req = ScoutApm::RequestManager.lookup
|
|
71
|
+
req.annotate_request(:queue_latency => latency(msg))
|
|
72
|
+
|
|
73
|
+
begin
|
|
74
|
+
req.start_layer(ScoutApm::Layer.new('Queue', queue))
|
|
75
|
+
started_queue = true
|
|
76
|
+
req.start_layer(ScoutApm::Layer.new('Job', job_class))
|
|
77
|
+
started_job = true
|
|
78
|
+
|
|
79
|
+
yield
|
|
80
|
+
rescue Exception => e
|
|
81
|
+
req.error!
|
|
82
|
+
raise
|
|
83
|
+
ensure
|
|
84
|
+
req.stop_layer if started_job
|
|
85
|
+
req.stop_layer if started_queue
|
|
86
|
+
end
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
UNKNOWN_CLASS_PLACEHOLDER = 'UnknownJob'.freeze
|
|
90
|
+
ACTIVE_JOB_KLASS = 'ActiveJob::QueueAdapters::ShoryukenAdapter::JobWrapper'.freeze
|
|
91
|
+
|
|
92
|
+
def latency(msg, time = Time.now.to_f)
|
|
93
|
+
ms_since_epoch_str = msg.attributes.fetch('SentTimestamp', 0)
|
|
94
|
+
return 0 if ms_since_epoch_str.nil?
|
|
95
|
+
|
|
96
|
+
# Convert from ms to seconds as a float
|
|
97
|
+
created_at = ms_since_epoch_str.to_i / 1000.0
|
|
98
|
+
|
|
99
|
+
time - created_at
|
|
100
|
+
rescue => e
|
|
101
|
+
0
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
# MSG: #<Shoryuken::Message:0x007fb742a96950 @client=#<Aws::SQS::Client>
|
|
108
|
+
# @data=#<struct Aws::SQS::Types::Message message_id="7a2ef0af-2bbd-4368-9c39-34cc89e4da15"
|
|
109
|
+
# receipt_handle="AQEB8YK4+TCyvCM3p0EanmhZiTbBCM6uMeyCn7zibNn+XZcMnjZp2Z8D8yoUs4mMX9vJqlQvaS8gRUGBYG7ciq+BthmEqDWfxbcJ8jN+Vp/PXIyyTgYL3vvlnHcQajDz3H7Bd30UmLu80sqeLSjXXNEiKolcIxdGuIsIdSM4aUEPXsecr5eH7o8pZHcDV+bGcLuE7VbvKRZT3A2HeezW7wWwkYve/wt6asS1bYB+VJurAORY0y26xgCooEMNbs5yqxcnSD/CiNT822hkmw0eHNpTHOjF9WLgxLbkpITnQl1lsfK5TsM/ukE1oB1F9nN5ZkCBVCDeFYJDBAo81VvVV9G16knxyCYzjnmpwhvHg2BqTA56iV6r9KZYbiwOaMPdH5ealKLRnWhFoLOEPNA4yjG1yw=="
|
|
110
|
+
# md5_of_body="8b3be018857a74f9e46b4c6ef3c3f515"
|
|
111
|
+
# body="Unique Person #7532"
|
|
112
|
+
# attributes={"SenderId"=>"AIDAJZXBVF26MLZPE6FOO"
|
|
113
|
+
# "ApproximateFirstReceiveTimestamp"=>"1534873932213"
|
|
114
|
+
# "ApproximateReceiveCount"=>"1"
|
|
115
|
+
# "SentTimestamp"=>"1534873927868"}
|
|
116
|
+
# md5_of_message_attributes="c70f52a6566cf42ec5e61e81877132dd"
|
|
117
|
+
# message_attributes={"shoryuken_class"=>#<struct Aws::SQS::Types::MessageAttributeValue string_value="DummyWorker"
|
|
118
|
+
# binary_value=nil
|
|
119
|
+
# string_list_values=[]
|
|
120
|
+
# binary_list_values=[]
|
|
121
|
+
# data_type="String">}>
|
|
122
|
+
# @queue_url="https://sqs.us-west-2.amazonaws.com/023109228371/shoryuken_test"
|
|
123
|
+
# @queue_name="shoryuken_test">
|
|
124
|
+
|
|
@@ -40,10 +40,10 @@ module ScoutApm
|
|
|
40
40
|
require 'sidekiq/processor' # sidekiq v4 has not loaded this file by this point
|
|
41
41
|
|
|
42
42
|
::Sidekiq::Processor.class_eval do
|
|
43
|
-
def initialize_with_scout(
|
|
43
|
+
def initialize_with_scout(*args)
|
|
44
44
|
agent = ::ScoutApm::Agent.instance
|
|
45
45
|
agent.start
|
|
46
|
-
initialize_without_scout(
|
|
46
|
+
initialize_without_scout(*args)
|
|
47
47
|
end
|
|
48
48
|
|
|
49
49
|
alias_method :initialize_without_scout, :initialize
|
|
@@ -59,20 +59,10 @@ module ScoutApm
|
|
|
59
59
|
req = ScoutApm::RequestManager.lookup
|
|
60
60
|
req.annotate_request(:queue_latency => latency(msg))
|
|
61
61
|
|
|
62
|
-
queue_layer = ScoutApm::Layer.new('Queue', queue)
|
|
63
|
-
job_layer = ScoutApm::Layer.new('Job', job_class(msg))
|
|
64
|
-
|
|
65
|
-
if ScoutApm::Agent.instance.context.config.value('profile') && SidekiqMiddleware.version_supports_profiling?
|
|
66
|
-
# Capture ScoutProf if we can
|
|
67
|
-
#req.enable_profiled_thread!
|
|
68
|
-
#job_layer.set_root_class(job_class)
|
|
69
|
-
#job_layer.traced!
|
|
70
|
-
end
|
|
71
|
-
|
|
72
62
|
begin
|
|
73
|
-
req.start_layer(
|
|
63
|
+
req.start_layer(ScoutApm::Layer.new('Queue', queue))
|
|
74
64
|
started_queue = true
|
|
75
|
-
req.start_layer(
|
|
65
|
+
req.start_layer(ScoutApm::Layer.new('Job', job_class(msg)))
|
|
76
66
|
started_job = true
|
|
77
67
|
|
|
78
68
|
yield
|
|
@@ -131,10 +121,6 @@ module ScoutApm
|
|
|
131
121
|
rescue
|
|
132
122
|
0
|
|
133
123
|
end
|
|
134
|
-
|
|
135
|
-
def self.version_supports_profiling?
|
|
136
|
-
@@sidekiq_supports_profling ||= defined?(::Sidekiq::VERSION) && Gem::Dependency.new('', '~> 4.0').match?('', ::Sidekiq::VERSION.to_s)
|
|
137
|
-
end
|
|
138
|
-
end # SidekiqMiddleware
|
|
124
|
+
end
|
|
139
125
|
end
|
|
140
126
|
end
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
module ScoutApm
|
|
2
|
+
module BackgroundJobIntegrations
|
|
3
|
+
class Sneakers
|
|
4
|
+
def name
|
|
5
|
+
:sneakers
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def present?
|
|
9
|
+
defined?(::Sneakers) && supported_version?
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
# Only support Sneakers 2.7 and up
|
|
13
|
+
def supported_version?
|
|
14
|
+
result = Gem::Version.new(::Sneakers::VERSION) > Gem::Version.new("2.7.0")
|
|
15
|
+
ScoutApm::Agent.instance.logger.info("Skipping Sneakers instrumentation. Only versions 2.7+ are supported. See docs or contact support@scoutapm.com for instrumentation of older versions.")
|
|
16
|
+
result
|
|
17
|
+
rescue
|
|
18
|
+
ScoutApm::Agent.instance.logger.info("Failed comparing Sneakers Version. Skipping")
|
|
19
|
+
false
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def forking?
|
|
23
|
+
false
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def install
|
|
27
|
+
install_worker_override
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def install_worker_override
|
|
31
|
+
::Sneakers::Worker.module_eval do
|
|
32
|
+
def initialize_with_scout(*args)
|
|
33
|
+
agent = ::ScoutApm::Agent.instance
|
|
34
|
+
agent.start
|
|
35
|
+
initialize_without_scout(*args)
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
alias_method :initialize_without_scout, :initialize
|
|
39
|
+
alias_method :initialize, :initialize_with_scout
|
|
40
|
+
|
|
41
|
+
def process_work_with_scout(*args)
|
|
42
|
+
delivery_info, _metadata, msg, _handler = args
|
|
43
|
+
|
|
44
|
+
queue = delivery_info[:routing_key] || UNKNOWN_QUEUE_PLACEHOLDER
|
|
45
|
+
|
|
46
|
+
job_class = begin
|
|
47
|
+
if self.class == ActiveJob::QueueAdapters::SneakersAdapter::JobWrapper
|
|
48
|
+
msg["job_class"] || UNKNOWN_CLASS_PLACEHOLDER
|
|
49
|
+
else
|
|
50
|
+
self.class.name
|
|
51
|
+
end
|
|
52
|
+
rescue => e
|
|
53
|
+
UNKNOWN_CLASS_PLACEHOLDER
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
req = ScoutApm::RequestManager.lookup
|
|
57
|
+
|
|
58
|
+
# RabbitMQ does not store a created-at timestamp
|
|
59
|
+
# req.annotate_request(:queue_latency => latency(msg))
|
|
60
|
+
|
|
61
|
+
begin
|
|
62
|
+
req.start_layer(ScoutApm::Layer.new('Queue', queue))
|
|
63
|
+
started_queue = true
|
|
64
|
+
req.start_layer(ScoutApm::Layer.new('Job', job_class))
|
|
65
|
+
started_job = true
|
|
66
|
+
|
|
67
|
+
process_work_without_scout(*args)
|
|
68
|
+
rescue Exception => e
|
|
69
|
+
req.error!
|
|
70
|
+
raise
|
|
71
|
+
ensure
|
|
72
|
+
req.stop_layer if started_job
|
|
73
|
+
req.stop_layer if started_queue
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
alias_method :process_work_without_scout, :process_work
|
|
78
|
+
alias_method :process_work, :process_work_with_scout
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
ACTIVE_JOB_KLASS = 'ActiveJob::QueueAdapters::SneakersAdapter::JobWrapper'.freeze
|
|
83
|
+
UNKNOWN_CLASS_PLACEHOLDER = 'UnknownJob'.freeze
|
|
84
|
+
UNKNOWN_QUEUE_PLACEHOLDER = 'default'.freeze
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end
|
data/lib/scout_apm/config.rb
CHANGED
|
@@ -6,10 +6,11 @@ require 'scout_apm/environment'
|
|
|
6
6
|
# Valid Config Options:
|
|
7
7
|
#
|
|
8
8
|
# This list is complete, but some are old and unused, or for developers of
|
|
9
|
-
# scout_apm itself. See the documentation at
|
|
9
|
+
# scout_apm itself. See the documentation at https://docs.scoutapm.com for
|
|
10
10
|
# customer-focused documentation.
|
|
11
11
|
#
|
|
12
12
|
# application_root - override the detected directory of the application
|
|
13
|
+
# collect_remote_ip - automatically capture user's IP into a Trace's Context
|
|
13
14
|
# compress_payload - true/false to enable gzipping of payload
|
|
14
15
|
# data_file - override the default temporary storage location. Must be a location in a writable directory
|
|
15
16
|
# dev_trace - true or false. Enables always-on tracing in development environmen only
|
|
@@ -30,6 +31,10 @@ require 'scout_apm/environment'
|
|
|
30
31
|
# uri_reporting - 'path' or 'full_path' default is 'full_path', which reports URL params as well as the path.
|
|
31
32
|
# remote_agent_host - Internal: What host to bind to, and also send messages to for remote. Default: 127.0.0.1.
|
|
32
33
|
# remote_agent_port - What port to bind the remote webserver to
|
|
34
|
+
# start_resque_server_instrument - Used in special situations with certain Resque installs
|
|
35
|
+
# timeline_traces - true/false to enable sending of of the timeline trace format.
|
|
36
|
+
# auto_instruments - true/false whether to install autoinstruments. Only installed if on a supported Ruby version.
|
|
37
|
+
# auto_instruments_ignore - An array of file names to exclude from autoinstruments (Ex: ['application_controller']).
|
|
33
38
|
#
|
|
34
39
|
# Any of these config settings can be set with an environment variable prefixed
|
|
35
40
|
# by SCOUT_ and uppercasing the key: SCOUT_LOG_LEVEL for instance.
|
|
@@ -39,6 +44,7 @@ module ScoutApm
|
|
|
39
44
|
KNOWN_CONFIG_OPTIONS = [
|
|
40
45
|
'application_root',
|
|
41
46
|
'async_recording',
|
|
47
|
+
'collect_remote_ip',
|
|
42
48
|
'compress_payload',
|
|
43
49
|
'config_file',
|
|
44
50
|
'data_file',
|
|
@@ -66,9 +72,21 @@ module ScoutApm
|
|
|
66
72
|
'remote_agent_host',
|
|
67
73
|
'remote_agent_port',
|
|
68
74
|
'report_format',
|
|
75
|
+
'revision_sha',
|
|
69
76
|
'scm_subdirectory',
|
|
77
|
+
'start_resque_server_instrument',
|
|
78
|
+
'ssl_cert_file',
|
|
70
79
|
'uri_reporting',
|
|
71
80
|
'instrument_http_url_length',
|
|
81
|
+
'timeline_traces',
|
|
82
|
+
'auto_instruments',
|
|
83
|
+
'auto_instruments_ignore',
|
|
84
|
+
|
|
85
|
+
# Error Service Related Configuration
|
|
86
|
+
'errors_enabled',
|
|
87
|
+
'errors_ignored_exceptions',
|
|
88
|
+
'errors_filtered_params',
|
|
89
|
+
'errors_host',
|
|
72
90
|
]
|
|
73
91
|
|
|
74
92
|
################################################################################
|
|
@@ -148,16 +166,25 @@ module ScoutApm
|
|
|
148
166
|
|
|
149
167
|
|
|
150
168
|
SETTING_COERCIONS = {
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
169
|
+
'async_recording' => BooleanCoercion.new,
|
|
170
|
+
'detailed_middleware' => BooleanCoercion.new,
|
|
171
|
+
'dev_trace' => BooleanCoercion.new,
|
|
172
|
+
'enable_background_jobs' => BooleanCoercion.new,
|
|
173
|
+
'ignore' => JsonCoercion.new,
|
|
174
|
+
'max_traces' => IntegerCoercion.new,
|
|
175
|
+
'monitor' => BooleanCoercion.new,
|
|
176
|
+
'collect_remote_ip' => BooleanCoercion.new,
|
|
177
|
+
'compress_payload' => BooleanCoercion.new,
|
|
158
178
|
'database_metric_limit' => IntegerCoercion.new,
|
|
159
179
|
'database_metric_report_limit' => IntegerCoercion.new,
|
|
160
180
|
'instrument_http_url_length' => IntegerCoercion.new,
|
|
181
|
+
'start_resque_server_instrument' => BooleanCoercion.new,
|
|
182
|
+
'timeline_traces' => BooleanCoercion.new,
|
|
183
|
+
'auto_instruments' => BooleanCoercion.new,
|
|
184
|
+
'auto_instruments_ignore' => JsonCoercion.new,
|
|
185
|
+
'errors_enabled' => BooleanCoercion.new,
|
|
186
|
+
'errors_ignored_exceptions' => JsonCoercion.new,
|
|
187
|
+
'errors_filtered_params' => JsonCoercion.new,
|
|
161
188
|
}
|
|
162
189
|
|
|
163
190
|
|
|
@@ -263,6 +290,16 @@ module ScoutApm
|
|
|
263
290
|
'database_metric_limit' => 5000, # The hard limit on db metrics
|
|
264
291
|
'database_metric_report_limit' => 1000,
|
|
265
292
|
'instrument_http_url_length' => 300,
|
|
293
|
+
'start_resque_server_instrument' => true, # still only starts if Resque is detected
|
|
294
|
+
'collect_remote_ip' => true,
|
|
295
|
+
'timeline_traces' => true,
|
|
296
|
+
'auto_instruments' => false,
|
|
297
|
+
'auto_instruments_ignore' => [],
|
|
298
|
+
'ssl_cert_file' => File.join( File.dirname(__FILE__), *%w[.. .. data cacert.pem] ),
|
|
299
|
+
'errors_enabled' => false,
|
|
300
|
+
'errors_ignored_exceptions' => %w(ActiveRecord::RecordNotFound ActionController::RoutingError),
|
|
301
|
+
'errors_filtered_params' => %w(password s3-key),
|
|
302
|
+
'errors_host' => 'https://errors.scoutapm.com',
|
|
266
303
|
}.freeze
|
|
267
304
|
|
|
268
305
|
def value(key)
|