scout_apm 1.6.8 → 2.0.0.pre

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.
Files changed (69) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +8 -1
  3. data/CHANGELOG.markdown +7 -57
  4. data/ext/allocations/allocations.c +84 -0
  5. data/ext/allocations/extconf.rb +3 -0
  6. data/lib/scout_apm/agent/reporting.rb +9 -32
  7. data/lib/scout_apm/agent.rb +45 -31
  8. data/lib/scout_apm/app_server_load.rb +1 -2
  9. data/lib/scout_apm/attribute_arranger.rb +0 -4
  10. data/lib/scout_apm/background_worker.rb +6 -9
  11. data/lib/scout_apm/bucket_name_splitter.rb +3 -3
  12. data/lib/scout_apm/call_set.rb +1 -0
  13. data/lib/scout_apm/config.rb +110 -66
  14. data/lib/scout_apm/environment.rb +16 -10
  15. data/lib/scout_apm/framework_integrations/rails_2.rb +12 -14
  16. data/lib/scout_apm/framework_integrations/rails_3_or_4.rb +5 -17
  17. data/lib/scout_apm/framework_integrations/ruby.rb +0 -4
  18. data/lib/scout_apm/framework_integrations/sinatra.rb +0 -4
  19. data/lib/scout_apm/histogram.rb +0 -20
  20. data/lib/scout_apm/instruments/action_controller_rails_3_rails4.rb +1 -4
  21. data/lib/scout_apm/instruments/active_record.rb +149 -8
  22. data/lib/scout_apm/instruments/mongoid.rb +5 -78
  23. data/lib/scout_apm/instruments/process/process_cpu.rb +0 -12
  24. data/lib/scout_apm/instruments/process/process_memory.rb +14 -43
  25. data/lib/scout_apm/layaway.rb +34 -134
  26. data/lib/scout_apm/layaway_file.rb +50 -27
  27. data/lib/scout_apm/layer.rb +45 -1
  28. data/lib/scout_apm/layer_converters/allocation_metric_converter.rb +17 -0
  29. data/lib/scout_apm/layer_converters/converter_base.rb +4 -6
  30. data/lib/scout_apm/layer_converters/job_converter.rb +1 -0
  31. data/lib/scout_apm/layer_converters/metric_converter.rb +2 -1
  32. data/lib/scout_apm/layer_converters/slow_job_converter.rb +42 -21
  33. data/lib/scout_apm/layer_converters/slow_request_converter.rb +58 -37
  34. data/lib/scout_apm/metric_meta.rb +1 -5
  35. data/lib/scout_apm/metric_set.rb +6 -15
  36. data/lib/scout_apm/reporter.rb +4 -6
  37. data/lib/scout_apm/serializers/metrics_to_json_serializer.rb +5 -1
  38. data/lib/scout_apm/serializers/payload_serializer_to_json.rb +1 -3
  39. data/lib/scout_apm/serializers/slow_jobs_serializer_to_json.rb +5 -3
  40. data/lib/scout_apm/slow_job_policy.rb +19 -89
  41. data/lib/scout_apm/slow_job_record.rb +12 -20
  42. data/lib/scout_apm/slow_request_policy.rb +12 -80
  43. data/lib/scout_apm/slow_transaction.rb +16 -20
  44. data/lib/scout_apm/stackprof_tree_collapser.rb +103 -0
  45. data/lib/scout_apm/store.rb +16 -78
  46. data/lib/scout_apm/tracked_request.rb +53 -36
  47. data/lib/scout_apm/utils/active_record_metric_name.rb +2 -0
  48. data/lib/scout_apm/utils/fake_stack_prof.rb +40 -0
  49. data/lib/scout_apm/utils/klass_helper.rb +26 -0
  50. data/lib/scout_apm/utils/sql_sanitizer.rb +1 -1
  51. data/lib/scout_apm/utils/sql_sanitizer_regex.rb +2 -2
  52. data/lib/scout_apm/utils/sql_sanitizer_regex_1_8_7.rb +2 -2
  53. data/lib/scout_apm/version.rb +1 -1
  54. data/lib/scout_apm.rb +13 -7
  55. data/scout_apm.gemspec +3 -1
  56. data/test/test_helper.rb +3 -4
  57. data/test/unit/layaway_test.rb +8 -5
  58. data/test/unit/serializers/payload_serializer_test.rb +2 -2
  59. data/test/unit/slow_item_set_test.rb +1 -2
  60. data/test/unit/sql_sanitizer_test.rb +0 -6
  61. metadata +28 -20
  62. data/LICENSE.md +0 -27
  63. data/lib/scout_apm/instruments/grape.rb +0 -69
  64. data/lib/scout_apm/instruments/percentile_sampler.rb +0 -37
  65. data/lib/scout_apm/request_histograms.rb +0 -46
  66. data/lib/scout_apm/scored_item_set.rb +0 -79
  67. data/test/unit/metric_set_test.rb +0 -101
  68. data/test/unit/scored_item_set_test.rb +0 -65
  69. data/test/unit/slow_request_policy_test.rb +0 -42
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 60e5f3ca394fce2b63871b71be1225d9634687aa
4
- data.tar.gz: 330e89e41635be1c597179faaca221af76ccbd2e
3
+ metadata.gz: b18724905e7c795caad3fc416688b3044e624d79
4
+ data.tar.gz: ee4ec99aeb9fa9e32c7b846caec0f010070546c2
5
5
  SHA512:
6
- metadata.gz: 0d9aa3156586ae561fd952135e0974157ae2d33347d772db695fd1d7519109a0fc2b6ae663163930d76c5f701c8282357fd70c7694299bafa53092369ff61b6c
7
- data.tar.gz: 189eba2d8cafd88043b09665e82a73560b3e53a418b3846b8f796d4e80f895a1e2082e8cb5e5bf43d8ec0eb8aef0e39b5c19649d6445700596e0509c88cda41c
6
+ metadata.gz: 236bfd93df93733c409684ac735dfbc77b5412f221127b5acbec9fc679b3141c6ac8e4c46c485295532aee7821b8fda36edd648233f820ed045d667905237448
7
+ data.tar.gz: 4b43e6158568bd089b3174bd8af445baef2260f92a33c31b50ed8627722a9f194fc2e4352c509c12e677e71f824e04e22226ce5c1b7a5c542f2e806167c0aabb
data/.gitignore CHANGED
@@ -5,6 +5,13 @@ Gemfile.lock
5
5
  pkg/*
6
6
  .rvmrc
7
7
  .idea
8
+ test/tmp/*
9
+ /tmp
10
+ /ext/stack_profile/stack_profile.bundle
11
+ /ext/stack_profile/stack_profile.so
12
+ /ext/stack_profile/stack_profile.o
13
+ /ext/stack_profile/mkmf.log
14
+ /ext/stack_profile/Makefile
15
+ .DS_Store
8
16
  test/tmp/*coverage/*
9
17
  coverage/*
10
- lib/*.bundle
data/CHANGELOG.markdown CHANGED
@@ -1,67 +1,17 @@
1
- # 1.6.8
1
+ # 2.0.0
2
2
 
3
- * Don't wait on a sleeping thread during shutdown
4
-
5
- # 1.6.7
6
-
7
- * Mongoid bugfixes
8
-
9
- # 1.6.6
10
-
11
- * Bugfix related to DB detection
12
-
13
- # 1.6.5
14
-
15
- * Add Mongoid 5.x support
16
- * Fix autodetection of mysql databases
17
-
18
- # 1.6.4
19
-
20
- * Add Grape instrumentation
21
- * Handle DATABASE_URL configurations better
22
- * Change default (undeteced) database to Postgres (was Mysql)
23
-
24
- # 1.6.3
25
-
26
- * Handle nil ignore_traces when ignoring trace patterns
27
-
28
- # 1.6.2
29
-
30
- * Use a more flexible approach to storing "Layaway Files" (the temporary data
31
- files the agent uses).
32
-
33
- # 1.6.1
34
-
35
- * Remove old & unused references to Stackprof. Prevent interaction with intentional usage of Stackprof
36
-
37
- # 1.6.0
38
-
39
- * Dynamic algorithm for selecting when to collect traces. Now, we will collect a
40
- more complete cross-section of your application's performance, dynamically
41
- tuned as your application runs.
42
- * Record and report 95th percentiles for each action
43
- * A variety of bug fixes
44
-
45
- # 1.5.5
46
-
47
- * Handle backslash escaped quotes inside mysql strings.
48
-
49
- # 1.5.4
50
-
51
- * Fix issue where error counts were being misreported
52
- * Politely ignore cases when `request.remote_ip` raises exceptions.
53
-
54
- # 1.5.3
55
-
56
- * Fix another minor bug related to iso8601 timestamps
3
+ * Reporting object allocation metrics and mem delta with slow requests and jobs.
57
4
 
58
5
  # 1.5.2
59
6
 
60
- * Force timestamps to be iso8601 format
7
+ * Fix deploy webhook endpoint
61
8
 
62
9
  # 1.5.1
63
10
 
64
- * Add `ignore_traces` config option to ignore SlowTransactions from certain URIs.
11
+ * Collecting memory metrics on slow transactions
12
+ * Collecting additional fields for slow transactions:
13
+ * hostname
14
+ * seconds_since_startup (larger memory increases and other other odd behavior more common when close to startup)
65
15
 
66
16
  # 1.5.0
67
17
 
@@ -0,0 +1,84 @@
1
+ #include <ruby/ruby.h>
2
+
3
+ VALUE mScoutApm;
4
+ VALUE mInstruments;
5
+ VALUE cAllocations;
6
+
7
+ #ifdef RUBY_INTERNAL_EVENT_NEWOBJ
8
+
9
+ #include <sys/resource.h> // is this needed?
10
+ #include <sys/time.h>
11
+ #include <ruby/debug.h>
12
+
13
+ static __thread uint64_t endpoint_allocations;
14
+ void increment_allocations() {
15
+ endpoint_allocations++;
16
+ }
17
+
18
+ static VALUE
19
+ get_allocation_count() {
20
+ return ULL2NUM(endpoint_allocations);
21
+ }
22
+
23
+ static void
24
+ tracepoint_handler(VALUE tpval, void *data)
25
+ {
26
+ rb_trace_arg_t *tparg = rb_tracearg_from_tracepoint(tpval);
27
+ if (rb_tracearg_event_flag(tparg) == RUBY_INTERNAL_EVENT_NEWOBJ) {
28
+ increment_allocations();
29
+ }
30
+ }
31
+
32
+ static VALUE
33
+ set_gc_hook(rb_event_flag_t event)
34
+ {
35
+ VALUE tpval;
36
+ // TODO - need to prevent applying the same tracepoint multiple times?
37
+ tpval = rb_tracepoint_new(0, event, tracepoint_handler, 0);
38
+ rb_tracepoint_enable(tpval);
39
+
40
+ return tpval;
41
+ }
42
+
43
+ void
44
+ Init_hooks(VALUE module)
45
+ {
46
+ set_gc_hook(RUBY_INTERNAL_EVENT_NEWOBJ);
47
+ }
48
+
49
+ void Init_allocations()
50
+ {
51
+ mScoutApm = rb_define_module("ScoutApm");
52
+ mInstruments = rb_define_module_under(mScoutApm, "Instruments");
53
+ cAllocations = rb_define_class_under(mInstruments, "Allocations", rb_cObject);
54
+ rb_define_singleton_method(cAllocations, "count", get_allocation_count, 0);
55
+ rb_define_singleton_method(cAllocations, "count", get_allocation_count, 0);
56
+ rb_define_const(cAllocations, "ENABLED", Qtrue);
57
+ Init_hooks(mScoutApm);
58
+ }
59
+
60
+ #else
61
+
62
+ static VALUE
63
+ get_allocation_count() {
64
+ return ULL2NUM(0);
65
+ }
66
+
67
+ void
68
+ Init_hooks(VALUE module)
69
+ {
70
+ }
71
+
72
+ void Init_allocations()
73
+ {
74
+ mScoutApm = rb_define_module("ScoutApm");
75
+ mInstruments = rb_define_module_under(mScoutApm, "Instruments");
76
+ cAllocations = rb_define_class_under(mInstruments, "Allocations", rb_cObject);
77
+ rb_define_singleton_method(cAllocations, "count", get_allocation_count, 0);
78
+ rb_define_singleton_method(cAllocations, "count", get_allocation_count, 0);
79
+ rb_define_const(cAllocations, "ENABLED", Qfalse);
80
+ Init_hooks(mScoutApm);
81
+ }
82
+
83
+ #endif //#ifdef RUBY_INTERNAL_EVENT_NEWOBJ
84
+
@@ -0,0 +1,3 @@
1
+ require 'mkmf'
2
+
3
+ create_makefile('allocations')
@@ -24,35 +24,17 @@ module ScoutApm
24
24
  report_to_server
25
25
  end
26
26
 
27
+ MAX_AGE_TO_REPORT = (10 * 60) # ten minutes as seconds
28
+
27
29
  # In a running app, one process will get one period ready for delivery, the others will see 0.
28
30
  def report_to_server
29
- period_to_report = ScoutApm::StoreReportingPeriodTimestamp.minutes_ago(2)
30
-
31
- logger.debug("Attempting to claim #{period_to_report.to_s}")
32
-
33
- did_write = layaway.with_claim(period_to_report) do |rps|
34
- logger.debug("Succeeded claiming #{period_to_report.to_s}")
35
-
36
- begin
37
- merged = rps.inject { |memo, rp| memo.merge(rp) }
38
- logger.debug("Merged #{rps.length} reporting periods, delivering")
39
- deliver_period(merged)
40
- true
41
- rescue => e
42
- logger.debug("Error merging reporting periods #{e.message}")
43
- logger.debug("Error merging reporting periods #{e.backtrace}")
44
- false
45
- end
46
-
31
+ reporting_periods = layaway.periods_ready_for_delivery
32
+ reporting_periods.reject! {|rp| rp.timestamp.age_in_seconds > MAX_AGE_TO_REPORT }
33
+ reporting_periods.each do |rp|
34
+ deliver_period(rp)
47
35
  end
48
-
49
- if !did_write
50
- logger.debug("Failed to obtain claim for #{period_to_report.to_s}")
51
- end
52
-
53
36
  end
54
37
 
55
-
56
38
  def deliver_period(reporting_period)
57
39
  metrics = reporting_period.metrics_payload
58
40
  slow_transactions = reporting_period.slow_transactions_payload
@@ -68,7 +50,7 @@ module ScoutApm
68
50
  :platform => "ruby",
69
51
  }
70
52
 
71
- log_deliver(metrics, slow_transactions, metadata, slow_jobs)
53
+ log_deliver(metrics, slow_transactions, metadata)
72
54
 
73
55
  payload = ScoutApm::Serializers::PayloadSerializer.serialize(metadata, metrics, slow_transactions, jobs, slow_jobs)
74
56
  logger.debug("Payload: #{payload}")
@@ -80,7 +62,7 @@ module ScoutApm
80
62
  logger.debug e.backtrace
81
63
  end
82
64
 
83
- def log_deliver(metrics, slow_transactions, metadata, jobs_traces)
65
+ def log_deliver(metrics, slow_transactions, metadata)
84
66
  total_request_count = metrics.
85
67
  select { |meta,stats| meta.metric_name =~ /\AController/ }.
86
68
  inject(0) {|sum, (_, stat)| sum + stat.call_count }
@@ -93,12 +75,7 @@ module ScoutApm
93
75
  "Recorded across (unknown) processes"
94
76
  end
95
77
 
96
- time_clause = "[#{Time.parse(metadata[:agent_time]).strftime("%H:%M")}]"
97
- metrics_clause = "#{metrics.length} Metrics for #{total_request_count} requests"
98
- slow_trans_clause = "#{slow_transactions.length} Slow Transaction Traces"
99
- job_clause = "#{jobs_traces.length} Job Traces"
100
-
101
- logger.info "#{time_clause} Delivering #{metrics_clause} and #{slow_trans_clause} and #{job_clause}, #{process_log_str}."
78
+ logger.info "[#{Time.parse(metadata[:agent_time]).strftime("%H:%M")}] Delivering #{metrics.length} Metrics for #{total_request_count} requests and #{slow_transactions.length} Slow Transaction Traces, #{process_log_str}."
102
79
  logger.debug("Metrics: #{metrics.pretty_inspect}\nSlowTrans: #{slow_transactions.pretty_inspect}\nMetadata: #{metadata.inspect.pretty_inspect}")
103
80
  end
104
81
 
@@ -19,13 +19,7 @@ module ScoutApm
19
19
  attr_accessor :metric_lookup # Hash used to lookup metric ids based on their name and scope
20
20
  attr_reader :slow_request_policy
21
21
  attr_reader :slow_job_policy
22
-
23
- # Histogram of the cumulative requests since the start of the process
24
- attr_reader :request_histograms
25
-
26
- # Histogram of the requests, distinct by reporting period (minute)
27
- # { StoreReportingPeriodTimestamp => RequestHistograms }
28
- attr_reader :request_histograms_by_time
22
+ attr_reader :process_start_time # used when creating slow transactions to report how far from startup the transaction was recorded.
29
23
 
30
24
  # All access to the agent is thru this class method to ensure multiple Agent instances are not initialized per-Ruby process.
31
25
  def self.instance(options = {})
@@ -37,18 +31,24 @@ module ScoutApm
37
31
  # be started (when forking).
38
32
  def initialize(options = {})
39
33
  @started = false
34
+ @process_start_time = Time.now
40
35
  @options ||= options
41
- @config = ScoutApm::Config.new(options[:config_path])
42
36
 
43
- @slow_request_policy = ScoutApm::SlowRequestPolicy.new
37
+ # Start up without attempting to load a configuration file. We need to be
38
+ # able to lookup configuration options like "application_root" which would
39
+ # then in turn influence where the configuration file came from.
40
+ #
41
+ # Later in initialization, we reset @config to include the file.
42
+ @config = ScoutApm::Config.without_file
43
+
44
44
  @slow_job_policy = ScoutApm::SlowJobPolicy.new
45
- @request_histograms = ScoutApm::RequestHistograms.new
46
- @request_histograms_by_time = Hash.new { |h, k| h[k] = ScoutApm::RequestHistograms.new }
47
45
 
48
46
  @store = ScoutApm::Store.new
49
47
  @layaway = ScoutApm::Layaway.new
50
48
  @metric_lookup = Hash.new
51
49
 
50
+ @slow_request_policy = ScoutApm::SlowRequestPolicy.new
51
+
52
52
  @capacity = ScoutApm::Capacity.new
53
53
  @installed_instruments = []
54
54
  end
@@ -78,7 +78,11 @@ module ScoutApm
78
78
  end
79
79
 
80
80
  if app_server_missing?(options) && background_job_missing?
81
- logger.warn "Couldn't find a supported app server or background job framework. #{force? ? 'Forcing agent to start' : 'Not starting agent'}."
81
+ if force?
82
+ logger.warn "Agent starting (forced)"
83
+ else
84
+ logger.warn "Deferring agent start. Standing by for first request"
85
+ end
82
86
  return false unless force?
83
87
  end
84
88
 
@@ -99,6 +103,7 @@ module ScoutApm
99
103
  # It initializes the agent and starts the worker thread (if appropiate).
100
104
  def start(options = {})
101
105
  @options.merge!(options)
106
+ @config = ScoutApm::Config.with_file(@config.value("config_file"))
102
107
  init_logger
103
108
  logger.info "Attempting to start Scout Agent [#{ScoutApm::VERSION}] on [#{environment.hostname}]"
104
109
 
@@ -112,10 +117,10 @@ module ScoutApm
112
117
 
113
118
  load_instruments if should_load_instruments?(options)
114
119
 
115
- [ ScoutApm::Instruments::Process::ProcessCpu.new(environment.processors, logger),
116
- ScoutApm::Instruments::Process::ProcessMemory.new(logger),
117
- ScoutApm::Instruments::PercentileSampler.new(logger, 95),
118
- ].each { |s| store.add_sampler(s) }
120
+ @samplers = [
121
+ ScoutApm::Instruments::Process::ProcessCpu.new(environment.processors, logger),
122
+ ScoutApm::Instruments::Process::ProcessMemory.new(logger)
123
+ ]
119
124
 
120
125
  app_server_load_hook
121
126
 
@@ -183,19 +188,14 @@ module ScoutApm
183
188
  def shutdown
184
189
  logger.info "Shutting down ScoutApm"
185
190
  return if !started?
186
-
187
191
  if @background_worker
188
- logger.info("Stopping background worker")
189
192
  @background_worker.stop
190
193
  store.write_to_layaway(layaway, :force)
191
194
  end
192
195
 
193
196
  # Make sure we don't exit the process while the background worker is running its task.
194
197
  logger.debug "Joining background worker thread"
195
- if @background_worker_thread
196
- @background_worker_thread.wakeup
197
- @background_worker_thread.join
198
- end
198
+ @background_worker_thread.join if @background_worker_thread
199
199
  end
200
200
 
201
201
  def started?
@@ -232,19 +232,16 @@ module ScoutApm
232
232
  @background_worker = ScoutApm::BackgroundWorker.new
233
233
  @background_worker_thread = Thread.new do
234
234
  @background_worker.start {
235
+ # First, run periodic samplers. These should run once a minute,
236
+ # rather than per-request. "CPU Load" and similar.
237
+ run_samplers
238
+ capacity.process
239
+
235
240
  ScoutApm::Agent.instance.process_metrics
236
- clean_old_percentiles
237
241
  }
238
242
  end
239
243
  end
240
244
 
241
- def clean_old_percentiles
242
- request_histograms_by_time.
243
- keys.
244
- select {|timestamp| timestamp.age_in_seconds > 60 * 10 }.
245
- each {|old_timestamp| request_histograms_by_time.delete(old_timestamp) }
246
- end
247
-
248
245
  # If we want to skip the app_server_check, then we must load it.
249
246
  def should_load_instruments?(options={})
250
247
  return true if options[:skip_app_server_check]
@@ -277,7 +274,10 @@ module ScoutApm
277
274
  install_instrument(ScoutApm::Instruments::Redis)
278
275
  install_instrument(ScoutApm::Instruments::InfluxDB)
279
276
  install_instrument(ScoutApm::Instruments::Elasticsearch)
280
- install_instrument(ScoutApm::Instruments::Grape)
277
+
278
+ if StackProf.respond_to?(:fake?) && StackProf.fake?
279
+ logger.info 'StackProf not found - add `gem "stackprof"` to your Gemfile to enable advanced code profiling (only for Ruby 2.1+)'
280
+ end
281
281
  rescue
282
282
  logger.warn "Exception loading instruments:"
283
283
  logger.warn $!.message
@@ -304,6 +304,20 @@ module ScoutApm
304
304
  environment.deploy_integration
305
305
  end
306
306
 
307
+ # TODO: Extract a proper class / registery for these. They don't really belong here
308
+ def run_samplers
309
+ @samplers.each do |sampler|
310
+ begin
311
+ result = sampler.run
312
+ store.track_one!(sampler.metric_type, sampler.metric_name, result) if result
313
+ rescue => e
314
+ logger.info "Error reading #{sampler.human_name}"
315
+ logger.debug e.message
316
+ logger.debug e.backtrace.join("\n")
317
+ end
318
+ end
319
+ end
320
+
307
321
  def app_server_missing?(options = {})
308
322
  !environment.app_server_integration(true).found? && !options[:skip_app_server_check]
309
323
  end
@@ -34,8 +34,7 @@ module ScoutApm
34
34
  :app_server => ScoutApm::Environment.instance.app_server,
35
35
  :ruby_version => RUBY_VERSION,
36
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
37
+ :database_engine => ScoutApm::Environment.instance.database_engine,
39
38
  :application_name => ScoutApm::Environment.instance.application_name,
40
39
  :libraries => ScoutApm::Utils::InstalledGems.new.run,
41
40
  :paas => ScoutApm::Environment.instance.platform_integration.name
@@ -7,10 +7,6 @@ module ScoutApm
7
7
  case attribute
8
8
  when Array
9
9
  attribute_hash[attribute[0]] = subject.send(attribute[1])
10
- when :bucket
11
- attribute_hash[attribute] = subject.bucket_type
12
- when :name
13
- attribute_hash[attribute] = subject.bucket_name
14
10
  when Symbol
15
11
  attribute_hash[attribute] = subject.send(attribute)
16
12
  end
@@ -12,7 +12,6 @@ module ScoutApm
12
12
  end
13
13
 
14
14
  def stop
15
- ScoutApm::Agent.instance.logger.debug "Background Worker: stop requested"
16
15
  @keep_running = false
17
16
  end
18
17
 
@@ -26,33 +25,31 @@ module ScoutApm
26
25
  @task = block
27
26
 
28
27
  begin
29
- ScoutApm::Agent.instance.logger.debug "Background Worker: Starting Background Worker, running every #{period} seconds"
28
+ ScoutApm::Agent.instance.logger.debug "Starting Background Worker, running every #{period} seconds"
30
29
 
31
30
  # The first run should be 1 period of time from now
32
31
  next_time = Time.now + period
33
32
 
34
33
  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
40
-
41
34
  now = Time.now
42
35
 
43
36
  # Sleep the correct amount of time to reach next_time
44
- while now < next_time && @keep_running
37
+ while now < next_time
45
38
  sleep_time = next_time - now
46
39
  sleep(sleep_time) if sleep_time > 0
47
40
  now = Time.now
48
41
  end
49
42
 
43
+ # Bail out if @keep_running is false
44
+ break unless @keep_running
45
+
50
46
  @task.call
51
47
 
52
48
  # Adjust the next time to run forward by @periods until it is in the future
53
49
  while next_time <= now
54
50
  next_time += period
55
51
  end
52
+
56
53
  end
57
54
  rescue
58
55
  ScoutApm::Agent.instance.logger.debug "Background Worker Exception!"
@@ -1,15 +1,15 @@
1
1
  module ScoutApm
2
2
  module BucketNameSplitter
3
- def bucket_type
3
+ def bucket
4
4
  split_metric_name(metric_name).first
5
5
  end
6
6
 
7
- def bucket_name
7
+ def name
8
8
  split_metric_name(metric_name).last
9
9
  end
10
10
 
11
11
  def key
12
- {:bucket => bucket_type, :name => bucket_name}
12
+ {:bucket => bucket, :name => name}
13
13
  end
14
14
 
15
15
  private
@@ -1,4 +1,5 @@
1
1
  module ScoutApm
2
+ # Encapsulates our logic to determine when a backtrace should be collected.
2
3
  class CallSet
3
4
 
4
5
  N_PLUS_ONE_MAGIC_NUMBER = 5 # Fetch backtraces on this number of calls to a layer. The caller data is only collected on this call to limit overhead.