newrelic_rpm 5.5.0.348 → 6.2.0.354
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/.travis.yml +36 -84
- data/.yardopts +1 -0
- data/CHANGELOG.md +149 -0
- data/README.md +1 -1
- data/config.dot +1 -0
- data/lib/new_relic/agent/agent.rb +15 -11
- data/lib/new_relic/agent/attribute_filter.rb +77 -17
- data/lib/new_relic/agent/configuration/default_source.rb +71 -1
- data/lib/new_relic/agent/configuration/security_policy_source.rb +14 -0
- data/lib/new_relic/agent/configuration/server_source.rb +2 -1
- data/lib/new_relic/agent/cross_app_monitor.rb +3 -3
- data/lib/new_relic/agent/datastores/metric_helper.rb +1 -2
- data/lib/new_relic/agent/datastores.rb +6 -8
- data/lib/new_relic/agent/distributed_trace_monitor.rb +1 -2
- data/lib/new_relic/agent/distributed_trace_payload.rb +7 -11
- data/lib/new_relic/agent/error_collector.rb +4 -6
- data/lib/new_relic/agent/external.rb +6 -4
- data/lib/new_relic/agent/hostname.rb +8 -0
- data/lib/new_relic/agent/instrumentation/action_cable_subscriber.rb +8 -5
- data/lib/new_relic/agent/instrumentation/action_controller_subscriber.rb +12 -8
- data/lib/new_relic/agent/instrumentation/action_view_subscriber.rb +1 -1
- data/lib/new_relic/agent/instrumentation/active_job.rb +6 -7
- data/lib/new_relic/agent/instrumentation/active_record.rb +2 -2
- data/lib/new_relic/agent/instrumentation/active_record_subscriber.rb +3 -3
- data/lib/new_relic/agent/instrumentation/active_storage.rb +23 -0
- data/lib/new_relic/agent/instrumentation/active_storage_subscriber.rb +59 -0
- data/lib/new_relic/agent/instrumentation/acts_as_solr.rb +1 -1
- data/lib/new_relic/agent/instrumentation/bunny.rb +16 -12
- data/lib/new_relic/agent/instrumentation/controller_instrumentation.rb +9 -3
- data/lib/new_relic/agent/instrumentation/curb.rb +18 -5
- data/lib/new_relic/agent/instrumentation/data_mapper.rb +1 -1
- data/lib/new_relic/agent/instrumentation/evented_subscriber.rb +1 -1
- data/lib/new_relic/agent/instrumentation/excon/connection.rb +1 -1
- data/lib/new_relic/agent/instrumentation/grape.rb +17 -4
- data/lib/new_relic/agent/instrumentation/middleware_proxy.rb +1 -1
- data/lib/new_relic/agent/instrumentation/middleware_tracing.rb +11 -4
- data/lib/new_relic/agent/instrumentation/net.rb +1 -1
- data/lib/new_relic/agent/instrumentation/rake.rb +2 -3
- data/lib/new_relic/agent/instrumentation/sequel.rb +1 -1
- data/lib/new_relic/agent/instrumentation/typhoeus.rb +3 -3
- data/lib/new_relic/agent/javascript_instrumentor.rb +1 -1
- data/lib/new_relic/agent/messaging.rb +9 -8
- data/lib/new_relic/agent/method_tracer_helpers.rb +2 -2
- data/lib/new_relic/agent/new_relic_service/json_marshaller.rb +0 -1
- data/lib/new_relic/agent/new_relic_service/marshaller.rb +5 -26
- data/lib/new_relic/agent/new_relic_service.rb +69 -25
- data/lib/new_relic/agent/span_event_primitive.rb +26 -16
- data/lib/new_relic/agent/sql_sampler.rb +3 -3
- data/lib/new_relic/agent/stats_engine.rb +2 -2
- data/lib/new_relic/agent/synthetics_monitor.rb +1 -2
- data/lib/new_relic/agent/system_info.rb +5 -0
- data/lib/new_relic/agent/threading/agent_thread.rb +1 -1
- data/lib/new_relic/agent/tracer.rb +462 -0
- data/lib/new_relic/agent/transaction/abstract_segment.rb +1 -1
- data/lib/new_relic/agent/transaction/datastore_segment.rb +0 -2
- data/lib/new_relic/agent/transaction/distributed_tracing.rb +1 -2
- data/lib/new_relic/agent/transaction/trace_node.rb +4 -2
- data/lib/new_relic/agent/transaction/tracing.rb +0 -99
- data/lib/new_relic/agent/transaction.rb +43 -88
- data/lib/new_relic/agent/transaction_time_aggregator.rb +49 -25
- data/lib/new_relic/agent/utilization_data.rb +36 -1
- data/lib/new_relic/agent.rb +8 -4
- data/lib/new_relic/build.rb +2 -2
- data/lib/new_relic/control/frameworks/rails6.rb +14 -0
- data/lib/new_relic/latest_changes.rb +2 -2
- data/lib/new_relic/rack/agent_middleware.rb +1 -1
- data/lib/new_relic/version.rb +2 -2
- data/newrelic_rpm.gemspec +2 -9
- data/test/agent_helper.rb +2 -2
- metadata +13 -39
- data/lib/new_relic/agent/transaction_state.rb +0 -186
@@ -109,13 +109,11 @@ module NewRelic
|
|
109
109
|
end
|
110
110
|
|
111
111
|
def add_instance_parameters
|
112
|
-
return unless NewRelic::Agent.config[:'datastore_tracer.instance_reporting.enabled']
|
113
112
|
params[:host] = host if host
|
114
113
|
params[:port_path_or_id] = port_path_or_id if port_path_or_id
|
115
114
|
end
|
116
115
|
|
117
116
|
def add_database_name_parameter
|
118
|
-
return unless NewRelic::Agent.config[:'datastore_tracer.database_name_reporting.enabled']
|
119
117
|
params[:database_name] = database_name if database_name
|
120
118
|
end
|
121
119
|
|
@@ -156,8 +156,7 @@ module NewRelic
|
|
156
156
|
!payload.parent_type.nil? &&
|
157
157
|
(!payload.transaction_id.nil? || !payload.id.nil?) &&
|
158
158
|
!payload.trace_id.nil? &&
|
159
|
-
!payload.timestamp.nil?
|
160
|
-
!payload.parent_account_id.nil?
|
159
|
+
!payload.timestamp.nil?
|
161
160
|
|
162
161
|
true
|
163
162
|
else
|
@@ -21,8 +21,10 @@ module NewRelic
|
|
21
21
|
@entry_timestamp = relative_start
|
22
22
|
@metric_name = metric_name || UNKNOWN_NODE_NAME
|
23
23
|
@exit_timestamp = relative_end
|
24
|
-
@children
|
25
|
-
@params = params
|
24
|
+
@children = nil
|
25
|
+
@params = params.select do |p|
|
26
|
+
NewRelic::Agent.instance.attribute_filter.allows_key? p, AttributeFilter::DST_TRANSACTION_SEGMENTS
|
27
|
+
end if params
|
26
28
|
@parent_node = parent
|
27
29
|
end
|
28
30
|
|
@@ -2,109 +2,10 @@
|
|
2
2
|
# This file is distributed under New Relic's license terms.
|
3
3
|
# See https://github.com/newrelic/rpm/blob/master/LICENSE for complete details.
|
4
4
|
|
5
|
-
require 'new_relic/agent/transaction/segment'
|
6
|
-
require 'new_relic/agent/transaction/datastore_segment'
|
7
|
-
require 'new_relic/agent/transaction/external_request_segment'
|
8
|
-
require 'new_relic/agent/transaction/message_broker_segment'
|
9
|
-
|
10
5
|
module NewRelic
|
11
6
|
module Agent
|
12
7
|
class Transaction
|
13
8
|
module Tracing
|
14
|
-
module ClassMethods
|
15
|
-
def start_segment(name:nil,
|
16
|
-
unscoped_metrics:nil,
|
17
|
-
start_time: nil,
|
18
|
-
parent: nil)
|
19
|
-
|
20
|
-
# ruby 2.0.0 does not support required kwargs
|
21
|
-
raise ArgumentError, 'missing required argument: name' if name.nil?
|
22
|
-
|
23
|
-
segment = Segment.new name, unscoped_metrics, start_time
|
24
|
-
|
25
|
-
start_and_add_segment segment, parent
|
26
|
-
end
|
27
|
-
|
28
|
-
UNKNOWN_PRODUCT = "Unknown".freeze
|
29
|
-
UNKNOWN_OPERATION = "other".freeze
|
30
|
-
|
31
|
-
def start_datastore_segment(product: nil,
|
32
|
-
operation: nil,
|
33
|
-
collection: nil,
|
34
|
-
host: nil,
|
35
|
-
port_path_or_id: nil,
|
36
|
-
database_name: nil,
|
37
|
-
start_time: nil,
|
38
|
-
parent: nil)
|
39
|
-
|
40
|
-
product ||= UNKNOWN_PRODUCT
|
41
|
-
operation ||= UNKNOWN_OPERATION
|
42
|
-
|
43
|
-
segment = DatastoreSegment.new product, operation, collection, host, port_path_or_id, database_name
|
44
|
-
start_and_add_segment segment, parent
|
45
|
-
end
|
46
|
-
|
47
|
-
def start_external_request_segment(library: nil,
|
48
|
-
uri: nil,
|
49
|
-
procedure: nil,
|
50
|
-
start_time: nil,
|
51
|
-
parent: nil)
|
52
|
-
|
53
|
-
# ruby 2.0.0 does not support required kwargs
|
54
|
-
raise ArgumentError, 'missing required argument: library' if library.nil?
|
55
|
-
raise ArgumentError, 'missing required argument: uri' if uri.nil?
|
56
|
-
raise ArgumentError, 'missing required argument: procedure' if procedure.nil?
|
57
|
-
|
58
|
-
segment = ExternalRequestSegment.new library, uri, procedure, start_time
|
59
|
-
start_and_add_segment segment, parent
|
60
|
-
end
|
61
|
-
|
62
|
-
# @api private
|
63
|
-
#
|
64
|
-
def start_message_broker_segment(action: nil,
|
65
|
-
library: nil,
|
66
|
-
destination_type: nil,
|
67
|
-
destination_name: nil,
|
68
|
-
headers: nil,
|
69
|
-
parameters: nil,
|
70
|
-
start_time: nil,
|
71
|
-
parent: nil)
|
72
|
-
|
73
|
-
# ruby 2.0.0 does not support required kwargs
|
74
|
-
raise ArgumentError, 'missing required argument: action' if action.nil?
|
75
|
-
raise ArgumentError, 'missing required argument: library' if library.nil?
|
76
|
-
raise ArgumentError, 'missing required argument: destination_type' if destination_type.nil?
|
77
|
-
raise ArgumentError, 'missing required argument: destination_name' if destination_name.nil?
|
78
|
-
|
79
|
-
segment = MessageBrokerSegment.new(
|
80
|
-
action: action,
|
81
|
-
library: library,
|
82
|
-
destination_type: destination_type,
|
83
|
-
destination_name: destination_name,
|
84
|
-
headers: headers,
|
85
|
-
parameters: parameters,
|
86
|
-
start_time: start_time
|
87
|
-
)
|
88
|
-
start_and_add_segment segment, parent
|
89
|
-
end
|
90
|
-
|
91
|
-
private
|
92
|
-
|
93
|
-
def start_and_add_segment segment, parent = nil
|
94
|
-
state = NewRelic::Agent::TransactionState.tl_get
|
95
|
-
if (txn = state.current_transaction) && state.is_execution_traced?
|
96
|
-
txn.add_segment segment, parent
|
97
|
-
else
|
98
|
-
segment.record_metrics = false
|
99
|
-
end
|
100
|
-
segment.start
|
101
|
-
segment
|
102
|
-
end
|
103
|
-
end
|
104
|
-
|
105
|
-
def self.included base
|
106
|
-
base.extend ClassMethods
|
107
|
-
end
|
108
9
|
|
109
10
|
attr_reader :current_segment
|
110
11
|
|
@@ -11,6 +11,7 @@ require 'new_relic/agent/transaction/tracing'
|
|
11
11
|
require 'new_relic/agent/transaction/distributed_tracing'
|
12
12
|
require 'new_relic/agent/cross_app_tracing'
|
13
13
|
require 'new_relic/agent/transaction_time_aggregator'
|
14
|
+
require 'new_relic/agent/deprecator'
|
14
15
|
|
15
16
|
module NewRelic
|
16
17
|
module Agent
|
@@ -36,7 +37,7 @@ module NewRelic
|
|
36
37
|
ACTION_CABLE_PREFIX = 'Controller/ActionCable/'.freeze
|
37
38
|
OTHER_TRANSACTION_PREFIX = 'OtherTransaction/'.freeze
|
38
39
|
|
39
|
-
WEB_TRANSACTION_CATEGORIES = [:controller, :uri, :rack, :sinatra, :grape, :middleware, :action_cable].freeze
|
40
|
+
WEB_TRANSACTION_CATEGORIES = [:web, :controller, :uri, :rack, :sinatra, :grape, :middleware, :action_cable].freeze
|
40
41
|
TRANSACTION_NAMING_SOURCES = [:child, :api].freeze
|
41
42
|
|
42
43
|
MIDDLEWARE_SUMMARY_METRICS = ['Middleware/all'.freeze].freeze
|
@@ -64,7 +65,6 @@ module NewRelic
|
|
64
65
|
:metrics,
|
65
66
|
:gc_start_snapshot,
|
66
67
|
:category,
|
67
|
-
:frame_stack,
|
68
68
|
:attributes,
|
69
69
|
:payload,
|
70
70
|
:nesting_max_depth,
|
@@ -83,28 +83,37 @@ module NewRelic
|
|
83
83
|
|
84
84
|
# Return the currently active transaction, or nil.
|
85
85
|
def self.tl_current
|
86
|
-
|
86
|
+
Tracer.current_transaction
|
87
87
|
end
|
88
88
|
|
89
|
-
def self.set_default_transaction_name(
|
89
|
+
def self.set_default_transaction_name(partial_name, category = nil) #THREAD_LOCAL_ACCESS
|
90
90
|
txn = tl_current
|
91
|
-
name =
|
92
|
-
txn.name_last_frame(node_name || name)
|
91
|
+
name = name_from_partial(partial_name, category || txn.category)
|
93
92
|
txn.set_default_transaction_name(name, category)
|
94
93
|
end
|
95
94
|
|
96
|
-
def self.set_overriding_transaction_name(
|
95
|
+
def self.set_overriding_transaction_name(partial_name, category = nil) #THREAD_LOCAL_ACCESS
|
97
96
|
txn = tl_current
|
98
97
|
return unless txn
|
99
98
|
|
100
|
-
name =
|
101
|
-
|
102
|
-
txn.name_last_frame(name)
|
99
|
+
name = name_from_partial(partial_name, category || txn.category)
|
103
100
|
txn.set_overriding_transaction_name(name, category)
|
104
101
|
end
|
105
102
|
|
103
|
+
def self.name_from_partial(partial_name, category)
|
104
|
+
namer = Instrumentation::ControllerInstrumentation::TransactionNamer
|
105
|
+
"#{namer.prefix_for_category(self, category)}#{partial_name}"
|
106
|
+
end
|
107
|
+
|
106
108
|
def self.wrap(state, name, category, options = {})
|
107
|
-
Transaction.
|
109
|
+
Deprecator.deprecate 'Transaction.wrap',
|
110
|
+
'Tracer#in_transaction'
|
111
|
+
|
112
|
+
finishable = Tracer.start_transaction_or_segment(
|
113
|
+
name: name,
|
114
|
+
category: category,
|
115
|
+
options: options
|
116
|
+
)
|
108
117
|
|
109
118
|
begin
|
110
119
|
# We shouldn't raise from Transaction.start, but only wrap the yield
|
@@ -114,24 +123,8 @@ module NewRelic
|
|
114
123
|
Transaction.notice_error(e)
|
115
124
|
raise e
|
116
125
|
ensure
|
117
|
-
|
118
|
-
end
|
119
|
-
end
|
120
|
-
|
121
|
-
def self.start(state, category, options)
|
122
|
-
category ||= :controller
|
123
|
-
txn = state.current_transaction
|
124
|
-
|
125
|
-
if txn
|
126
|
-
txn.create_nested_frame(category, options)
|
127
|
-
else
|
128
|
-
txn = start_new_transaction(state, category, options)
|
126
|
+
finishable.finish if finishable
|
129
127
|
end
|
130
|
-
|
131
|
-
txn
|
132
|
-
rescue => e
|
133
|
-
NewRelic::Agent.logger.error("Exception during Transaction.start", e)
|
134
|
-
nil
|
135
128
|
end
|
136
129
|
|
137
130
|
def self.start_new_transaction(state, category, options)
|
@@ -142,32 +135,6 @@ module NewRelic
|
|
142
135
|
txn
|
143
136
|
end
|
144
137
|
|
145
|
-
FAILED_TO_STOP_MESSAGE = "Failed during Transaction.stop because there is no current transaction"
|
146
|
-
|
147
|
-
def self.stop(state)
|
148
|
-
txn = state.current_transaction
|
149
|
-
|
150
|
-
if txn.nil?
|
151
|
-
NewRelic::Agent.logger.error(FAILED_TO_STOP_MESSAGE)
|
152
|
-
return
|
153
|
-
end
|
154
|
-
|
155
|
-
nested_frame = txn.frame_stack.pop
|
156
|
-
|
157
|
-
if txn.frame_stack.empty?
|
158
|
-
txn.stop(nested_frame) if nested_frame
|
159
|
-
state.reset
|
160
|
-
else
|
161
|
-
nested_frame.finish
|
162
|
-
end
|
163
|
-
|
164
|
-
:transaction_stopped
|
165
|
-
rescue => e
|
166
|
-
state.reset
|
167
|
-
NewRelic::Agent.logger.error("Exception during Transaction.stop", e)
|
168
|
-
nil
|
169
|
-
end
|
170
|
-
|
171
138
|
def self.nested_transaction_name(name)
|
172
139
|
if name.start_with?(CONTROLLER_PREFIX) || name.start_with?(OTHER_TRANSACTION_PREFIX)
|
173
140
|
"#{SUBTRANSACTION_PREFIX}#{name}"
|
@@ -179,15 +146,13 @@ module NewRelic
|
|
179
146
|
# Indicate that you don't want to keep the currently saved transaction
|
180
147
|
# information
|
181
148
|
def self.abort_transaction! #THREAD_LOCAL_ACCESS
|
182
|
-
|
183
|
-
txn = state.current_transaction
|
149
|
+
txn = Tracer.current_transaction
|
184
150
|
txn.abort_transaction! if txn
|
185
151
|
end
|
186
152
|
|
187
153
|
# See NewRelic::Agent.notice_error for options and commentary
|
188
154
|
def self.notice_error(e, options={}) #THREAD_LOCAL_ACCESS
|
189
|
-
|
190
|
-
txn = state.current_transaction
|
155
|
+
txn = Tracer.current_transaction
|
191
156
|
if txn
|
192
157
|
txn.notice_error(e, options)
|
193
158
|
elsif NewRelic::Agent.instance
|
@@ -260,7 +225,6 @@ module NewRelic
|
|
260
225
|
@nesting_max_depth = 0
|
261
226
|
@current_segment = nil
|
262
227
|
@segments = []
|
263
|
-
@frame_stack = []
|
264
228
|
|
265
229
|
self.default_name = options[:transaction_name]
|
266
230
|
@overridden_name = nil
|
@@ -288,6 +252,8 @@ module NewRelic
|
|
288
252
|
@sampled = nil
|
289
253
|
@priority = nil
|
290
254
|
|
255
|
+
@starting_thread_id = Thread.current.object_id
|
256
|
+
|
291
257
|
@attributes = Attributes.new(NewRelic::Agent.instance.attribute_filter)
|
292
258
|
|
293
259
|
merge_request_parameters(@filtered_params)
|
@@ -357,11 +323,6 @@ module NewRelic
|
|
357
323
|
merge_untrusted_agent_attributes(params, :'request.parameters', AttributeFilter::DST_NONE)
|
358
324
|
end
|
359
325
|
|
360
|
-
def make_transaction_name(name, category=nil)
|
361
|
-
namer = Instrumentation::ControllerInstrumentation::TransactionNamer
|
362
|
-
"#{namer.prefix_for_category(self, category)}#{name}"
|
363
|
-
end
|
364
|
-
|
365
326
|
def set_default_transaction_name(name, category)
|
366
327
|
return log_frozen_name(name) if name_frozen?
|
367
328
|
if influences_transaction_name?(category)
|
@@ -378,18 +339,13 @@ module NewRelic
|
|
378
339
|
end
|
379
340
|
end
|
380
341
|
|
381
|
-
def name_last_frame(name)
|
382
|
-
name = self.class.nested_transaction_name(name) if nesting_max_depth > 1
|
383
|
-
frame_stack.last.name = name
|
384
|
-
end
|
385
|
-
|
386
342
|
def log_frozen_name(name)
|
387
343
|
NewRelic::Agent.logger.warn("Attempted to rename transaction to '#{name}' after transaction name was already frozen as '#{@frozen_name}'.")
|
388
344
|
nil
|
389
345
|
end
|
390
346
|
|
391
347
|
def influences_transaction_name?(category)
|
392
|
-
!category ||
|
348
|
+
!category || nesting_max_depth == 1 || similar_category?(category)
|
393
349
|
end
|
394
350
|
|
395
351
|
def best_name
|
@@ -403,10 +359,6 @@ module NewRelic
|
|
403
359
|
attr_accessor :xray_session_id
|
404
360
|
# End common interface
|
405
361
|
|
406
|
-
def name_set?
|
407
|
-
(@overridden_name || @default_name) ? true : false
|
408
|
-
end
|
409
|
-
|
410
362
|
def promoted_transaction_name(name)
|
411
363
|
if name.start_with?(MIDDLEWARE_PREFIX)
|
412
364
|
"#{CONTROLLER_PREFIX}#{name}"
|
@@ -447,14 +399,14 @@ module NewRelic
|
|
447
399
|
|
448
400
|
ignore! if user_defined_rules_ignore?
|
449
401
|
|
450
|
-
create_initial_segment
|
402
|
+
create_initial_segment
|
451
403
|
end
|
452
404
|
|
453
405
|
def initial_segment
|
454
406
|
segments.first
|
455
407
|
end
|
456
408
|
|
457
|
-
def create_initial_segment
|
409
|
+
def create_initial_segment
|
458
410
|
segment = create_segment @default_name
|
459
411
|
segment.record_scoped_metric = false
|
460
412
|
end
|
@@ -468,16 +420,15 @@ module NewRelic
|
|
468
420
|
|
469
421
|
@nesting_max_depth += 1
|
470
422
|
|
471
|
-
segment =
|
423
|
+
segment = Tracer.start_segment(
|
472
424
|
name: name,
|
473
425
|
unscoped_metrics: summary_metrics
|
474
426
|
)
|
475
427
|
|
476
|
-
frame_stack.push segment
|
477
428
|
segment
|
478
429
|
end
|
479
430
|
|
480
|
-
def
|
431
|
+
def create_nested_segment(category, options)
|
481
432
|
if options[:filtered_params] && !options[:filtered_params].empty?
|
482
433
|
@filtered_params = options[:filtered_params]
|
483
434
|
merge_request_parameters(options[:filtered_params])
|
@@ -488,8 +439,9 @@ module NewRelic
|
|
488
439
|
|
489
440
|
nest_initial_segment if nesting_max_depth == 1
|
490
441
|
nested_name = self.class.nested_transaction_name options[:transaction_name]
|
491
|
-
create_segment nested_name
|
442
|
+
result = create_segment nested_name
|
492
443
|
set_default_transaction_name(options[:transaction_name], category)
|
444
|
+
result
|
493
445
|
end
|
494
446
|
|
495
447
|
def nest_initial_segment
|
@@ -527,23 +479,26 @@ module NewRelic
|
|
527
479
|
name.start_with?(MIDDLEWARE_PREFIX)
|
528
480
|
end
|
529
481
|
|
530
|
-
def
|
531
|
-
return
|
532
|
-
return self.class.stop(state) unless outermost_frame
|
533
|
-
|
482
|
+
def finish
|
483
|
+
return unless state.is_execution_traced?
|
534
484
|
@end_time = Time.now
|
535
485
|
@duration = @end_time.to_f - @start_time.to_f
|
536
486
|
freeze_name_and_execute_if_not_ignored
|
537
487
|
|
538
488
|
if nesting_max_depth == 1
|
539
|
-
|
489
|
+
initial_segment.name = @frozen_name
|
540
490
|
end
|
541
491
|
|
542
|
-
|
492
|
+
initial_segment.finish
|
543
493
|
|
544
|
-
NewRelic::Agent::TransactionTimeAggregator.transaction_stop(@end_time)
|
494
|
+
NewRelic::Agent::TransactionTimeAggregator.transaction_stop(@end_time, @starting_thread_id)
|
545
495
|
|
546
|
-
commit!(
|
496
|
+
commit!(initial_segment.name) unless @ignore_this_transaction
|
497
|
+
rescue => e
|
498
|
+
NewRelic::Agent.logger.error("Exception during Transaction#finish", e)
|
499
|
+
nil
|
500
|
+
ensure
|
501
|
+
state.reset
|
547
502
|
end
|
548
503
|
|
549
504
|
def user_defined_rules_ignore?
|
@@ -2,8 +2,6 @@
|
|
2
2
|
# This file is distributed under New Relic's license terms.
|
3
3
|
# See https://github.com/newrelic/rpm/blob/master/LICENSE for complete details.
|
4
4
|
|
5
|
-
require 'objspace'
|
6
|
-
|
7
5
|
# This module powers the Busy calculation for the Capacity report in
|
8
6
|
# APM (https://rpm.newrelic.com/accounts/.../applications/.../optimize/capacity_analysis).
|
9
7
|
#
|
@@ -23,37 +21,37 @@ module NewRelic
|
|
23
21
|
h[k] = TransactionStats.new nil, 0.0
|
24
22
|
end
|
25
23
|
|
26
|
-
def reset!(
|
27
|
-
@harvest_cycle_started_at =
|
24
|
+
def reset!(timestamp = Time.now)
|
25
|
+
@harvest_cycle_started_at = timestamp
|
28
26
|
@stats.clear
|
29
27
|
end
|
30
28
|
|
31
|
-
def transaction_start(
|
29
|
+
def transaction_start(timestamp = Time.now)
|
32
30
|
@lock.synchronize do
|
33
|
-
set_transaction_start_time
|
31
|
+
set_transaction_start_time timestamp
|
34
32
|
end
|
35
33
|
end
|
36
34
|
|
37
|
-
def transaction_stop(
|
35
|
+
def transaction_stop(timestamp = Time.now, starting_thread_id = current_thread)
|
38
36
|
@lock.synchronize do
|
39
|
-
record_elapsed_transaction_time_until
|
40
|
-
set_transaction_start_time nil
|
37
|
+
record_elapsed_transaction_time_until timestamp, starting_thread_id
|
38
|
+
set_transaction_start_time nil, starting_thread_id
|
41
39
|
end
|
42
40
|
end
|
43
41
|
|
44
42
|
INSTANCE_BUSY_METRIC = 'Instance/Busy'.freeze
|
45
43
|
|
46
|
-
def harvest!(
|
44
|
+
def harvest!(timestamp = Time.now)
|
47
45
|
active_threads = 0
|
48
46
|
result = @lock.synchronize do
|
49
47
|
# Sum up the transaction times spent in each thread
|
50
48
|
elapsed_transaction_time = @stats.inject(0.0) do |total, (thread_id, entry)|
|
51
|
-
total + transaction_time_in_thread(thread_id, entry
|
49
|
+
total + transaction_time_in_thread(timestamp, thread_id, entry)
|
52
50
|
end
|
53
51
|
|
54
52
|
active_threads = @stats.size
|
55
|
-
elapsed_harvest_time = (
|
56
|
-
@harvest_cycle_started_at =
|
53
|
+
elapsed_harvest_time = (timestamp - @harvest_cycle_started_at) * active_threads
|
54
|
+
@harvest_cycle_started_at = timestamp
|
57
55
|
|
58
56
|
# Clear out the stats for all threads, _except_ the live ones
|
59
57
|
# that have transactions still open (we'll count the rest of
|
@@ -81,12 +79,16 @@ module NewRelic
|
|
81
79
|
:transaction_stop,
|
82
80
|
:harvest!
|
83
81
|
|
84
|
-
class <<self
|
82
|
+
class << self
|
85
83
|
private
|
86
84
|
|
87
|
-
def record_elapsed_transaction_time_until(timestamp, thread_id
|
88
|
-
@stats[thread_id].
|
89
|
-
|
85
|
+
def record_elapsed_transaction_time_until(timestamp, thread_id = current_thread)
|
86
|
+
if @stats[thread_id].transaction_started_at
|
87
|
+
@stats[thread_id].elapsed_transaction_time +=
|
88
|
+
(timestamp - (@stats[thread_id].transaction_started_at || 0.0))
|
89
|
+
else
|
90
|
+
log_missing_elapsed_transaction_time
|
91
|
+
end
|
90
92
|
end
|
91
93
|
|
92
94
|
def in_transaction?(thread_id = current_thread)
|
@@ -98,33 +100,55 @@ module NewRelic
|
|
98
100
|
end
|
99
101
|
|
100
102
|
def thread_is_alive?(thread_id)
|
101
|
-
thread =
|
103
|
+
thread = thread_by_id thread_id
|
102
104
|
thread && thread.alive?
|
103
105
|
rescue StandardError
|
104
106
|
false
|
105
107
|
end
|
106
108
|
|
107
|
-
|
108
|
-
|
109
|
+
# ObjectSpace is faster on MRI, but disabled by default on JRuby for
|
110
|
+
# perfomance reasons. We have two implmentations of `thread_by_id`
|
111
|
+
# based on ruby implementation.
|
112
|
+
if RUBY_ENGINE == 'jruby'
|
113
|
+
def thread_by_id thread_id
|
114
|
+
Thread.list.detect { |t| t.object_id == thread_id }
|
115
|
+
end
|
116
|
+
else
|
117
|
+
require 'objspace'
|
118
|
+
|
119
|
+
def thread_by_id thread_id
|
120
|
+
ObjectSpace._id2ref(thread_id)
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
def set_transaction_start_time(timestamp, thread_id = current_thread)
|
125
|
+
@stats[thread_id].transaction_started_at = timestamp
|
109
126
|
end
|
110
127
|
|
111
|
-
def split_transaction_at_harvest(
|
128
|
+
def split_transaction_at_harvest(timestamp, thread_id = nil)
|
112
129
|
raise ArgumentError, 'thread_id required' unless thread_id
|
113
|
-
@stats[thread_id].transaction_started_at =
|
130
|
+
@stats[thread_id].transaction_started_at = timestamp
|
114
131
|
@stats[thread_id].elapsed_transaction_time = 0.0
|
115
132
|
end
|
116
133
|
|
117
|
-
def transaction_time_in_thread thread_id, entry
|
134
|
+
def transaction_time_in_thread timestamp, thread_id, entry
|
118
135
|
return entry.elapsed_transaction_time unless in_transaction? thread_id
|
119
136
|
|
120
137
|
# Count the portion of the transaction that's elapsed so far,...
|
121
|
-
elapsed = record_elapsed_transaction_time_until
|
138
|
+
elapsed = record_elapsed_transaction_time_until timestamp, thread_id
|
122
139
|
|
123
140
|
# ...then readjust the transaction start time to the next harvest
|
124
|
-
split_transaction_at_harvest
|
141
|
+
split_transaction_at_harvest timestamp, thread_id
|
125
142
|
|
126
143
|
elapsed
|
127
144
|
end
|
145
|
+
|
146
|
+
def log_missing_elapsed_transaction_time
|
147
|
+
transaction_name = Tracer.current_transaction &&
|
148
|
+
Tracer.current_transaction.best_name ||
|
149
|
+
"unknown"
|
150
|
+
NewRelic::Agent.logger.warn("Unable to calculate elapsed transaction time for #{transaction_name}")
|
151
|
+
end
|
128
152
|
end
|
129
153
|
end
|
130
154
|
end
|