scout_apm 3.0.0.pre11 → 3.0.0.pre12
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.
- 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
|
#################################
|