scout_apm 2.2.0.pre3 → 2.3.0.pre
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 +147 -2
- data/Guardfile +43 -0
- data/Rakefile +2 -2
- data/ext/allocations/allocations.c +6 -0
- data/ext/allocations/extconf.rb +1 -0
- data/ext/rusage/README.md +26 -0
- data/ext/rusage/extconf.rb +5 -0
- data/ext/rusage/rusage.c +52 -0
- data/lib/scout_apm.rb +28 -15
- data/lib/scout_apm/agent.rb +89 -37
- data/lib/scout_apm/agent/logging.rb +6 -1
- data/lib/scout_apm/agent/reporting.rb +9 -6
- data/lib/scout_apm/app_server_load.rb +21 -10
- data/lib/scout_apm/attribute_arranger.rb +6 -3
- data/lib/scout_apm/background_job_integrations/delayed_job.rb +71 -1
- data/lib/scout_apm/background_job_integrations/resque.rb +85 -0
- data/lib/scout_apm/background_job_integrations/sidekiq.rb +22 -20
- data/lib/scout_apm/background_recorder.rb +43 -0
- data/lib/scout_apm/background_worker.rb +19 -15
- data/lib/scout_apm/config.rb +138 -28
- 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/debug.rb +37 -0
- data/lib/scout_apm/environment.rb +22 -15
- data/lib/scout_apm/git_revision.rb +51 -0
- data/lib/scout_apm/histogram.rb +11 -2
- data/lib/scout_apm/instant/assets/xmlhttp_instrumentation.html +2 -2
- data/lib/scout_apm/instant/middleware.rb +196 -54
- data/lib/scout_apm/instruments/action_controller_rails_3_rails4.rb +89 -68
- data/lib/scout_apm/instruments/action_view.rb +49 -0
- data/lib/scout_apm/instruments/active_record.rb +127 -3
- data/lib/scout_apm/instruments/grape.rb +4 -3
- data/lib/scout_apm/instruments/middleware_detailed.rb +4 -6
- data/lib/scout_apm/instruments/mongoid.rb +24 -3
- data/lib/scout_apm/instruments/net_http.rb +7 -2
- data/lib/scout_apm/instruments/percentile_sampler.rb +36 -19
- data/lib/scout_apm/instruments/process/process_cpu.rb +3 -2
- data/lib/scout_apm/instruments/process/process_memory.rb +3 -3
- data/lib/scout_apm/instruments/resque.rb +40 -0
- data/lib/scout_apm/layaway.rb +67 -28
- data/lib/scout_apm/layer.rb +19 -59
- data/lib/scout_apm/layer_children_set.rb +77 -0
- data/lib/scout_apm/layer_converters/allocation_metric_converter.rb +5 -6
- data/lib/scout_apm/layer_converters/converter_base.rb +201 -14
- data/lib/scout_apm/layer_converters/database_converter.rb +55 -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 +36 -50
- data/lib/scout_apm/layer_converters/metric_converter.rb +17 -19
- data/lib/scout_apm/layer_converters/request_queue_time_converter.rb +10 -12
- data/lib/scout_apm/layer_converters/slow_job_converter.rb +41 -115
- data/lib/scout_apm/layer_converters/slow_request_converter.rb +33 -117
- data/lib/scout_apm/limited_layer.rb +126 -0
- data/lib/scout_apm/metric_meta.rb +0 -5
- data/lib/scout_apm/metric_set.rb +9 -1
- data/lib/scout_apm/metric_stats.rb +7 -8
- data/lib/scout_apm/rack.rb +26 -0
- data/lib/scout_apm/remote/message.rb +23 -0
- data/lib/scout_apm/remote/recorder.rb +57 -0
- data/lib/scout_apm/remote/router.rb +49 -0
- data/lib/scout_apm/remote/server.rb +58 -0
- data/lib/scout_apm/reporter.rb +51 -15
- data/lib/scout_apm/request_histograms.rb +4 -0
- data/lib/scout_apm/request_manager.rb +2 -1
- data/lib/scout_apm/scored_item_set.rb +7 -0
- data/lib/scout_apm/serializers/db_query_serializer_to_json.rb +15 -0
- data/lib/scout_apm/serializers/histograms_serializer_to_json.rb +21 -0
- data/lib/scout_apm/serializers/payload_serializer.rb +10 -3
- data/lib/scout_apm/serializers/payload_serializer_to_json.rb +6 -6
- data/lib/scout_apm/serializers/slow_jobs_serializer_to_json.rb +2 -1
- data/lib/scout_apm/server_integrations/puma.rb +5 -2
- data/lib/scout_apm/slow_job_policy.rb +1 -10
- data/lib/scout_apm/slow_job_record.rb +6 -1
- data/lib/scout_apm/slow_request_policy.rb +1 -10
- data/lib/scout_apm/slow_transaction.rb +20 -2
- data/lib/scout_apm/store.rb +66 -12
- data/lib/scout_apm/synchronous_recorder.rb +26 -0
- data/lib/scout_apm/tracked_request.rb +136 -71
- data/lib/scout_apm/utils/active_record_metric_name.rb +8 -4
- data/lib/scout_apm/utils/backtrace_parser.rb +3 -3
- data/lib/scout_apm/utils/gzip_helper.rb +24 -0
- data/lib/scout_apm/utils/numbers.rb +14 -0
- data/lib/scout_apm/utils/scm.rb +14 -0
- data/lib/scout_apm/version.rb +1 -1
- data/scout_apm.gemspec +5 -4
- data/test/test_helper.rb +18 -0
- data/test/unit/config_test.rb +59 -8
- 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/git_revision_test.rb +15 -0
- data/test/unit/histogram_test.rb +14 -0
- data/test/unit/instruments/net_http_test.rb +21 -0
- data/test/unit/instruments/percentile_sampler_test.rb +137 -0
- data/test/unit/layaway_test.rb +20 -0
- data/test/unit/layer_children_set_test.rb +88 -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/limited_layer_test.rb +53 -0
- data/test/unit/remote/test_message.rb +13 -0
- data/test/unit/remote/test_router.rb +33 -0
- data/test/unit/remote/test_server.rb +15 -0
- data/test/unit/serializers/payload_serializer_test.rb +3 -12
- data/test/unit/store_test.rb +66 -0
- data/test/unit/test_tracked_request.rb +87 -0
- data/test/unit/utils/active_record_metric_name_test.rb +8 -0
- data/test/unit/utils/backtrace_parser_test.rb +5 -0
- data/test/unit/utils/numbers_test.rb +15 -0
- data/test/unit/utils/scm.rb +17 -0
- metadata +125 -30
- data/ext/stacks/extconf.rb +0 -37
- data/ext/stacks/scout_atomics.h +0 -86
- data/ext/stacks/stacks.c +0 -811
- data/lib/scout_apm/capacity.rb +0 -57
- data/lib/scout_apm/deploy_integrations/capistrano_2.cap +0 -12
- data/lib/scout_apm/deploy_integrations/capistrano_2.rb +0 -83
- data/lib/scout_apm/deploy_integrations/capistrano_3.cap +0 -12
- data/lib/scout_apm/deploy_integrations/capistrano_3.rb +0 -88
- data/lib/scout_apm/instruments/delayed_job.rb +0 -57
- data/lib/scout_apm/serializers/deploy_serializer.rb +0 -16
- data/lib/scout_apm/trace_compactor.rb +0 -312
- data/lib/scout_apm/utils/fake_stacks.rb +0 -87
- data/tester.rb +0 -53
@@ -1,31 +1,29 @@
|
|
1
1
|
module ScoutApm
|
2
2
|
module LayerConverters
|
3
3
|
class SlowRequestConverter < ConverterBase
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
@points =
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
4
|
+
###################
|
5
|
+
# Converter API #
|
6
|
+
###################
|
7
|
+
def record!
|
8
|
+
return nil unless request.web?
|
9
|
+
@points = ScoutApm::Agent.instance.slow_request_policy.score(request)
|
10
|
+
|
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)
|
14
14
|
end
|
15
15
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
def score
|
21
|
-
@points
|
22
|
-
end
|
16
|
+
#####################
|
17
|
+
# ScoreItemSet API #
|
18
|
+
#####################
|
19
|
+
def name; request.unique_name; end
|
20
|
+
def score; @points; end
|
23
21
|
|
24
22
|
# Unconditionally attempts to convert this into a SlowTransaction object.
|
25
23
|
# Can return nil if the request didn't have any scope_layer.
|
26
24
|
def call
|
27
|
-
|
28
|
-
return nil unless
|
25
|
+
return nil unless request.web?
|
26
|
+
return nil unless scope_layer
|
29
27
|
|
30
28
|
ScoutApm::Agent.instance.slow_request_policy.stored!(request)
|
31
29
|
|
@@ -35,12 +33,13 @@ module ScoutApm
|
|
35
33
|
uri = request.annotations[:uri] || ""
|
36
34
|
|
37
35
|
timing_metrics, allocation_metrics = create_metrics
|
36
|
+
|
38
37
|
unless ScoutApm::Instruments::Allocations::ENABLED
|
39
38
|
allocation_metrics = {}
|
40
39
|
end
|
41
40
|
|
42
41
|
SlowTransaction.new(uri,
|
43
|
-
|
42
|
+
scope_layer.legacy_metric_name,
|
44
43
|
root_layer.total_call_time,
|
45
44
|
timing_metrics,
|
46
45
|
allocation_metrics,
|
@@ -49,119 +48,36 @@ module ScoutApm
|
|
49
48
|
[], # stackprof, now unused.
|
50
49
|
mem_delta,
|
51
50
|
root_layer.total_allocations,
|
52
|
-
@points
|
53
|
-
|
54
|
-
|
55
|
-
# Iterates over the TrackedRequest's MetricMetas that have backtraces and attaches each to correct MetricMeta in the Metric Hash.
|
56
|
-
def attach_backtraces(metric_hash)
|
57
|
-
@backtraces.each do |meta_with_backtrace|
|
58
|
-
metric_hash.keys.find { |k| k == meta_with_backtrace }.backtrace = meta_with_backtrace.backtrace
|
59
|
-
end
|
60
|
-
metric_hash
|
51
|
+
@points,
|
52
|
+
limited?)
|
61
53
|
end
|
62
54
|
|
63
55
|
# Full metrics from this request. These get stored permanently in a SlowTransaction.
|
64
56
|
# Some merging of metrics will happen here, so if a request calls the same
|
65
57
|
# ActiveRecord or View repeatedly, it'll get merged.
|
66
|
-
#
|
58
|
+
#
|
67
59
|
# This returns a 2-element of Metric Hashes (the first element is timing metrics, the second element is allocation metrics)
|
68
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
|
+
|
69
65
|
metric_hash = Hash.new
|
70
66
|
allocation_metric_hash = Hash.new
|
71
67
|
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
walker.before do |layer|
|
78
|
-
if layer.subscopable?
|
79
|
-
subscope_layers.push(layer)
|
80
|
-
end
|
81
|
-
end
|
82
|
-
|
83
|
-
walker.after do |layer|
|
84
|
-
if layer.subscopable?
|
85
|
-
subscope_layers.pop
|
86
|
-
end
|
68
|
+
walker.on do |layer|
|
69
|
+
next if skip_layer?(layer)
|
70
|
+
store_specific_metric(layer, metric_hash, allocation_metric_hash)
|
71
|
+
store_aggregate_metric(layer, metric_hash, allocation_metric_hash)
|
87
72
|
end
|
88
73
|
|
89
|
-
|
90
|
-
|
91
|
-
# want to make an entry for it. See ActiveRecord instrumentation for
|
92
|
-
# an example. We start capturing before we know if a query is cached
|
93
|
-
# or not, and want to skip any cached queries.
|
94
|
-
if layer.annotations[:ignorable]
|
95
|
-
next
|
96
|
-
end
|
97
|
-
|
98
|
-
meta_options = if subscope_layers.first && layer != subscope_layers.first # Don't scope under ourself.
|
99
|
-
subscope_name = subscope_layers.first.legacy_metric_name
|
100
|
-
{:scope => subscope_name}
|
101
|
-
elsif layer == scope_layer # We don't scope the controller under itself
|
102
|
-
{}
|
103
|
-
else
|
104
|
-
{:scope => scope_layer.legacy_metric_name}
|
105
|
-
end
|
106
|
-
|
107
|
-
# Specific Metric
|
108
|
-
meta_options.merge!(:desc => layer.desc.to_s) if layer.desc
|
109
|
-
meta = MetricMeta.new(layer.legacy_metric_name, meta_options)
|
110
|
-
meta.extra.merge!(layer.annotations)
|
111
|
-
if layer.backtrace
|
112
|
-
bt = ScoutApm::Utils::BacktraceParser.new(layer.backtrace).call
|
113
|
-
if bt.any? # we could walk thru the call stack and not find in-app code
|
114
|
-
meta.backtrace = bt
|
115
|
-
# Why not just call meta.backtrace and call it done? The walker
|
116
|
-
# could access a later later that generates the same MetricMeta
|
117
|
-
# but doesn't have a backtrace. This could be lost in the
|
118
|
-
# metric_hash if it is replaced by the new key.
|
119
|
-
@backtraces << meta
|
120
|
-
else
|
121
|
-
ScoutApm::Agent.instance.logger.debug { "Unable to capture an app-specific backtrace for #{meta.inspect}\n#{layer.backtrace}" }
|
122
|
-
end
|
123
|
-
end
|
124
|
-
metric_hash[meta] ||= MetricStats.new( meta_options.has_key?(:scope) )
|
125
|
-
allocation_metric_hash[meta] ||= MetricStats.new( meta_options.has_key?(:scope) )
|
126
|
-
# timing
|
127
|
-
stat = metric_hash[meta]
|
128
|
-
stat.update!(layer.total_call_time, layer.total_exclusive_time)
|
129
|
-
stat.add_traces(layer.traces.as_json)
|
130
|
-
|
131
|
-
# Debug logging for scoutprof traces
|
132
|
-
if ScoutApm::Agent.instance.config.value('profile')
|
133
|
-
if layer.type =~ %r{^(Controller|Queue|Job)$}.freeze
|
134
|
-
ScoutApm::Agent.instance.logger.debug do
|
135
|
-
traces_inspect = layer.traces.inspect
|
136
|
-
"****** Slow Request #{layer.type} Traces (#{layer.name}, tet: #{layer.total_exclusive_time}, tct: #{layer.total_call_time}), total raw traces: #{layer.traces.cube.total_count}, total clean traces: #{layer.traces.total_count}, skipped gc: #{layer.traces.skipped_in_gc}, skipped handler: #{layer.traces.skipped_in_handler}, skipped registered #{layer.traces.skipped_in_job_registered}, skipped not_running #{layer.traces.skipped_in_not_running}:\n#{traces_inspect}"
|
137
|
-
end
|
138
|
-
end
|
139
|
-
else
|
140
|
-
if layer.type =~ %r{^(Controller|Queue|Job)$}.freeze
|
141
|
-
ScoutApm::Agent.instance.logger.debug "****** Slow Request #{layer.type} Traces: Scoutprof is not enabled"
|
142
|
-
end
|
143
|
-
end
|
144
|
-
|
145
|
-
# allocations
|
146
|
-
stat = allocation_metric_hash[meta]
|
147
|
-
stat.update!(layer.total_allocations, layer.total_exclusive_allocations)
|
148
|
-
|
149
|
-
# Merged Metric (no specifics, just sum up by type)
|
150
|
-
meta = MetricMeta.new("#{layer.type}/all")
|
151
|
-
metric_hash[meta] ||= MetricStats.new(false)
|
152
|
-
allocation_metric_hash[meta] ||= MetricStats.new(false)
|
153
|
-
# timing
|
154
|
-
stat = metric_hash[meta]
|
155
|
-
stat.update!(layer.total_call_time, layer.total_exclusive_time)
|
156
|
-
# allocations
|
157
|
-
stat = allocation_metric_hash[meta]
|
158
|
-
stat.update!(layer.total_allocations, layer.total_exclusive_allocations)
|
159
|
-
end
|
74
|
+
# And now run through the walk we just defined
|
75
|
+
walker.walk
|
160
76
|
|
161
77
|
metric_hash = attach_backtraces(metric_hash)
|
162
78
|
allocation_metric_hash = attach_backtraces(allocation_metric_hash)
|
163
79
|
|
164
|
-
[metric_hash,allocation_metric_hash]
|
80
|
+
[metric_hash, allocation_metric_hash]
|
165
81
|
end
|
166
82
|
end
|
167
83
|
end
|
@@ -0,0 +1,126 @@
|
|
1
|
+
module ScoutApm
|
2
|
+
# A LimitedLayer is a lossy-compression approach to fall back on once we max out
|
3
|
+
# the number of detailed layer objects we store. See LayerChildrenSet for the
|
4
|
+
# logic on when that change over happens
|
5
|
+
#
|
6
|
+
# QUESTION: What do we do if we attempt to merge an item that has children?
|
7
|
+
class LimitedLayer
|
8
|
+
attr_reader :type
|
9
|
+
|
10
|
+
def initialize(type)
|
11
|
+
@type = type
|
12
|
+
|
13
|
+
@total_call_time = 0
|
14
|
+
@total_exclusive_time = 0
|
15
|
+
@total_allocations = 0
|
16
|
+
@total_exclusive_allocations = 0
|
17
|
+
@total_layers = 0
|
18
|
+
end
|
19
|
+
|
20
|
+
def absorb(layer)
|
21
|
+
@total_layers += 1
|
22
|
+
|
23
|
+
@total_call_time += layer.total_call_time
|
24
|
+
@total_exclusive_time += layer.total_exclusive_time
|
25
|
+
|
26
|
+
@total_allocations += layer.total_allocations
|
27
|
+
@total_exclusive_allocations += layer.total_exclusive_allocations
|
28
|
+
end
|
29
|
+
|
30
|
+
def total_call_time
|
31
|
+
@total_call_time
|
32
|
+
end
|
33
|
+
|
34
|
+
def total_exclusive_time
|
35
|
+
@total_exclusive_time
|
36
|
+
end
|
37
|
+
|
38
|
+
def total_allocations
|
39
|
+
@total_allocations
|
40
|
+
end
|
41
|
+
|
42
|
+
def total_exclusive_allocations
|
43
|
+
@total_exclusive_allocations
|
44
|
+
end
|
45
|
+
|
46
|
+
def count
|
47
|
+
@total_layers
|
48
|
+
end
|
49
|
+
|
50
|
+
# This is the old style name. This function is used for now, but should be
|
51
|
+
# removed, and the new type & name split should be enforced through the
|
52
|
+
# app.
|
53
|
+
def legacy_metric_name
|
54
|
+
"#{type}/Limited"
|
55
|
+
end
|
56
|
+
|
57
|
+
def children
|
58
|
+
Set.new
|
59
|
+
end
|
60
|
+
|
61
|
+
def annotations
|
62
|
+
nil
|
63
|
+
end
|
64
|
+
|
65
|
+
def to_s
|
66
|
+
"<LimitedLayer type=#{type} count=#{count}>"
|
67
|
+
end
|
68
|
+
|
69
|
+
def limited?
|
70
|
+
true
|
71
|
+
end
|
72
|
+
|
73
|
+
######################################################
|
74
|
+
# Stub out some methods with static default values #
|
75
|
+
######################################################
|
76
|
+
def subscopable?
|
77
|
+
false
|
78
|
+
end
|
79
|
+
|
80
|
+
def desc
|
81
|
+
nil
|
82
|
+
end
|
83
|
+
|
84
|
+
def backtrace
|
85
|
+
nil
|
86
|
+
end
|
87
|
+
|
88
|
+
|
89
|
+
#######################################################################
|
90
|
+
# Many methods don't make any sense on a limited layer. Raise errors #
|
91
|
+
# aggressively for now to detect mistaken calls #
|
92
|
+
#######################################################################
|
93
|
+
|
94
|
+
def add_child
|
95
|
+
raise "Should never call add_child on a limited_layer"
|
96
|
+
end
|
97
|
+
|
98
|
+
def record_stop_time!(*)
|
99
|
+
raise "Should never call record_stop_time! on a limited_layer"
|
100
|
+
end
|
101
|
+
|
102
|
+
def record_allocations!
|
103
|
+
raise "Should never call record_allocations! on a limited_layer"
|
104
|
+
end
|
105
|
+
|
106
|
+
def desc=(*)
|
107
|
+
raise "Should never call desc on a limited_layer"
|
108
|
+
end
|
109
|
+
|
110
|
+
def annotate_layer(*)
|
111
|
+
raise "Should never call annotate_layer on a limited_layer"
|
112
|
+
end
|
113
|
+
|
114
|
+
def subscopable!
|
115
|
+
raise "Should never call subscopable! on a limited_layer"
|
116
|
+
end
|
117
|
+
|
118
|
+
def capture_backtrace!
|
119
|
+
raise "Should never call capture_backtrace on a limited_layer"
|
120
|
+
end
|
121
|
+
|
122
|
+
def caller_array
|
123
|
+
raise "Should never call caller_array on a limited_layer"
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
@@ -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
|
data/lib/scout_apm/metric_set.rb
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
module ScoutApm
|
2
2
|
class MetricSet
|
3
|
-
# We can't aggregate
|
3
|
+
# We can't aggregate a handful of things like samplers (CPU, Memory), or
|
4
|
+
# Controller, and Percentiles so pass through these metrics directly
|
5
|
+
#
|
4
6
|
# TODO: Figure out a way to not have this duplicate what's in Samplers, and also on server's ingest
|
5
7
|
PASSTHROUGH_METRICS = ["CPU", "Memory", "Instance", "Controller", "SlowTransaction", "Percentile", "Job"]
|
6
8
|
|
@@ -49,5 +51,11 @@ module ScoutApm
|
|
49
51
|
@combine_in_progress = false
|
50
52
|
self
|
51
53
|
end
|
54
|
+
|
55
|
+
|
56
|
+
def eql?(other)
|
57
|
+
metrics == other.metrics
|
58
|
+
end
|
59
|
+
alias :== :eql?
|
52
60
|
end
|
53
61
|
end
|
@@ -9,7 +9,6 @@ class MetricStats
|
|
9
9
|
attr_accessor :sum_of_squares
|
10
10
|
attr_accessor :queue
|
11
11
|
attr_accessor :latency
|
12
|
-
attr_accessor :traces
|
13
12
|
|
14
13
|
def initialize(scoped = false)
|
15
14
|
@scoped = scoped
|
@@ -19,7 +18,6 @@ class MetricStats
|
|
19
18
|
self.min_call_time = 0.0
|
20
19
|
self.max_call_time = 0.0
|
21
20
|
self.sum_of_squares = 0.0
|
22
|
-
self.traces = []
|
23
21
|
end
|
24
22
|
|
25
23
|
# Note, that you must include exclusive_time if you wish to set
|
@@ -41,10 +39,6 @@ class MetricStats
|
|
41
39
|
self
|
42
40
|
end
|
43
41
|
|
44
|
-
def add_traces(traces)
|
45
|
-
self.traces += Array(traces)
|
46
|
-
end
|
47
|
-
|
48
42
|
# combines data from another MetricStats object
|
49
43
|
def combine!(other)
|
50
44
|
self.call_count += other.call_count
|
@@ -53,12 +47,17 @@ class MetricStats
|
|
53
47
|
self.min_call_time = other.min_call_time if self.min_call_time.zero? or other.min_call_time < self.min_call_time
|
54
48
|
self.max_call_time = other.max_call_time if other.max_call_time > self.max_call_time
|
55
49
|
self.sum_of_squares += other.sum_of_squares
|
56
|
-
self.traces = Array(self.traces) + Array(other.traces)
|
57
50
|
self
|
58
51
|
end
|
59
52
|
|
60
53
|
def as_json
|
61
|
-
json_attributes = [
|
54
|
+
json_attributes = [
|
55
|
+
:call_count,
|
56
|
+
:max_call_time,
|
57
|
+
:min_call_time,
|
58
|
+
:total_call_time,
|
59
|
+
:total_exclusive_time,
|
60
|
+
]
|
62
61
|
ScoutApm::AttributeArranger.call(self, json_attributes)
|
63
62
|
end
|
64
63
|
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module ScoutApm
|
2
|
+
module Rack
|
3
|
+
def self.install!
|
4
|
+
ScoutApm::Agent.instance.start(:skip_app_server_check => true)
|
5
|
+
ScoutApm::Agent.instance.start_background_worker
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.transaction(endpoint_name, env)
|
9
|
+
req = ScoutApm::RequestManager.lookup
|
10
|
+
req.annotate_request(:uri => env["REQUEST_PATH"]) rescue nil
|
11
|
+
req.context.add_user(:ip => env["REMOTE_ADDR"]) rescue nil
|
12
|
+
|
13
|
+
req.web!
|
14
|
+
req.start_layer(ScoutApm::Layer.new('Controller', endpoint_name))
|
15
|
+
|
16
|
+
begin
|
17
|
+
yield
|
18
|
+
rescue
|
19
|
+
req.error!
|
20
|
+
raise
|
21
|
+
ensure
|
22
|
+
req.stop_layer
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module ScoutApm
|
2
|
+
module Remote
|
3
|
+
class Message
|
4
|
+
attr_reader :type
|
5
|
+
attr_reader :command
|
6
|
+
attr_reader :args
|
7
|
+
|
8
|
+
def initialize(type, command, *args)
|
9
|
+
@type = type
|
10
|
+
@command = command
|
11
|
+
@args = args
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.decode(msg)
|
15
|
+
Marshal.load(msg)
|
16
|
+
end
|
17
|
+
|
18
|
+
def encode
|
19
|
+
Marshal.dump(self)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|