newrelic_rpm 4.8.0.341 → 5.1.0.344
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.travis.yml +27 -0
- data/CHANGELOG.md +93 -0
- data/README.md +0 -3
- data/config.dot +0 -3
- data/lib/new_relic/agent/{throughput_monitor.rb → adaptive_sampler.rb} +22 -13
- data/lib/new_relic/agent/agent.rb +3 -4
- data/lib/new_relic/agent/configuration/default_source.rb +41 -19
- data/lib/new_relic/agent/configuration/high_security_source.rb +0 -2
- data/lib/new_relic/agent/database/explain_plan_helpers.rb +11 -0
- data/lib/new_relic/agent/database.rb +5 -0
- data/lib/new_relic/agent/distributed_trace_monitor.rb +4 -2
- data/lib/new_relic/agent/distributed_trace_payload.rb +85 -119
- data/lib/new_relic/agent/error_collector.rb +17 -1
- data/lib/new_relic/agent/external.rb +14 -0
- data/lib/new_relic/agent/heap.rb +140 -0
- data/lib/new_relic/agent/instrumentation/active_record_5.rb +5 -0
- data/lib/new_relic/agent/instrumentation/active_record_prepend.rb +14 -1
- data/lib/new_relic/agent/instrumentation/bunny.rb +5 -1
- data/lib/new_relic/agent/instrumentation/grape.rb +33 -29
- data/lib/new_relic/agent/instrumentation/rails5/action_cable.rb +5 -1
- data/lib/new_relic/agent/instrumentation/resque.rb +17 -36
- data/lib/new_relic/agent/instrumentation/sequel.rb +0 -1
- data/lib/new_relic/agent/javascript_instrumentor.rb +2 -2
- data/lib/new_relic/agent/messaging.rb +10 -0
- data/lib/new_relic/agent/method_tracer.rb +23 -18
- data/lib/new_relic/agent/new_relic_service.rb +43 -23
- data/lib/new_relic/agent/priority_sampled_buffer.rb +68 -0
- data/lib/new_relic/agent/supported_versions.rb +1 -1
- data/lib/new_relic/agent/transaction/attributes.rb +1 -0
- data/lib/new_relic/agent/transaction/distributed_tracing.rb +173 -55
- data/lib/new_relic/agent/transaction/external_request_segment.rb +14 -64
- data/lib/new_relic/agent/transaction/message_broker_segment.rb +12 -4
- data/lib/new_relic/agent/transaction.rb +15 -8
- data/lib/new_relic/agent/transaction_error_primitive.rb +2 -8
- data/lib/new_relic/agent/transaction_event_aggregator.rb +16 -13
- data/lib/new_relic/agent/transaction_event_primitive.rb +5 -3
- data/lib/new_relic/agent/transaction_event_recorder.rb +3 -11
- data/lib/new_relic/agent.rb +27 -0
- data/lib/new_relic/build.rb +2 -2
- data/lib/new_relic/recipes/capistrano3.rb +5 -2
- data/lib/new_relic/version.rb +2 -2
- data/newrelic_rpm.gemspec +3 -2
- metadata +39 -9
- data/lib/new_relic/agent/distributed_trace_priority_sampled_buffer.rb +0 -72
@@ -22,52 +22,33 @@ DependencyDetection.defer do
|
|
22
22
|
end
|
23
23
|
|
24
24
|
executes do
|
25
|
-
module Resque
|
26
|
-
|
27
|
-
|
28
|
-
include NewRelic::Agent::Instrumentation::ControllerInstrumentation
|
25
|
+
module ::Resque
|
26
|
+
class Job
|
27
|
+
include NewRelic::Agent::Instrumentation::ControllerInstrumentation
|
29
28
|
|
30
|
-
|
31
|
-
begin
|
32
|
-
perform_action_with_newrelic_trace(
|
33
|
-
:name => 'perform',
|
34
|
-
:class_name => self.name,
|
35
|
-
:category => 'OtherTransaction/ResqueJob') do
|
29
|
+
alias_method :perform_without_instrumentation, :perform
|
36
30
|
|
37
|
-
|
38
|
-
|
31
|
+
def perform
|
32
|
+
begin
|
33
|
+
perform_action_with_newrelic_trace(
|
34
|
+
:name => 'perform',
|
35
|
+
:class_name => self.payload_class,
|
36
|
+
:category => 'OtherTransaction/ResqueJob') do
|
39
37
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
end
|
45
|
-
end
|
46
|
-
end
|
47
|
-
end
|
48
|
-
end
|
38
|
+
NewRelic::Agent::Transaction.merge_untrusted_agent_attributes(
|
39
|
+
args,
|
40
|
+
:'job.resque.args',
|
41
|
+
NewRelic::Agent::AttributeFilter::DST_NONE)
|
49
42
|
|
50
|
-
|
51
|
-
module Agent
|
52
|
-
module Instrumentation
|
53
|
-
module ResqueInstrumentationInstaller
|
54
|
-
def payload_class
|
55
|
-
klass = super
|
56
|
-
klass.instance_eval do
|
57
|
-
extend ::Resque::Plugins::NewRelicInstrumentation
|
58
|
-
end
|
43
|
+
perform_without_instrumentation
|
59
44
|
end
|
45
|
+
ensure
|
46
|
+
NewRelic::Agent.agent.flush_pipe_data
|
60
47
|
end
|
61
48
|
end
|
62
49
|
end
|
63
50
|
end
|
64
51
|
|
65
|
-
::Resque::Job.class_eval do
|
66
|
-
def self.new(*args)
|
67
|
-
super(*args).extend NewRelic::Agent::Instrumentation::ResqueInstrumentationInstaller
|
68
|
-
end
|
69
|
-
end
|
70
|
-
|
71
52
|
if NewRelic::LanguageSupport.can_fork?
|
72
53
|
::Resque.before_first_fork do
|
73
54
|
NewRelic::Agent.manual_start(:dispatcher => :resque,
|
@@ -104,7 +104,7 @@ module NewRelic
|
|
104
104
|
end
|
105
105
|
|
106
106
|
def browser_timing_loader
|
107
|
-
html_safe_if_needed("\n<script
|
107
|
+
html_safe_if_needed("\n<script>#{Agent.config[:js_agent_loader]}</script>")
|
108
108
|
end
|
109
109
|
|
110
110
|
def browser_timing_config(state)
|
@@ -114,7 +114,7 @@ module NewRelic
|
|
114
114
|
txn.freeze_name_and_execute_if_not_ignored do
|
115
115
|
data = data_for_js_agent(state)
|
116
116
|
json = ::JSON.dump(data)
|
117
|
-
return html_safe_if_needed("\n<script
|
117
|
+
return html_safe_if_needed("\n<script>window.NREUM||(NREUM={});NREUM.info=#{json}</script>")
|
118
118
|
end
|
119
119
|
|
120
120
|
''
|
@@ -364,7 +364,17 @@ module NewRelic
|
|
364
364
|
transaction_name
|
365
365
|
end
|
366
366
|
|
367
|
+
NEWRELIC_TRACE_KEY = "NewRelicTrace".freeze
|
368
|
+
RABBITMQ_TRANSPORT_TYPE = "RabbitMQ".freeze
|
369
|
+
|
367
370
|
def consume_message_headers headers, transaction, state
|
371
|
+
if Agent.config[:'distributed_tracing.enabled']
|
372
|
+
payload = headers[NEWRELIC_TRACE_KEY]
|
373
|
+
if transaction.accept_distributed_trace_payload payload
|
374
|
+
transaction.distributed_trace_payload.caller_transport_type = RABBITMQ_TRANSPORT_TYPE
|
375
|
+
end
|
376
|
+
end
|
377
|
+
|
368
378
|
if CrossAppTracing.cross_app_enabled? && CrossAppTracing.message_has_crossapp_request_header?(headers)
|
369
379
|
decode_id headers[CrossAppTracing::NR_MESSAGE_BROKER_ID_HEADER], state
|
370
380
|
decode_txn_info headers[CrossAppTracing::NR_MESSAGE_BROKER_TXN_HEADER], state
|
@@ -291,7 +291,27 @@ module NewRelic
|
|
291
291
|
#
|
292
292
|
# @api public
|
293
293
|
#
|
294
|
-
def add_method_tracer(method_name, metric_name_code=nil, options = {})
|
294
|
+
def add_method_tracer(method_name, metric_name_code = nil, options = {})
|
295
|
+
::NewRelic::Agent.add_or_defer_method_tracer(self, method_name, metric_name_code, options)
|
296
|
+
end
|
297
|
+
|
298
|
+
# For tests only because tracers must be removed in reverse-order
|
299
|
+
# from when they were added, or else other tracers that were added to the same method
|
300
|
+
# may get removed as well.
|
301
|
+
def remove_method_tracer(method_name, metric_name_code) # :nodoc:
|
302
|
+
return unless Agent.config[:agent_enabled]
|
303
|
+
if method_defined? "#{_traced_method_name(method_name, metric_name_code)}"
|
304
|
+
alias_method method_name, "#{_untraced_method_name(method_name, metric_name_code)}"
|
305
|
+
undef_method "#{_traced_method_name(method_name, metric_name_code)}"
|
306
|
+
::NewRelic::Agent.logger.debug("removed method tracer #{method_name} #{metric_name_code}\n")
|
307
|
+
else
|
308
|
+
raise "No tracer for '#{metric_name_code}' on method '#{method_name}'"
|
309
|
+
end
|
310
|
+
end
|
311
|
+
|
312
|
+
private
|
313
|
+
|
314
|
+
def _add_method_tracer_now(method_name, metric_name_code, options)
|
295
315
|
NewRelic::Agent.record_api_supportability_metric(:add_method_tracer)
|
296
316
|
|
297
317
|
return unless newrelic_method_exists?(method_name)
|
@@ -308,24 +328,9 @@ module NewRelic
|
|
308
328
|
send visibility, method_name
|
309
329
|
send visibility, _traced_method_name(method_name, metric_name_code)
|
310
330
|
::NewRelic::Agent.logger.debug("Traced method: class = #{derived_class_name},"+
|
311
|
-
|
312
|
-
|
313
|
-
end
|
314
|
-
|
315
|
-
# For tests only because tracers must be removed in reverse-order
|
316
|
-
# from when they were added, or else other tracers that were added to the same method
|
317
|
-
# may get removed as well.
|
318
|
-
def remove_method_tracer(method_name, metric_name_code) # :nodoc:
|
319
|
-
return unless Agent.config[:agent_enabled]
|
320
|
-
if method_defined? "#{_traced_method_name(method_name, metric_name_code)}"
|
321
|
-
alias_method method_name, "#{_untraced_method_name(method_name, metric_name_code)}"
|
322
|
-
undef_method "#{_traced_method_name(method_name, metric_name_code)}"
|
323
|
-
::NewRelic::Agent.logger.debug("removed method tracer #{method_name} #{metric_name_code}\n")
|
324
|
-
else
|
325
|
-
raise "No tracer for '#{metric_name_code}' on method '#{method_name}'"
|
326
|
-
end
|
331
|
+
"method = #{method_name}, "+
|
332
|
+
"metric = '#{metric_name_code}'")
|
327
333
|
end
|
328
|
-
private
|
329
334
|
|
330
335
|
# given a method and a metric, this method returns the
|
331
336
|
# untraced alias of the method name
|
@@ -15,7 +15,8 @@ module NewRelic
|
|
15
15
|
# Specifies the version of the agent's communication protocol with
|
16
16
|
# the NewRelic hosted site.
|
17
17
|
|
18
|
-
PROTOCOL_VERSION =
|
18
|
+
PROTOCOL_VERSION = 15
|
19
|
+
|
19
20
|
# 1f147a42: v10 (tag 3.5.3.17)
|
20
21
|
# cf0d1ff1: v9 (tag 3.5.0)
|
21
22
|
# 14105: v8 (tag 2.10.3)
|
@@ -30,8 +31,8 @@ module NewRelic
|
|
30
31
|
# underlying TCP connection may be in a bad state.
|
31
32
|
CONNECTION_ERRORS = [Timeout::Error, EOFError, SystemCallError, SocketError].freeze
|
32
33
|
|
33
|
-
attr_accessor :request_timeout
|
34
|
-
attr_reader :collector, :marshaller
|
34
|
+
attr_accessor :request_timeout
|
35
|
+
attr_reader :collector, :marshaller, :agent_id
|
35
36
|
|
36
37
|
def initialize(license_key=nil, collector=control.server)
|
37
38
|
@license_key = license_key
|
@@ -41,18 +42,12 @@ module NewRelic
|
|
41
42
|
@in_session = nil
|
42
43
|
@agent_id = nil
|
43
44
|
@shared_tcp_connection = nil
|
45
|
+
reset_remote_method_uris
|
44
46
|
|
45
47
|
@audit_logger = ::NewRelic::Agent::AuditLogger.new
|
46
48
|
Agent.config.register_callback(:'audit_log.enabled') do |enabled|
|
47
49
|
@audit_logger.enabled = enabled
|
48
50
|
end
|
49
|
-
Agent.config.register_callback(:ssl) do |ssl|
|
50
|
-
if !ssl
|
51
|
-
::NewRelic::Agent.logger.warn("Agent is configured not to use SSL when communicating with New Relic's servers")
|
52
|
-
else
|
53
|
-
::NewRelic::Agent.logger.debug("Agent is configured to use SSL")
|
54
|
-
end
|
55
|
-
end
|
56
51
|
|
57
52
|
Agent.config.register_callback(:marshaller) do |marshaller|
|
58
53
|
if marshaller != 'json'
|
@@ -63,17 +58,26 @@ module NewRelic
|
|
63
58
|
end
|
64
59
|
end
|
65
60
|
|
61
|
+
def agent_id=(id)
|
62
|
+
# Remote URIs have the agent run ID in them, so we need to
|
63
|
+
# clear out our cached values whenever the run ID changes.
|
64
|
+
#
|
65
|
+
reset_remote_method_uris
|
66
|
+
|
67
|
+
@agent_id = id
|
68
|
+
end
|
69
|
+
|
66
70
|
def connect(settings={})
|
67
|
-
if host =
|
71
|
+
if host = preconnect
|
68
72
|
@collector = NewRelic::Control.instance.server_from_host(host)
|
69
73
|
end
|
70
74
|
response = invoke_remote(:connect, [settings])
|
71
|
-
|
75
|
+
self.agent_id = response['agent_run_id']
|
72
76
|
response
|
73
77
|
end
|
74
78
|
|
75
|
-
def
|
76
|
-
invoke_remote(:
|
79
|
+
def preconnect
|
80
|
+
invoke_remote(:preconnect)
|
77
81
|
end
|
78
82
|
|
79
83
|
def shutdown(time)
|
@@ -261,8 +265,7 @@ module NewRelic
|
|
261
265
|
conn.verify_mode = OpenSSL::SSL::VERIFY_PEER
|
262
266
|
conn.cert_store = ssl_cert_store
|
263
267
|
rescue StandardError, LoadError
|
264
|
-
msg = "
|
265
|
-
msg << "Either disable SSL in the agent configuration, or install SSL support."
|
268
|
+
msg = "SSL is not available in the environment; please install SSL support."
|
266
269
|
raise UnrecoverableAgentException.new(msg)
|
267
270
|
end
|
268
271
|
|
@@ -296,7 +299,7 @@ module NewRelic
|
|
296
299
|
conn = Net::HTTP.new(@collector.name, @collector.port)
|
297
300
|
end
|
298
301
|
|
299
|
-
setup_connection_for_ssl(conn)
|
302
|
+
setup_connection_for_ssl(conn)
|
300
303
|
setup_connection_timeouts(conn)
|
301
304
|
|
302
305
|
::NewRelic::Agent.logger.debug("Created net/http handle to #{conn.address}:#{conn.port}")
|
@@ -335,11 +338,28 @@ module NewRelic
|
|
335
338
|
NewRelic::Control.instance
|
336
339
|
end
|
337
340
|
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
342
|
-
|
341
|
+
def remote_method_uri(method)
|
342
|
+
@remote_method_uris[method]
|
343
|
+
end
|
344
|
+
|
345
|
+
def reset_remote_method_uris
|
346
|
+
@remote_method_uris = Hash.new do |hash, remote_method|
|
347
|
+
hash[remote_method] = generate_remote_method_uri(remote_method)
|
348
|
+
end
|
349
|
+
end
|
350
|
+
|
351
|
+
def generate_remote_method_uri(method)
|
352
|
+
params = {
|
353
|
+
'protocol_version' => PROTOCOL_VERSION,
|
354
|
+
'license_key' => license_key,
|
355
|
+
'run_id' => @agent_id,
|
356
|
+
'method' => method,
|
357
|
+
'marshal_format' => 'json', # Other formats are explicitly
|
358
|
+
# ruled out; see the initializer
|
359
|
+
}
|
360
|
+
|
361
|
+
uri = "/agent_listener/invoke_raw_method?"
|
362
|
+
uri << params.map do |k,v|
|
343
363
|
next unless v
|
344
364
|
"#{k}=#{v}"
|
345
365
|
end.compact.join('&')
|
@@ -368,7 +388,7 @@ module NewRelic
|
|
368
388
|
data, encoding = compress_request_if_needed(data)
|
369
389
|
size = data.size
|
370
390
|
|
371
|
-
uri = remote_method_uri(method
|
391
|
+
uri = remote_method_uri(method)
|
372
392
|
full_uri = "#{@collector}#{uri}"
|
373
393
|
|
374
394
|
@audit_logger.log_request(full_uri, payload, @marshaller)
|
@@ -0,0 +1,68 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# This file is distributed under New Relic's license terms.
|
3
|
+
# See https://github.com/newrelic/rpm/blob/master/LICENSE for complete details.
|
4
|
+
|
5
|
+
require 'new_relic/agent/heap'
|
6
|
+
|
7
|
+
module NewRelic
|
8
|
+
module Agent
|
9
|
+
class PrioritySampledBuffer < SampledBuffer
|
10
|
+
PRIORITY_KEY = "priority".freeze
|
11
|
+
|
12
|
+
attr_reader :seen_lifetime, :captured_lifetime
|
13
|
+
|
14
|
+
def initialize(capacity)
|
15
|
+
super
|
16
|
+
@captured_lifetime = 0
|
17
|
+
@seen_lifetime = 0
|
18
|
+
end
|
19
|
+
|
20
|
+
# expects priority and a block, or an event as a hash with a `priority` key.
|
21
|
+
def append(priority: nil, event: nil, &blk)
|
22
|
+
increment_seen
|
23
|
+
|
24
|
+
if @seen == @capacity
|
25
|
+
@items = Heap.new(@items) { |x| priority_for(x) }
|
26
|
+
end
|
27
|
+
|
28
|
+
if full?
|
29
|
+
priority ||= priority_for(event)
|
30
|
+
if priority_for(@items[0]) < priority
|
31
|
+
@items[0] = event || blk.call
|
32
|
+
@items.fix(0)
|
33
|
+
end
|
34
|
+
else
|
35
|
+
@items << (event || blk.call)
|
36
|
+
@captured_lifetime += 1
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
alias_method :append_event, :append
|
41
|
+
|
42
|
+
def capacity=(new_capacity)
|
43
|
+
@capacity = new_capacity
|
44
|
+
old_items = @items.to_a
|
45
|
+
old_seen = @seen
|
46
|
+
reset!
|
47
|
+
old_items.each { |i| append(event: i) }
|
48
|
+
@seen = old_seen
|
49
|
+
end
|
50
|
+
|
51
|
+
def to_a
|
52
|
+
@items.to_a.dup
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
def increment_seen
|
58
|
+
@seen += 1
|
59
|
+
@seen_lifetime += 1
|
60
|
+
end
|
61
|
+
|
62
|
+
def priority_for(event)
|
63
|
+
event[0][PRIORITY_KEY]
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
@@ -11,7 +11,7 @@ module NewRelic
|
|
11
11
|
{
|
12
12
|
:type => :ruby,
|
13
13
|
:name => "MRI",
|
14
|
-
:supported => ["2.0.0", "~>2.1.0", "~>2.2.0", "~>2.3.0", "~>2.4.0"],
|
14
|
+
:supported => ["2.0.0", "~>2.1.0", "~>2.2.0", "~>2.3.0", "~>2.4.0", "~>2.5.0"],
|
15
15
|
:deprecated => ["1.8.6", "1.8.7", "1.9.2", "1.9.3"],
|
16
16
|
:url => "https://www.ruby-lang.org",
|
17
17
|
:feed => "https://www.ruby-lang.org/en/feeds/news.rss",
|
@@ -14,92 +14,79 @@ module NewRelic
|
|
14
14
|
!!distributed_trace_payload
|
15
15
|
end
|
16
16
|
|
17
|
-
|
17
|
+
SUPPORTABILITY_CREATE_PAYLOAD_SUCCESS = "Supportability/DistributedTrace/CreatePayload/Success".freeze
|
18
|
+
SUPPORTABILITY_CREATE_PAYLOAD_EXCEPTION = "Supportability/DistributedTrace/CreatePayload/Exception".freeze
|
19
|
+
|
20
|
+
def create_distributed_trace_payload
|
18
21
|
return unless Agent.config[:'distributed_tracing.enabled']
|
19
|
-
self.
|
20
|
-
DistributedTracePayload.for_transaction self
|
22
|
+
self.distributed_trace_payload_created = true
|
23
|
+
payload = DistributedTracePayload.for_transaction self
|
24
|
+
NewRelic::Agent.increment_metric SUPPORTABILITY_CREATE_PAYLOAD_SUCCESS
|
25
|
+
payload
|
26
|
+
rescue => e
|
27
|
+
NewRelic::Agent.increment_metric SUPPORTABILITY_CREATE_PAYLOAD_EXCEPTION
|
28
|
+
NewRelic::Agent.logger.warn "Failed to create distributed trace payload", e
|
29
|
+
nil
|
21
30
|
end
|
22
31
|
|
23
|
-
|
32
|
+
SUPPORTABILITY_ACCEPT_PAYLOAD_SUCCESS = "Supportability/DistributedTrace/AcceptPayload/Success".freeze
|
33
|
+
SUPPORTABILITY_ACCEPT_PAYLOAD_EXCEPTION = "Supportability/DistributedTrace/AcceptPayload/Exception".freeze
|
24
34
|
|
25
|
-
def accept_distributed_trace_payload
|
35
|
+
def accept_distributed_trace_payload payload
|
26
36
|
return unless Agent.config[:'distributed_tracing.enabled']
|
27
|
-
if
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
NewRelic::Agent.increment_metric "Supportability/DistributedTracing/AcceptFailure/CreateDistributedTracePayload-before-AcceptDistributedTracePayload"
|
32
|
-
return false
|
33
|
-
elsif name_frozen?
|
34
|
-
NewRelic::Agent.increment_metric "Supportability/DistributedTracing/AcceptFailure/BrowserAgentInjected"
|
35
|
-
return false
|
36
|
-
end
|
37
|
-
|
38
|
-
payload = if payload.start_with? LBRACE
|
39
|
-
DistributedTracePayload.from_json payload
|
40
|
-
else
|
41
|
-
DistributedTracePayload.from_http_safe payload
|
42
|
-
end
|
43
|
-
|
44
|
-
payload.caller_transport_type = transport_type
|
45
|
-
self.distributed_trace_payload = payload
|
37
|
+
return false if check_payload_ignored(payload)
|
38
|
+
return false unless payload = decode_payload(payload)
|
39
|
+
return false unless check_valid_version(payload)
|
40
|
+
return false unless check_trusted_account(payload)
|
46
41
|
|
47
|
-
|
42
|
+
assign_payload_and_sampling_params(payload)
|
48
43
|
|
44
|
+
NewRelic::Agent.increment_metric SUPPORTABILITY_ACCEPT_PAYLOAD_SUCCESS
|
49
45
|
true
|
50
46
|
rescue => e
|
51
|
-
NewRelic::Agent.increment_metric
|
47
|
+
NewRelic::Agent.increment_metric SUPPORTABILITY_ACCEPT_PAYLOAD_EXCEPTION
|
52
48
|
NewRelic::Agent.logger.warn "Failed to accept distributed trace payload", e
|
53
49
|
false
|
54
50
|
end
|
55
51
|
|
56
|
-
def
|
52
|
+
def trace_id
|
57
53
|
if distributed_trace_payload
|
58
|
-
distributed_trace_payload.
|
54
|
+
distributed_trace_payload.trace_id
|
59
55
|
else
|
60
56
|
guid
|
61
57
|
end
|
62
58
|
end
|
63
59
|
|
64
|
-
def
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
inbound_ids.push guid
|
70
|
-
if inbound_ids.size > 3
|
71
|
-
inbound_ids.shift
|
72
|
-
end
|
73
|
-
inbound_ids
|
74
|
-
else
|
75
|
-
[guid]
|
76
|
-
end
|
60
|
+
def parent_id
|
61
|
+
# The payload comes from our parent transaction, so its ID
|
62
|
+
# is our parent ID.
|
63
|
+
#
|
64
|
+
distributed_trace_payload && distributed_trace_payload.id
|
77
65
|
end
|
78
66
|
|
79
|
-
def
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
end
|
67
|
+
def grandparent_id
|
68
|
+
# The payload comes from our parent transaction, so its
|
69
|
+
# parent ID is our grandparent ID.
|
70
|
+
#
|
71
|
+
distributed_trace_payload && distributed_trace_payload.parent_id
|
85
72
|
end
|
86
73
|
|
87
|
-
def
|
88
|
-
@
|
74
|
+
def distributed_trace_payload_created?
|
75
|
+
@distributed_trace_payload_created ||= false
|
89
76
|
end
|
90
77
|
|
91
|
-
attr_writer :
|
78
|
+
attr_writer :distributed_trace_payload_created
|
92
79
|
|
93
|
-
def
|
80
|
+
def append_distributed_trace_info transaction_payload
|
94
81
|
return unless Agent.config[:'distributed_tracing.enabled']
|
95
82
|
if distributed_trace_payload
|
96
|
-
distributed_trace_payload.assign_intrinsics self,
|
97
|
-
elsif
|
98
|
-
DistributedTracePayload.
|
83
|
+
distributed_trace_payload.assign_intrinsics self, transaction_payload
|
84
|
+
elsif distributed_trace_payload_created?
|
85
|
+
DistributedTracePayload.assign_intrinsics_for_first_trace self, transaction_payload
|
99
86
|
end
|
100
87
|
end
|
101
88
|
|
102
|
-
def
|
89
|
+
def assign_distributed_trace_intrinsics
|
103
90
|
return unless Agent.config[:'distributed_tracing.enabled']
|
104
91
|
DistributedTracePayload::INTRINSIC_KEYS.each do |key|
|
105
92
|
next unless value = @payload[key]
|
@@ -115,7 +102,138 @@ module NewRelic
|
|
115
102
|
return unless distributed_trace_payload
|
116
103
|
(start_time.to_f * 1000 - distributed_trace_payload.timestamp) / 1000
|
117
104
|
end
|
105
|
+
|
106
|
+
private
|
107
|
+
|
108
|
+
SUPPORTABILITY_CREATE_BEFORE_ACCEPT_PAYLOAD = "Supportability/DistributedTrace/AcceptPayload/Ignored/CreateBeforeAccept".freeze
|
109
|
+
SUPPORTABILITY_MULTIPLE_ACCEPT_PAYLOAD = "Supportability/DistributedTrace/AcceptPayload/Ignored/Multiple".freeze
|
110
|
+
SUPPORTABILITY_PAYLOAD_ACCEPT_IGNORED_NULL = "Supportability/DistributedTrace/AcceptPayload/Ignored/Null".freeze
|
111
|
+
SUPPORTABILITY_PAYLOAD_ACCEPT_IGNORED_BROWSER = "Supportability/DistributedTrace/AcceptPayload/Ignored/BrowserAgentInjected".freeze
|
112
|
+
|
113
|
+
def check_payload_ignored(payload)
|
114
|
+
if payload.nil?
|
115
|
+
NewRelic::Agent.increment_metric SUPPORTABILITY_PAYLOAD_ACCEPT_IGNORED_NULL
|
116
|
+
return true
|
117
|
+
elsif distributed_trace_payload
|
118
|
+
NewRelic::Agent.increment_metric SUPPORTABILITY_MULTIPLE_ACCEPT_PAYLOAD
|
119
|
+
return true
|
120
|
+
elsif distributed_trace_payload_created?
|
121
|
+
NewRelic::Agent.increment_metric SUPPORTABILITY_CREATE_BEFORE_ACCEPT_PAYLOAD
|
122
|
+
return true
|
123
|
+
end
|
124
|
+
false
|
125
|
+
end
|
126
|
+
|
127
|
+
SUPPORTABILITY_PAYLOAD_ACCEPT_IGNORED_PARSE_EXCEPTION = "Supportability/DistributedTrace/AcceptPayload/ParseException".freeze
|
128
|
+
LBRACE = "{".freeze
|
129
|
+
|
130
|
+
def decode_payload(payload)
|
131
|
+
if payload.start_with? LBRACE
|
132
|
+
DistributedTracePayload.from_json payload
|
133
|
+
else
|
134
|
+
DistributedTracePayload.from_http_safe payload
|
135
|
+
end
|
136
|
+
rescue => e
|
137
|
+
NewRelic::Agent.increment_metric SUPPORTABILITY_PAYLOAD_ACCEPT_IGNORED_PARSE_EXCEPTION
|
138
|
+
NewRelic::Agent.logger.warn "Error parsing distributed trace payload", e
|
139
|
+
nil
|
140
|
+
end
|
141
|
+
|
142
|
+
SUPPORTABILITY_PAYLOAD_ACCEPT_IGNORED_MAJOR_VERSION = "Supportability/DistributedTrace/AcceptPayload/Ignored/MajorVersion".freeze
|
143
|
+
|
144
|
+
def check_valid_version(payload)
|
145
|
+
if DistributedTracePayload.major_version_matches?(payload)
|
146
|
+
true
|
147
|
+
else
|
148
|
+
NewRelic::Agent.increment_metric SUPPORTABILITY_PAYLOAD_ACCEPT_IGNORED_MAJOR_VERSION
|
149
|
+
false
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
SUPPORTABILITY_PAYLOAD_ACCEPT_UNTRUSTED_ACCOUNT = "Supportability/DistributedTrace/AcceptPayload/Ignored/UntrustedAccount".freeze
|
154
|
+
|
155
|
+
def check_trusted_account(payload)
|
156
|
+
trusted_account_ids = NewRelic::Agent.config[:trusted_account_ids]
|
157
|
+
trusted = trusted_account_ids.include?(payload.parent_account_id.to_i)
|
158
|
+
|
159
|
+
unless trusted
|
160
|
+
NewRelic::Agent.increment_metric SUPPORTABILITY_PAYLOAD_ACCEPT_UNTRUSTED_ACCOUNT
|
161
|
+
return false
|
162
|
+
end
|
163
|
+
|
164
|
+
true
|
165
|
+
end
|
166
|
+
|
167
|
+
def assign_payload_and_sampling_params(payload)
|
168
|
+
self.distributed_trace_payload = payload
|
169
|
+
|
170
|
+
unless payload.sampled.nil?
|
171
|
+
self.sampled = payload.sampled
|
172
|
+
self.priority = payload.priority if payload.priority
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
ALL_SUFFIX = "all".freeze
|
177
|
+
ALL_WEB_SUFFIX = "allWeb".freeze
|
178
|
+
ALL_OTHER_SUFFIX = "allOther".freeze
|
179
|
+
|
180
|
+
def transaction_type_suffix
|
181
|
+
if Transaction.recording_web_transaction?
|
182
|
+
ALL_WEB_SUFFIX
|
183
|
+
else
|
184
|
+
ALL_OTHER_SUFFIX
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
def record_distributed_tracing_metrics
|
189
|
+
return unless Agent.config[:'distributed_tracing.enabled']
|
190
|
+
|
191
|
+
record_caller_by_duration_metrics
|
192
|
+
record_transport_duration_metrics
|
193
|
+
record_errors_by_caller_metrics
|
194
|
+
end
|
195
|
+
|
196
|
+
DURATION_BY_CALLER_UNKOWN_PREFIX = "DurationByCaller/Unknown/Unknown/Unknown/Unknown".freeze
|
197
|
+
|
198
|
+
def record_caller_by_duration_metrics
|
199
|
+
prefix = if distributed_trace?
|
200
|
+
payload = distributed_trace_payload
|
201
|
+
"DurationByCaller/#{payload.parent_type}/#{payload.parent_account_id}/#{payload.parent_app_id}/#{payload.caller_transport_type}"
|
202
|
+
else
|
203
|
+
DURATION_BY_CALLER_UNKOWN_PREFIX
|
204
|
+
end
|
205
|
+
|
206
|
+
metrics.record_unscoped "#{prefix}/#{ALL_SUFFIX}", duration
|
207
|
+
metrics.record_unscoped "#{prefix}/#{transaction_type_suffix}", duration
|
208
|
+
end
|
209
|
+
|
210
|
+
def record_transport_duration_metrics
|
211
|
+
return unless distributed_trace?
|
212
|
+
|
213
|
+
payload = distributed_trace_payload
|
214
|
+
prefix = "TransportDuration/#{payload.parent_type}/#{payload.parent_account_id}/#{payload.parent_app_id}/#{payload.caller_transport_type}"
|
215
|
+
|
216
|
+
metrics.record_unscoped "#{prefix}/#{ALL_SUFFIX}", transport_duration
|
217
|
+
metrics.record_unscoped "#{prefix}/#{transaction_type_suffix}", transport_duration
|
218
|
+
end
|
219
|
+
|
220
|
+
ERRORS_BY_CALLER_UNKOWN_PREFIX = "ErrorsByCaller/Unknown/Unknown/Unknown/Unknown".freeze
|
221
|
+
|
222
|
+
def record_errors_by_caller_metrics
|
223
|
+
return unless exceptions.size > 0
|
224
|
+
|
225
|
+
prefix = if distributed_trace?
|
226
|
+
payload = distributed_trace_payload
|
227
|
+
"ErrorsByCaller/#{payload.parent_type}/#{payload.parent_account_id}/#{payload.parent_app_id}/#{payload.caller_transport_type}"
|
228
|
+
else
|
229
|
+
ERRORS_BY_CALLER_UNKOWN_PREFIX
|
230
|
+
end
|
231
|
+
|
232
|
+
metrics.record_unscoped "#{prefix}/#{ALL_SUFFIX}", 1
|
233
|
+
metrics.record_unscoped "#{prefix}/#{transaction_type_suffix}", 1
|
234
|
+
end
|
118
235
|
end
|
119
236
|
end
|
120
237
|
end
|
121
238
|
end
|
239
|
+
|