scout_apm 2.6.10 → 3.0.0.pre0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.gitignore +1 -2
- data/.rubocop.yml +3 -11
- data/CHANGELOG.markdown +4 -362
- data/Gemfile +1 -14
- data/README.markdown +7 -52
- data/Rakefile +1 -0
- data/ext/allocations/allocations.c +1 -7
- data/ext/allocations/extconf.rb +0 -1
- data/ext/rusage/rusage.c +0 -26
- data/ext/stacks/extconf.rb +37 -0
- data/ext/stacks/scout_atomics.h +86 -0
- data/ext/stacks/stacks.c +811 -0
- data/lib/scout_apm/agent/logging.rb +69 -0
- data/lib/scout_apm/agent/reporting.rb +126 -0
- data/lib/scout_apm/agent.rb +259 -138
- data/lib/scout_apm/app_server_load.rb +15 -41
- data/lib/scout_apm/attribute_arranger.rb +3 -14
- data/lib/scout_apm/background_job_integrations/delayed_job.rb +1 -70
- data/lib/scout_apm/background_job_integrations/sidekiq.rb +24 -31
- data/lib/scout_apm/background_worker.rb +12 -23
- data/lib/scout_apm/capacity.rb +57 -0
- data/lib/scout_apm/config.rb +37 -206
- data/lib/scout_apm/context.rb +4 -20
- data/lib/scout_apm/deploy_integrations/capistrano_2.cap +12 -0
- data/lib/scout_apm/deploy_integrations/capistrano_2.rb +83 -0
- data/lib/scout_apm/deploy_integrations/capistrano_3.cap +12 -0
- data/lib/scout_apm/deploy_integrations/capistrano_3.rb +88 -0
- data/lib/scout_apm/environment.rb +28 -42
- data/lib/scout_apm/fake_store.rb +0 -12
- data/lib/scout_apm/framework_integrations/rails_2.rb +1 -2
- data/lib/scout_apm/framework_integrations/rails_3_or_4.rb +6 -17
- data/lib/scout_apm/framework_integrations/sinatra.rb +1 -1
- data/lib/scout_apm/histogram.rb +3 -12
- data/lib/scout_apm/instant/assets/xmlhttp_instrumentation.html +2 -2
- data/lib/scout_apm/instant/middleware.rb +54 -202
- data/lib/scout_apm/instant_reporting.rb +7 -7
- data/lib/scout_apm/instruments/.DS_Store +0 -0
- data/lib/scout_apm/instruments/action_controller_rails_2.rb +9 -15
- data/lib/scout_apm/instruments/action_controller_rails_3_rails4.rb +76 -124
- data/lib/scout_apm/instruments/active_record.rb +29 -324
- data/lib/scout_apm/instruments/delayed_job.rb +57 -0
- data/lib/scout_apm/instruments/elasticsearch.rb +6 -10
- data/lib/scout_apm/instruments/grape.rb +9 -12
- data/lib/scout_apm/instruments/http_client.rb +7 -14
- data/lib/scout_apm/instruments/influxdb.rb +6 -10
- data/lib/scout_apm/instruments/middleware_detailed.rb +11 -15
- data/lib/scout_apm/instruments/middleware_summary.rb +5 -11
- data/lib/scout_apm/instruments/mongoid.rb +8 -39
- data/lib/scout_apm/instruments/moped.rb +6 -11
- data/lib/scout_apm/instruments/net_http.rb +9 -27
- data/lib/scout_apm/instruments/percentile_sampler.rb +23 -42
- data/lib/scout_apm/instruments/process/process_cpu.rb +6 -11
- data/lib/scout_apm/instruments/process/process_memory.rb +12 -17
- data/lib/scout_apm/instruments/rails_router.rb +6 -12
- data/lib/scout_apm/instruments/redis.rb +6 -10
- data/lib/scout_apm/instruments/sinatra.rb +4 -5
- data/lib/scout_apm/job_record.rb +2 -4
- data/lib/scout_apm/layaway.rb +34 -88
- data/lib/scout_apm/layaway_file.rb +3 -13
- data/lib/scout_apm/layer.rb +60 -25
- data/lib/scout_apm/layer_converters/allocation_metric_converter.rb +6 -7
- data/lib/scout_apm/layer_converters/converter_base.rb +14 -203
- data/lib/scout_apm/layer_converters/depth_first_walker.rb +10 -22
- data/lib/scout_apm/layer_converters/error_converter.rb +8 -8
- data/lib/scout_apm/layer_converters/job_converter.rb +50 -37
- data/lib/scout_apm/layer_converters/metric_converter.rb +19 -18
- data/lib/scout_apm/layer_converters/request_queue_time_converter.rb +13 -13
- data/lib/scout_apm/layer_converters/slow_job_converter.rb +116 -52
- data/lib/scout_apm/layer_converters/slow_request_converter.rb +120 -51
- data/lib/scout_apm/metric_meta.rb +5 -0
- data/lib/scout_apm/metric_set.rb +1 -9
- data/lib/scout_apm/metric_stats.rb +8 -7
- data/lib/scout_apm/middleware.rb +9 -7
- data/lib/scout_apm/reporter.rb +24 -71
- data/lib/scout_apm/request_histograms.rb +0 -12
- data/lib/scout_apm/request_manager.rb +7 -5
- data/lib/scout_apm/scored_item_set.rb +0 -7
- data/lib/scout_apm/serializers/app_server_load_serializer.rb +0 -4
- data/lib/scout_apm/serializers/deploy_serializer.rb +16 -0
- data/lib/scout_apm/serializers/directive_serializer.rb +0 -4
- data/lib/scout_apm/serializers/payload_serializer.rb +4 -11
- data/lib/scout_apm/serializers/payload_serializer_to_json.rb +16 -35
- data/lib/scout_apm/serializers/slow_jobs_serializer_to_json.rb +1 -2
- data/lib/scout_apm/server_integrations/passenger.rb +1 -1
- data/lib/scout_apm/server_integrations/puma.rb +2 -5
- data/lib/scout_apm/slow_job_policy.rb +13 -25
- data/lib/scout_apm/slow_job_record.rb +4 -13
- data/lib/scout_apm/slow_request_policy.rb +13 -25
- data/lib/scout_apm/slow_transaction.rb +5 -25
- data/lib/scout_apm/store.rb +32 -99
- data/lib/scout_apm/trace_compactor.rb +312 -0
- data/lib/scout_apm/tracer.rb +31 -35
- data/lib/scout_apm/tracked_request.rb +95 -262
- data/lib/scout_apm/utils/active_record_metric_name.rb +13 -88
- data/lib/scout_apm/utils/backtrace_parser.rb +4 -7
- data/lib/scout_apm/utils/fake_stacks.rb +87 -0
- data/lib/scout_apm/utils/installed_gems.rb +3 -7
- data/lib/scout_apm/utils/klass_helper.rb +2 -8
- data/lib/scout_apm/utils/null_logger.rb +13 -0
- data/lib/scout_apm/utils/sql_sanitizer.rb +5 -16
- data/lib/scout_apm/utils/sql_sanitizer_regex.rb +0 -7
- data/lib/scout_apm/utils/sql_sanitizer_regex_1_8_7.rb +0 -6
- data/lib/scout_apm/utils/unique_id.rb +0 -27
- data/lib/scout_apm/version.rb +2 -1
- data/lib/scout_apm.rb +25 -84
- data/scout_apm.gemspec +3 -17
- data/test/test_helper.rb +3 -57
- data/test/unit/agent_test.rb +54 -1
- data/test/unit/background_job_integrations/sidekiq_test.rb +3 -0
- data/test/unit/config_test.rb +12 -25
- data/test/unit/context_test.rb +4 -4
- data/test/unit/histogram_test.rb +4 -25
- data/test/unit/ignored_uris_test.rb +1 -1
- data/test/unit/instruments/active_record_instruments_test.rb +5 -0
- data/test/unit/layaway_test.rb +2 -62
- data/test/unit/serializers/payload_serializer_test.rb +15 -43
- data/test/unit/slow_request_policy_test.rb +6 -15
- data/test/unit/sql_sanitizer_test.rb +6 -53
- data/test/unit/store_test.rb +4 -73
- data/test/unit/utils/active_record_metric_name_test.rb +5 -59
- data/test/unit/utils/backtrace_parser_test.rb +1 -6
- data/tester.rb +53 -0
- metadata +28 -229
- data/.travis.yml +0 -26
- data/Guardfile +0 -43
- data/gems/README.md +0 -28
- data/gems/octoshark.gemfile +0 -4
- data/gems/rails3.gemfile +0 -5
- data/gems/rails4.gemfile +0 -4
- data/gems/rails5.gemfile +0 -4
- data/gems/rails6.gemfile +0 -4
- data/lib/scout_apm/agent/exit_handler.rb +0 -65
- data/lib/scout_apm/agent/preconditions.rb +0 -81
- data/lib/scout_apm/agent_context.rb +0 -261
- data/lib/scout_apm/auto_instrument/instruction_sequence.rb +0 -31
- data/lib/scout_apm/auto_instrument/layer.rb +0 -23
- data/lib/scout_apm/auto_instrument/parser.rb +0 -27
- data/lib/scout_apm/auto_instrument/rails.rb +0 -175
- data/lib/scout_apm/auto_instrument.rb +0 -5
- data/lib/scout_apm/background_job_integrations/legacy_sneakers.rb +0 -55
- data/lib/scout_apm/background_job_integrations/que.rb +0 -134
- data/lib/scout_apm/background_job_integrations/resque.rb +0 -88
- data/lib/scout_apm/background_job_integrations/shoryuken.rb +0 -124
- data/lib/scout_apm/background_job_integrations/sneakers.rb +0 -87
- data/lib/scout_apm/background_recorder.rb +0 -48
- data/lib/scout_apm/db_query_metric_set.rb +0 -97
- data/lib/scout_apm/db_query_metric_stats.rb +0 -102
- data/lib/scout_apm/debug.rb +0 -37
- data/lib/scout_apm/detailed_trace.rb +0 -217
- data/lib/scout_apm/error.rb +0 -27
- data/lib/scout_apm/error_service/error_buffer.rb +0 -39
- data/lib/scout_apm/error_service/error_record.rb +0 -211
- data/lib/scout_apm/error_service/ignored_exceptions.rb +0 -66
- data/lib/scout_apm/error_service/middleware.rb +0 -32
- data/lib/scout_apm/error_service/notifier.rb +0 -33
- data/lib/scout_apm/error_service/payload.rb +0 -47
- data/lib/scout_apm/error_service/periodic_work.rb +0 -17
- data/lib/scout_apm/error_service/railtie.rb +0 -11
- data/lib/scout_apm/error_service/sidekiq.rb +0 -80
- data/lib/scout_apm/error_service.rb +0 -32
- data/lib/scout_apm/extensions/config.rb +0 -87
- data/lib/scout_apm/extensions/transaction_callback_payload.rb +0 -74
- data/lib/scout_apm/git_revision.rb +0 -59
- data/lib/scout_apm/instrument_manager.rb +0 -88
- data/lib/scout_apm/instruments/action_view.rb +0 -141
- data/lib/scout_apm/instruments/http.rb +0 -48
- data/lib/scout_apm/instruments/memcached.rb +0 -43
- data/lib/scout_apm/instruments/resque.rb +0 -39
- data/lib/scout_apm/instruments/samplers.rb +0 -11
- data/lib/scout_apm/layer_children_set.rb +0 -86
- data/lib/scout_apm/layer_converters/database_converter.rb +0 -70
- data/lib/scout_apm/layer_converters/find_layer_by_type.rb +0 -38
- data/lib/scout_apm/layer_converters/histograms.rb +0 -15
- data/lib/scout_apm/layer_converters/trace_converter.rb +0 -184
- data/lib/scout_apm/limited_layer.rb +0 -126
- data/lib/scout_apm/logger.rb +0 -158
- data/lib/scout_apm/periodic_work.rb +0 -47
- data/lib/scout_apm/rack.rb +0 -26
- data/lib/scout_apm/remote/message.rb +0 -27
- data/lib/scout_apm/remote/recorder.rb +0 -57
- data/lib/scout_apm/remote/router.rb +0 -49
- data/lib/scout_apm/remote/server.rb +0 -60
- data/lib/scout_apm/reporting.rb +0 -143
- data/lib/scout_apm/serializers/db_query_serializer_to_json.rb +0 -15
- data/lib/scout_apm/serializers/histograms_serializer_to_json.rb +0 -21
- data/lib/scout_apm/synchronous_recorder.rb +0 -30
- data/lib/scout_apm/tasks/doctor.rb +0 -75
- data/lib/scout_apm/tasks/support.rb +0 -22
- data/lib/scout_apm/transaction.rb +0 -13
- data/lib/scout_apm/transaction_time_consumed.rb +0 -51
- data/lib/scout_apm/utils/gzip_helper.rb +0 -24
- data/lib/scout_apm/utils/marshal_logging.rb +0 -90
- data/lib/scout_apm/utils/numbers.rb +0 -14
- data/lib/scout_apm/utils/scm.rb +0 -14
- data/lib/tasks/doctor.rake +0 -11
- data/test/tmp/README.md +0 -17
- data/test/unit/agent_context_test.rb +0 -15
- data/test/unit/auto_instrument/assignments-instrumented.rb +0 -31
- data/test/unit/auto_instrument/assignments.rb +0 -31
- data/test/unit/auto_instrument/controller-ast.txt +0 -57
- data/test/unit/auto_instrument/controller-instrumented.rb +0 -49
- data/test/unit/auto_instrument/controller.rb +0 -49
- data/test/unit/auto_instrument/rescue_from-instrumented.rb +0 -13
- data/test/unit/auto_instrument/rescue_from.rb +0 -13
- data/test/unit/auto_instrument_test.rb +0 -54
- data/test/unit/db_query_metric_set_test.rb +0 -67
- data/test/unit/db_query_metric_stats_test.rb +0 -113
- data/test/unit/error_service/error_buffer_test.rb +0 -25
- data/test/unit/error_service/ignored_exceptions_test.rb +0 -49
- data/test/unit/extensions/periodic_callbacks_test.rb +0 -58
- data/test/unit/extensions/transaction_callbacks_test.rb +0 -58
- data/test/unit/fake_store_test.rb +0 -10
- data/test/unit/git_revision_test.rb +0 -15
- data/test/unit/instruments/active_record_test.rb +0 -40
- data/test/unit/instruments/net_http_test.rb +0 -27
- data/test/unit/instruments/percentile_sampler_test.rb +0 -133
- data/test/unit/layer_children_set_test.rb +0 -97
- data/test/unit/layer_converters/depth_first_walker_test.rb +0 -70
- data/test/unit/layer_converters/metric_converter_test.rb +0 -22
- data/test/unit/layer_converters/stubs.rb +0 -33
- data/test/unit/limited_layer_test.rb +0 -53
- data/test/unit/logger_test.rb +0 -69
- data/test/unit/remote/test_message.rb +0 -13
- data/test/unit/remote/test_router.rb +0 -33
- data/test/unit/remote/test_server.rb +0 -15
- data/test/unit/request_histograms_test.rb +0 -17
- data/test/unit/tracer_test.rb +0 -76
- data/test/unit/tracked_request_test.rb +0 -71
- data/test/unit/transaction_test.rb +0 -14
- data/test/unit/transaction_time_consumed_test.rb +0 -46
- data/test/unit/utils/numbers_test.rb +0 -15
- data/test/unit/utils/scm.rb +0 -17
@@ -1,9 +1,6 @@
|
|
1
1
|
module ScoutApm
|
2
2
|
module BackgroundJobIntegrations
|
3
3
|
class DelayedJob
|
4
|
-
ACTIVE_JOB_KLASS = 'ActiveJob::QueueAdapters::DelayedJobAdapter::JobWrapper'.freeze
|
5
|
-
DJ_PERFORMABLE_METHOD = 'Delayed::PerformableMethod'.freeze
|
6
|
-
|
7
4
|
attr_reader :logger
|
8
5
|
|
9
6
|
def name
|
@@ -11,78 +8,12 @@ module ScoutApm
|
|
11
8
|
end
|
12
9
|
|
13
10
|
def present?
|
14
|
-
defined?(::Delayed::Job)
|
11
|
+
defined?(::Delayed::Job) && (File.basename($0) =~ /\Adelayed_job/)
|
15
12
|
end
|
16
13
|
|
17
14
|
def forking?
|
18
15
|
false
|
19
16
|
end
|
20
|
-
|
21
|
-
def install
|
22
|
-
plugin = Class.new(Delayed::Plugin) do
|
23
|
-
require 'delayed_job'
|
24
|
-
|
25
|
-
callbacks do |lifecycle|
|
26
|
-
lifecycle.around(:invoke_job) do |job, *args, &block|
|
27
|
-
ScoutApm::Agent.instance.start_background_worker unless ScoutApm::Agent.instance.background_worker_running?
|
28
|
-
|
29
|
-
name = begin
|
30
|
-
case job.payload_object.class.to_s
|
31
|
-
|
32
|
-
# ActiveJob's class wraps the actual job class
|
33
|
-
when ACTIVE_JOB_KLASS
|
34
|
-
job.payload_object.job_data["job_class"]
|
35
|
-
|
36
|
-
# An adhoc job, called like `@user.delay.fib(10)`.
|
37
|
-
# returns a string like "User#fib"
|
38
|
-
when DJ_PERFORMABLE_METHOD
|
39
|
-
job.name
|
40
|
-
|
41
|
-
# A "real" job called like `Delayed::Job.enqueue(MyJob.new)`
|
42
|
-
# returns "MyJob"
|
43
|
-
else
|
44
|
-
job.payload_object.class.to_s
|
45
|
-
end
|
46
|
-
rescue
|
47
|
-
# Fall back to whatever DJ thinks the name is.
|
48
|
-
job.name
|
49
|
-
end
|
50
|
-
|
51
|
-
queue = job.queue || "default"
|
52
|
-
|
53
|
-
req = ScoutApm::RequestManager.lookup
|
54
|
-
|
55
|
-
begin
|
56
|
-
latency = Time.now - [job.created_at, job.run_at].max
|
57
|
-
req.annotate_request(:queue_latency => latency)
|
58
|
-
rescue
|
59
|
-
end
|
60
|
-
|
61
|
-
queue_layer = ScoutApm::Layer.new('Queue', queue)
|
62
|
-
job_layer = ScoutApm::Layer.new('Job', name)
|
63
|
-
|
64
|
-
begin
|
65
|
-
req.start_layer(queue_layer)
|
66
|
-
started_queue = true
|
67
|
-
req.start_layer(job_layer)
|
68
|
-
started_job = true
|
69
|
-
|
70
|
-
# Call the job itself.
|
71
|
-
block.call(job, *args)
|
72
|
-
rescue
|
73
|
-
req.error!
|
74
|
-
raise
|
75
|
-
ensure
|
76
|
-
req.stop_layer if started_job
|
77
|
-
req.stop_layer if started_queue
|
78
|
-
end
|
79
|
-
end
|
80
|
-
end
|
81
|
-
end
|
82
|
-
|
83
|
-
Delayed::Worker.plugins << plugin # ScoutApm::BackgroundJobIntegrations::DelayedJobPlugin
|
84
|
-
end
|
85
17
|
end
|
86
18
|
end
|
87
19
|
end
|
88
|
-
|
@@ -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(boss)
|
44
44
|
agent = ::ScoutApm::Agent.instance
|
45
|
-
agent.
|
46
|
-
initialize_without_scout(
|
45
|
+
agent.start_background_worker
|
46
|
+
initialize_without_scout(boss)
|
47
47
|
end
|
48
48
|
|
49
49
|
alias_method :initialize_without_scout, :initialize
|
@@ -55,14 +55,27 @@ 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
|
+
|
58
60
|
def call(_worker, msg, queue)
|
59
61
|
req = ScoutApm::RequestManager.lookup
|
62
|
+
req.job!
|
60
63
|
req.annotate_request(:queue_latency => latency(msg))
|
61
64
|
|
65
|
+
queue_layer = ScoutApm::Layer.new('Queue', queue)
|
66
|
+
job_layer = ScoutApm::Layer.new('Job', job_class(msg))
|
67
|
+
|
68
|
+
if ScoutApm::Agent.instance.config.value('profile') && SidekiqMiddleware.version_supports_profiling?
|
69
|
+
# Capture ScoutProf if we can
|
70
|
+
#req.enable_profiled_thread!
|
71
|
+
#job_layer.set_root_class(job_class)
|
72
|
+
#job_layer.traced!
|
73
|
+
end
|
74
|
+
|
62
75
|
begin
|
63
|
-
req.start_layer(
|
76
|
+
req.start_layer(queue_layer)
|
64
77
|
started_queue = true
|
65
|
-
req.start_layer(
|
78
|
+
req.start_layer(job_layer)
|
66
79
|
started_job = true
|
67
80
|
|
68
81
|
yield
|
@@ -76,36 +89,12 @@ module ScoutApm
|
|
76
89
|
end
|
77
90
|
|
78
91
|
UNKNOWN_CLASS_PLACEHOLDER = 'UnknownJob'.freeze
|
79
|
-
ACTIVE_JOB_KLASS = 'ActiveJob::QueueAdapters::SidekiqAdapter::JobWrapper'.freeze
|
80
|
-
DELAYED_WRAPPER_KLASS = 'Sidekiq::Extensions::DelayedClass'.freeze
|
81
|
-
|
82
92
|
|
83
93
|
def job_class(msg)
|
84
94
|
job_class = msg.fetch('class', UNKNOWN_CLASS_PLACEHOLDER)
|
85
|
-
|
86
95
|
if job_class == ACTIVE_JOB_KLASS && msg.key?('wrapped')
|
87
|
-
|
88
|
-
job_class = msg['wrapped']
|
89
|
-
rescue
|
90
|
-
ACTIVE_JOB_KLASS
|
91
|
-
end
|
92
|
-
elsif job_class == DELAYED_WRAPPER_KLASS
|
93
|
-
begin
|
94
|
-
# Extract the info out of the wrapper
|
95
|
-
yml = msg['args'].first
|
96
|
-
deserialized_args = YAML.load(yml)
|
97
|
-
klass, method, *rest = deserialized_args
|
98
|
-
|
99
|
-
# If this is an instance of a class, get the class itself
|
100
|
-
# Prevents instances from coming through named like "#<Foo:0x007ffd7a9dd8a0>"
|
101
|
-
klass = klass.class unless klass.is_a? Module
|
102
|
-
|
103
|
-
job_class = [klass, method].map(&:to_s).join(".")
|
104
|
-
rescue
|
105
|
-
DELAYED_WRAPPER_KLASS
|
106
|
-
end
|
96
|
+
job_class = msg['wrapped']
|
107
97
|
end
|
108
|
-
|
109
98
|
job_class
|
110
99
|
rescue
|
111
100
|
UNKNOWN_CLASS_PLACEHOLDER
|
@@ -121,6 +110,10 @@ module ScoutApm
|
|
121
110
|
rescue
|
122
111
|
0
|
123
112
|
end
|
124
|
-
|
113
|
+
|
114
|
+
def self.version_supports_profiling?
|
115
|
+
@@sidekiq_supports_profling ||= defined?(::Sidekiq::VERSION) && Gem::Dependency.new('', '~> 4.0').match?('', ::Sidekiq::VERSION.to_s)
|
116
|
+
end
|
117
|
+
end # SidekiqMiddleware
|
125
118
|
end
|
126
119
|
end
|
@@ -6,24 +6,13 @@ module ScoutApm
|
|
6
6
|
|
7
7
|
attr_reader :period
|
8
8
|
|
9
|
-
|
10
|
-
|
11
|
-
def initialize(context, period=DEFAULT_PERIOD)
|
12
|
-
@context = context
|
9
|
+
def initialize(period=DEFAULT_PERIOD)
|
13
10
|
@period = period
|
14
11
|
@keep_running = true
|
15
12
|
end
|
16
13
|
|
17
|
-
def logger
|
18
|
-
context.logger
|
19
|
-
end
|
20
|
-
|
21
|
-
def running?
|
22
|
-
@keep_running
|
23
|
-
end
|
24
|
-
|
25
14
|
def stop
|
26
|
-
logger.debug "Background Worker: stop requested"
|
15
|
+
ScoutApm::Agent.instance.logger.debug "Background Worker: stop requested"
|
27
16
|
@keep_running = false
|
28
17
|
end
|
29
18
|
|
@@ -36,13 +25,19 @@ module ScoutApm
|
|
36
25
|
def start(&block)
|
37
26
|
@task = block
|
38
27
|
|
39
|
-
logger.debug "Background Worker:
|
28
|
+
ScoutApm::Agent.instance.logger.debug "Background Worker: Starting Background Worker, running every #{period} seconds"
|
40
29
|
|
41
30
|
# The first run should be 1 period of time from now
|
42
31
|
next_time = Time.now + period
|
43
32
|
|
44
33
|
loop do
|
45
34
|
begin
|
35
|
+
# Bail out if @keep_running is false
|
36
|
+
unless @keep_running
|
37
|
+
ScoutApm::Agent.instance.logger.debug "Background Worker: breaking from loop"
|
38
|
+
break
|
39
|
+
end
|
40
|
+
|
46
41
|
now = Time.now
|
47
42
|
|
48
43
|
# Sleep the correct amount of time to reach next_time
|
@@ -52,12 +47,6 @@ module ScoutApm
|
|
52
47
|
now = Time.now
|
53
48
|
end
|
54
49
|
|
55
|
-
# Bail out if @keep_running is false
|
56
|
-
unless @keep_running
|
57
|
-
logger.debug "Background Worker: breaking from loop"
|
58
|
-
break
|
59
|
-
end
|
60
|
-
|
61
50
|
@task.call
|
62
51
|
|
63
52
|
# Adjust the next time to run forward by @periods until it is in the future
|
@@ -65,9 +54,9 @@ module ScoutApm
|
|
65
54
|
next_time += period
|
66
55
|
end
|
67
56
|
rescue
|
68
|
-
logger.debug "Background Worker Exception!"
|
69
|
-
logger.debug $!.message
|
70
|
-
logger.debug $!.backtrace
|
57
|
+
ScoutApm::Agent.instance.logger.debug "Background Worker Exception!"
|
58
|
+
ScoutApm::Agent.instance.logger.debug $!.message
|
59
|
+
ScoutApm::Agent.instance.logger.debug $!.backtrace
|
71
60
|
end
|
72
61
|
end
|
73
62
|
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# Encapsulates logic for determining capacity utilization of the Ruby processes.
|
2
|
+
module ScoutApm
|
3
|
+
class Capacity
|
4
|
+
attr_reader :processing_start_time, :accumulated_time, :transaction_entry_time
|
5
|
+
|
6
|
+
def initialize
|
7
|
+
@processing_start_time = Time.now
|
8
|
+
@lock ||= Mutex.new # the transaction_entry_time could be modified while processing a request or when #process is called.
|
9
|
+
@accumulated_time = 0.0
|
10
|
+
end
|
11
|
+
|
12
|
+
# Called when a transaction is traced.
|
13
|
+
def start_transaction!
|
14
|
+
@lock.synchronize do
|
15
|
+
@transaction_entry_time = Time.now
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
# Called when a transaction completes to record its time used.
|
20
|
+
def finish_transaction!
|
21
|
+
@lock.synchronize do
|
22
|
+
if transaction_entry_time
|
23
|
+
@accumulated_time += (Time.now - transaction_entry_time).to_f
|
24
|
+
else
|
25
|
+
ScoutApm::Agent.instance.logger.warn "No transaction entry time. Not recording capacity metrics for transaction."
|
26
|
+
end
|
27
|
+
@transaction_entry_time = nil
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
# Ran when sending metrics to server. Reports capacity usage metrics.
|
32
|
+
def process
|
33
|
+
process_time = Time.now
|
34
|
+
ScoutApm::Agent.instance.logger.debug "Processing capacity usage for [#{@processing_start_time}] to [#{process_time}]. Time Spent: #{@accumulated_time}."
|
35
|
+
@lock.synchronize do
|
36
|
+
time_spent = @accumulated_time
|
37
|
+
@accumulated_time = 0.0
|
38
|
+
# If a transaction is still running, capture its running time up to now and
|
39
|
+
# reset the +transaction_entry_time+ to now.
|
40
|
+
if @transaction_entry_time
|
41
|
+
time_spent += (process_time - @transaction_entry_time).to_f
|
42
|
+
ScoutApm::Agent.instance.logger.debug "A transaction is running while calculating capacity. Start time: [#{transaction_entry_time}]. Will update the entry time to [#{process_time}]."
|
43
|
+
@transaction_entry_time = process_time # prevent from over-counting capacity usage. update the transaction start time to now.
|
44
|
+
end
|
45
|
+
time_spent = 0.0 if time_spent < 0.0
|
46
|
+
|
47
|
+
window = (process_time - processing_start_time).to_f # time period we are evaulating capacity usage.
|
48
|
+
window = 1.0 if window <= 0.0 # prevent divide-by-zero if clock adjusted.
|
49
|
+
capacity = time_spent / window
|
50
|
+
ScoutApm::Agent.instance.logger.debug "Instance/Capacity: #{capacity}"
|
51
|
+
ScoutApm::Agent.instance.store.track_one!("Instance", "Capacity", capacity)
|
52
|
+
|
53
|
+
@processing_start_time = process_time
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
data/lib/scout_apm/config.rb
CHANGED
@@ -5,89 +5,25 @@ require 'scout_apm/environment'
|
|
5
5
|
|
6
6
|
# Valid Config Options:
|
7
7
|
#
|
8
|
-
# This list is complete, but some are old and unused, or for developers of
|
9
|
-
# scout_apm itself. See the documentation at https://docs.scoutapm.com for
|
10
|
-
# customer-focused documentation.
|
11
|
-
#
|
12
8
|
# application_root - override the detected directory of the application
|
13
|
-
# collect_remote_ip - automatically capture user's IP into a Trace's Context
|
14
|
-
# compress_payload - true/false to enable gzipping of payload
|
15
9
|
# data_file - override the default temporary storage location. Must be a location in a writable directory
|
16
|
-
#
|
10
|
+
# host - override the default hostname detection. Default varies by environment - either system hostname, or PAAS hostname
|
17
11
|
# direct_host - override the default "direct" host. The direct_host bypasses the ingestion pipeline and goes directly to the webserver, and is primarily used for features under development.
|
18
|
-
# enable_background_jobs - true or false
|
19
|
-
# host - configuration used in development
|
20
|
-
# hostname - override the default hostname detection. Default varies by environment - either system hostname, or PAAS hostname
|
21
12
|
# key - the account key with Scout APM. Found in Settings in the Web UI
|
22
13
|
# log_file_path - either a directory or "STDOUT".
|
23
14
|
# log_level - DEBUG / INFO / WARN as usual
|
24
|
-
# max_traces - Internal: An experiment in trace quality, this requires a server-side setting as well. Setting this to a higher value will make your app server work harder for no benefit.
|
25
15
|
# monitor - true or false. False prevents any instrumentation from starting
|
26
16
|
# name - override the name reported to APM. This is the name that shows in the Web UI
|
27
|
-
# profile - turn on/off scoutprof (only applicable in Gem versions including scoutprof)
|
28
|
-
# proxy - an http proxy
|
29
|
-
# report_format - 'json' or 'marshal'. Marshal is legacy and will be removed.
|
30
|
-
# scm_subdirectory - if the app root lives in source management in a subdirectory. E.g. #{SCM_ROOT}/src
|
31
17
|
# uri_reporting - 'path' or 'full_path' default is 'full_path', which reports URL params as well as the path.
|
32
|
-
#
|
33
|
-
#
|
34
|
-
#
|
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']).
|
18
|
+
# report_format - 'json' or 'marshal'. Marshal is legacy and will be removed.
|
19
|
+
# dev_trace - true or false. Enables always-on tracing in development environmen only
|
20
|
+
# enable_background_jobs - true or false
|
38
21
|
#
|
39
22
|
# Any of these config settings can be set with an environment variable prefixed
|
40
23
|
# by SCOUT_ and uppercasing the key: SCOUT_LOG_LEVEL for instance.
|
41
24
|
|
42
25
|
module ScoutApm
|
43
26
|
class Config
|
44
|
-
KNOWN_CONFIG_OPTIONS = [
|
45
|
-
'application_root',
|
46
|
-
'async_recording',
|
47
|
-
'collect_remote_ip',
|
48
|
-
'compress_payload',
|
49
|
-
'config_file',
|
50
|
-
'data_file',
|
51
|
-
'database_metric_limit',
|
52
|
-
'database_metric_report_limit',
|
53
|
-
'detailed_middleware',
|
54
|
-
'dev_trace',
|
55
|
-
'direct_host',
|
56
|
-
'disabled_instruments',
|
57
|
-
'enable_background_jobs',
|
58
|
-
'host',
|
59
|
-
'hostname',
|
60
|
-
'ignore',
|
61
|
-
'key',
|
62
|
-
'log_class',
|
63
|
-
'log_file_path',
|
64
|
-
'log_level',
|
65
|
-
'log_stderr',
|
66
|
-
'log_stdout',
|
67
|
-
'max_traces',
|
68
|
-
'monitor',
|
69
|
-
'name',
|
70
|
-
'profile',
|
71
|
-
'proxy',
|
72
|
-
'remote_agent_host',
|
73
|
-
'remote_agent_port',
|
74
|
-
'report_format',
|
75
|
-
'revision_sha',
|
76
|
-
'scm_subdirectory',
|
77
|
-
'start_resque_server_instrument',
|
78
|
-
'ssl_cert_file',
|
79
|
-
'uri_reporting',
|
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',
|
90
|
-
]
|
91
27
|
|
92
28
|
################################################################################
|
93
29
|
# Coersions
|
@@ -151,12 +87,6 @@ module ScoutApm
|
|
151
87
|
end
|
152
88
|
end
|
153
89
|
|
154
|
-
class IntegerCoercion
|
155
|
-
def coerce(val)
|
156
|
-
val.to_i
|
157
|
-
end
|
158
|
-
end
|
159
|
-
|
160
90
|
# Simply returns the passed in value, without change
|
161
91
|
class NullCoercion
|
162
92
|
def coerce(val)
|
@@ -166,25 +96,10 @@ module ScoutApm
|
|
166
96
|
|
167
97
|
|
168
98
|
SETTING_COERCIONS = {
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
'ignore' => JsonCoercion.new,
|
174
|
-
'max_traces' => IntegerCoercion.new,
|
175
|
-
'monitor' => BooleanCoercion.new,
|
176
|
-
'collect_remote_ip' => BooleanCoercion.new,
|
177
|
-
'compress_payload' => BooleanCoercion.new,
|
178
|
-
'database_metric_limit' => IntegerCoercion.new,
|
179
|
-
'database_metric_report_limit' => IntegerCoercion.new,
|
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,
|
99
|
+
"monitor" => BooleanCoercion.new,
|
100
|
+
"enable_background_jobs" => BooleanCoercion.new,
|
101
|
+
"dev_trace" => BooleanCoercion.new,
|
102
|
+
"ignore" => JsonCoercion.new,
|
188
103
|
}
|
189
104
|
|
190
105
|
|
@@ -194,44 +109,34 @@ module ScoutApm
|
|
194
109
|
|
195
110
|
# Load up a config instance without attempting to load a file.
|
196
111
|
# Useful for bootstrapping.
|
197
|
-
def self.without_file
|
112
|
+
def self.without_file
|
198
113
|
overlays = [
|
199
114
|
ConfigEnvironment.new,
|
200
115
|
ConfigDefaults.new,
|
201
116
|
ConfigNull.new,
|
202
117
|
]
|
203
|
-
new(
|
118
|
+
new(overlays)
|
204
119
|
end
|
205
120
|
|
206
121
|
# Load up a config instance, attempting to load a yaml file. Allows a
|
207
122
|
# definite location if requested, or will attempt to load the default
|
208
123
|
# configuration file: APP_ROOT/config/scout_apm.yml
|
209
|
-
def self.with_file(
|
124
|
+
def self.with_file(file_path=nil, config={})
|
210
125
|
overlays = [
|
211
126
|
ConfigEnvironment.new,
|
212
|
-
ConfigFile.new(
|
127
|
+
ConfigFile.new(file_path, config),
|
213
128
|
ConfigDefaults.new,
|
214
129
|
ConfigNull.new,
|
215
130
|
]
|
216
|
-
new(
|
131
|
+
new(overlays)
|
217
132
|
end
|
218
133
|
|
219
|
-
def initialize(
|
220
|
-
@context = context
|
134
|
+
def initialize(overlays)
|
221
135
|
@overlays = Array(overlays)
|
222
136
|
end
|
223
137
|
|
224
|
-
# For a given key, what is the first overlay says that it can handle it?
|
225
|
-
def overlay_for_key(key)
|
226
|
-
@overlays.detect{ |overlay| overlay.has_key?(key) }
|
227
|
-
end
|
228
|
-
|
229
138
|
def value(key)
|
230
|
-
|
231
|
-
logger.debug("Requested looking up a unknown configuration key: #{key} (not a problem. Evaluate and add to config.rb)")
|
232
|
-
end
|
233
|
-
|
234
|
-
o = overlay_for_key(key)
|
139
|
+
o = @overlays.detect{ |overlay| overlay.has_key?(key) }
|
235
140
|
raw_value = if o
|
236
141
|
o.value(key)
|
237
142
|
else
|
@@ -243,63 +148,18 @@ module ScoutApm
|
|
243
148
|
coercion.coerce(raw_value)
|
244
149
|
end
|
245
150
|
|
246
|
-
# Did we load anything for configuration?
|
247
|
-
def any_keys_found?
|
248
|
-
@overlays.any? { |overlay| overlay.any_keys_found? }
|
249
|
-
end
|
250
|
-
|
251
|
-
# Returns an array of config keys, values, and source
|
252
|
-
# {key: "monitor", value: "true", source: "environment"}
|
253
|
-
#
|
254
|
-
def all_settings
|
255
|
-
KNOWN_CONFIG_OPTIONS.inject([]) do |memo, key|
|
256
|
-
o = overlay_for_key(key)
|
257
|
-
memo << {:key => key, :value => value(key).inspect, :source => o.name}
|
258
|
-
end
|
259
|
-
end
|
260
|
-
|
261
|
-
def log_settings(logger)
|
262
|
-
logger.debug(
|
263
|
-
"Resolved Setting Values:\n" +
|
264
|
-
all_settings.map{|hsh| "#{hsh[:source]} - #{hsh[:key]}: #{hsh[:value]}"}.join("\n")
|
265
|
-
)
|
266
|
-
end
|
267
|
-
|
268
|
-
def logger
|
269
|
-
@context.logger
|
270
|
-
end
|
271
|
-
|
272
151
|
class ConfigDefaults
|
273
152
|
DEFAULTS = {
|
274
|
-
'
|
275
|
-
'detailed_middleware' => false,
|
276
|
-
'dev_trace' => false,
|
153
|
+
'host' => 'https://checkin.scoutapp.com',
|
277
154
|
'direct_host' => 'https://apm.scoutapp.com',
|
155
|
+
'log_level' => 'info',
|
156
|
+
'uri_reporting' => 'full_path',
|
157
|
+
'report_format' => 'json',
|
278
158
|
'disabled_instruments' => [],
|
279
159
|
'enable_background_jobs' => true,
|
280
|
-
'host' => 'https://checkin.scoutapp.com',
|
281
160
|
'ignore' => [],
|
282
|
-
'
|
283
|
-
'
|
284
|
-
'profile' => true, # for scoutprof
|
285
|
-
'report_format' => 'json',
|
286
|
-
'scm_subdirectory' => '',
|
287
|
-
'uri_reporting' => 'full_path',
|
288
|
-
'remote_agent_host' => '127.0.0.1',
|
289
|
-
'remote_agent_port' => 7721, # picked at random
|
290
|
-
'database_metric_limit' => 5000, # The hard limit on db metrics
|
291
|
-
'database_metric_report_limit' => 1000,
|
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',
|
161
|
+
'dev_trace' => false,
|
162
|
+
'profile' => true # for scoutprof
|
303
163
|
}.freeze
|
304
164
|
|
305
165
|
def value(key)
|
@@ -309,15 +169,6 @@ module ScoutApm
|
|
309
169
|
def has_key?(key)
|
310
170
|
DEFAULTS.has_key?(key)
|
311
171
|
end
|
312
|
-
|
313
|
-
# Defaults are here, but not counted as user specified.
|
314
|
-
def any_keys_found?
|
315
|
-
false
|
316
|
-
end
|
317
|
-
|
318
|
-
def name
|
319
|
-
"defaults"
|
320
|
-
end
|
321
172
|
end
|
322
173
|
|
323
174
|
|
@@ -332,14 +183,6 @@ module ScoutApm
|
|
332
183
|
def has_key?(*)
|
333
184
|
true
|
334
185
|
end
|
335
|
-
|
336
|
-
def any_keys_found?
|
337
|
-
false
|
338
|
-
end
|
339
|
-
|
340
|
-
def name
|
341
|
-
"no-config"
|
342
|
-
end
|
343
186
|
end
|
344
187
|
|
345
188
|
class ConfigEnvironment
|
@@ -355,24 +198,13 @@ module ScoutApm
|
|
355
198
|
def key_to_env_key(key)
|
356
199
|
'SCOUT_' + key.upcase
|
357
200
|
end
|
358
|
-
|
359
|
-
def any_keys_found?
|
360
|
-
KNOWN_CONFIG_OPTIONS.any? { |option|
|
361
|
-
ENV.has_key?(key_to_env_key(option))
|
362
|
-
}
|
363
|
-
end
|
364
|
-
|
365
|
-
def name
|
366
|
-
"environment"
|
367
|
-
end
|
368
201
|
end
|
369
202
|
|
370
203
|
# Attempts to load a configuration file, and parse it as YAML. If the file
|
371
204
|
# is not found, inaccessbile, or unparsable, log a message to that effect,
|
372
205
|
# and move on.
|
373
206
|
class ConfigFile
|
374
|
-
def initialize(
|
375
|
-
@context = context
|
207
|
+
def initialize(file_path=nil, config={})
|
376
208
|
@config = config || {}
|
377
209
|
@resolved_file_path = file_path || determine_file_path
|
378
210
|
load_file(@resolved_file_path)
|
@@ -391,20 +223,8 @@ module ScoutApm
|
|
391
223
|
@settings.has_key?(key)
|
392
224
|
end
|
393
225
|
|
394
|
-
def any_keys_found?
|
395
|
-
KNOWN_CONFIG_OPTIONS.any? { |option|
|
396
|
-
@settings.has_key?(option)
|
397
|
-
}
|
398
|
-
end
|
399
|
-
|
400
|
-
def name
|
401
|
-
"config-file"
|
402
|
-
end
|
403
|
-
|
404
226
|
private
|
405
227
|
|
406
|
-
attr_reader :context
|
407
|
-
|
408
228
|
def load_file(file)
|
409
229
|
@settings = {}
|
410
230
|
if !File.exist?(@resolved_file_path)
|
@@ -434,21 +254,32 @@ module ScoutApm
|
|
434
254
|
@file_loaded = false
|
435
255
|
end
|
436
256
|
rescue Exception => e # Explicit `Exception` handling to catch SyntaxError and anything else that ERB or YAML may throw
|
437
|
-
logger.
|
257
|
+
logger.debug("Failed loading configuration file: #{e.message}. ScoutAPM will continue starting with configuration from ENV and defaults")
|
438
258
|
@file_loaded = false
|
439
259
|
end
|
440
260
|
end
|
441
261
|
|
442
262
|
def determine_file_path
|
443
|
-
File.join(
|
263
|
+
File.join(ScoutApm::Environment.instance.root, "config", "scout_apm.yml")
|
444
264
|
end
|
445
265
|
|
446
266
|
def app_environment
|
447
|
-
@config[:environment] ||
|
267
|
+
@config[:environment] || ScoutApm::Environment.instance.env
|
448
268
|
end
|
449
269
|
|
450
270
|
def logger
|
451
|
-
|
271
|
+
if ScoutApm::Agent.instance.logger
|
272
|
+
return ScoutApm::Agent.instance.logger
|
273
|
+
else
|
274
|
+
l = Logger.new(STDOUT)
|
275
|
+
if ENV["SCOUT_LOG_LEVEL"] == "debug"
|
276
|
+
l.level = Logger::DEBUG
|
277
|
+
else
|
278
|
+
l.level = Logger::INFO
|
279
|
+
end
|
280
|
+
|
281
|
+
return l
|
282
|
+
end
|
452
283
|
end
|
453
284
|
end
|
454
285
|
end
|