scout_apm 2.3.5 → 2.4.0.pre

Sign up to get free protection for your applications and to get access to all the features.
Files changed (94) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.markdown +0 -23
  3. data/lib/scout_apm.rb +21 -10
  4. data/lib/scout_apm/agent.rb +98 -336
  5. data/lib/scout_apm/agent/exit_handler.rb +64 -0
  6. data/lib/scout_apm/agent/preconditions.rb +69 -0
  7. data/lib/scout_apm/agent_context.rb +226 -0
  8. data/lib/scout_apm/app_server_load.rb +20 -18
  9. data/lib/scout_apm/background_job_integrations/resque.rb +7 -8
  10. data/lib/scout_apm/background_job_integrations/sidekiq.rb +2 -8
  11. data/lib/scout_apm/background_recorder.rb +8 -3
  12. data/lib/scout_apm/background_worker.rb +14 -7
  13. data/lib/scout_apm/config.rb +35 -29
  14. data/lib/scout_apm/context.rb +11 -4
  15. data/lib/scout_apm/db_query_metric_set.rb +17 -5
  16. data/lib/scout_apm/debug.rb +1 -1
  17. data/lib/scout_apm/environment.rb +10 -14
  18. data/lib/scout_apm/framework_integrations/sinatra.rb +1 -1
  19. data/lib/scout_apm/git_revision.rb +13 -8
  20. data/lib/scout_apm/histogram.rb +1 -1
  21. data/lib/scout_apm/instant/middleware.rb +7 -7
  22. data/lib/scout_apm/instant_reporting.rb +7 -7
  23. data/lib/scout_apm/instrument_manager.rb +87 -0
  24. data/lib/scout_apm/instruments/action_controller_rails_2.rb +12 -7
  25. data/lib/scout_apm/instruments/action_controller_rails_3_rails4.rb +16 -11
  26. data/lib/scout_apm/instruments/action_view.rb +11 -7
  27. data/lib/scout_apm/instruments/active_record.rb +28 -51
  28. data/lib/scout_apm/instruments/elasticsearch.rb +10 -6
  29. data/lib/scout_apm/instruments/grape.rb +12 -8
  30. data/lib/scout_apm/instruments/http_client.rb +11 -10
  31. data/lib/scout_apm/instruments/influxdb.rb +10 -6
  32. data/lib/scout_apm/instruments/middleware_detailed.rb +11 -5
  33. data/lib/scout_apm/instruments/middleware_summary.rb +11 -5
  34. data/lib/scout_apm/instruments/mongoid.rb +10 -5
  35. data/lib/scout_apm/instruments/moped.rb +11 -6
  36. data/lib/scout_apm/instruments/net_http.rb +11 -9
  37. data/lib/scout_apm/instruments/percentile_sampler.rb +8 -6
  38. data/lib/scout_apm/instruments/process/process_cpu.rb +8 -4
  39. data/lib/scout_apm/instruments/process/process_memory.rb +15 -10
  40. data/lib/scout_apm/instruments/rails_router.rb +12 -6
  41. data/lib/scout_apm/instruments/redis.rb +10 -6
  42. data/lib/scout_apm/instruments/samplers.rb +11 -0
  43. data/lib/scout_apm/instruments/sinatra.rb +5 -4
  44. data/lib/scout_apm/layaway.rb +26 -39
  45. data/lib/scout_apm/layaway_file.rb +8 -3
  46. data/lib/scout_apm/layer.rb +1 -1
  47. data/lib/scout_apm/layer_converters/converter_base.rb +4 -2
  48. data/lib/scout_apm/layer_converters/database_converter.rb +1 -1
  49. data/lib/scout_apm/layer_converters/histograms.rb +2 -2
  50. data/lib/scout_apm/layer_converters/slow_job_converter.rb +4 -3
  51. data/lib/scout_apm/layer_converters/slow_request_converter.rb +5 -4
  52. data/lib/scout_apm/logger.rb +143 -0
  53. data/lib/scout_apm/middleware.rb +7 -9
  54. data/lib/scout_apm/periodic_work.rb +28 -0
  55. data/lib/scout_apm/remote/server.rb +0 -2
  56. data/lib/scout_apm/reporter.rb +14 -8
  57. data/lib/scout_apm/reporting.rb +135 -0
  58. data/lib/scout_apm/request_manager.rb +4 -7
  59. data/lib/scout_apm/serializers/payload_serializer.rb +1 -1
  60. data/lib/scout_apm/slow_job_policy.rb +6 -2
  61. data/lib/scout_apm/slow_job_record.rb +5 -5
  62. data/lib/scout_apm/slow_request_policy.rb +6 -2
  63. data/lib/scout_apm/slow_transaction.rb +5 -5
  64. data/lib/scout_apm/store.rb +22 -16
  65. data/lib/scout_apm/synchronous_recorder.rb +7 -3
  66. data/lib/scout_apm/tasks/doctor.rb +75 -0
  67. data/lib/scout_apm/tasks/support.rb +22 -0
  68. data/lib/scout_apm/tracer.rb +5 -5
  69. data/lib/scout_apm/tracked_request.rb +23 -35
  70. data/lib/scout_apm/utils/backtrace_parser.rb +1 -1
  71. data/lib/scout_apm/utils/installed_gems.rb +7 -3
  72. data/lib/scout_apm/utils/klass_helper.rb +8 -2
  73. data/lib/scout_apm/utils/scm.rb +1 -1
  74. data/lib/scout_apm/utils/sql_sanitizer.rb +4 -6
  75. data/lib/scout_apm/version.rb +1 -1
  76. data/lib/tasks/doctor.rake +11 -0
  77. data/test/test_helper.rb +15 -2
  78. data/test/unit/agent_test.rb +1 -54
  79. data/test/unit/config_test.rb +9 -5
  80. data/test/unit/context_test.rb +4 -4
  81. data/test/unit/db_query_metric_set_test.rb +11 -4
  82. data/test/unit/fake_store_test.rb +1 -1
  83. data/test/unit/git_revision_test.rb +3 -3
  84. data/test/unit/instruments/net_http_test.rb +2 -1
  85. data/test/unit/instruments/percentile_sampler_test.rb +5 -9
  86. data/test/unit/layaway_test.rb +10 -5
  87. data/test/unit/layer_converters/metric_converter_test.rb +2 -2
  88. data/test/unit/slow_request_policy_test.rb +7 -3
  89. data/test/unit/sql_sanitizer_test.rb +0 -6
  90. data/test/unit/store_test.rb +11 -8
  91. metadata +15 -7
  92. data/lib/scout_apm/agent/logging.rb +0 -74
  93. data/lib/scout_apm/agent/reporting.rb +0 -129
  94. data/lib/scout_apm/utils/null_logger.rb +0 -13
@@ -1,25 +1,29 @@
1
1
  module ScoutApm
2
2
  module Instruments
3
3
  class Elasticsearch
4
- attr_reader :logger
4
+ attr_reader :context
5
5
 
6
- def initalize(logger=ScoutApm::Agent.instance.logger)
7
- @logger = logger
6
+ def initialize(context)
7
+ @context = context
8
8
  @installed = false
9
9
  end
10
10
 
11
+ def logger
12
+ context.logger
13
+ end
14
+
11
15
  def installed?
12
16
  @installed
13
17
  end
14
18
 
15
19
  def install
16
- @installed = true
17
-
18
20
  if defined?(::Elasticsearch) &&
19
21
  defined?(::Elasticsearch::Transport) &&
20
22
  defined?(::Elasticsearch::Transport::Client)
21
23
 
22
- ScoutApm::Agent.instance.logger.info "Instrumenting Elasticsearch"
24
+ @installed = true
25
+
26
+ logger.info "Instrumenting Elasticsearch"
23
27
 
24
28
  ::Elasticsearch::Transport::Client.class_eval do
25
29
  include ScoutApm::Tracer
@@ -1,22 +1,26 @@
1
1
  module ScoutApm
2
2
  module Instruments
3
3
  class Grape
4
- attr_reader :logger
4
+ attr_reader :context
5
5
 
6
- def initalize(logger=ScoutApm::Agent.instance.logger)
7
- @logger = logger
6
+ def initialize(context)
7
+ @context = context
8
8
  @installed = false
9
9
  end
10
10
 
11
+ def logger
12
+ context.logger
13
+ end
14
+
11
15
  def installed?
12
16
  @installed
13
17
  end
14
18
 
15
19
  def install
16
- @installed = true
17
-
18
20
  if defined?(::Grape) && defined?(::Grape::Endpoint)
19
- ScoutApm::Agent.instance.logger.info "Instrumenting Grape::Endpoint"
21
+ @installed = true
22
+
23
+ logger.info "Instrumenting Grape::Endpoint"
20
24
 
21
25
  ::Grape::Endpoint.class_eval do
22
26
  include ScoutApm::Instruments::GrapeEndpointInstruments
@@ -33,7 +37,7 @@ module ScoutApm
33
37
  request = ::Grape::Request.new(env || args.first)
34
38
  req = ScoutApm::RequestManager.lookup
35
39
 
36
- path = ScoutApm::Agent.instance.config.value("uri_reporting") == 'path' ? request.path : request.fullpath
40
+ path = ScoutApm::Agent.instance.context.config.value("uri_reporting") == 'path' ? request.path : request.fullpath
37
41
  req.annotate_request(:uri => path)
38
42
 
39
43
  # IP Spoofing Protection can throw an exception, just move on w/o remote ip
@@ -50,7 +54,7 @@ module ScoutApm
50
54
  self.options[:path].first,
51
55
  ].compact.map{ |n| n.to_s }.join("/")
52
56
  rescue => e
53
- ScoutApm::Agent.instance.logger.info("Error getting Grape Endpoint Name. Error: #{e.message}. Options: #{self.options.inspect}")
57
+ logger.info("Error getting Grape Endpoint Name. Error: #{e.message}. Options: #{self.options.inspect}")
54
58
  name = "Grape/Unknown"
55
59
  end
56
60
 
@@ -1,33 +1,34 @@
1
1
  module ScoutApm
2
2
  module Instruments
3
3
  class HttpClient
4
- attr_reader :logger
4
+ attr_reader :context
5
5
 
6
- def initalize(logger=ScoutApm::Agent.instance.logger)
7
- @logger = logger
6
+ def initialize(context)
7
+ @context = context
8
8
  @installed = false
9
9
  end
10
10
 
11
+ def logger
12
+ context.logger
13
+ end
14
+
11
15
  def installed?
12
16
  @installed
13
17
  end
14
18
 
15
19
  def install
16
- @installed = true
17
-
18
20
  if defined?(::HTTPClient)
19
- ScoutApm::Agent.instance.logger.info "Instrumenting HTTPClient"
21
+ @installed = true
22
+
23
+ logger.info "Instrumenting HTTPClient"
20
24
 
21
25
  ::HTTPClient.class_eval do
22
26
  include ScoutApm::Tracer
23
27
 
24
28
  def request_with_scout_instruments(*args, &block)
25
-
26
29
  method = args[0].to_s
27
30
  url = args[1]
28
-
29
- max_length = ScoutApm::Agent.instance.config.value('instrument_http_url_length')
30
- url = url && url.to_s[0..(max_length - 1)]
31
+ url = url && url.to_s[0..99]
31
32
 
32
33
  self.class.instrument("HTTP", method, :desc => url) do
33
34
  request_without_scout_instruments(*args, &block)
@@ -1,22 +1,26 @@
1
1
  module ScoutApm
2
2
  module Instruments
3
3
  class InfluxDB
4
- attr_reader :logger
4
+ attr_reader :context
5
5
 
6
- def initalize(logger=ScoutApm::Agent.instance.logger)
7
- @logger = logger
6
+ def initialize(context)
7
+ @context = context
8
8
  @installed = false
9
9
  end
10
10
 
11
+ def logger
12
+ context.logger
13
+ end
14
+
11
15
  def installed?
12
16
  @installed
13
17
  end
14
18
 
15
19
  def install
16
- @installed = true
17
-
18
20
  if defined?(::InfluxDB)
19
- ScoutApm::Agent.instance.logger.debug "Instrumenting InfluxDB"
21
+ @installed = true
22
+
23
+ logger.debug "Instrumenting InfluxDB"
20
24
 
21
25
  ::InfluxDB::Client.class_eval do
22
26
  include ScoutApm::Tracer
@@ -9,22 +9,28 @@
9
9
  module ScoutApm
10
10
  module Instruments
11
11
  class MiddlewareDetailed
12
- def initalize(logger=ScoutApm::Agent.instance.logger)
13
- @logger = logger
12
+ attr_reader :context
13
+
14
+ def initialize(context)
15
+ @context = context
14
16
  @installed = false
15
17
  end
16
18
 
19
+ def logger
20
+ context.logger
21
+ end
22
+
17
23
  def installed?
18
24
  @installed
19
25
  end
20
26
 
21
27
  def install
22
- @installed = true
23
-
24
28
  if defined?(ActionDispatch) && defined?(ActionDispatch::MiddlewareStack) && defined?(ActionDispatch::MiddlewareStack::Middleware)
29
+ @installed = true
30
+
25
31
  ActionDispatch::MiddlewareStack::Middleware.class_eval do
26
32
  def build(app)
27
- ScoutApm::Agent.instance.logger.info("Building Middleware #{klass.name}")
33
+ logger.info("Building Middleware #{klass.name}")
28
34
  new_mw = klass.new(app, *args, &block)
29
35
  MiddlewareWrapper.new(new_mw, klass.name)
30
36
  end
@@ -6,20 +6,26 @@
6
6
  module ScoutApm
7
7
  module Instruments
8
8
  class MiddlewareSummary
9
- def initalize(logger=ScoutApm::Agent.instance.logger)
10
- @logger = logger
9
+ attr_reader :context
10
+
11
+ def initialize(context)
12
+ @context = context
11
13
  @installed = false
12
14
  end
13
15
 
16
+ def logger
17
+ context.logger
18
+ end
19
+
14
20
  def installed?
15
21
  @installed
16
22
  end
17
23
 
18
24
  def install
19
- @installed = true
20
-
21
25
  if defined?(ActionDispatch) && defined?(ActionDispatch::MiddlewareStack)
22
- ScoutApm::Agent.instance.logger.info("Instrumenting Middleware")
26
+ @installed = true
27
+
28
+ logger.info("Instrumenting Middleware")
23
29
  ActionDispatch::MiddlewareStack.class_eval do
24
30
  def build_with_scout_instruments(app = nil, &block)
25
31
  mw_stack = build_without_scout_instruments(app) { block.call if block }
@@ -1,13 +1,17 @@
1
1
  module ScoutApm
2
2
  module Instruments
3
3
  class Mongoid
4
- attr_reader :logger
4
+ attr_reader :context
5
5
 
6
- def initalize(logger=ScoutApm::Agent.instance.logger)
7
- @logger = logger
6
+ def initialize(context)
7
+ @context = context
8
8
  @installed = false
9
9
  end
10
10
 
11
+ def logger
12
+ context.logger
13
+ end
14
+
11
15
  def installed?
12
16
  @installed
13
17
  end
@@ -17,7 +21,8 @@ module ScoutApm
17
21
 
18
22
  # Mongoid versions that use Moped should instrument Moped.
19
23
  if defined?(::Mongoid) and !defined?(::Moped)
20
- ScoutApm::Agent.instance.logger.info "Instrumenting Mongoid 2.x"
24
+ logger.info "Instrumenting Mongoid 2.x"
25
+ @installed = true
21
26
 
22
27
  ### OLD (2.x) mongoids
23
28
  if defined?(::Mongoid::Collection)
@@ -33,7 +38,7 @@ module ScoutApm
33
38
 
34
39
  ### 5.x Mongoid
35
40
  if (mongoid_v5? || mongoid_v6?) && defined?(::Mongoid::Contextual::Mongo)
36
- ScoutApm::Agent.instance.logger.info "Instrumenting Mongoid 5.x/6.x"
41
+ logger.info "Instrumenting Mongoid 5.x/6.x"
37
42
  # All the public methods from Mongoid::Contextual::Mongo.
38
43
  # TODO: Geo and MapReduce support (?). They are in other Contextual::* classes
39
44
  methods = [
@@ -1,22 +1,27 @@
1
1
  module ScoutApm
2
2
  module Instruments
3
3
  class Moped
4
- attr_reader :logger
4
+ attr_reader :context
5
5
 
6
- def initalize(logger=ScoutApm::Agent.instance.logger)
7
- @logger = logger
6
+ def initialize(context)
7
+ @context = context
8
8
  @installed = false
9
9
  end
10
10
 
11
+ def logger
12
+ context.logger
13
+ end
14
+
11
15
  def installed?
12
16
  @installed
13
17
  end
14
18
 
15
19
  def install
16
- @installed = true
17
-
18
20
  if defined?(::Moped)
19
- ScoutApm::Agent.instance.logger.info "Instrumenting Moped"
21
+ @installed = true
22
+
23
+ logger.info "Instrumenting Moped"
24
+
20
25
  ::Moped::Node.class_eval do
21
26
  include ScoutApm::Tracer
22
27
 
@@ -1,22 +1,26 @@
1
1
  module ScoutApm
2
2
  module Instruments
3
3
  class NetHttp
4
- attr_reader :logger
4
+ attr_reader :context
5
5
 
6
- def initalize(logger=ScoutApm::Agent.instance.logger)
7
- @logger = logger
6
+ def initialize(context)
7
+ @context = context
8
8
  @installed = false
9
9
  end
10
10
 
11
+ def logger
12
+ context.logger
13
+ end
14
+
11
15
  def installed?
12
16
  @installed
13
17
  end
14
18
 
15
19
  def install
16
- @installed = true
17
-
18
20
  if defined?(::Net) && defined?(::Net::HTTP)
19
- ScoutApm::Agent.instance.logger.info "Instrumenting Net::HTTP"
21
+ @installed = true
22
+
23
+ logger.info "Instrumenting Net::HTTP"
20
24
 
21
25
  ::Net::HTTP.class_eval do
22
26
  include ScoutApm::Tracer
@@ -30,9 +34,7 @@ module ScoutApm
30
34
  def request_scout_description(req)
31
35
  path = req.path
32
36
  path = path.path if path.respond_to?(:path)
33
-
34
- max_length = ScoutApm::Agent.instance.config.value('instrument_http_url_length')
35
- (@address + path.split('?').first)[0..(max_length - 1)]
37
+ (@address + path.split('?').first)[0..99]
36
38
  end
37
39
 
38
40
  alias request_without_scout_instruments request
@@ -18,14 +18,16 @@ module ScoutApm
18
18
  end
19
19
 
20
20
  class PercentileSampler
21
- attr_reader :logger
21
+ def initialize(context)
22
+ @context = context
23
+ end
22
24
 
23
- # A hash of { time => RequestHistograms }
24
- attr_reader :histograms
25
+ def histograms
26
+ @context.request_histograms_by_time
27
+ end
25
28
 
26
- def initialize(logger, histograms)
27
- @logger = logger
28
- @histograms = histograms
29
+ def logger
30
+ @context.logger
29
31
  end
30
32
 
31
33
  def human_name
@@ -2,14 +2,14 @@ module ScoutApm
2
2
  module Instruments
3
3
  module Process
4
4
  class ProcessCpu
5
- attr_reader :logger
6
5
  attr_reader :num_processors
7
6
  attr_accessor :last_run, :last_utime, :last_stime
7
+ attr_reader :context
8
8
 
9
+ def initialize(context)
10
+ @context = context
9
11
 
10
- def initialize(num_processors, logger)
11
- @num_processors = [num_processors, 1].compact.max
12
- @logger = logger
12
+ @num_processors = [context.environment.processors, 1].compact.max
13
13
 
14
14
  t = ::Process.times
15
15
  @last_run = Time.now
@@ -98,6 +98,10 @@ module ScoutApm
98
98
  self.last_utime = utime
99
99
  self.last_stime = stime
100
100
  end
101
+
102
+ def logger
103
+ context.logger
104
+ end
101
105
  end
102
106
  end
103
107
  end
@@ -2,23 +2,24 @@ module ScoutApm
2
2
  module Instruments
3
3
  module Process
4
4
  class ProcessMemory
5
- attr_reader :logger
6
-
7
- # Account for Darwin returning maxrss in bytes and Linux in KB. Used by the slow converters. Doesn't feel like this should go here though...more of a utility.
8
- def self.rss_to_mb(rss)
9
- rss.to_f/1024/(ScoutApm::Agent.instance.environment.os == 'darwin' ? 1024 : 1)
5
+ # Account for Darwin returning maxrss in bytes and Linux in KB. Used by
6
+ # the slow converters. Doesn't feel like this should go here
7
+ # though...more of a utility.
8
+ def rss_to_mb(rss)
9
+ kilobyte_adjust = @context.environment.os == 'darwin' ? 1024 : 1
10
+ rss.to_f / 1024 / kilobyte_adjust
10
11
  end
11
12
 
12
- def self.rss
13
+ def rss
13
14
  ::Process.rusage.maxrss
14
15
  end
15
16
 
16
- def self.rss_in_mb
17
+ def rss_in_mb
17
18
  rss_to_mb(rss)
18
19
  end
19
20
 
20
- def initialize(logger)
21
- @logger = logger
21
+ def initialize(context)
22
+ @context = context
22
23
  end
23
24
 
24
25
  def metric_type
@@ -46,7 +47,11 @@ module ScoutApm
46
47
  end
47
48
 
48
49
  def run
49
- self.class.rss_in_mb.tap { |res| logger.debug "#{human_name}: #{res.inspect}" }
50
+ rss_in_mb.tap { |res| logger.debug "#{human_name}: #{res.inspect}" }
51
+ end
52
+
53
+ def logger
54
+ @context.logger
50
55
  end
51
56
  end
52
57
  end