scout_apm 2.0.0.pre2 → 2.0.0.pre3
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 +9 -0
- data/lib/scout_apm/agent.rb +14 -33
- data/lib/scout_apm/config.rb +0 -1
- data/lib/scout_apm/instruments/percentile_sampler.rb +7 -8
- data/lib/scout_apm/instruments/process/process_cpu.rb +12 -0
- data/lib/scout_apm/instruments/process/process_memory.rb +12 -0
- data/lib/scout_apm/layer_converters/slow_request_converter.rb +1 -4
- data/lib/scout_apm/slow_transaction.rb +1 -4
- data/lib/scout_apm/store.rb +24 -0
- data/lib/scout_apm/tracked_request.rb +2 -13
- data/lib/scout_apm/version.rb +1 -1
- data/lib/scout_apm.rb +0 -6
- data/test/unit/serializers/payload_serializer_test.rb +0 -1
- metadata +2 -4
- data/lib/scout_apm/stackprof_tree_collapser.rb +0 -103
- data/lib/scout_apm/utils/fake_stack_prof.rb +0 -40
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d49313e6479d1530b66fcc237fbe105646dd33d8
|
4
|
+
data.tar.gz: bfc290ad58b83f3c3509cc81ffb14d9d08ab1237
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 420825d2d15e709e0d07209ff6d32c03fb51400123b31b880de67dd1c1890e4ab23421a05830d1821569db135aa4f30ab9e1b9b82e1112b713d0b09a797c8f5b
|
7
|
+
data.tar.gz: 21d53aadf8fbb4584e5c5a75437f6b1433f28d7792c4715435b49f7f0170b619fc38246bae2e8b64b3e6acd546c57b7eead417d8ddafaafa1a34abd3c2f8f777
|
data/CHANGELOG.markdown
CHANGED
@@ -8,6 +8,15 @@
|
|
8
8
|
* seconds_since_startup (larger memory increases and other other odd behavior more common when close to startup)
|
9
9
|
* Initial support for instant traces
|
10
10
|
* Collect 95th percentiles
|
11
|
+
* Remove unused & old references to Stackprof
|
12
|
+
|
13
|
+
# 1.6.0
|
14
|
+
|
15
|
+
* Dynamic algorithm for selecting when to collect traces. Now, we will collect a
|
16
|
+
more complete cross-section of your application's performance, dynamically
|
17
|
+
tuned as your application runs.
|
18
|
+
* Record and report 95th percentiles for each action
|
19
|
+
* A variety of bug fixes
|
11
20
|
|
12
21
|
# 1.5.5
|
13
22
|
|
data/lib/scout_apm/agent.rb
CHANGED
@@ -24,8 +24,9 @@ module ScoutApm
|
|
24
24
|
# Histogram of the cumulative requests since the start of the process
|
25
25
|
attr_reader :request_histograms
|
26
26
|
|
27
|
-
# Histogram of the requests
|
28
|
-
|
27
|
+
# Histogram of the requests, distinct by reporting period (minute)
|
28
|
+
# { StoreReportingPeriodTimestamp => RequestHistograms }
|
29
|
+
attr_reader :request_histograms_by_time
|
29
30
|
|
30
31
|
# All access to the agent is thru this class method to ensure multiple Agent instances are not initialized per-Ruby process.
|
31
32
|
def self.instance(options = {})
|
@@ -50,7 +51,7 @@ module ScoutApm
|
|
50
51
|
@slow_request_policy = ScoutApm::SlowRequestPolicy.new
|
51
52
|
@slow_job_policy = ScoutApm::SlowJobPolicy.new
|
52
53
|
@request_histograms = ScoutApm::RequestHistograms.new
|
53
|
-
@
|
54
|
+
@request_histograms_by_time = Hash.new { |h, k| h[k] = ScoutApm::RequestHistograms.new }
|
54
55
|
|
55
56
|
@store = ScoutApm::Store.new
|
56
57
|
@layaway = ScoutApm::Layaway.new
|
@@ -124,11 +125,10 @@ module ScoutApm
|
|
124
125
|
|
125
126
|
load_instruments if should_load_instruments?(options)
|
126
127
|
|
127
|
-
|
128
|
-
ScoutApm::Instruments::Process::ProcessCpu.new(environment.processors, logger),
|
128
|
+
[ ScoutApm::Instruments::Process::ProcessCpu.new(environment.processors, logger),
|
129
129
|
ScoutApm::Instruments::Process::ProcessMemory.new(logger),
|
130
130
|
ScoutApm::Instruments::PercentileSampler.new(logger, 95),
|
131
|
-
]
|
131
|
+
].each { |s| store.add_sampler(s) }
|
132
132
|
|
133
133
|
app_server_load_hook
|
134
134
|
|
@@ -242,16 +242,19 @@ module ScoutApm
|
|
242
242
|
@background_worker = ScoutApm::BackgroundWorker.new
|
243
243
|
@background_worker_thread = Thread.new do
|
244
244
|
@background_worker.start {
|
245
|
-
# First, run periodic samplers. These should run once a minute,
|
246
|
-
# rather than per-request. "CPU Load" and similar.
|
247
|
-
run_samplers
|
248
|
-
capacity.process
|
249
|
-
|
250
245
|
ScoutApm::Agent.instance.process_metrics
|
246
|
+
clean_old_percentiles
|
251
247
|
}
|
252
248
|
end
|
253
249
|
end
|
254
250
|
|
251
|
+
def clean_old_percentiles
|
252
|
+
request_histograms_by_time.
|
253
|
+
keys.
|
254
|
+
select {|timestamp| timestamp.age_in_seconds > 60 * 10 }.
|
255
|
+
each {|old_timestamp| request_histograms_by_time.delete(old_timestamp) }
|
256
|
+
end
|
257
|
+
|
255
258
|
# If we want to skip the app_server_check, then we must load it.
|
256
259
|
def should_load_instruments?(options={})
|
257
260
|
return true if options[:skip_app_server_check]
|
@@ -284,10 +287,6 @@ module ScoutApm
|
|
284
287
|
install_instrument(ScoutApm::Instruments::Redis)
|
285
288
|
install_instrument(ScoutApm::Instruments::InfluxDB)
|
286
289
|
install_instrument(ScoutApm::Instruments::Elasticsearch)
|
287
|
-
|
288
|
-
if StackProf.respond_to?(:fake?) && StackProf.fake?
|
289
|
-
logger.info 'StackProf not found - add `gem "stackprof"` to your Gemfile to enable advanced code profiling (only for Ruby 2.1+)'
|
290
|
-
end
|
291
290
|
rescue
|
292
291
|
logger.warn "Exception loading instruments:"
|
293
292
|
logger.warn $!.message
|
@@ -314,24 +313,6 @@ module ScoutApm
|
|
314
313
|
environment.deploy_integration
|
315
314
|
end
|
316
315
|
|
317
|
-
# TODO: Extract a proper class / registery for these. They don't really belong here
|
318
|
-
def run_samplers
|
319
|
-
@samplers.each do |sampler|
|
320
|
-
begin
|
321
|
-
if sampler.respond_to? :metrics
|
322
|
-
store.track!(sampler.metrics)
|
323
|
-
else
|
324
|
-
result = sampler.run
|
325
|
-
store.track_one!(sampler.metric_type, sampler.metric_name, result) if result
|
326
|
-
end
|
327
|
-
rescue => e
|
328
|
-
logger.info "Error reading #{sampler.human_name}"
|
329
|
-
logger.debug e.message
|
330
|
-
logger.debug e.backtrace.join("\n")
|
331
|
-
end
|
332
|
-
end
|
333
|
-
end
|
334
|
-
|
335
316
|
def app_server_missing?(options = {})
|
336
317
|
!environment.app_server_integration(true).found? && !options[:skip_app_server_check]
|
337
318
|
end
|
data/lib/scout_apm/config.rb
CHANGED
@@ -68,7 +68,6 @@ module ScoutApm
|
|
68
68
|
'host' => 'https://checkin.scoutapp.com',
|
69
69
|
'direct_host' => 'https://apm.scoutapp.com',
|
70
70
|
'log_level' => 'info',
|
71
|
-
'stackprof_interval' => 20000, # microseconds, 1000 = 1 millisecond, so 20k == 20 milliseconds
|
72
71
|
'uri_reporting' => 'full_path',
|
73
72
|
'report_format' => 'json',
|
74
73
|
'disabled_instruments' => [],
|
@@ -14,25 +14,24 @@ module ScoutApm
|
|
14
14
|
"Percentiles"
|
15
15
|
end
|
16
16
|
|
17
|
-
|
17
|
+
# Gets the 95th%ile for the time requested
|
18
|
+
def metrics(time)
|
18
19
|
ms = {}
|
19
|
-
|
20
|
-
|
20
|
+
histos = ScoutApm::Agent.instance.request_histograms_by_time[time]
|
21
|
+
histos.each_name do |name|
|
21
22
|
percentiles.each do |percentile|
|
22
23
|
meta = MetricMeta.new("Percentile/#{percentile}/#{name}")
|
23
24
|
stat = MetricStats.new
|
24
|
-
stat.update!(
|
25
|
+
stat.update!(histos.quantile(name, percentile))
|
25
26
|
ms[meta] = stat
|
26
27
|
end
|
27
28
|
end
|
28
29
|
|
29
|
-
# Wipe the histograms
|
30
|
-
ScoutApm::Agent.instance.
|
30
|
+
# Wipe the histograms we just collected data on
|
31
|
+
ScoutApm::Agent.instance.request_histograms_by_time.delete(time)
|
31
32
|
|
32
33
|
ms
|
33
34
|
end
|
34
|
-
|
35
|
-
private
|
36
35
|
end
|
37
36
|
end
|
38
37
|
end
|
@@ -29,6 +29,18 @@ module ScoutApm
|
|
29
29
|
"Process CPU"
|
30
30
|
end
|
31
31
|
|
32
|
+
def metrics(_time)
|
33
|
+
result = run
|
34
|
+
if result
|
35
|
+
meta = MetricMeta.new("#{metric_type}/#{metric_name}")
|
36
|
+
stat = MetricStats.new(false)
|
37
|
+
stat.update!(result)
|
38
|
+
{ meta => stat }
|
39
|
+
else
|
40
|
+
{}
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
32
44
|
# TODO: Figure out a good default instead of nil
|
33
45
|
def run
|
34
46
|
res = nil
|
@@ -33,6 +33,18 @@ module ScoutApm
|
|
33
33
|
"Process Memory"
|
34
34
|
end
|
35
35
|
|
36
|
+
def metrics(_time)
|
37
|
+
result = run
|
38
|
+
if result
|
39
|
+
meta = MetricMeta.new("#{metric_type}/#{metric_name}")
|
40
|
+
stat = MetricStats.new(false)
|
41
|
+
stat.update!(result)
|
42
|
+
{ meta => stat }
|
43
|
+
else
|
44
|
+
{}
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
36
48
|
def run
|
37
49
|
self.class.rss_in_mb.tap { |res| logger.debug "#{human_name}: #{res.inspect}" }
|
38
50
|
end
|
@@ -46,9 +46,6 @@ module ScoutApm
|
|
46
46
|
end
|
47
47
|
end
|
48
48
|
|
49
|
-
# Disable stackprof output for now
|
50
|
-
stackprof = [] # request.stackprof
|
51
|
-
|
52
49
|
SlowTransaction.new(uri,
|
53
50
|
scope.legacy_metric_name,
|
54
51
|
root_layer.total_call_time,
|
@@ -56,7 +53,7 @@ module ScoutApm
|
|
56
53
|
allocation_metrics,
|
57
54
|
request.context,
|
58
55
|
root_layer.stop_time,
|
59
|
-
stackprof,
|
56
|
+
[], # stackprof, now unused.
|
60
57
|
mem_delta,
|
61
58
|
root_layer.total_allocations,
|
62
59
|
@points)
|
@@ -11,7 +11,6 @@ module ScoutApm
|
|
11
11
|
attr_reader :context
|
12
12
|
attr_reader :time
|
13
13
|
attr_reader :prof
|
14
|
-
attr_reader :raw_prof
|
15
14
|
attr_reader :mem_delta
|
16
15
|
attr_reader :allocations
|
17
16
|
attr_accessor :hostname # hack - we need to reset these server side.
|
@@ -25,9 +24,7 @@ module ScoutApm
|
|
25
24
|
@allocation_metrics = allocation_metrics
|
26
25
|
@context = context
|
27
26
|
@time = time
|
28
|
-
@prof =
|
29
|
-
@raw_prof = raw_stackprof # Send whole data up to server
|
30
|
-
|
27
|
+
@prof = []
|
31
28
|
@mem_delta = mem_delta
|
32
29
|
@allocations = allocations
|
33
30
|
@seconds_since_startup = (Time.now - ScoutApm::Agent.instance.process_start_time)
|
data/lib/scout_apm/store.rb
CHANGED
@@ -6,9 +6,13 @@ module ScoutApm
|
|
6
6
|
# A hash of reporting periods. { StoreReportingPeriodTimestamp => StoreReportingPeriod }
|
7
7
|
attr_reader :reporting_periods
|
8
8
|
|
9
|
+
# Used to pull metrics into each reporting period, as that reporting period is finished.
|
10
|
+
attr_reader :samplers
|
11
|
+
|
9
12
|
def initialize
|
10
13
|
@mutex = Mutex.new
|
11
14
|
@reporting_periods = Hash.new { |h,k| h[k] = StoreReportingPeriod.new(k) }
|
15
|
+
@samplers = []
|
12
16
|
end
|
13
17
|
|
14
18
|
def current_timestamp
|
@@ -66,12 +70,32 @@ module ScoutApm
|
|
66
70
|
@mutex.synchronize {
|
67
71
|
reporting_periods.select { |time, rp| force || time.timestamp < current_timestamp.timestamp}.
|
68
72
|
each { |time, rp|
|
73
|
+
collect_samplers(rp)
|
69
74
|
layaway.add_reporting_period(time, rp)
|
70
75
|
reporting_periods.delete(time)
|
71
76
|
}
|
72
77
|
}
|
73
78
|
ScoutApm::Agent.instance.logger.debug("Finished writing to layaway")
|
74
79
|
end
|
80
|
+
|
81
|
+
######################################
|
82
|
+
# Sampler support
|
83
|
+
def add_sampler(sampler)
|
84
|
+
@samplers << sampler
|
85
|
+
end
|
86
|
+
|
87
|
+
def collect_samplers(rp)
|
88
|
+
@samplers.each do |sampler|
|
89
|
+
begin
|
90
|
+
metrics = sampler.metrics(rp.timestamp)
|
91
|
+
rp.absorb_metrics!(metrics)
|
92
|
+
rescue => e
|
93
|
+
ScoutApm::Agent.instance.logger.info "Error reading #{sampler.human_name} for period: #{rp}"
|
94
|
+
ScoutApm::Agent.instance.logger.debug e.message
|
95
|
+
ScoutApm::Agent.instance.logger.debug e.backtrace.join("\n")
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
75
99
|
end
|
76
100
|
|
77
101
|
# A timestamp, normalized to the beginning of a minute. Used as a hash key to
|
@@ -22,10 +22,6 @@ module ScoutApm
|
|
22
22
|
# :queue_latency - how long a background Job spent in the queue before starting processing
|
23
23
|
attr_reader :annotations
|
24
24
|
|
25
|
-
# Nil until the request is finalized, at which point it will hold the
|
26
|
-
# entire raw stackprof output for this request
|
27
|
-
attr_reader :stackprof
|
28
|
-
|
29
25
|
# Headers as recorded by rails
|
30
26
|
# Can be nil if we never reach a Rails Controller
|
31
27
|
attr_reader :headers
|
@@ -52,7 +48,6 @@ module ScoutApm
|
|
52
48
|
@ignoring_children = false
|
53
49
|
@context = Context.new
|
54
50
|
@root_layer = nil
|
55
|
-
@stackprof = nil
|
56
51
|
@error = false
|
57
52
|
@instant_key = nil
|
58
53
|
@mem_start = mem_usage
|
@@ -158,21 +153,14 @@ module ScoutApm
|
|
158
153
|
# Run at the beginning of the whole request
|
159
154
|
#
|
160
155
|
# * Capture the first layer as the root_layer
|
161
|
-
# * Start Stackprof (disabling to avoid conflicts if stackprof is included as middleware since we aren't sending this up to server now)
|
162
156
|
def start_request(layer)
|
163
157
|
@root_layer = layer unless @root_layer # capture root layer
|
164
|
-
#StackProf.start(:mode => :wall, :interval => ScoutApm::Agent.instance.config.value("stackprof_interval"))
|
165
158
|
end
|
166
159
|
|
167
160
|
# Run at the end of the whole request
|
168
161
|
#
|
169
|
-
# * Collect stackprof info
|
170
162
|
# * Send the request off to be stored
|
171
163
|
def stop_request
|
172
|
-
# ScoutApm::Agent.instance.logger.debug("stop_request: #{annotations[:uri]}" )
|
173
|
-
#StackProf.stop # disabling to avoid conflicts if stackprof is included as middleware since we aren't sending this up to server now
|
174
|
-
#@stackprof = StackProf.results
|
175
|
-
|
176
164
|
record!
|
177
165
|
end
|
178
166
|
|
@@ -234,7 +222,8 @@ module ScoutApm
|
|
234
222
|
# Update immediate and long-term histograms for both job and web requests
|
235
223
|
if unique_name != :unknown
|
236
224
|
ScoutApm::Agent.instance.request_histograms.add(unique_name, root_layer.total_call_time)
|
237
|
-
ScoutApm::Agent.instance.
|
225
|
+
ScoutApm::Agent.instance.request_histograms_by_time[ScoutApm::Agent.instance.store.current_timestamp].
|
226
|
+
add(unique_name, root_layer.total_call_time)
|
238
227
|
end
|
239
228
|
|
240
229
|
metrics = LayerConverters::MetricConverter.new(self).call
|
data/lib/scout_apm/version.rb
CHANGED
data/lib/scout_apm.rb
CHANGED
@@ -18,11 +18,6 @@ require 'yaml'
|
|
18
18
|
#####################################
|
19
19
|
# Gem Requires
|
20
20
|
#####################################
|
21
|
-
begin
|
22
|
-
require 'stackprof'
|
23
|
-
rescue LoadError
|
24
|
-
require 'scout_apm/utils/fake_stack_prof'
|
25
|
-
end
|
26
21
|
require 'rusage'
|
27
22
|
|
28
23
|
#####################################
|
@@ -116,7 +111,6 @@ require 'scout_apm/metric_set'
|
|
116
111
|
require 'scout_apm/store'
|
117
112
|
require 'scout_apm/tracer'
|
118
113
|
require 'scout_apm/context'
|
119
|
-
require 'scout_apm/stackprof_tree_collapser'
|
120
114
|
require 'scout_apm/instant_reporting'
|
121
115
|
|
122
116
|
require 'scout_apm/metric_meta'
|
@@ -6,7 +6,6 @@ require 'scout_apm/serializers/payload_serializer_to_json'
|
|
6
6
|
require 'scout_apm/slow_transaction'
|
7
7
|
require 'scout_apm/metric_meta'
|
8
8
|
require 'scout_apm/metric_stats'
|
9
|
-
require 'scout_apm/stackprof_tree_collapser'
|
10
9
|
require 'scout_apm/utils/fake_stack_prof'
|
11
10
|
require 'scout_apm/context'
|
12
11
|
require 'ostruct'
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: scout_apm
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.0.0.
|
4
|
+
version: 2.0.0.pre3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Derek Haynes
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2016-06-
|
12
|
+
date: 2016-06-16 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rusage
|
@@ -200,13 +200,11 @@ files:
|
|
200
200
|
- lib/scout_apm/slow_request_policy.rb
|
201
201
|
- lib/scout_apm/slow_transaction.rb
|
202
202
|
- lib/scout_apm/stack_item.rb
|
203
|
-
- lib/scout_apm/stackprof_tree_collapser.rb
|
204
203
|
- lib/scout_apm/store.rb
|
205
204
|
- lib/scout_apm/tracer.rb
|
206
205
|
- lib/scout_apm/tracked_request.rb
|
207
206
|
- lib/scout_apm/utils/active_record_metric_name.rb
|
208
207
|
- lib/scout_apm/utils/backtrace_parser.rb
|
209
|
-
- lib/scout_apm/utils/fake_stack_prof.rb
|
210
208
|
- lib/scout_apm/utils/installed_gems.rb
|
211
209
|
- lib/scout_apm/utils/klass_helper.rb
|
212
210
|
- lib/scout_apm/utils/null_logger.rb
|
@@ -1,103 +0,0 @@
|
|
1
|
-
module ScoutApm
|
2
|
-
class StackprofTreeCollapser
|
3
|
-
attr_reader :raw_stackprof
|
4
|
-
attr_reader :nodes
|
5
|
-
|
6
|
-
def initialize(raw_stackprof)
|
7
|
-
@raw_stackprof = raw_stackprof
|
8
|
-
|
9
|
-
# Log the raw stackprof info
|
10
|
-
#unless StackProf.respond_to?(:fake?) && StackProf.fake?
|
11
|
-
# begin
|
12
|
-
# ScoutApm::Agent.instance.logger.debug("StackProf - Samples: #{raw_stackprof[:samples]}, GC: #{raw_stackprof[:gc_samples]}, missed: #{raw_stackprof[:missed_samples]}, Interval: #{raw_stackprof[:interval]}")
|
13
|
-
# rescue
|
14
|
-
# ScoutApm::Agent.instance.logger.debug("StackProf Raw - #{raw_stackprof.inspect}")
|
15
|
-
# end
|
16
|
-
#end
|
17
|
-
end
|
18
|
-
|
19
|
-
def call
|
20
|
-
build_tree
|
21
|
-
connect_children
|
22
|
-
total_samples_of_app_nodes
|
23
|
-
rescue
|
24
|
-
[]
|
25
|
-
end
|
26
|
-
|
27
|
-
private
|
28
|
-
|
29
|
-
def build_tree
|
30
|
-
@nodes = raw_stackprof[:frames].map do |(frame_id, frame_data)|
|
31
|
-
TreeNode.new(frame_id, # frame_id
|
32
|
-
frame_data[:name], # name
|
33
|
-
frame_data[:file], # file
|
34
|
-
frame_data[:line], # line
|
35
|
-
frame_data[:samples], # samples
|
36
|
-
frame_data[:total_samples], # total_samples
|
37
|
-
(frame_data[:edges] || {}), # children_edges [ { id => weight } ]
|
38
|
-
[], # children [ treenode, ... ]
|
39
|
-
[] # parents [ [treenode, int (weight) ], [...] ]
|
40
|
-
)
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
def connect_children
|
45
|
-
nodes.each do |node|
|
46
|
-
children = nodes.find_all { |n| node.children_edges.keys.include? n.frame_id }
|
47
|
-
|
48
|
-
node.children_edges.each do |(frame_id, weight)|
|
49
|
-
child = children.detect{ |c| c.frame_id == frame_id }
|
50
|
-
child.parents << [node, weight]
|
51
|
-
end
|
52
|
-
|
53
|
-
node.children = children
|
54
|
-
end
|
55
|
-
end
|
56
|
-
|
57
|
-
def in_app_nodes
|
58
|
-
nodes.select {|n| n.app? }
|
59
|
-
end
|
60
|
-
|
61
|
-
def total_samples_of_app_nodes
|
62
|
-
in_app_nodes.reject{|n| n.calls_only_app_nodes? && !n.has_samples? }.
|
63
|
-
map{|n| { :samples => n.total_samples,
|
64
|
-
:name => n.name,
|
65
|
-
:file => n.file,
|
66
|
-
:line => n.line
|
67
|
-
}
|
68
|
-
}
|
69
|
-
end
|
70
|
-
|
71
|
-
###########################################
|
72
|
-
# TreeNode class represents a single node.
|
73
|
-
###########################################
|
74
|
-
TreeNode = Struct.new(:frame_id, :name, :file, :line, :samples, :total_samples,
|
75
|
-
:children_edges, :children, :parents) do
|
76
|
-
def app?
|
77
|
-
@is_app ||= file =~ /^#{ScoutApm::Environment.instance.root}/
|
78
|
-
end
|
79
|
-
|
80
|
-
# Force object_id to be the equality mechanism, rather than struct's
|
81
|
-
# default which delegates to == on each value. That is wrong because
|
82
|
-
# we want to be able to dup a node in the tree construction process and
|
83
|
-
# not have those compare equal to each other.
|
84
|
-
def ==(other)
|
85
|
-
object_id == other.object_id
|
86
|
-
end
|
87
|
-
|
88
|
-
def inspect
|
89
|
-
"#{frame_id}: #{name} - ##{samples}\n" +
|
90
|
-
" Parents: #{parents.map{ |(p, w)| "#{p.name}: #{w}"}.join("\n ") }\n" +
|
91
|
-
" Children: #{children_edges.inspect} \n"
|
92
|
-
end
|
93
|
-
|
94
|
-
def calls_only_app_nodes?
|
95
|
-
children.all?(&:app?)
|
96
|
-
end
|
97
|
-
|
98
|
-
def has_samples?
|
99
|
-
samples > 0
|
100
|
-
end
|
101
|
-
end
|
102
|
-
end
|
103
|
-
end
|
@@ -1,40 +0,0 @@
|
|
1
|
-
# A fake implementation of stackprof, for systems that don't support it.
|
2
|
-
module StackProf
|
3
|
-
def self.start(*args)
|
4
|
-
@running = true
|
5
|
-
end
|
6
|
-
|
7
|
-
def self.stop(*args)
|
8
|
-
@running = false
|
9
|
-
end
|
10
|
-
|
11
|
-
def self.running?
|
12
|
-
!!@running
|
13
|
-
end
|
14
|
-
|
15
|
-
def self.run(*args)
|
16
|
-
start
|
17
|
-
yield
|
18
|
-
stop
|
19
|
-
results
|
20
|
-
end
|
21
|
-
|
22
|
-
def self.sample(*args)
|
23
|
-
end
|
24
|
-
|
25
|
-
def self.results(*args)
|
26
|
-
{
|
27
|
-
:version => 0.0,
|
28
|
-
:mode => :wall,
|
29
|
-
:interval => 1000,
|
30
|
-
:samples => 0,
|
31
|
-
:gc_samples => 0,
|
32
|
-
:missed_samples => 0,
|
33
|
-
:frames => {},
|
34
|
-
}
|
35
|
-
end
|
36
|
-
|
37
|
-
def self.fake?
|
38
|
-
true
|
39
|
-
end
|
40
|
-
end
|