scout_apm 3.0.0.pre11 → 3.0.0.pre12
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.markdown +13 -4
- data/Guardfile +1 -0
- data/lib/scout_apm.rb +6 -0
- data/lib/scout_apm/agent/reporting.rb +2 -1
- data/lib/scout_apm/attribute_arranger.rb +14 -1
- data/lib/scout_apm/config.rb +12 -0
- data/lib/scout_apm/db_query_metric_set.rb +80 -0
- data/lib/scout_apm/db_query_metric_stats.rb +102 -0
- data/lib/scout_apm/fake_store.rb +6 -0
- data/lib/scout_apm/instant/middleware.rb +6 -1
- data/lib/scout_apm/instruments/active_record.rb +111 -0
- data/lib/scout_apm/layer.rb +4 -0
- data/lib/scout_apm/layer_converters/allocation_metric_converter.rb +5 -6
- data/lib/scout_apm/layer_converters/converter_base.rb +7 -19
- data/lib/scout_apm/layer_converters/database_converter.rb +81 -0
- data/lib/scout_apm/layer_converters/depth_first_walker.rb +22 -10
- data/lib/scout_apm/layer_converters/error_converter.rb +5 -7
- data/lib/scout_apm/layer_converters/find_layer_by_type.rb +34 -0
- data/lib/scout_apm/layer_converters/histograms.rb +14 -0
- data/lib/scout_apm/layer_converters/job_converter.rb +35 -49
- data/lib/scout_apm/layer_converters/metric_converter.rb +16 -18
- data/lib/scout_apm/layer_converters/request_queue_time_converter.rb +10 -12
- data/lib/scout_apm/layer_converters/slow_job_converter.rb +33 -35
- data/lib/scout_apm/layer_converters/slow_request_converter.rb +22 -18
- data/lib/scout_apm/limited_layer.rb +4 -0
- data/lib/scout_apm/metric_meta.rb +0 -5
- data/lib/scout_apm/metric_stats.rb +8 -1
- data/lib/scout_apm/serializers/db_query_serializer_to_json.rb +15 -0
- data/lib/scout_apm/serializers/payload_serializer.rb +4 -3
- data/lib/scout_apm/serializers/payload_serializer_to_json.rb +5 -2
- data/lib/scout_apm/slow_job_policy.rb +1 -10
- data/lib/scout_apm/slow_request_policy.rb +1 -10
- data/lib/scout_apm/store.rb +41 -22
- data/lib/scout_apm/tracked_request.rb +28 -40
- data/lib/scout_apm/utils/active_record_metric_name.rb +8 -4
- data/lib/scout_apm/version.rb +1 -1
- data/test/unit/db_query_metric_set_test.rb +56 -0
- data/test/unit/db_query_metric_stats_test.rb +113 -0
- data/test/unit/fake_store_test.rb +10 -0
- data/test/unit/layer_converters/depth_first_walker_test.rb +66 -0
- data/test/unit/layer_converters/metric_converter_test.rb +22 -0
- data/test/unit/layer_converters/stubs.rb +33 -0
- data/test/unit/serializers/payload_serializer_test.rb +3 -12
- data/test/unit/store_test.rb +4 -4
- data/test/unit/utils/active_record_metric_name_test.rb +8 -0
- metadata +20 -2
@@ -4,38 +4,36 @@ module ScoutApm
|
|
4
4
|
|
5
5
|
HEADERS = %w(X-Queue-Start X-Request-Start X-QUEUE-START X-REQUEST-START x-queue-start x-request-start)
|
6
6
|
|
7
|
-
|
8
|
-
|
9
|
-
super(request)
|
10
|
-
@headers = request.headers
|
7
|
+
def headers
|
8
|
+
request.headers
|
11
9
|
end
|
12
10
|
|
13
|
-
def
|
14
|
-
return
|
11
|
+
def record!
|
12
|
+
return unless request.web?
|
13
|
+
|
14
|
+
return unless headers
|
15
15
|
|
16
16
|
raw_start = locate_timestamp
|
17
|
-
return
|
17
|
+
return unless raw_start
|
18
18
|
|
19
19
|
parsed_start = parse(raw_start)
|
20
|
-
return
|
20
|
+
return unless parsed_start
|
21
21
|
|
22
22
|
request_start = root_layer.start_time
|
23
23
|
queue_time = (request_start - parsed_start).to_f
|
24
24
|
|
25
25
|
# If we end up with a negative value, just bail out and don't report anything
|
26
|
-
return
|
26
|
+
return if queue_time < 0
|
27
27
|
|
28
28
|
meta = MetricMeta.new("QueueTime/Request", {:scope => scope_layer.legacy_metric_name})
|
29
29
|
stat = MetricStats.new(true)
|
30
30
|
stat.update!(queue_time)
|
31
31
|
|
32
|
-
{ meta => stat }
|
32
|
+
@store.track!({ meta => stat })
|
33
33
|
end
|
34
34
|
|
35
35
|
private
|
36
36
|
|
37
|
-
attr_reader :headers
|
38
|
-
|
39
37
|
# Looks through the possible headers with this data, and extracts the raw
|
40
38
|
# value of the header
|
41
39
|
# Returns nil if not found
|
@@ -1,31 +1,33 @@
|
|
1
|
+
# Uses a different workflow than normal metrics. We ignore the shared walk of
|
2
|
+
# the layer tree, and instead wait until we're sure we even want to do any
|
3
|
+
# work. Only then do we go realize all the SlowJobRecord & metrics associated.
|
4
|
+
#
|
1
5
|
module ScoutApm
|
2
6
|
module LayerConverters
|
3
7
|
class SlowJobConverter < ConverterBase
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
else
|
11
|
-
-1
|
12
|
-
end
|
13
|
-
|
14
|
-
setup_subscopable_callbacks
|
15
|
-
end
|
8
|
+
###################
|
9
|
+
# Converter API #
|
10
|
+
###################
|
11
|
+
def record!
|
12
|
+
return nil unless request.job?
|
13
|
+
@points = ScoutApm::Agent.instance.slow_job_policy.score(request)
|
16
14
|
|
17
|
-
|
18
|
-
|
15
|
+
# Let the store know we're here, and if it wants our data, it will call
|
16
|
+
# back into #call
|
17
|
+
@store.track_slow_job!(self)
|
19
18
|
end
|
20
19
|
|
21
|
-
|
22
|
-
|
23
|
-
|
20
|
+
#####################
|
21
|
+
# ScoreItemSet API #
|
22
|
+
#####################
|
23
|
+
def name; request.unique_name; end
|
24
|
+
def score; @points; end
|
24
25
|
|
26
|
+
# Called by the set to force this to actually be created.
|
25
27
|
def call
|
26
28
|
return nil unless request.job?
|
27
|
-
return nil unless
|
28
|
-
return nil unless
|
29
|
+
return nil unless layer_finder.queue
|
30
|
+
return nil unless layer_finder.job
|
29
31
|
|
30
32
|
ScoutApm::Agent.instance.slow_job_policy.stored!(request)
|
31
33
|
|
@@ -54,26 +56,15 @@ module ScoutApm
|
|
54
56
|
)
|
55
57
|
end
|
56
58
|
|
57
|
-
def queue_layer
|
58
|
-
@queue_layer ||= find_first_layer_of_type("Queue")
|
59
|
-
end
|
60
|
-
|
61
|
-
def job_layer
|
62
|
-
@job_layer ||= find_first_layer_of_type("Job")
|
63
|
-
end
|
64
|
-
|
65
|
-
|
66
|
-
# The queue_layer is useful to capture for other reasons, but doesn't
|
67
|
-
# create a MetricMeta/Stat of its own
|
68
|
-
def skip_layer?(layer)
|
69
|
-
super(layer) || layer == queue_layer
|
70
|
-
end
|
71
|
-
|
72
59
|
def create_metrics
|
60
|
+
# Create a new walker, and wire up the subscope stuff
|
61
|
+
walker = LayerConverters::DepthFirstWalker.new(self.root_layer)
|
62
|
+
register_hooks(walker)
|
63
|
+
|
73
64
|
metric_hash = Hash.new
|
74
65
|
allocation_metric_hash = Hash.new
|
75
66
|
|
76
|
-
walker.
|
67
|
+
walker.on do |layer|
|
77
68
|
next if skip_layer?(layer)
|
78
69
|
|
79
70
|
debug_scoutprof(layer)
|
@@ -82,11 +73,18 @@ module ScoutApm
|
|
82
73
|
store_aggregate_metric(layer, metric_hash, allocation_metric_hash)
|
83
74
|
end
|
84
75
|
|
76
|
+
# And now run through the walk we just defined
|
77
|
+
walker.walk
|
78
|
+
|
85
79
|
metric_hash = attach_backtraces(metric_hash)
|
86
80
|
allocation_metric_hash = attach_backtraces(allocation_metric_hash)
|
87
81
|
|
88
82
|
[metric_hash, allocation_metric_hash]
|
89
83
|
end
|
84
|
+
|
85
|
+
def skip_layer?(layer); super(layer) || layer == queue_layer; end
|
86
|
+
def queue_layer; layer_finder.queue; end
|
87
|
+
def job_layer; layer_finder.job; end
|
90
88
|
end
|
91
89
|
end
|
92
90
|
end
|
@@ -1,26 +1,23 @@
|
|
1
1
|
module ScoutApm
|
2
2
|
module LayerConverters
|
3
3
|
class SlowRequestConverter < ConverterBase
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
else
|
11
|
-
-1
|
12
|
-
end
|
4
|
+
###################
|
5
|
+
# Converter API #
|
6
|
+
###################
|
7
|
+
def record!
|
8
|
+
return nil unless request.web?
|
9
|
+
@points = ScoutApm::Agent.instance.slow_request_policy.score(request)
|
13
10
|
|
14
|
-
|
11
|
+
# Let the store know we're here, and if it wants our data, it will call
|
12
|
+
# back into #call
|
13
|
+
@store.track_slow_transaction!(self)
|
15
14
|
end
|
16
15
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
def score
|
22
|
-
@points
|
23
|
-
end
|
16
|
+
#####################
|
17
|
+
# ScoreItemSet API #
|
18
|
+
#####################
|
19
|
+
def name; request.unique_name; end
|
20
|
+
def score; @points; end
|
24
21
|
|
25
22
|
# Unconditionally attempts to convert this into a SlowTransaction object.
|
26
23
|
# Can return nil if the request didn't have any scope_layer.
|
@@ -61,10 +58,14 @@ module ScoutApm
|
|
61
58
|
#
|
62
59
|
# This returns a 2-element of Metric Hashes (the first element is timing metrics, the second element is allocation metrics)
|
63
60
|
def create_metrics
|
61
|
+
# Create a new walker, and wire up the subscope stuff
|
62
|
+
walker = LayerConverters::DepthFirstWalker.new(self.root_layer)
|
63
|
+
register_hooks(walker)
|
64
|
+
|
64
65
|
metric_hash = Hash.new
|
65
66
|
allocation_metric_hash = Hash.new
|
66
67
|
|
67
|
-
walker.
|
68
|
+
walker.on do |layer|
|
68
69
|
next if skip_layer?(layer)
|
69
70
|
|
70
71
|
debug_scoutprof(layer)
|
@@ -73,6 +74,9 @@ module ScoutApm
|
|
73
74
|
store_aggregate_metric(layer, metric_hash, allocation_metric_hash)
|
74
75
|
end
|
75
76
|
|
77
|
+
# And now run through the walk we just defined
|
78
|
+
walker.walk
|
79
|
+
|
76
80
|
metric_hash = attach_backtraces(metric_hash)
|
77
81
|
allocation_metric_hash = attach_backtraces(allocation_metric_hash)
|
78
82
|
|
@@ -66,6 +66,10 @@ module ScoutApm
|
|
66
66
|
"<LimitedLayer type=#{type} count=#{count}>"
|
67
67
|
end
|
68
68
|
|
69
|
+
def limited?
|
70
|
+
true
|
71
|
+
end
|
72
|
+
|
69
73
|
######################################################
|
70
74
|
# Stub out some methods with static default values #
|
71
75
|
######################################################
|
@@ -33,11 +33,6 @@ class MetricMeta
|
|
33
33
|
!!(metric_name =~ /\A(Controller|Job)\//)
|
34
34
|
end
|
35
35
|
|
36
|
-
# To avoid conflicts with different JSON libaries
|
37
|
-
def to_json(*a)
|
38
|
-
%Q[{"metric_id":#{metric_id || 'null'},"metric_name":#{metric_name.to_json},"scope":#{scope.to_json || 'null'}}]
|
39
|
-
end
|
40
|
-
|
41
36
|
def ==(o)
|
42
37
|
self.eql?(o)
|
43
38
|
end
|
@@ -58,7 +58,14 @@ class MetricStats
|
|
58
58
|
end
|
59
59
|
|
60
60
|
def as_json
|
61
|
-
json_attributes = [
|
61
|
+
json_attributes = [
|
62
|
+
:call_count,
|
63
|
+
:max_call_time,
|
64
|
+
:min_call_time,
|
65
|
+
:total_call_time,
|
66
|
+
:total_exclusive_time,
|
67
|
+
:traces,
|
68
|
+
]
|
62
69
|
ScoutApm::AttributeArranger.call(self, json_attributes)
|
63
70
|
end
|
64
71
|
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module ScoutApm
|
2
|
+
module Serializers
|
3
|
+
class DbQuerySerializerToJson
|
4
|
+
attr_reader :db_query_metrics
|
5
|
+
|
6
|
+
def initialize(db_query_metrics)
|
7
|
+
@db_query_metrics = db_query_metrics
|
8
|
+
end
|
9
|
+
|
10
|
+
def as_json
|
11
|
+
db_query_metrics.map{|metric| metric.as_json }
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -2,9 +2,9 @@
|
|
2
2
|
module ScoutApm
|
3
3
|
module Serializers
|
4
4
|
class PayloadSerializer
|
5
|
-
def self.serialize(metadata, metrics, slow_transactions, jobs, slow_jobs, histograms)
|
5
|
+
def self.serialize(metadata, metrics, slow_transactions, jobs, slow_jobs, histograms, db_query_metrics)
|
6
6
|
if ScoutApm::Agent.instance.config.value("report_format") == 'json'
|
7
|
-
ScoutApm::Serializers::PayloadSerializerToJson.serialize(metadata, metrics, slow_transactions, jobs, slow_jobs, histograms)
|
7
|
+
ScoutApm::Serializers::PayloadSerializerToJson.serialize(metadata, metrics, slow_transactions, jobs, slow_jobs, histograms, db_query_metrics)
|
8
8
|
else
|
9
9
|
metadata = metadata.dup
|
10
10
|
metadata.default = nil
|
@@ -21,7 +21,8 @@ module ScoutApm
|
|
21
21
|
# array, use this to maintain compatibility with json
|
22
22
|
# payloads. At this point, the marshal code branch is
|
23
23
|
# very rarely used anyway.
|
24
|
-
:histograms => HistogramsSerializerToJson.new(histograms).as_json
|
24
|
+
:histograms => HistogramsSerializerToJson.new(histograms).as_json,
|
25
|
+
:db_query_metrics => db_query_metrics)
|
25
26
|
end
|
26
27
|
end
|
27
28
|
|
@@ -2,7 +2,7 @@ module ScoutApm
|
|
2
2
|
module Serializers
|
3
3
|
module PayloadSerializerToJson
|
4
4
|
class << self
|
5
|
-
def serialize(metadata, metrics, slow_transactions, jobs, slow_jobs, histograms)
|
5
|
+
def serialize(metadata, metrics, slow_transactions, jobs, slow_jobs, histograms, db_query_metrics)
|
6
6
|
metadata.merge!({:payload_version => 2})
|
7
7
|
|
8
8
|
jsonify_hash({:metadata => metadata,
|
@@ -11,7 +11,10 @@ module ScoutApm
|
|
11
11
|
:jobs => JobsSerializerToJson.new(jobs).as_json,
|
12
12
|
:slow_jobs => SlowJobsSerializerToJson.new(slow_jobs).as_json,
|
13
13
|
:histograms => HistogramsSerializerToJson.new(histograms).as_json,
|
14
|
-
|
14
|
+
:db_metrics => {
|
15
|
+
:query => DbQuerySerializerToJson.new(db_query_metrics).as_json,
|
16
|
+
},
|
17
|
+
})
|
15
18
|
end
|
16
19
|
|
17
20
|
# For the old style of metric serializing.
|
@@ -31,7 +31,7 @@ module ScoutApm
|
|
31
31
|
end
|
32
32
|
|
33
33
|
def stored!(request)
|
34
|
-
last_seen[
|
34
|
+
last_seen[request.unique_name] = Time.now
|
35
35
|
end
|
36
36
|
|
37
37
|
# Determine if this job trace should be fully analyzed by scoring it
|
@@ -61,15 +61,6 @@ module ScoutApm
|
|
61
61
|
|
62
62
|
private
|
63
63
|
|
64
|
-
def unique_name_for(request)
|
65
|
-
scope_layer = LayerConverters::ConverterBase.new(request).scope_layer
|
66
|
-
if scope_layer
|
67
|
-
scope_layer.legacy_metric_name
|
68
|
-
else
|
69
|
-
:unknown
|
70
|
-
end
|
71
|
-
end
|
72
|
-
|
73
64
|
# Time in seconds
|
74
65
|
# Logarithm keeps huge times from swamping the other metrics.
|
75
66
|
# 1+ is necessary to keep the log function in positive territory.
|
@@ -31,7 +31,7 @@ module ScoutApm
|
|
31
31
|
end
|
32
32
|
|
33
33
|
def stored!(request)
|
34
|
-
last_seen[
|
34
|
+
last_seen[request.unique_name] = Time.now
|
35
35
|
end
|
36
36
|
|
37
37
|
# Determine if this request trace should be fully analyzed by scoring it
|
@@ -61,15 +61,6 @@ module ScoutApm
|
|
61
61
|
|
62
62
|
private
|
63
63
|
|
64
|
-
def unique_name_for(request)
|
65
|
-
scope_layer = LayerConverters::ConverterBase.new(request).scope_layer
|
66
|
-
if scope_layer
|
67
|
-
scope_layer.legacy_metric_name
|
68
|
-
else
|
69
|
-
:unknown
|
70
|
-
end
|
71
|
-
end
|
72
|
-
|
73
64
|
# Time in seconds
|
74
65
|
# Logarithm keeps huge times from swamping the other metrics.
|
75
66
|
# 1+ is necessary to keep the log function in positive territory.
|
data/lib/scout_apm/store.rb
CHANGED
@@ -3,12 +3,6 @@
|
|
3
3
|
# the layaway file for cross-process aggregation.
|
4
4
|
module ScoutApm
|
5
5
|
class Store
|
6
|
-
# A hash of reporting periods. { StoreReportingPeriodTimestamp => StoreReportingPeriod }
|
7
|
-
attr_reader :reporting_periods
|
8
|
-
|
9
|
-
# Used to pull metrics into each reporting period, as that reporting period is finished.
|
10
|
-
attr_reader :samplers
|
11
|
-
|
12
6
|
def initialize
|
13
7
|
@mutex = Mutex.new
|
14
8
|
@reporting_periods = Hash.new { |h,k| h[k] = StoreReportingPeriod.new(k) }
|
@@ -20,32 +14,41 @@ module ScoutApm
|
|
20
14
|
end
|
21
15
|
|
22
16
|
def current_period
|
23
|
-
reporting_periods[current_timestamp]
|
17
|
+
@reporting_periods[current_timestamp]
|
24
18
|
end
|
19
|
+
private :current_period
|
20
|
+
|
21
|
+
def find_period(timestamp = nil)
|
22
|
+
if timestamp
|
23
|
+
@reporting_periods[timestamp]
|
24
|
+
else
|
25
|
+
current_period
|
26
|
+
end
|
27
|
+
end
|
28
|
+
private :find_period
|
25
29
|
|
26
30
|
# Save newly collected metrics
|
27
31
|
def track!(metrics, options={})
|
28
32
|
@mutex.synchronize {
|
29
|
-
period =
|
30
|
-
@reporting_periods[options[:timestamp]]
|
31
|
-
else
|
32
|
-
current_period
|
33
|
-
end
|
33
|
+
period = find_period(options[:timestamp])
|
34
34
|
period.absorb_metrics!(metrics)
|
35
35
|
}
|
36
36
|
end
|
37
37
|
|
38
38
|
def track_histograms!(histograms, options={})
|
39
39
|
@mutex.synchronize {
|
40
|
-
period =
|
41
|
-
@reporting_periods[options[:timestamp]]
|
42
|
-
else
|
43
|
-
current_period
|
44
|
-
end
|
40
|
+
period = find_period(options[:timestamp])
|
45
41
|
period.merge_histograms!(histograms)
|
46
42
|
}
|
47
43
|
end
|
48
44
|
|
45
|
+
def track_db_query_metrics!(db_query_metric_set, options={})
|
46
|
+
@mutex.synchronize {
|
47
|
+
period = find_period(options[:timestamp])
|
48
|
+
period.merge_db_query_metrics!(db_query_metric_set)
|
49
|
+
}
|
50
|
+
end
|
51
|
+
|
49
52
|
def track_one!(type, name, value, options={})
|
50
53
|
meta = MetricMeta.new("#{type}/#{name}")
|
51
54
|
stat = MetricStats.new(false)
|
@@ -83,7 +86,7 @@ module ScoutApm
|
|
83
86
|
def write_to_layaway(layaway, force=false)
|
84
87
|
ScoutApm::Agent.instance.logger.debug("Writing to layaway#{" (Forced)" if force}")
|
85
88
|
|
86
|
-
reporting_periods.select { |time, rp| force || (time.timestamp < current_timestamp.timestamp) }.
|
89
|
+
@reporting_periods.select { |time, rp| force || (time.timestamp < current_timestamp.timestamp) }.
|
87
90
|
each { |time, rp| collect_samplers(rp) }.
|
88
91
|
each { |time, rp| write_reporting_period(layaway, time, rp) }
|
89
92
|
end
|
@@ -95,10 +98,11 @@ module ScoutApm
|
|
95
98
|
rescue => e
|
96
99
|
ScoutApm::Agent.instance.logger.warn("Failed writing data to layaway file: #{e.message} / #{e.backtrace}")
|
97
100
|
ensure
|
98
|
-
ScoutApm::Agent.instance.logger.debug("Before delete, reporting periods length: #{reporting_periods.size}")
|
99
|
-
deleted_items = reporting_periods.delete(time)
|
100
|
-
ScoutApm::Agent.instance.logger.debug("After delete, reporting periods length: #{reporting_periods.size}. Did delete #{deleted_items}")
|
101
|
+
ScoutApm::Agent.instance.logger.debug("Before delete, reporting periods length: #{@reporting_periods.size}")
|
102
|
+
deleted_items = @reporting_periods.delete(time)
|
103
|
+
ScoutApm::Agent.instance.logger.debug("After delete, reporting periods length: #{@reporting_periods.size}. Did delete #{deleted_items}")
|
101
104
|
end
|
105
|
+
private :write_reporting_period
|
102
106
|
|
103
107
|
######################################
|
104
108
|
# Sampler support
|
@@ -116,6 +120,7 @@ module ScoutApm
|
|
116
120
|
end
|
117
121
|
end
|
118
122
|
end
|
123
|
+
private :collect_samplers
|
119
124
|
end
|
120
125
|
|
121
126
|
# A timestamp, normalized to the beginning of a minute. Used as a hash key to
|
@@ -184,6 +189,8 @@ module ScoutApm
|
|
184
189
|
|
185
190
|
attr_reader :metric_set
|
186
191
|
|
192
|
+
attr_reader :db_query_metric_set
|
193
|
+
|
187
194
|
def initialize(timestamp)
|
188
195
|
@timestamp = timestamp
|
189
196
|
|
@@ -193,6 +200,8 @@ module ScoutApm
|
|
193
200
|
@histograms = []
|
194
201
|
|
195
202
|
@metric_set = MetricSet.new
|
203
|
+
@db_query_metric_set = DbQueryMetricSet.new
|
204
|
+
|
196
205
|
@jobs = Hash.new
|
197
206
|
end
|
198
207
|
|
@@ -203,7 +212,8 @@ module ScoutApm
|
|
203
212
|
merge_slow_transactions!(other.slow_transactions_payload).
|
204
213
|
merge_jobs!(other.jobs).
|
205
214
|
merge_slow_jobs!(other.slow_jobs_payload).
|
206
|
-
merge_histograms!(other.histograms)
|
215
|
+
merge_histograms!(other.histograms).
|
216
|
+
merge_db_query_metrics!(other.db_query_metric_set)
|
207
217
|
self
|
208
218
|
end
|
209
219
|
|
@@ -224,6 +234,11 @@ module ScoutApm
|
|
224
234
|
self
|
225
235
|
end
|
226
236
|
|
237
|
+
def merge_db_query_metrics!(other_metric_set)
|
238
|
+
db_query_metric_set.combine!(other_metric_set)
|
239
|
+
self
|
240
|
+
end
|
241
|
+
|
227
242
|
def merge_slow_transactions!(new_transactions)
|
228
243
|
Array(new_transactions).each do |one_transaction|
|
229
244
|
request_traces << one_transaction
|
@@ -282,6 +297,10 @@ module ScoutApm
|
|
282
297
|
job_traces.to_a
|
283
298
|
end
|
284
299
|
|
300
|
+
def db_query_metrics_payload
|
301
|
+
db_query_metric_set.metrics_to_report
|
302
|
+
end
|
303
|
+
|
285
304
|
#################################
|
286
305
|
# Debug Helpers
|
287
306
|
#################################
|