newrelic_rpm 3.6.2.96 → 3.6.3.103.beta
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +3 -0
- data/CHANGELOG +33 -1
- data/README.md +7 -7
- data/lib/new_relic/agent/agent.rb +51 -22
- data/lib/new_relic/agent/agent_logger.rb +22 -11
- data/lib/new_relic/agent/configuration/defaults.rb +6 -1
- data/lib/new_relic/agent/instrumentation/action_controller_subscriber.rb +1 -6
- data/lib/new_relic/agent/instrumentation/action_view_subscriber.rb +1 -1
- data/lib/new_relic/agent/instrumentation/active_record.rb +8 -48
- data/lib/new_relic/agent/instrumentation/active_record_helper.rb +9 -1
- data/lib/new_relic/agent/instrumentation/controller_instrumentation.rb +4 -3
- data/lib/new_relic/agent/instrumentation/data_mapper.rb +4 -4
- data/lib/new_relic/agent/instrumentation/metric_frame.rb +10 -8
- data/lib/new_relic/agent/instrumentation/padrino.rb +32 -0
- data/lib/new_relic/agent/instrumentation/sinatra/ignorer.rb +52 -0
- data/lib/new_relic/agent/instrumentation/sinatra/transaction_namer.rb +56 -0
- data/lib/new_relic/agent/instrumentation/sinatra.rb +113 -48
- data/lib/new_relic/agent/new_relic_service.rb +6 -0
- data/lib/new_relic/agent/pipe_channel_manager.rb +13 -8
- data/lib/new_relic/agent/request_sampler.rb +205 -0
- data/lib/new_relic/agent/sampler.rb +0 -1
- data/lib/new_relic/agent/stats_engine/samplers.rb +0 -1
- data/lib/new_relic/agent/stats_engine/transactions.rb +12 -16
- data/lib/new_relic/agent/transaction.rb +27 -4
- data/lib/new_relic/agent/transaction_sample_builder.rb +47 -6
- data/lib/new_relic/agent/transaction_sampler.rb +0 -5
- data/lib/new_relic/agent.rb +17 -0
- data/lib/new_relic/build.rb +2 -2
- data/lib/new_relic/coerce.rb +3 -1
- data/lib/new_relic/rack/agent_hooks.rb +17 -3
- data/lib/new_relic/rack/browser_monitoring.rb +8 -3
- data/lib/new_relic/rack/error_collector.rb +2 -0
- data/lib/new_relic/transaction_sample/segment.rb +0 -23
- data/lib/new_relic/transaction_sample.rb +0 -9
- data/lib/new_relic/version.rb +1 -1
- data/test/agent_helper.rb +204 -0
- data/test/config/newrelic.yml +0 -1
- data/test/config/test_control.rb +3 -1
- data/test/multiverse/suites/agent_only/key_transactions_test.rb +8 -5
- data/test/multiverse/suites/agent_only/logging_test.rb +1 -1
- data/test/multiverse/suites/agent_only/thread_profiling_test.rb +7 -8
- data/test/multiverse/suites/datamapper/Envfile +7 -0
- data/test/multiverse/suites/datamapper/datamapper_test.rb +105 -0
- data/test/multiverse/suites/padrino/Envfile +16 -0
- data/test/multiverse/suites/padrino/config/newrelic.yml +24 -0
- data/test/multiverse/suites/padrino/padrino_test.rb +54 -0
- data/test/multiverse/suites/rails/Envfile +5 -5
- data/test/multiverse/suites/rails/app.rb +1 -0
- data/test/multiverse/suites/rails/request_statistics_test.rb +118 -0
- data/test/multiverse/suites/sinatra/Envfile +8 -2
- data/test/multiverse/suites/sinatra/ignoring_test.rb +185 -0
- data/test/multiverse/suites/sinatra/sinatra_classic_test.rb +92 -0
- data/test/multiverse/suites/sinatra/sinatra_metric_explosion_test.rb +0 -3
- data/test/multiverse/suites/sinatra/sinatra_modular_test.rb +89 -0
- data/test/multiverse/suites/sinatra/sinatra_test_cases.rb +120 -0
- data/test/new_relic/agent/agent_logger_test.rb +149 -56
- data/test/new_relic/agent/agent_test.rb +23 -0
- data/test/new_relic/agent/agent_test_controller_test.rb +8 -1
- data/test/new_relic/agent/autostart_test.rb +10 -6
- data/test/new_relic/agent/instrumentation/action_controller_subscriber_test.rb +36 -31
- data/test/new_relic/agent/instrumentation/action_view_subscriber_test.rb +7 -0
- data/test/new_relic/agent/instrumentation/active_record_helper_test.rb +20 -4
- data/test/new_relic/agent/instrumentation/active_record_instrumentation_test.rb +20 -9
- data/test/new_relic/agent/instrumentation/active_record_subscriber_test.rb +23 -19
- data/test/new_relic/agent/instrumentation/sequel_test.rb +118 -79
- data/test/new_relic/agent/instrumentation/sinatra/transaction_namer_test.rb +55 -0
- data/test/new_relic/agent/instrumentation/sinatra_test.rb +60 -11
- data/test/new_relic/agent/method_tracer_test.rb +7 -4
- data/test/new_relic/agent/new_relic_service_test.rb +6 -0
- data/test/new_relic/agent/pipe_channel_manager_test.rb +6 -2
- data/test/new_relic/agent/request_sampler_test.rb +159 -0
- data/test/new_relic/agent/stats_engine/samplers_test.rb +1 -5
- data/test/new_relic/agent/stats_engine_test.rb +14 -0
- data/test/new_relic/agent/transaction_sample_builder_test.rb +43 -6
- data/test/new_relic/agent/transaction_sampler_test.rb +31 -1
- data/test/new_relic/agent/transaction_test.rb +29 -0
- data/test/new_relic/agent_test.rb +7 -0
- data/test/new_relic/coerce_test.rb +13 -0
- data/test/new_relic/fake_collector.rb +31 -1
- data/test/new_relic/metric_spec_test.rb +14 -10
- data/test/new_relic/rack/agent_hooks_test.rb +9 -2
- data/test/new_relic/rack/browser_monitoring_test.rb +16 -7
- data/test/new_relic/rack/developer_mode_test.rb +7 -0
- data/test/new_relic/rack/error_collector_test.rb +10 -6
- data/test/new_relic/transaction_sample/segment_test.rb +0 -61
- data/test/new_relic/transaction_sample_subtest_test.rb +0 -19
- data/test/script/ci.sh +14 -0
- data/test/test_helper.rb +79 -203
- data.tar.gz.sig +0 -0
- metadata +50 -18
- metadata.gz.sig +0 -0
- data/test/multiverse/suites/datamapper/encoding_test.rb +0 -40
- data/test/multiverse/suites/sinatra/sinatra_test.rb +0 -143
@@ -0,0 +1,205 @@
|
|
1
|
+
# -*- ruby -*-
|
2
|
+
# encoding: utf-8
|
3
|
+
# This file is distributed under New Relic's license terms.
|
4
|
+
# See https://github.com/newrelic/rpm/blob/master/LICENSE for complete details.
|
5
|
+
|
6
|
+
require 'monitor'
|
7
|
+
|
8
|
+
require 'newrelic_rpm' unless defined?( NewRelic )
|
9
|
+
require 'new_relic/agent' unless defined?( NewRelic::Agent )
|
10
|
+
|
11
|
+
class NewRelic::Agent::RequestSampler
|
12
|
+
include NewRelic::Coerce,
|
13
|
+
MonitorMixin
|
14
|
+
|
15
|
+
# The amount of time between samples, in milliseconds
|
16
|
+
DEFAULT_SAMPLE_RATE_MS = 50
|
17
|
+
|
18
|
+
# The minimum amount of time between samples, in milliseconds
|
19
|
+
MIN_SAMPLE_RATE_MS = 25
|
20
|
+
|
21
|
+
# The number of seconds between harvests
|
22
|
+
# :TODO: Get this from the agent instead?
|
23
|
+
DEFAULT_REPORT_FREQUENCY = 60
|
24
|
+
|
25
|
+
# The namespace and keys of config values
|
26
|
+
CONFIG_NAMESPACE = 'request_sampler'
|
27
|
+
SAMPLE_RATE_KEY = "#{CONFIG_NAMESPACE}.sample_rate_ms".to_sym
|
28
|
+
ENABLED_KEY = "#{CONFIG_NAMESPACE}.enabled".to_sym
|
29
|
+
|
30
|
+
# The type field of the sample
|
31
|
+
SAMPLE_TYPE = 'Transaction'
|
32
|
+
|
33
|
+
# Strings for static keys of the sample structure
|
34
|
+
TYPE_KEY = 'type'
|
35
|
+
TIMESTAMP_KEY = 'timestamp'
|
36
|
+
NAME_KEY = 'name'
|
37
|
+
DURATION_KEY = 'duration'
|
38
|
+
|
39
|
+
|
40
|
+
# Create a new RequestSampler that will keep samples added to it every
|
41
|
+
# +sample_rate_ms+ milliseconds.
|
42
|
+
def initialize( event_listener )
|
43
|
+
super()
|
44
|
+
|
45
|
+
@enabled = false
|
46
|
+
@sample_rate_ms = DEFAULT_SAMPLE_RATE_MS
|
47
|
+
@normal_sample_rate_ms = @sample_rate_ms
|
48
|
+
@last_sample_taken = nil
|
49
|
+
@last_harvest = nil
|
50
|
+
@samples = []
|
51
|
+
|
52
|
+
event_listener.subscribe( :transaction_finished, &method(:on_transaction_finished) )
|
53
|
+
self.register_config_callbacks
|
54
|
+
end
|
55
|
+
|
56
|
+
|
57
|
+
######
|
58
|
+
public
|
59
|
+
######
|
60
|
+
|
61
|
+
# The sample rate, in milliseconds between samples, that the sampler uses
|
62
|
+
# under normal circumstances
|
63
|
+
attr_reader :normal_sample_rate_ms
|
64
|
+
|
65
|
+
# The current sample rate, which may be different from the #normal_sample_rate_ms
|
66
|
+
# if the sampler is throttled.
|
67
|
+
attr_reader :sample_rate_ms
|
68
|
+
|
69
|
+
# The Time when the last sample was kept
|
70
|
+
attr_reader :last_sample_taken
|
71
|
+
|
72
|
+
|
73
|
+
### Fetch a copy of the sampler's gathered samples. (Synchronized)
|
74
|
+
def samples
|
75
|
+
return self.synchronize { @samples.dup }
|
76
|
+
end
|
77
|
+
|
78
|
+
|
79
|
+
# Clear any existing samples and reset the last sample time. (Synchronized)
|
80
|
+
def reset
|
81
|
+
NewRelic::Agent.logger.debug "Resetting RequestSampler"
|
82
|
+
|
83
|
+
self.synchronize do
|
84
|
+
@samples.clear
|
85
|
+
@sample_rate_ms = @normal_sample_rate_ms
|
86
|
+
@last_sample_taken = Time.now
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
|
91
|
+
#
|
92
|
+
# :group: Event handlers
|
93
|
+
#
|
94
|
+
|
95
|
+
def register_config_callbacks
|
96
|
+
NewRelic::Agent.config.register_callback(SAMPLE_RATE_KEY) do |rate_ms|
|
97
|
+
NewRelic::Agent.logger.debug "RequestSampler sample rate to %dms" % [ rate_ms ]
|
98
|
+
|
99
|
+
if rate_ms < MIN_SAMPLE_RATE_MS
|
100
|
+
NewRelic::Agent.logger.warn " limiting RequestSampler frequency to %dms (was %dms)" %
|
101
|
+
[ MIN_SAMPLE_RATE_MS, rate_ms ]
|
102
|
+
rate_ms = MIN_SAMPLE_RATE_MS
|
103
|
+
end
|
104
|
+
|
105
|
+
@normal_sample_rate_ms = rate_ms
|
106
|
+
self.reset
|
107
|
+
end
|
108
|
+
|
109
|
+
NewRelic::Agent.config.register_callback(ENABLED_KEY) do |enabled|
|
110
|
+
NewRelic::Agent.logger.info "%sabling the Request Sampler." % [ enabled ? 'En' : 'Dis' ]
|
111
|
+
@enabled = enabled
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
|
116
|
+
# Event handler for the :transaction_finished event.
|
117
|
+
def on_transaction_finished( metric, duration, options={} )
|
118
|
+
return unless @enabled
|
119
|
+
self << {
|
120
|
+
NAME_KEY => string(metric),
|
121
|
+
DURATION_KEY => float(duration)
|
122
|
+
}.merge(options)
|
123
|
+
end
|
124
|
+
|
125
|
+
|
126
|
+
|
127
|
+
#
|
128
|
+
# :group: Sample API
|
129
|
+
# These methods are synchronized.
|
130
|
+
#
|
131
|
+
|
132
|
+
# Add a datapoint to the sampler if a sample is due. The +sample+ should be
|
133
|
+
# of the form:
|
134
|
+
#
|
135
|
+
# {
|
136
|
+
# 'name' => '<transaction/metric name>',
|
137
|
+
# 'duration' => <duration in seconds as a Float>,
|
138
|
+
# }
|
139
|
+
#
|
140
|
+
# This method is synchronized.
|
141
|
+
def <<( sample )
|
142
|
+
self.synchronize do
|
143
|
+
self.add_sample( sample ) if should_sample?
|
144
|
+
end
|
145
|
+
|
146
|
+
return self
|
147
|
+
end
|
148
|
+
|
149
|
+
|
150
|
+
# Downsample the gathered data and reduce the sampling rate to conserve memory. The amount
|
151
|
+
# the sampler is throttled is proportional to +resolution+, which defaults to the number of
|
152
|
+
# normal report periods which have elapsed. E.g., if three sessions with the agent have failed,
|
153
|
+
# the sampler downsamples its data to include one out of even three samples, and only samples
|
154
|
+
# a third of the time it normally would.
|
155
|
+
#
|
156
|
+
# This method is synchronized.
|
157
|
+
def throttle( resolution=nil )
|
158
|
+
|
159
|
+
# Only throttle if the sampler was running
|
160
|
+
self.synchronize do
|
161
|
+
if @last_sample_taken && !@samples.empty?
|
162
|
+
resolution ||= (Time.now - @last_sample_taken) / DEFAULT_REPORT_FREQUENCY
|
163
|
+
@sample_rate_ms = @normal_sample_rate_ms * resolution
|
164
|
+
self.downsample_data( resolution )
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
if resolution
|
169
|
+
NewRelic::Agent.logger.debug " resolution is now: %d -> 1 sample every %dms" %
|
170
|
+
[ resolution, @sample_rate_ms ]
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
|
175
|
+
#########
|
176
|
+
protected
|
177
|
+
#########
|
178
|
+
|
179
|
+
# Returns +true+ if a sample added now should be kept based on the sample
|
180
|
+
# frequency.
|
181
|
+
def should_sample?
|
182
|
+
return false unless @last_sample_taken
|
183
|
+
return ((Time.now - @last_sample_taken) * 1000).ceil >= @sample_rate_ms
|
184
|
+
end
|
185
|
+
|
186
|
+
|
187
|
+
# Add the given +sample+ to the sampler (unconditionally).
|
188
|
+
def add_sample( sample )
|
189
|
+
@last_sample_taken = Time.now
|
190
|
+
|
191
|
+
sample[TYPE_KEY] = SAMPLE_TYPE
|
192
|
+
sample[TIMESTAMP_KEY] = @last_sample_taken
|
193
|
+
|
194
|
+
@samples << sample
|
195
|
+
end
|
196
|
+
|
197
|
+
|
198
|
+
# Downsample the current data to match the specified +resolution+.
|
199
|
+
def downsample_data( resolution )
|
200
|
+
goalsize = @samples.length * ( (resolution - 1) / resolution.to_f )
|
201
|
+
0.step( goalsize.ceil, resolution - 1 ) {|i| @samples.slice!(i+1) }
|
202
|
+
end
|
203
|
+
|
204
|
+
end # class NewRelic::Agent::RequestSampler
|
205
|
+
|
@@ -34,19 +34,6 @@ module Agent
|
|
34
34
|
def pop_scope(*args); end
|
35
35
|
end
|
36
36
|
|
37
|
-
attr_reader :transaction_sampler
|
38
|
-
|
39
|
-
# add a new transaction sampler, unless we're currently in a
|
40
|
-
# transaction (then we fail)
|
41
|
-
def transaction_sampler= sampler
|
42
|
-
fail "Can't add a scope listener midflight in a transaction" if scope_stack.any?
|
43
|
-
@transaction_sampler = sampler
|
44
|
-
end
|
45
|
-
|
46
|
-
# removes a transaction sampler
|
47
|
-
def remove_transaction_sampler(l)
|
48
|
-
@transaction_sampler = nil
|
49
|
-
end
|
50
37
|
|
51
38
|
# Pushes a scope onto the transaction stack - this generates a
|
52
39
|
# TransactionSample::Segment at the end of transaction execution
|
@@ -56,7 +43,7 @@ module Agent
|
|
56
43
|
# identify this scope if the stack gets corrupted.
|
57
44
|
def push_scope(tag, time = Time.now.to_f, deduct_call_time_from_parent = true)
|
58
45
|
stack = scope_stack
|
59
|
-
|
46
|
+
transaction_sampler.notice_push_scope(time) if sampler_enabled?
|
60
47
|
scope = ScopeStackElement.new(tag, time, deduct_call_time_from_parent)
|
61
48
|
stack.push scope
|
62
49
|
scope
|
@@ -80,13 +67,22 @@ module Agent
|
|
80
67
|
stack.last.children_time += scope.children_time
|
81
68
|
end
|
82
69
|
end
|
83
|
-
|
70
|
+
transaction_sampler.notice_pop_scope(name, time) if sampler_enabled?
|
84
71
|
scope.name = name
|
85
72
|
scope
|
86
73
|
end
|
87
74
|
|
88
75
|
def sampler_enabled?
|
89
|
-
|
76
|
+
Agent.config[:'transaction_tracer.enabled'] || Agent.config[:developer_mode]
|
77
|
+
end
|
78
|
+
|
79
|
+
def transaction_sampler
|
80
|
+
Agent.instance.transaction_sampler
|
81
|
+
end
|
82
|
+
|
83
|
+
# deprecated--used to add transaction sampler, now we always look to the agent
|
84
|
+
def transaction_sampler= sampler
|
85
|
+
NewRelic::Agent.logger.warn("NewRelic::Agent::StatsEngine#transaction_sampler is deprecated")
|
90
86
|
end
|
91
87
|
|
92
88
|
# set the name of the transaction for the current thread, which will be used
|
@@ -43,9 +43,9 @@ module NewRelic
|
|
43
43
|
return txn
|
44
44
|
end
|
45
45
|
|
46
|
-
def self.stop(metric_name=nil)
|
46
|
+
def self.stop(metric_name=nil, end_time=Time.now)
|
47
47
|
txn = self.stack.pop
|
48
|
-
txn.stop(metric_name) if txn
|
48
|
+
txn.stop(metric_name, end_time) if txn
|
49
49
|
return txn
|
50
50
|
end
|
51
51
|
|
@@ -105,7 +105,7 @@ module NewRelic
|
|
105
105
|
if !@name_frozen
|
106
106
|
@name = name
|
107
107
|
else
|
108
|
-
NewRelic::Agent.logger.warn("Attempted to rename transaction to #{name} after transaction name was already frozen.")
|
108
|
+
NewRelic::Agent.logger.warn("Attempted to rename transaction to '#{name}' after transaction name was already frozen as '#{@name}'.")
|
109
109
|
end
|
110
110
|
end
|
111
111
|
|
@@ -157,9 +157,10 @@ module NewRelic
|
|
157
157
|
transaction_sampler.ignore_transaction
|
158
158
|
end
|
159
159
|
|
160
|
+
|
160
161
|
# Unwind one stack level. It knows if it's back at the outermost caller and
|
161
162
|
# does the appropriate wrapup of the context.
|
162
|
-
def stop(metric=::NewRelic::Agent::UNKNOWN_METRIC)
|
163
|
+
def stop(metric=::NewRelic::Agent::UNKNOWN_METRIC, end_time=Time.now)
|
163
164
|
@name ||= metric unless name_frozen?
|
164
165
|
freeze_name
|
165
166
|
log_underflow if @type.nil?
|
@@ -175,6 +176,7 @@ module NewRelic
|
|
175
176
|
end
|
176
177
|
@transaction_trace = transaction_sampler.notice_scope_empty(self, Time.now, gc_time)
|
177
178
|
sql_sampler.notice_scope_empty(@name)
|
179
|
+
overview_metrics = transaction_overview_metrics
|
178
180
|
end
|
179
181
|
|
180
182
|
record_exceptions
|
@@ -183,6 +185,7 @@ module NewRelic
|
|
183
185
|
# these tear everything down so need to be done
|
184
186
|
# after the pop
|
185
187
|
if self.class.stack.empty?
|
188
|
+
agent.events.notify(:transaction_finished, @name, end_time.to_f - start_time.to_f, overview_metrics)
|
186
189
|
agent.stats_engine.end_transaction
|
187
190
|
end
|
188
191
|
end
|
@@ -194,6 +197,24 @@ module NewRelic
|
|
194
197
|
end
|
195
198
|
end
|
196
199
|
|
200
|
+
OVERVIEW_SPECS = [
|
201
|
+
[:web_duration, MetricSpec.new('HttpDispatcher')],
|
202
|
+
[:queue_duration, MetricSpec.new('WebFrontend/QueueTime')],
|
203
|
+
[:external_duration, MetricSpec.new('External/allWeb')],
|
204
|
+
[:database_duration, MetricSpec.new('ActiveRecord/all')],
|
205
|
+
[:gc_cumulative, MetricSpec.new("GC/cumulative")],
|
206
|
+
[:memcache_duration, MetricSpec.new('Memcache/allWeb')]
|
207
|
+
]
|
208
|
+
|
209
|
+
def transaction_overview_metrics
|
210
|
+
metrics = {}
|
211
|
+
stats = agent.stats_engine.transaction_stats_hash
|
212
|
+
OVERVIEW_SPECS.each do |(dest_key, spec)|
|
213
|
+
metrics[dest_key] = stats[spec].total_call_time if stats.key?(spec)
|
214
|
+
end
|
215
|
+
metrics
|
216
|
+
end
|
217
|
+
|
197
218
|
# If we have an active transaction, notice the error and increment the error metric.
|
198
219
|
# Options:
|
199
220
|
# * <tt>:request</tt> => Request object to get the uri and referer
|
@@ -299,6 +320,8 @@ module NewRelic
|
|
299
320
|
user_attributes.merge!(attributes)
|
300
321
|
end
|
301
322
|
|
323
|
+
# Returns truthy if the current in-progress transaction is considered a
|
324
|
+
# a web transaction (as opposed to, e.g., a background transaction).
|
302
325
|
def self.recording_web_transaction?
|
303
326
|
self.current && self.current.recording_web_transaction?
|
304
327
|
end
|
@@ -11,7 +11,36 @@ module NewRelic
|
|
11
11
|
# a builder is created with every sampled transaction, to dynamically
|
12
12
|
# generate the sampled data. It is a thread-local object, and is not
|
13
13
|
# accessed by any other thread so no need for synchronization.
|
14
|
+
#
|
15
|
+
# @api private
|
14
16
|
class TransactionSampleBuilder
|
17
|
+
|
18
|
+
# Once we hit the TT segment limit, we use this class to hold our place in
|
19
|
+
# the tree so that we can still get accurate names and times on the
|
20
|
+
# segments we've already created. The placeholder segment keeps a
|
21
|
+
# depth counter that's incremented on each segment entry, and decremented
|
22
|
+
# on exit, until it reaches zero, when we throw the placeholder away.
|
23
|
+
# There should only ever be zero or one placeholder segment at a time.
|
24
|
+
#
|
25
|
+
# @api private
|
26
|
+
class PlaceholderSegment
|
27
|
+
attr_reader :parent_segment
|
28
|
+
attr_accessor :depth
|
29
|
+
|
30
|
+
def initialize(parent_segment)
|
31
|
+
@parent_segment = parent_segment
|
32
|
+
@depth = 1
|
33
|
+
end
|
34
|
+
|
35
|
+
# No-op - some clients expect to be able to use this to attach params to
|
36
|
+
# TT segments.
|
37
|
+
def []=(key, value); end
|
38
|
+
|
39
|
+
# No-op - some clients expect to be able to use this to read params from
|
40
|
+
# TT segments.
|
41
|
+
def [](key); end
|
42
|
+
end
|
43
|
+
|
15
44
|
attr_reader :current_segment, :sample
|
16
45
|
|
17
46
|
include NewRelic::CollectionHelper
|
@@ -39,22 +68,34 @@ module NewRelic
|
|
39
68
|
end
|
40
69
|
|
41
70
|
def trace_entry(time)
|
42
|
-
if @sample.count_segments < segment_limit
|
71
|
+
if @sample.count_segments < segment_limit
|
43
72
|
segment = @sample.create_segment(time.to_f - @sample_start)
|
44
73
|
@current_segment.add_called_segment(segment)
|
45
74
|
@current_segment = segment
|
46
75
|
if @sample.count_segments == segment_limit()
|
47
76
|
::NewRelic::Agent.logger.debug("Segment limit of #{segment_limit} reached, ceasing collection.")
|
48
77
|
end
|
49
|
-
|
78
|
+
else
|
79
|
+
if @current_segment.is_a?(PlaceholderSegment)
|
80
|
+
@current_segment.depth += 1
|
81
|
+
else
|
82
|
+
@current_segment = PlaceholderSegment.new(@current_segment)
|
83
|
+
end
|
50
84
|
end
|
85
|
+
@current_segment
|
51
86
|
end
|
52
87
|
|
53
88
|
def trace_exit(metric_name, time)
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
89
|
+
if @current_segment.is_a?(PlaceholderSegment)
|
90
|
+
@current_segment.depth -= 1
|
91
|
+
if @current_segment.depth == 0
|
92
|
+
@current_segment = @current_segment.parent_segment
|
93
|
+
end
|
94
|
+
else
|
95
|
+
@current_segment.metric_name = metric_name
|
96
|
+
@current_segment.end_trace(time.to_f - @sample_start)
|
97
|
+
@current_segment = @current_segment.parent_segment
|
98
|
+
end
|
58
99
|
end
|
59
100
|
|
60
101
|
def finish_trace(time=Time.now.to_f, custom_params={})
|
@@ -400,12 +400,7 @@ module NewRelic
|
|
400
400
|
end
|
401
401
|
|
402
402
|
# Clamp the number of TTs we'll keep in memory and send
|
403
|
-
#
|
404
403
|
result = clamp_number_tts(result, 20) if result.length > 20
|
405
|
-
|
406
|
-
# Truncate the samples at 2100 segments. The UI will clamp them at 2000 segments anyway.
|
407
|
-
# This will save us memory and bandwidth.
|
408
|
-
result.each { |sample| sample.truncate(Agent.config[:'transaction_tracer.limit_segments']) }
|
409
404
|
result
|
410
405
|
end
|
411
406
|
|