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.
- checksums.yaml +4 -4
- data/.gitignore +1 -1
- data/CHANGELOG.markdown +2 -161
- data/Rakefile +2 -2
- data/ext/allocations/allocations.c +0 -6
- data/ext/allocations/extconf.rb +0 -1
- data/ext/stacks/extconf.rb +33 -0
- data/ext/stacks/scout_atomics.h +86 -0
- data/ext/stacks/stacks.c +744 -0
- data/lib/scout_apm.rb +16 -24
- data/lib/scout_apm/agent.rb +38 -93
- data/lib/scout_apm/agent/logging.rb +1 -6
- data/lib/scout_apm/agent/reporting.rb +6 -8
- data/lib/scout_apm/app_server_load.rb +10 -21
- data/lib/scout_apm/attribute_arranger.rb +2 -0
- data/lib/scout_apm/background_job_integrations/delayed_job.rb +1 -71
- data/lib/scout_apm/background_job_integrations/sidekiq.rb +27 -66
- data/lib/scout_apm/background_worker.rb +15 -19
- data/lib/scout_apm/capacity.rb +57 -0
- data/lib/scout_apm/config.rb +29 -135
- data/lib/scout_apm/context.rb +5 -9
- 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 +15 -22
- data/lib/scout_apm/histogram.rb +2 -11
- data/lib/scout_apm/instant/assets/xmlhttp_instrumentation.html +2 -2
- data/lib/scout_apm/instant/middleware.rb +57 -198
- data/lib/scout_apm/instruments/action_controller_rails_2.rb +2 -1
- data/lib/scout_apm/instruments/action_controller_rails_3_rails4.rb +59 -90
- data/lib/scout_apm/instruments/active_record.rb +5 -7
- data/lib/scout_apm/instruments/delayed_job.rb +57 -0
- data/lib/scout_apm/instruments/grape.rb +3 -4
- data/lib/scout_apm/instruments/middleware_detailed.rb +6 -4
- data/lib/scout_apm/instruments/middleware_summary.rb +1 -39
- data/lib/scout_apm/instruments/mongoid.rb +3 -24
- data/lib/scout_apm/instruments/net_http.rb +2 -7
- data/lib/scout_apm/instruments/percentile_sampler.rb +19 -36
- data/lib/scout_apm/instruments/process/process_cpu.rb +2 -3
- data/lib/scout_apm/instruments/process/process_memory.rb +3 -3
- data/lib/scout_apm/layaway.rb +33 -76
- data/lib/scout_apm/layer.rb +59 -16
- data/lib/scout_apm/layer_converters/converter_base.rb +0 -199
- data/lib/scout_apm/layer_converters/job_converter.rb +1 -1
- data/lib/scout_apm/layer_converters/metric_converter.rb +1 -1
- data/lib/scout_apm/layer_converters/slow_job_converter.rb +90 -15
- data/lib/scout_apm/layer_converters/slow_request_converter.rb +101 -13
- data/lib/scout_apm/metric_set.rb +1 -9
- data/lib/scout_apm/metric_stats.rb +8 -8
- data/lib/scout_apm/reporter.rb +15 -51
- data/lib/scout_apm/request_histograms.rb +0 -4
- data/lib/scout_apm/request_manager.rb +1 -2
- data/lib/scout_apm/scored_item_set.rb +0 -7
- data/lib/scout_apm/serializers/deploy_serializer.rb +16 -0
- data/lib/scout_apm/serializers/payload_serializer.rb +3 -9
- data/lib/scout_apm/serializers/payload_serializer_to_json.rb +5 -2
- data/lib/scout_apm/serializers/slow_jobs_serializer_to_json.rb +1 -2
- data/lib/scout_apm/server_integrations/puma.rb +2 -5
- data/lib/scout_apm/slow_item_set.rb +80 -0
- data/lib/scout_apm/slow_job_record.rb +1 -6
- data/lib/scout_apm/slow_transaction.rb +2 -20
- data/lib/scout_apm/store.rb +12 -50
- data/lib/scout_apm/trace_compactor.rb +311 -0
- data/lib/scout_apm/tracked_request.rb +37 -128
- data/lib/scout_apm/utils/backtrace_parser.rb +5 -7
- data/lib/scout_apm/utils/fake_stacks.rb +83 -0
- data/lib/scout_apm/version.rb +1 -1
- data/scout_apm.gemspec +4 -6
- data/test/test_helper.rb +0 -56
- data/test/unit/config_test.rb +9 -60
- data/test/unit/histogram_test.rb +0 -14
- data/test/unit/layaway_test.rb +16 -31
- data/test/unit/serializers/payload_serializer_test.rb +105 -3
- data/test/unit/slow_item_set_test.rb +94 -0
- data/test/unit/slow_job_policy_test.rb +49 -0
- data/test/unit/slow_request_policy_test.rb +5 -4
- data/test/unit/utils/backtrace_parser_test.rb +0 -19
- data/tester.rb +53 -0
- metadata +29 -124
- data/.rubocop.yml +0 -8
- data/Guardfile +0 -42
- data/ext/rusage/README.md +0 -26
- data/ext/rusage/extconf.rb +0 -5
- data/ext/rusage/rusage.c +0 -52
- data/lib/scout_apm/background_job_integrations/resque.rb +0 -85
- data/lib/scout_apm/background_recorder.rb +0 -43
- data/lib/scout_apm/debug.rb +0 -37
- data/lib/scout_apm/git_revision.rb +0 -51
- data/lib/scout_apm/instruments/action_view.rb +0 -49
- data/lib/scout_apm/instruments/resque.rb +0 -40
- data/lib/scout_apm/layer_children_set.rb +0 -77
- data/lib/scout_apm/limited_layer.rb +0 -122
- data/lib/scout_apm/rack.rb +0 -26
- data/lib/scout_apm/remote/message.rb +0 -23
- 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 -58
- data/lib/scout_apm/serializers/histograms_serializer_to_json.rb +0 -21
- data/lib/scout_apm/synchronous_recorder.rb +0 -26
- data/lib/scout_apm/utils/gzip_helper.rb +0 -24
- data/lib/scout_apm/utils/numbers.rb +0 -14
- data/lib/scout_apm/utils/scm.rb +0 -14
- data/test/unit/background_job_integrations/sidekiq_test.rb +0 -104
- data/test/unit/context_test.rb +0 -30
- data/test/unit/git_revision_test.rb +0 -15
- data/test/unit/instruments/net_http_test.rb +0 -21
- data/test/unit/instruments/percentile_sampler_test.rb +0 -137
- data/test/unit/layer_children_set_test.rb +0 -88
- data/test/unit/limited_layer_test.rb +0 -53
- 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/store_test.rb +0 -89
- data/test/unit/test_tracked_request.rb +0 -87
- data/test/unit/utils/numbers_test.rb +0 -15
- 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.
|
data/ext/rusage/extconf.rb
DELETED
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
|
data/lib/scout_apm/debug.rb
DELETED
@@ -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
|