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
data/ext/rusage/README.md DELETED
@@ -1,26 +0,0 @@
1
- This is a vendored copy of the rusage gem.
2
-
3
-
4
- = rusage
5
-
6
- * http://github.com/sandofsky/rusage
7
-
8
- == DESCRIPTION:
9
-
10
- A gem that calls getrusage to get details on the current process.
11
-
12
- Ripped out of the proc/wait3 library, originally written by Daniel J. Berger.
13
-
14
- http://raa.ruby-lang.org/project/proc-wait3/
15
-
16
- == LICENSE:
17
-
18
- Inherits the Artistic License 2.0 from proc/wait3.
19
-
20
- == COPYRIGHT:
21
-
22
- The original code is still copyright Daniel J. Berger.
23
-
24
- rusage gem is copyright Ben Sandofsky.
25
-
26
- Code changes after being added to this repository are copyright Zimuth, Inc.
@@ -1,5 +0,0 @@
1
- require 'mkmf'
2
-
3
- dir_config("rusage")
4
-
5
- create_makefile("rusage")
data/ext/rusage/rusage.c DELETED
@@ -1,52 +0,0 @@
1
- // VERSION = "x.y.z"
2
- #include <ruby.h>
3
- #include <sys/resource.h>
4
-
5
- VALUE v_usage_struct;
6
-
7
- static VALUE do_rusage_get(int who){
8
- struct rusage r;
9
- int ret;
10
-
11
- ret = getrusage(who, &r);
12
- if(ret == -1)
13
- rb_sys_fail("getrusage");
14
-
15
- return rb_struct_new(v_usage_struct,
16
- rb_float_new((double)r.ru_utime.tv_sec+(double)r.ru_utime.tv_usec/1e6),
17
- rb_float_new((double)r.ru_stime.tv_sec+(double)r.ru_stime.tv_usec/1e6),
18
- LONG2NUM(r.ru_maxrss),
19
- LONG2NUM(r.ru_ixrss),
20
- LONG2NUM(r.ru_idrss),
21
- LONG2NUM(r.ru_isrss),
22
- LONG2NUM(r.ru_minflt),
23
- LONG2NUM(r.ru_majflt),
24
- LONG2NUM(r.ru_nswap),
25
- LONG2NUM(r.ru_inblock),
26
- LONG2NUM(r.ru_oublock),
27
- LONG2NUM(r.ru_msgsnd),
28
- LONG2NUM(r.ru_msgrcv),
29
- LONG2NUM(r.ru_nsignals),
30
- LONG2NUM(r.ru_nvcsw),
31
- LONG2NUM(r.ru_nivcsw)
32
- );
33
- }
34
-
35
- static VALUE rusage_get(int argc, VALUE* argv, VALUE mod){
36
- return do_rusage_get(RUSAGE_SELF);
37
- }
38
-
39
- static VALUE crusage_get(int argc, VALUE* argv, VALUE mod){
40
- return do_rusage_get(RUSAGE_CHILDREN);
41
- }
42
-
43
- void Init_rusage(){
44
- v_usage_struct =
45
- rb_struct_define("RUsage","utime","stime","maxrss","ixrss","idrss",
46
- "isrss","minflt","majflt","nswap","inblock","oublock","msgsnd",
47
- "msgrcv","nsignals","nvcsw","nivcsw",NULL
48
- );
49
-
50
- rb_define_module_function(rb_mProcess, "rusage", rusage_get, -1);
51
- rb_define_module_function(rb_mProcess, "crusage", crusage_get, -1);
52
- }
@@ -1,85 +0,0 @@
1
- module ScoutApm
2
- module BackgroundJobIntegrations
3
- class Resque
4
- def name
5
- :resque
6
- end
7
-
8
- def present?
9
- defined?(::Resque) &&
10
- ::Resque.respond_to?(:before_first_fork) &&
11
- ::Resque.respond_to?(:after_fork)
12
- end
13
-
14
- # Lies. This forks really aggressively, but we have to do handling
15
- # of it manually here, rather than via any sort of automatic
16
- # background worker starting
17
- def forking?
18
- false
19
- end
20
-
21
- def install
22
- install_before_fork
23
- install_after_fork
24
- end
25
-
26
- def install_before_fork
27
- ::Resque.before_first_fork do
28
- begin
29
- ScoutApm::Agent.instance.start(:skip_app_server_check => true)
30
- ScoutApm::Agent.instance.start_background_worker
31
- ScoutApm::Agent.instance.start_remote_server(bind, port)
32
- rescue Errno::EADDRINUSE
33
- ScoutApm::Agent.instance.logger.warn "Error while Installing Resque Instruments, Port #{port} already in use. Set via the `remote_agent_port` configuration option"
34
- rescue => e
35
- ScoutApm::Agent.instance.logger.warn "Error while Installing Resque before_first_fork: #{e.inspect}"
36
- end
37
- end
38
- end
39
-
40
- def install_after_fork
41
- ::Resque.after_fork do
42
- begin
43
- ScoutApm::Agent.instance.use_remote_recorder(bind, port)
44
- inject_job_instrument
45
- rescue => e
46
- ScoutApm::Agent.instance.logger.warn "Error while Installing Resque after_fork: #{e.inspect}"
47
- end
48
- end
49
- end
50
-
51
- # Insert ourselves into the point when resque turns a string "TestJob"
52
- # into the class constant TestJob, and insert our instrumentation plugin
53
- # into that constantized class
54
- #
55
- # This automates away any need for the user to insert our instrumentation into
56
- # each of their jobs
57
- def inject_job_instrument
58
- ::Resque::Job.class_eval do
59
- def payload_class_with_scout_instruments
60
- klass = payload_class_without_scout_instruments
61
- klass.extend(ScoutApm::Instruments::Resque)
62
- klass
63
- end
64
- alias_method :payload_class_without_scout_instruments, :payload_class
65
- alias_method :payload_class, :payload_class_with_scout_instruments
66
- end
67
- end
68
-
69
- private
70
-
71
- def bind
72
- config.value("remote_agent_host")
73
- end
74
-
75
- def port
76
- config.value("remote_agent_port")
77
- end
78
-
79
- def config
80
- @config || ScoutApm::Agent.instance.config
81
- end
82
- end
83
- end
84
- end
85
-
@@ -1,43 +0,0 @@
1
- # Provide a background thread queue to do the processing of
2
- # TrackedRequest objects, to remove it from the hot-path of returning a
3
- # web response
4
-
5
- module ScoutApm
6
- class BackgroundRecorder
7
- attr_reader :queue
8
- attr_reader :thread
9
- attr_reader :logger
10
-
11
- def initialize(logger)
12
- @logger = logger
13
- @queue = Queue.new
14
- end
15
-
16
- def start
17
- logger.info("Starting BackgroundRecorder")
18
- @thread = Thread.new(&method(:thread_func))
19
- self
20
- end
21
-
22
- def stop
23
- @thread.kill
24
- end
25
-
26
- def record!(request)
27
- start unless @thread.alive?
28
- @queue.push(request)
29
- end
30
-
31
- def thread_func
32
- while req = queue.pop
33
- begin
34
- logger.debug("recording in thread. Queue size: #{queue.size}")
35
- # For now, just proxy right back into the TrackedRequest object's record function
36
- req.record!
37
- rescue => e
38
- logger.warn("Error in BackgroundRecorder - #{e.message} : #{e.backtrace}")
39
- end
40
- end
41
- end
42
- end
43
- end
@@ -1,37 +0,0 @@
1
- module ScoutApm
2
- class Debug
3
- # see self.instance
4
- @@instance = nil
5
-
6
- def self.instance
7
- @@instance ||= new
8
- end
9
-
10
- def register_periodic_hook(&hook)
11
- @periodic_hooks << hook
12
- end
13
-
14
- def call_periodic_hooks
15
- @periodic_hooks.each do |hook|
16
- begin
17
- hook.call
18
- rescue => e
19
- logger.info("Periodic debug hook failed to run: #{e}\n\t#{e.backtrace.join("\n\t")}")
20
- end
21
- end
22
- rescue
23
- # Something went super wrong for the inner rescue to not catch this. Just
24
- # swallow the error. The debug tool should never crash the app.
25
- end
26
-
27
- private
28
-
29
- def initialize
30
- @periodic_hooks = []
31
- end
32
-
33
- def logger
34
- ScoutApm::Agent.instance.logger
35
- end
36
- end
37
- end
@@ -1,51 +0,0 @@
1
- module ScoutApm
2
- class GitRevision
3
-
4
- attr_accessor :sha
5
-
6
- def initialize
7
- @sha = detect
8
- ScoutApm::Agent.instance.logger.debug "Detected Git Revision [#{@sha}]"
9
- end
10
-
11
- private
12
-
13
- def detect
14
- detect_from_env_var ||
15
- detect_from_heroku ||
16
- detect_from_capistrano ||
17
- detect_from_git
18
- end
19
-
20
- def detect_from_heroku
21
- ENV['HEROKU_SLUG_COMMIT']
22
- end
23
-
24
- def detect_from_env_var
25
- ENV['SCOUT_REVISION_SHA']
26
- end
27
-
28
- def detect_from_capistrano
29
- version = File.read(File.join(app_root, 'REVISION')).strip
30
- # Capistrano 3.0 - 3.1.x
31
- version || File.open(File.join(app_root, '..', 'revisions.log')).to_a.last.strip.sub(/.*as release ([0-9]+).*/, '\1')
32
- rescue
33
- ScoutApm::Agent.instance.logger.debug "Unable to detect Git Revision from Capistrano: #{$!.message}"
34
- nil
35
- end
36
-
37
- def detect_from_git
38
- if File.directory?(".git")
39
- `git rev-parse --short HEAD`.strip
40
- end
41
- rescue
42
- ScoutApm::Agent.instance.logger.debug "Unable to detect Git Revision from Git: #{$!.message}"
43
- nil
44
- end
45
-
46
- def app_root
47
- ScoutApm::Environment.instance.root
48
- end
49
-
50
- end
51
- end
@@ -1,49 +0,0 @@
1
- module ScoutApm
2
- module Instruments
3
- # instrumentation for Rails 3 and Rails 4 is the same.
4
- class ActionView
5
- attr_reader :logger
6
-
7
- def initalize(logger=ScoutApm::Agent.instance.logger)
8
- @logger = logger
9
- @installed = false
10
- end
11
-
12
- def installed?
13
- @installed
14
- end
15
-
16
- def install
17
- @installed = true
18
-
19
- if defined?(::ActionView) && defined?(::ActionView::PartialRenderer)
20
- ScoutApm::Agent.instance.logger.info "Instrumenting ActionView::PartialRenderer"
21
- ::ActionView::PartialRenderer.class_eval do
22
- include ScoutApm::Tracer
23
-
24
- instrument_method :render_partial,
25
- :type => "View",
26
- :name => '#{@template.virtual_path rescue "Unknown Partial"}/Rendering',
27
- :scope => true
28
-
29
- instrument_method :collection_with_template,
30
- :type => "View",
31
- :name => '#{@template.virtual_path rescue "Unknown Collection"}/Rendering',
32
- :scope => true
33
- end
34
-
35
- ScoutApm::Agent.instance.logger.info "Instrumenting ActionView::TemplateRenderer"
36
- ::ActionView::TemplateRenderer.class_eval do
37
- include ScoutApm::Tracer
38
- instrument_method :render_template,
39
- :type => "View",
40
- :name => '#{args[0].virtual_path rescue "Unknown"}/Rendering',
41
- :scope => true
42
- end
43
- end
44
- end
45
- end
46
- end
47
- end
48
-
49
-
@@ -1,40 +0,0 @@
1
- module ScoutApm
2
- module Instruments
3
- module Resque
4
- def around_perform_with_scout_instruments(*args)
5
- job_name = self.to_s
6
- queue = find_queue
7
-
8
- if job_name == "ActiveJob::QueueAdapters::ResqueAdapter::JobWrapper"
9
- job_name = args.first["job_class"] rescue job_name
10
- queue = args.first["queue_name"] rescue queue_name
11
- end
12
-
13
- req = ScoutApm::RequestManager.lookup
14
- req.job!
15
-
16
- begin
17
- req.start_layer(ScoutApm::Layer.new('Queue', queue))
18
- started_queue = true
19
- req.start_layer(ScoutApm::Layer.new('Job', job_name))
20
- started_job = true
21
-
22
- yield
23
- rescue => e
24
- req.error!
25
- raise
26
- ensure
27
- req.stop_layer if started_job
28
- req.stop_layer if started_queue
29
- end
30
- end
31
-
32
- def find_queue
33
- return @queue if @queue
34
- return queue if self.respond_to?(:queue)
35
- return "unknown"
36
- end
37
- end
38
- end
39
- end
40
-
@@ -1,77 +0,0 @@
1
- module ScoutApm
2
- # A set of children records for any given Layer. This implements some
3
- # rate-limiting logic.
4
- #
5
- # We store the first `unique_cutoff` count of each layer type. So if cutoff
6
- # is 1000, we'd store 1000 HTTP layers, and 1000 ActiveRecord calls, and 1000
7
- # of each other layer type. After that, make a LimitedLayer object and store
8
- # only aggregate counts and times of future layers of that type. (So the
9
- # 1001st an onward of ActiveRecord would get only aggregate times, and
10
- # counts, without any detail about the SQL called)
11
- #
12
- # When the set of children is small, keep them unique
13
- # When the set of children gets large enough, stop keeping details
14
- #
15
- # The next optimization, which is not yet implemented:
16
- # when the set of children gets larger, attempt to merge them without data loss
17
- class LayerChildrenSet
18
- include Enumerable
19
-
20
- # By default, how many unique children of a type do we store before
21
- # flipping over to storing only aggregate info.
22
- DEFAULT_UNIQUE_CUTOFF = 2000
23
- attr_reader :unique_cutoff
24
-
25
- # The Set of children objects
26
- attr_reader :children
27
- private :children
28
-
29
- def initialize(unique_cutoff = DEFAULT_UNIQUE_CUTOFF)
30
- @children = Hash.new
31
- @limited_layers = nil # populated when needed
32
- @unique_cutoff = unique_cutoff
33
- end
34
-
35
- def child_set(metric_type)
36
- children[metric_type] = Set.new if !children.has_key?(metric_type)
37
- children[metric_type]
38
- end
39
-
40
- # Add a new layer into this set
41
- # Only add completed layers - otherwise this will collect up incorrect info
42
- # into the created LimitedLayer, since it will "freeze" any current data for
43
- # total_call_time and similar methods.
44
- def <<(child)
45
- metric_type = child.type
46
- set = child_set(metric_type)
47
-
48
- if set.size >= unique_cutoff
49
- # find limited_layer
50
- @limited_layers || init_limited_layers
51
- @limited_layers[metric_type].absorb(child)
52
- else
53
- # we have space just add it
54
- set << child
55
- end
56
- end
57
-
58
- def each
59
- children.each do |_type, set|
60
- set.each do |child_layer|
61
- yield child_layer
62
- end
63
- end
64
-
65
- if @limited_layers
66
- @limited_layers.each do |_type, limited_layer|
67
- yield limited_layer
68
- end
69
- end
70
- end
71
-
72
- # hold off initializing this until we know we need it
73
- def init_limited_layers
74
- @limited_layers ||= Hash.new { |hash, key| hash[key] = LimitedLayer.new(key) }
75
- end
76
- end
77
- end