scout_apm 2.1.32 → 2.2.0.pre0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (117) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -1
  3. data/CHANGELOG.markdown +2 -161
  4. data/Rakefile +2 -2
  5. data/ext/allocations/allocations.c +0 -6
  6. data/ext/allocations/extconf.rb +0 -1
  7. data/ext/stacks/extconf.rb +33 -0
  8. data/ext/stacks/scout_atomics.h +86 -0
  9. data/ext/stacks/stacks.c +744 -0
  10. data/lib/scout_apm.rb +16 -24
  11. data/lib/scout_apm/agent.rb +38 -93
  12. data/lib/scout_apm/agent/logging.rb +1 -6
  13. data/lib/scout_apm/agent/reporting.rb +6 -8
  14. data/lib/scout_apm/app_server_load.rb +10 -21
  15. data/lib/scout_apm/attribute_arranger.rb +2 -0
  16. data/lib/scout_apm/background_job_integrations/delayed_job.rb +1 -71
  17. data/lib/scout_apm/background_job_integrations/sidekiq.rb +27 -66
  18. data/lib/scout_apm/background_worker.rb +15 -19
  19. data/lib/scout_apm/capacity.rb +57 -0
  20. data/lib/scout_apm/config.rb +29 -135
  21. data/lib/scout_apm/context.rb +5 -9
  22. data/lib/scout_apm/deploy_integrations/capistrano_2.cap +12 -0
  23. data/lib/scout_apm/deploy_integrations/capistrano_2.rb +83 -0
  24. data/lib/scout_apm/deploy_integrations/capistrano_3.cap +12 -0
  25. data/lib/scout_apm/deploy_integrations/capistrano_3.rb +88 -0
  26. data/lib/scout_apm/environment.rb +15 -22
  27. data/lib/scout_apm/histogram.rb +2 -11
  28. data/lib/scout_apm/instant/assets/xmlhttp_instrumentation.html +2 -2
  29. data/lib/scout_apm/instant/middleware.rb +57 -198
  30. data/lib/scout_apm/instruments/action_controller_rails_2.rb +2 -1
  31. data/lib/scout_apm/instruments/action_controller_rails_3_rails4.rb +59 -90
  32. data/lib/scout_apm/instruments/active_record.rb +5 -7
  33. data/lib/scout_apm/instruments/delayed_job.rb +57 -0
  34. data/lib/scout_apm/instruments/grape.rb +3 -4
  35. data/lib/scout_apm/instruments/middleware_detailed.rb +6 -4
  36. data/lib/scout_apm/instruments/middleware_summary.rb +1 -39
  37. data/lib/scout_apm/instruments/mongoid.rb +3 -24
  38. data/lib/scout_apm/instruments/net_http.rb +2 -7
  39. data/lib/scout_apm/instruments/percentile_sampler.rb +19 -36
  40. data/lib/scout_apm/instruments/process/process_cpu.rb +2 -3
  41. data/lib/scout_apm/instruments/process/process_memory.rb +3 -3
  42. data/lib/scout_apm/layaway.rb +33 -76
  43. data/lib/scout_apm/layer.rb +59 -16
  44. data/lib/scout_apm/layer_converters/converter_base.rb +0 -199
  45. data/lib/scout_apm/layer_converters/job_converter.rb +1 -1
  46. data/lib/scout_apm/layer_converters/metric_converter.rb +1 -1
  47. data/lib/scout_apm/layer_converters/slow_job_converter.rb +90 -15
  48. data/lib/scout_apm/layer_converters/slow_request_converter.rb +101 -13
  49. data/lib/scout_apm/metric_set.rb +1 -9
  50. data/lib/scout_apm/metric_stats.rb +8 -8
  51. data/lib/scout_apm/reporter.rb +15 -51
  52. data/lib/scout_apm/request_histograms.rb +0 -4
  53. data/lib/scout_apm/request_manager.rb +1 -2
  54. data/lib/scout_apm/scored_item_set.rb +0 -7
  55. data/lib/scout_apm/serializers/deploy_serializer.rb +16 -0
  56. data/lib/scout_apm/serializers/payload_serializer.rb +3 -9
  57. data/lib/scout_apm/serializers/payload_serializer_to_json.rb +5 -2
  58. data/lib/scout_apm/serializers/slow_jobs_serializer_to_json.rb +1 -2
  59. data/lib/scout_apm/server_integrations/puma.rb +2 -5
  60. data/lib/scout_apm/slow_item_set.rb +80 -0
  61. data/lib/scout_apm/slow_job_record.rb +1 -6
  62. data/lib/scout_apm/slow_transaction.rb +2 -20
  63. data/lib/scout_apm/store.rb +12 -50
  64. data/lib/scout_apm/trace_compactor.rb +311 -0
  65. data/lib/scout_apm/tracked_request.rb +37 -128
  66. data/lib/scout_apm/utils/backtrace_parser.rb +5 -7
  67. data/lib/scout_apm/utils/fake_stacks.rb +83 -0
  68. data/lib/scout_apm/version.rb +1 -1
  69. data/scout_apm.gemspec +4 -6
  70. data/test/test_helper.rb +0 -56
  71. data/test/unit/config_test.rb +9 -60
  72. data/test/unit/histogram_test.rb +0 -14
  73. data/test/unit/layaway_test.rb +16 -31
  74. data/test/unit/serializers/payload_serializer_test.rb +105 -3
  75. data/test/unit/slow_item_set_test.rb +94 -0
  76. data/test/unit/slow_job_policy_test.rb +49 -0
  77. data/test/unit/slow_request_policy_test.rb +5 -4
  78. data/test/unit/utils/backtrace_parser_test.rb +0 -19
  79. data/tester.rb +53 -0
  80. metadata +29 -124
  81. data/.rubocop.yml +0 -8
  82. data/Guardfile +0 -42
  83. data/ext/rusage/README.md +0 -26
  84. data/ext/rusage/extconf.rb +0 -5
  85. data/ext/rusage/rusage.c +0 -52
  86. data/lib/scout_apm/background_job_integrations/resque.rb +0 -85
  87. data/lib/scout_apm/background_recorder.rb +0 -43
  88. data/lib/scout_apm/debug.rb +0 -37
  89. data/lib/scout_apm/git_revision.rb +0 -51
  90. data/lib/scout_apm/instruments/action_view.rb +0 -49
  91. data/lib/scout_apm/instruments/resque.rb +0 -40
  92. data/lib/scout_apm/layer_children_set.rb +0 -77
  93. data/lib/scout_apm/limited_layer.rb +0 -122
  94. data/lib/scout_apm/rack.rb +0 -26
  95. data/lib/scout_apm/remote/message.rb +0 -23
  96. data/lib/scout_apm/remote/recorder.rb +0 -57
  97. data/lib/scout_apm/remote/router.rb +0 -49
  98. data/lib/scout_apm/remote/server.rb +0 -58
  99. data/lib/scout_apm/serializers/histograms_serializer_to_json.rb +0 -21
  100. data/lib/scout_apm/synchronous_recorder.rb +0 -26
  101. data/lib/scout_apm/utils/gzip_helper.rb +0 -24
  102. data/lib/scout_apm/utils/numbers.rb +0 -14
  103. data/lib/scout_apm/utils/scm.rb +0 -14
  104. data/test/unit/background_job_integrations/sidekiq_test.rb +0 -104
  105. data/test/unit/context_test.rb +0 -30
  106. data/test/unit/git_revision_test.rb +0 -15
  107. data/test/unit/instruments/net_http_test.rb +0 -21
  108. data/test/unit/instruments/percentile_sampler_test.rb +0 -137
  109. data/test/unit/layer_children_set_test.rb +0 -88
  110. data/test/unit/limited_layer_test.rb +0 -53
  111. data/test/unit/remote/test_message.rb +0 -13
  112. data/test/unit/remote/test_router.rb +0 -33
  113. data/test/unit/remote/test_server.rb +0 -15
  114. data/test/unit/store_test.rb +0 -89
  115. data/test/unit/test_tracked_request.rb +0 -87
  116. data/test/unit/utils/numbers_test.rb +0 -15
  117. data/test/unit/utils/scm.rb +0 -17
@@ -5,6 +5,8 @@ module ScoutApm
5
5
  def self.call(subject, attributes_list)
6
6
  attributes_list.inject({}) do |attribute_hash, attribute|
7
7
  case attribute
8
+ when :traces
9
+ attribute_hash[attribute] = subject.traces.to_a
8
10
  when Array
9
11
  attribute_hash[attribute[0]] = subject.send(attribute[1])
10
12
  when :bucket
@@ -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,79 +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
- req.job!
55
-
56
- begin
57
- latency = Time.now - job.created_at
58
- req.annotate_request(:queue_latency => latency)
59
- rescue
60
- end
61
-
62
- queue_layer = ScoutApm::Layer.new('Queue', queue)
63
- job_layer = ScoutApm::Layer.new('Job', name)
64
-
65
- begin
66
- req.start_layer(queue_layer)
67
- started_queue = true
68
- req.start_layer(job_layer)
69
- started_job = true
70
-
71
- # Call the job itself.
72
- block.call(job, *args)
73
- rescue
74
- req.error!
75
- raise
76
- ensure
77
- req.stop_layer if started_job
78
- req.stop_layer if started_queue
79
- end
80
- end
81
- end
82
- end
83
-
84
- Delayed::Worker.plugins << plugin # ScoutApm::BackgroundJobIntegrations::DelayedJobPlugin
85
- end
86
17
  end
87
18
  end
88
19
  end
89
-
@@ -8,7 +8,7 @@ module ScoutApm
8
8
  end
9
9
 
10
10
  def present?
11
- defined?(::Sidekiq) && File.basename($PROGRAM_NAME).start_with?('sidekiq')
11
+ defined?(::Sidekiq) && (File.basename($0) =~ /\Asidekiq/)
12
12
  end
13
13
 
14
14
  def forking?
@@ -16,33 +16,22 @@ module ScoutApm
16
16
  end
17
17
 
18
18
  def install
19
- install_tracer
20
- add_middleware
21
- install_processor
22
- end
23
-
24
- def install_tracer
25
19
  # ScoutApm::Tracer is not available when this class is defined
26
20
  SidekiqMiddleware.class_eval do
27
21
  include ScoutApm::Tracer
28
22
  end
29
- end
30
23
 
31
- def add_middleware
32
24
  ::Sidekiq.configure_server do |config|
33
25
  config.server_middleware do |chain|
34
26
  chain.add SidekiqMiddleware
35
27
  end
36
28
  end
37
- end
38
29
 
39
- def install_processor
40
30
  require 'sidekiq/processor' # sidekiq v4 has not loaded this file by this point
41
31
 
42
32
  ::Sidekiq::Processor.class_eval do
43
33
  def initialize_with_scout(boss)
44
- agent = ::ScoutApm::Agent.instance
45
- agent.start_background_worker
34
+ ::ScoutApm::Agent.instance.start_background_worker unless ::ScoutApm::Agent.instance.background_worker_running?
46
35
  initialize_without_scout(boss)
47
36
  end
48
37
 
@@ -52,69 +41,41 @@ module ScoutApm
52
41
  end
53
42
  end
54
43
 
55
- # We insert this middleware into the Sidekiq stack, to capture each job,
56
- # and time them.
57
44
  class SidekiqMiddleware
58
- def call(_worker, msg, queue)
45
+ def call(worker, msg, queue)
46
+ job_class = msg["class"] # TODO: Validate this across different versions of Sidekiq
47
+ if job_class == "ActiveJob::QueueAdapters::SidekiqAdapter::JobWrapper" && msg.has_key?("wrapped")
48
+ job_class = msg["wrapped"]
49
+ end
50
+
51
+ latency = (Time.now.to_f - (msg['enqueued_at'] || msg['created_at']))
52
+
59
53
  req = ScoutApm::RequestManager.lookup
60
54
  req.job!
61
- req.annotate_request(:queue_latency => latency(msg))
55
+ req.annotate_request(:queue_latency => latency)
62
56
 
63
- begin
64
- req.start_layer(ScoutApm::Layer.new('Queue', queue))
65
- started_queue = true
66
- req.start_layer(ScoutApm::Layer.new('Job', job_class(msg)))
67
- started_job = true
57
+ queue_layer = ScoutApm::Layer.new("Queue", queue)
58
+ job_layer = ScoutApm::Layer.new("Job", job_class)
59
+
60
+ #if ScoutApm::Agent.instance.config.value('profile')
61
+ # Capture ScoutProf if we can
62
+ #req.enable_profiled_thread!
63
+ #job_layer.set_root_class(job_class)
64
+ #job_layer.traced!
65
+ #end
68
66
 
67
+ req.start_layer(queue_layer)
68
+ req.start_layer(job_layer)
69
+
70
+ begin
69
71
  yield
70
72
  rescue
71
73
  req.error!
72
74
  raise
73
- ensure
74
- req.stop_layer if started_job
75
- req.stop_layer if started_queue
76
- end
77
- end
78
-
79
- UNKNOWN_CLASS_PLACEHOLDER = 'UnknownJob'.freeze
80
- ACTIVE_JOB_KLASS = 'ActiveJob::QueueAdapters::SidekiqAdapter::JobWrapper'.freeze
81
- DELAYED_WRAPPER_KLASS = 'Sidekiq::Extensions::DelayedClass'.freeze
82
-
83
-
84
- def job_class(msg)
85
- job_class = msg.fetch('class', UNKNOWN_CLASS_PLACEHOLDER)
86
-
87
- if job_class == ACTIVE_JOB_KLASS && msg.key?('wrapped')
88
- begin
89
- job_class = msg['wrapped']
90
- rescue
91
- ACTIVE_JOB_KLASS
92
- end
93
- elsif job_class == DELAYED_WRAPPER_KLASS
94
- begin
95
- yml = msg['args'].first
96
- deserialized_args = YAML.load(yml)
97
- klass, method, *rest = deserialized_args
98
- job_class = [klass,method].map(&:to_s).join(".")
99
- rescue
100
- DELAYED_WRAPPER_KLASS
101
- end
102
- end
103
-
104
- job_class
105
- rescue
106
- UNKNOWN_CLASS_PLACEHOLDER
107
- end
108
-
109
- def latency(msg, time = Time.now.to_f)
110
- created_at = msg['enqueued_at'] || msg['created_at']
111
- if created_at
112
- (time - created_at)
113
- else
114
- 0
115
75
  end
116
- rescue
117
- 0
76
+ ensure
77
+ req.stop_layer # Job
78
+ req.stop_layer # Queue
118
79
  end
119
80
  end
120
81
  end
@@ -11,10 +11,6 @@ module ScoutApm
11
11
  @keep_running = true
12
12
  end
13
13
 
14
- def running?
15
- @keep_running
16
- end
17
-
18
14
  def stop
19
15
  ScoutApm::Agent.instance.logger.debug "Background Worker: stop requested"
20
16
  @keep_running = false
@@ -29,13 +25,19 @@ module ScoutApm
29
25
  def start(&block)
30
26
  @task = block
31
27
 
32
- ScoutApm::Agent.instance.logger.debug "Background Worker: Starting Background Worker, running every #{period} seconds"
28
+ begin
29
+ ScoutApm::Agent.instance.logger.debug "Background Worker: Starting Background Worker, running every #{period} seconds"
33
30
 
34
- # The first run should be 1 period of time from now
35
- next_time = Time.now + period
31
+ # The first run should be 1 period of time from now
32
+ next_time = Time.now + period
33
+
34
+ loop do
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
36
40
 
37
- loop do
38
- begin
39
41
  now = Time.now
40
42
 
41
43
  # Sleep the correct amount of time to reach next_time
@@ -45,23 +47,17 @@ module ScoutApm
45
47
  now = Time.now
46
48
  end
47
49
 
48
- # Bail out if @keep_running is false
49
- unless @keep_running
50
- ScoutApm::Agent.instance.logger.debug "Background Worker: breaking from loop"
51
- break
52
- end
53
-
54
50
  @task.call
55
51
 
56
52
  # Adjust the next time to run forward by @periods until it is in the future
57
53
  while next_time <= now
58
54
  next_time += period
59
55
  end
60
- rescue
61
- ScoutApm::Agent.instance.logger.debug "Background Worker Exception!"
62
- ScoutApm::Agent.instance.logger.debug $!.message
63
- ScoutApm::Agent.instance.logger.debug $!.backtrace
64
56
  end
57
+ rescue
58
+ ScoutApm::Agent.instance.logger.debug "Background Worker Exception!"
59
+ ScoutApm::Agent.instance.logger.debug $!.message
60
+ ScoutApm::Agent.instance.logger.debug $!.backtrace
65
61
  end
66
62
  end
67
63
  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
@@ -5,63 +5,30 @@ 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 http://help.apm.scoutapp.com for
10
- # customer-focused documentation.
11
- #
12
8
  # application_root - override the detected directory of the application
13
- # compress_payload - true/false to enable gzipping of payload
14
9
  # data_file - override the default temporary storage location. Must be a location in a writable directory
15
- # dev_trace - true or false. Enables always-on tracing in development environmen only
10
+ # host - override the default hostname detection. Default varies by environment - either system hostname, or PAAS hostname
16
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.
17
- # enable_background_jobs - true or false
18
- # host - configuration used in development
19
- # hostname - override the default hostname detection. Default varies by environment - either system hostname, or PAAS hostname
20
12
  # key - the account key with Scout APM. Found in Settings in the Web UI
21
13
  # log_file_path - either a directory or "STDOUT".
22
14
  # log_level - DEBUG / INFO / WARN as usual
23
15
  # monitor - true or false. False prevents any instrumentation from starting
24
16
  # name - override the name reported to APM. This is the name that shows in the Web UI
25
- # profile - turn on/off scoutprof (only applicable in Gem versions including scoutprof)
26
- # proxy - an http proxy
27
- # report_format - 'json' or 'marshal'. Marshal is legacy and will be removed.
28
- # scm_subdirectory - if the app root lives in source management in a subdirectory. E.g. #{SCM_ROOT}/src
29
17
  # 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
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
32
21
  #
33
22
  # Any of these config settings can be set with an environment variable prefixed
34
23
  # by SCOUT_ and uppercasing the key: SCOUT_LOG_LEVEL for instance.
35
24
 
25
+
26
+ # Config - Made up of config overlay
27
+ # Default -> File -> Environment Var
28
+ # QUESTION: How to embed arrays or hashes into ENV?
29
+
36
30
  module ScoutApm
37
31
  class Config
38
- KNOWN_CONFIG_OPTIONS = [
39
- 'application_root',
40
- 'async_recording',
41
- 'compress_payload',
42
- 'config_file',
43
- 'data_file',
44
- 'detailed_middleware',
45
- 'dev_trace',
46
- 'direct_host',
47
- 'disabled_instruments',
48
- 'enable_background_jobs',
49
- 'host',
50
- 'hostname',
51
- 'ignore',
52
- 'key',
53
- 'log_file_path',
54
- 'log_level',
55
- 'monitor',
56
- 'name',
57
- 'profile',
58
- 'proxy',
59
- 'remote_agent_host',
60
- 'remote_agent_port',
61
- 'report_format',
62
- 'scm_subdirectory',
63
- 'uri_reporting',
64
- ]
65
32
 
66
33
  ################################################################################
67
34
  # Coersions
@@ -134,12 +101,10 @@ module ScoutApm
134
101
 
135
102
 
136
103
  SETTING_COERCIONS = {
137
- "async_recording" => BooleanCoercion.new,
138
- "detailed_middleware" => BooleanCoercion.new,
139
- "dev_trace" => BooleanCoercion.new,
104
+ "monitor" => BooleanCoercion.new,
140
105
  "enable_background_jobs" => BooleanCoercion.new,
106
+ "dev_trace" => BooleanCoercion.new,
141
107
  "ignore" => JsonCoercion.new,
142
- "monitor" => BooleanCoercion.new,
143
108
  }
144
109
 
145
110
 
@@ -164,7 +129,7 @@ module ScoutApm
164
129
  def self.with_file(file_path=nil, config={})
165
130
  overlays = [
166
131
  ConfigEnvironment.new,
167
- ConfigFile.new(file_path, config),
132
+ ConfigFile.new(file_path, config[:file]),
168
133
  ConfigDefaults.new,
169
134
  ConfigNull.new,
170
135
  ]
@@ -172,61 +137,28 @@ module ScoutApm
172
137
  end
173
138
 
174
139
  def initialize(overlays)
175
- @overlays = Array(overlays)
176
- end
177
-
178
- # For a given key, what is the first overlay says that it can handle it?
179
- def overlay_for_key(key)
180
- @overlays.detect{ |overlay| overlay.has_key?(key) }
140
+ @overlays = overlays
181
141
  end
182
142
 
183
143
  def value(key)
184
- if ! KNOWN_CONFIG_OPTIONS.include?(key)
185
- ScoutApm::Agent.instance.logger.debug("Requested looking up a unknown configuration key: #{key} (not a problem. Evaluate and add to config.rb)")
186
- end
187
-
188
- o = overlay_for_key(key)
189
- raw_value = if o
190
- o.value(key)
191
- else
192
- # No overlay said it could handle this key, bail out with nil.
193
- nil
194
- end
144
+ raw_value = @overlays.detect{ |overlay| overlay.has_key?(key) }.value(key)
195
145
 
196
- coercion = SETTING_COERCIONS.fetch(key, NullCoercion.new)
146
+ coercion = SETTING_COERCIONS[key] || NullCoercion.new
197
147
  coercion.coerce(raw_value)
198
148
  end
199
149
 
200
- # Did we load anything for configuration?
201
- def any_keys_found?
202
- @overlays.any? { |overlay| overlay.any_keys_found? }
203
- end
204
-
205
- def log_settings
206
- messages = KNOWN_CONFIG_OPTIONS.inject([]) do |memo, key|
207
- o = overlay_for_key(key)
208
- memo << "#{o.name} - #{key}: #{value(key).inspect}"
209
- end
210
- ScoutApm::Agent.instance.logger.debug("Resolved Setting Values:\n" + messages.join("\n"))
211
- end
212
-
213
150
  class ConfigDefaults
214
151
  DEFAULTS = {
215
- 'compress_payload' => true,
216
- 'detailed_middleware' => false,
217
- 'dev_trace' => false,
152
+ 'host' => 'https://checkin.scoutapp.com',
218
153
  'direct_host' => 'https://apm.scoutapp.com',
154
+ 'log_level' => 'info',
155
+ 'uri_reporting' => 'full_path',
156
+ 'report_format' => 'json',
219
157
  'disabled_instruments' => [],
220
158
  'enable_background_jobs' => true,
221
- 'host' => 'https://checkin.scoutapp.com',
222
159
  'ignore' => [],
223
- 'log_level' => 'info',
224
- 'profile' => true, # for scoutprof
225
- 'report_format' => 'json',
226
- 'scm_subdirectory' => '',
227
- 'uri_reporting' => 'full_path',
228
- 'remote_agent_host' => '127.0.0.1',
229
- 'remote_agent_port' => 7721, # picked at random
160
+ 'dev_trace' => false, # false for now so code can live in main branch
161
+ 'profile' => true # for scoutprof
230
162
  }.freeze
231
163
 
232
164
  def value(key)
@@ -236,15 +168,6 @@ module ScoutApm
236
168
  def has_key?(key)
237
169
  DEFAULTS.has_key?(key)
238
170
  end
239
-
240
- # Defaults are here, but not counted as user specified.
241
- def any_keys_found?
242
- false
243
- end
244
-
245
- def name
246
- "defaults"
247
- end
248
171
  end
249
172
 
250
173
 
@@ -259,14 +182,6 @@ module ScoutApm
259
182
  def has_key?(*)
260
183
  true
261
184
  end
262
-
263
- def any_keys_found?
264
- false
265
- end
266
-
267
- def name
268
- "no-config"
269
- end
270
185
  end
271
186
 
272
187
  class ConfigEnvironment
@@ -282,16 +197,6 @@ module ScoutApm
282
197
  def key_to_env_key(key)
283
198
  'SCOUT_' + key.upcase
284
199
  end
285
-
286
- def any_keys_found?
287
- KNOWN_CONFIG_OPTIONS.any? { |option|
288
- ENV.has_key?(key_to_env_key(option))
289
- }
290
- end
291
-
292
- def name
293
- "environment"
294
- end
295
200
  end
296
201
 
297
202
  # Attempts to load a configuration file, and parse it as YAML. If the file
@@ -317,16 +222,6 @@ module ScoutApm
317
222
  @settings.has_key?(key)
318
223
  end
319
224
 
320
- def any_keys_found?
321
- KNOWN_CONFIG_OPTIONS.any? { |option|
322
- @settings.has_key?(option)
323
- }
324
- end
325
-
326
- def name
327
- "config-file"
328
- end
329
-
330
225
  private
331
226
 
332
227
  def load_file(file)
@@ -347,18 +242,17 @@ module ScoutApm
347
242
  raw_file = File.read(@resolved_file_path)
348
243
  erb_file = ERB.new(raw_file).result(binding)
349
244
  parsed_yaml = YAML.load(erb_file)
350
- file_settings = parsed_yaml[app_environment]
245
+ @settings = parsed_yaml[app_environment]
351
246
 
352
- if file_settings.is_a? Hash
353
- logger.debug("Loaded Configuration: #{@resolved_file_path}. Using environment: #{app_environment}")
354
- @settings = file_settings
355
- @file_loaded = true
356
- else
357
- logger.info("Couldn't find configuration in #{@resolved_file_path} for environment: #{app_environment}. Configuration in ENV will still be applied.")
358
- @file_loaded = false
247
+ if !@settings.is_a? Hash
248
+ raise ("Missing environment key for: #{app_environment}. This can happen if the key is missing, or with a malformed configuration file," +
249
+ " check that there is a top level #{app_environment} key.")
359
250
  end
251
+
252
+ logger.debug("Loaded Configuration: #{@resolved_file_path}. Using environment: #{app_environment}")
253
+ @file_loaded = true
360
254
  rescue Exception => e # Explicit `Exception` handling to catch SyntaxError and anything else that ERB or YAML may throw
361
- logger.info("Failed loading configuration file (#{@resolved_file_path}): #{e.message}. ScoutAPM will continue starting with configuration from ENV and defaults")
255
+ logger.debug("Failed loading configuration file: #{e.message}. ScoutAPM will continue starting with configuration from ENV and defaults")
362
256
  @file_loaded = false
363
257
  end
364
258
  end