newrelic_rpm 6.8.0.360 → 6.9.0.363

Sign up to get free protection for your applications and to get access to all the features.
Files changed (72) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +16 -16
  3. data/CHANGELOG.md +64 -0
  4. data/lib/new_relic/agent.rb +6 -5
  5. data/lib/new_relic/agent/agent.rb +43 -36
  6. data/lib/new_relic/agent/attributes.rb +2 -4
  7. data/lib/new_relic/agent/configuration/default_source.rb +23 -22
  8. data/lib/new_relic/agent/configuration/server_source.rb +1 -1
  9. data/lib/new_relic/agent/configuration/yaml_source.rb +1 -1
  10. data/lib/new_relic/agent/database.rb +1 -2
  11. data/lib/new_relic/agent/distributed_tracing.rb +155 -6
  12. data/lib/new_relic/agent/{cross_app_payload.rb → distributed_tracing/cross_app_payload.rb} +0 -0
  13. data/lib/new_relic/agent/{cross_app_tracing.rb → distributed_tracing/cross_app_tracing.rb} +60 -45
  14. data/lib/new_relic/agent/distributed_tracing/distributed_trace_intrinsics.rb +80 -0
  15. data/lib/new_relic/agent/distributed_tracing/distributed_trace_metrics.rb +75 -0
  16. data/lib/new_relic/agent/{distributed_trace_payload.rb → distributed_tracing/distributed_trace_payload.rb} +19 -28
  17. data/lib/new_relic/agent/distributed_tracing/distributed_trace_transport_type.rb +39 -0
  18. data/lib/new_relic/agent/distributed_tracing/trace_context.rb +246 -0
  19. data/lib/new_relic/agent/{trace_context_payload.rb → distributed_tracing/trace_context_payload.rb} +3 -11
  20. data/lib/new_relic/agent/error_collector.rb +3 -5
  21. data/lib/new_relic/agent/error_event_aggregator.rb +3 -1
  22. data/lib/new_relic/agent/external.rb +7 -7
  23. data/lib/new_relic/agent/instrumentation/action_cable_subscriber.rb +1 -2
  24. data/lib/new_relic/agent/instrumentation/bunny.rb +1 -1
  25. data/lib/new_relic/agent/instrumentation/curb.rb +1 -1
  26. data/lib/new_relic/agent/instrumentation/excon.rb +1 -1
  27. data/lib/new_relic/agent/instrumentation/grape.rb +5 -10
  28. data/lib/new_relic/agent/instrumentation/http.rb +1 -1
  29. data/lib/new_relic/agent/instrumentation/httpclient.rb +1 -1
  30. data/lib/new_relic/agent/instrumentation/net.rb +1 -1
  31. data/lib/new_relic/agent/instrumentation/resque.rb +3 -0
  32. data/lib/new_relic/agent/instrumentation/typhoeus.rb +1 -1
  33. data/lib/new_relic/agent/logging.rb +13 -3
  34. data/lib/new_relic/agent/messaging.rb +5 -73
  35. data/lib/new_relic/agent/method_tracer.rb +3 -2
  36. data/lib/new_relic/agent/method_tracer_helpers.rb +1 -1
  37. data/lib/new_relic/agent/monitors.rb +27 -0
  38. data/lib/new_relic/agent/monitors/cross_app_monitor.rb +110 -0
  39. data/lib/new_relic/agent/monitors/distributed_tracing_monitor.rb +27 -0
  40. data/lib/new_relic/agent/{inbound_request_monitor.rb → monitors/inbound_request_monitor.rb} +1 -1
  41. data/lib/new_relic/agent/{synthetics_monitor.rb → monitors/synthetics_monitor.rb} +2 -4
  42. data/lib/new_relic/agent/span_event_primitive.rb +25 -29
  43. data/lib/new_relic/agent/sql_sampler.rb +2 -2
  44. data/lib/new_relic/agent/supported_versions.rb +2 -2
  45. data/lib/new_relic/agent/tracer.rb +3 -3
  46. data/lib/new_relic/agent/transaction.rb +21 -28
  47. data/lib/new_relic/agent/transaction/distributed_tracer.rb +171 -0
  48. data/lib/new_relic/agent/transaction/distributed_tracing.rb +61 -69
  49. data/lib/new_relic/agent/transaction/external_request_segment.rb +8 -44
  50. data/lib/new_relic/agent/transaction/message_broker_segment.rb +3 -11
  51. data/lib/new_relic/agent/transaction/trace.rb +2 -4
  52. data/lib/new_relic/agent/transaction/trace_context.rb +88 -79
  53. data/lib/new_relic/agent/transaction/trace_node.rb +2 -5
  54. data/lib/new_relic/agent/transaction_error_primitive.rb +2 -2
  55. data/lib/new_relic/agent/transaction_event_primitive.rb +26 -29
  56. data/lib/new_relic/coerce.rb +5 -3
  57. data/lib/new_relic/constants.rb +34 -0
  58. data/lib/new_relic/noticed_error.rb +2 -4
  59. data/lib/new_relic/rack/browser_monitoring.rb +4 -0
  60. data/lib/new_relic/supportability_helper.rb +14 -0
  61. data/lib/new_relic/version.rb +1 -1
  62. data/lib/tasks/tests.rake +6 -1
  63. data/newrelic_rpm.gemspec +4 -2
  64. data/test/agent_helper.rb +21 -1
  65. metadata +49 -19
  66. data/lib/new_relic/agent/cross_app_monitor.rb +0 -110
  67. data/lib/new_relic/agent/distributed_trace_intrinsics.rb +0 -90
  68. data/lib/new_relic/agent/distributed_trace_metrics.rb +0 -74
  69. data/lib/new_relic/agent/distributed_trace_monitor.rb +0 -30
  70. data/lib/new_relic/agent/distributed_trace_transport_type.rb +0 -43
  71. data/lib/new_relic/agent/trace_context.rb +0 -244
  72. data/lib/new_relic/agent/trace_context_request_monitor.rb +0 -42
@@ -1,43 +1,68 @@
1
1
  # encoding: utf-8
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
+ # frozen_string_literal: true
4
5
 
5
- require 'new_relic/agent/distributed_trace_payload'
6
- require 'new_relic/agent/distributed_trace_intrinsics'
7
- require 'new_relic/agent/distributed_trace_metrics'
6
+ require 'new_relic/agent/distributed_tracing/distributed_trace_payload'
7
+ require 'new_relic/agent/distributed_tracing/distributed_trace_intrinsics'
8
+ require 'new_relic/agent/distributed_tracing/distributed_trace_metrics'
8
9
 
9
10
  module NewRelic
10
11
  module Agent
11
12
  class Transaction
12
13
  module DistributedTracing
13
14
  attr_accessor :distributed_trace_payload
15
+ attr_writer :distributed_trace_payload_created
16
+
17
+ SUPPORTABILITY_DISTRIBUTED_TRACE = "Supportability/DistributedTrace"
18
+ CREATE_PREFIX = "#{SUPPORTABILITY_DISTRIBUTED_TRACE}/CreatePayload"
19
+ ACCEPT_PREFIX = "#{SUPPORTABILITY_DISTRIBUTED_TRACE}/AcceptPayload"
20
+ IGNORE_PREFIX = "#{ACCEPT_PREFIX}/Ignored"
21
+
22
+ CREATE_SUCCESS_METRIC = "#{CREATE_PREFIX}/Success"
23
+ CREATE_EXCEPTION_METRIC = "#{CREATE_PREFIX}/Exception"
24
+ ACCEPT_SUCCESS_METRIC = "#{ACCEPT_PREFIX}/Success"
25
+ ACCEPT_EXCEPTION_METRIC = "#{ACCEPT_PREFIX}/Exception"
26
+ ACCEPT_PARSE_EXCEPTION_METRIC = "#{ACCEPT_PREFIX}/ParseException"
27
+
28
+ IGNORE_ACCEPT_AFTER_CREATE_METRIC = "#{IGNORE_PREFIX}/CreateBeforeAccept"
29
+ IGNORE_MULTIPLE_ACCEPT_METRIC = "#{IGNORE_PREFIX}/Multiple"
30
+ IGNORE_ACCEPT_NULL_METRIC = "#{IGNORE_PREFIX}/Null"
31
+ IGNORE_ACCEPT_MAJOR_VERSION_METRIC = "#{IGNORE_PREFIX}/MajorVersion"
32
+ IGNORE_ACCEPT_UNTRUSTED_ACCOUNT_METRIC = "#{IGNORE_PREFIX}/UntrustedAccount"
33
+
34
+ LBRACE = "{"
35
+ NULL_PAYLOAD = 'null'
36
+
37
+ NEWRELIC_TRACE_KEY = "HTTP_NEWRELIC"
38
+
39
+ def accept_distributed_tracing_incoming_request request
40
+ return unless Agent.config[:'distributed_tracing.enabled']
41
+ return unless payload = request[NEWRELIC_TRACE_KEY]
42
+
43
+ accept_distributed_trace_payload payload
44
+ end
14
45
 
15
- SUPPORTABILITY_CREATE_PAYLOAD_SUCCESS = "Supportability/DistributedTrace/CreatePayload/Success".freeze
16
- SUPPORTABILITY_CREATE_PAYLOAD_EXCEPTION = "Supportability/DistributedTrace/CreatePayload/Exception".freeze
46
+ def distributed_trace_payload_created?
47
+ @distributed_trace_payload_created ||= false
48
+ end
17
49
 
18
50
  def create_distributed_trace_payload
19
- unless Agent.config[:'distributed_tracing.enabled'] && (Agent.config[:'distributed_tracing.format'] == NR_FORMAT)
20
- NewRelic::Agent.logger.warn "Not configured to create New Relic distributed trace payload"
21
- return
22
- end
23
- self.distributed_trace_payload_created = true
24
- payload = DistributedTracePayload.for_transaction self
25
- NewRelic::Agent.increment_metric SUPPORTABILITY_CREATE_PAYLOAD_SUCCESS
51
+ return unless Agent.config[:'distributed_tracing.enabled']
52
+
53
+ @distributed_trace_payload_created = true
54
+ payload = DistributedTracePayload.for_transaction transaction
55
+ NewRelic::Agent.increment_metric CREATE_SUCCESS_METRIC
26
56
  payload
27
57
  rescue => e
28
- NewRelic::Agent.increment_metric SUPPORTABILITY_CREATE_PAYLOAD_EXCEPTION
58
+ NewRelic::Agent.increment_metric CREATE_EXCEPTION_METRIC
29
59
  NewRelic::Agent.logger.warn "Failed to create distributed trace payload", e
30
60
  nil
31
61
  end
32
62
 
33
- SUPPORTABILITY_ACCEPT_PAYLOAD_SUCCESS = "Supportability/DistributedTrace/AcceptPayload/Success".freeze
34
- SUPPORTABILITY_ACCEPT_PAYLOAD_EXCEPTION = "Supportability/DistributedTrace/AcceptPayload/Exception".freeze
35
-
36
63
  def accept_distributed_trace_payload payload
37
- unless Agent.config[:'distributed_tracing.enabled'] && (Agent.config[:'distributed_tracing.format'] == NR_FORMAT)
38
- NewRelic::Agent.logger.warn "Not configured to accept New Relic distributed trace payload"
39
- return
40
- end
64
+ return unless Agent.config[:'distributed_tracing.enabled']
65
+
41
66
  return false if check_payload_ignored(payload)
42
67
  return false unless check_payload_present(payload)
43
68
  return false unless payload = decode_payload(payload)
@@ -47,67 +72,37 @@ module NewRelic
47
72
 
48
73
  assign_payload_and_sampling_params(payload)
49
74
 
50
- NewRelic::Agent.increment_metric SUPPORTABILITY_ACCEPT_PAYLOAD_SUCCESS
75
+ NewRelic::Agent.increment_metric ACCEPT_SUCCESS_METRIC
51
76
  true
52
77
  rescue => e
53
- NewRelic::Agent.increment_metric SUPPORTABILITY_ACCEPT_PAYLOAD_EXCEPTION
78
+ NewRelic::Agent.increment_metric ACCEPT_EXCEPTION_METRIC
54
79
  NewRelic::Agent.logger.warn "Failed to accept distributed trace payload", e
55
80
  false
56
81
  end
57
82
 
58
- def distributed_trace_payload_created?
59
- @distributed_trace_payload_created ||= false
60
- end
61
-
62
- attr_writer :distributed_trace_payload_created
63
-
64
- def append_distributed_trace_info transaction_payload
65
- return unless Agent.config[:'distributed_tracing.enabled']
66
- DistributedTraceIntrinsics.copy_from_transaction \
67
- self,
68
- distributed_trace_payload,
69
- transaction_payload
70
- end
71
-
72
- NR_FORMAT = "newrelic".freeze
73
-
74
- def nr_distributed_tracing_enabled?
75
- Agent.config[:'distributed_tracing.enabled'] && (Agent.config[:'distributed_tracing.format'] == NR_FORMAT) && Agent.instance.connected?
76
- end
77
-
78
83
  private
79
84
 
80
- SUPPORTABILITY_CREATE_BEFORE_ACCEPT_PAYLOAD = "Supportability/DistributedTrace/AcceptPayload/Ignored/CreateBeforeAccept".freeze
81
- SUPPORTABILITY_MULTIPLE_ACCEPT_PAYLOAD = "Supportability/DistributedTrace/AcceptPayload/Ignored/Multiple".freeze
82
- SUPPORTABILITY_PAYLOAD_ACCEPT_IGNORED_NULL = "Supportability/DistributedTrace/AcceptPayload/Ignored/Null".freeze
83
- SUPPORTABILITY_PAYLOAD_ACCEPT_IGNORED_BROWSER = "Supportability/DistributedTrace/AcceptPayload/Ignored/BrowserAgentInjected".freeze
84
-
85
85
  def check_payload_ignored(payload)
86
86
  if distributed_trace_payload
87
- NewRelic::Agent.increment_metric SUPPORTABILITY_MULTIPLE_ACCEPT_PAYLOAD
87
+ NewRelic::Agent.increment_metric IGNORE_MULTIPLE_ACCEPT_METRIC
88
88
  return true
89
89
  elsif distributed_trace_payload_created?
90
- NewRelic::Agent.increment_metric SUPPORTABILITY_CREATE_BEFORE_ACCEPT_PAYLOAD
90
+ NewRelic::Agent.increment_metric IGNORE_ACCEPT_AFTER_CREATE_METRIC
91
91
  return true
92
92
  end
93
93
  false
94
94
  end
95
95
 
96
- NULL_PAYLOAD = 'null'.freeze
97
-
98
96
  def check_payload_present(payload)
99
97
  # We might be passed a Ruby `nil` object _or_ the JSON "null"
100
98
  if payload.nil? || payload == NULL_PAYLOAD
101
- NewRelic::Agent.increment_metric SUPPORTABILITY_PAYLOAD_ACCEPT_IGNORED_NULL
99
+ NewRelic::Agent.increment_metric IGNORE_ACCEPT_NULL_METRIC
102
100
  return nil
103
101
  end
104
102
 
105
103
  payload
106
104
  end
107
105
 
108
- SUPPORTABILITY_PAYLOAD_ACCEPT_IGNORED_PARSE_EXCEPTION = "Supportability/DistributedTrace/AcceptPayload/ParseException".freeze
109
- LBRACE = "{".freeze
110
-
111
106
  def decode_payload(payload)
112
107
  decoded = if payload.start_with? LBRACE
113
108
  DistributedTracePayload.from_json payload
@@ -119,7 +114,7 @@ module NewRelic
119
114
 
120
115
  decoded
121
116
  rescue => e
122
- NewRelic::Agent.increment_metric SUPPORTABILITY_PAYLOAD_ACCEPT_IGNORED_PARSE_EXCEPTION
117
+ NewRelic::Agent.increment_metric ACCEPT_PARSE_EXCEPTION_METRIC
123
118
  NewRelic::Agent.logger.warn "Error parsing distributed trace payload", e
124
119
  nil
125
120
  end
@@ -136,42 +131,39 @@ module NewRelic
136
131
 
137
132
  true
138
133
  else
139
- NewRelic::Agent.increment_metric SUPPORTABILITY_PAYLOAD_ACCEPT_IGNORED_PARSE_EXCEPTION
134
+ NewRelic::Agent.increment_metric ACCEPT_PARSE_EXCEPTION_METRIC
140
135
  false
141
136
  end
142
137
  end
143
138
 
144
- SUPPORTABILITY_PAYLOAD_ACCEPT_IGNORED_MAJOR_VERSION = "Supportability/DistributedTrace/AcceptPayload/Ignored/MajorVersion".freeze
145
-
146
139
  def check_valid_version(payload)
147
140
  if DistributedTracePayload.major_version_matches?(payload)
148
141
  true
149
142
  else
150
- NewRelic::Agent.increment_metric SUPPORTABILITY_PAYLOAD_ACCEPT_IGNORED_MAJOR_VERSION
143
+ NewRelic::Agent.increment_metric IGNORE_ACCEPT_MAJOR_VERSION_METRIC
151
144
  false
152
145
  end
153
146
  end
154
147
 
155
- SUPPORTABILITY_PAYLOAD_ACCEPT_UNTRUSTED_ACCOUNT = "Supportability/DistributedTrace/AcceptPayload/Ignored/UntrustedAccount".freeze
156
-
157
148
  def check_trusted_account(payload)
158
149
  compare_key = payload.trusted_account_key || payload.parent_account_id
159
150
  unless compare_key == NewRelic::Agent.config[:trusted_account_key]
160
- NewRelic::Agent.increment_metric SUPPORTABILITY_PAYLOAD_ACCEPT_UNTRUSTED_ACCOUNT
151
+ NewRelic::Agent.increment_metric IGNORE_ACCEPT_UNTRUSTED_ACCOUNT_METRIC
161
152
  return false
162
153
  end
163
154
  true
164
155
  end
165
156
 
166
157
  def assign_payload_and_sampling_params(payload)
167
- self.distributed_trace_payload = payload
168
- @trace_id = payload.trace_id
169
- @parent_transaction_id = payload.transaction_id
170
- @parent_span_id = payload.id
158
+ @distributed_trace_payload = payload
159
+ return if transaction.distributed_tracer.trace_context_header_data
160
+ transaction.trace_id = payload.trace_id
161
+ transaction.distributed_tracer.parent_transaction_id = payload.transaction_id
162
+ transaction.parent_span_id = payload.id
171
163
 
172
164
  unless payload.sampled.nil?
173
- self.sampled = payload.sampled
174
- self.priority = payload.priority if payload.priority
165
+ transaction.sampled = payload.sampled
166
+ transaction.priority = payload.priority if payload.priority
175
167
  end
176
168
  end
177
169
  end
@@ -14,10 +14,12 @@ module NewRelic
14
14
  #
15
15
  # @api public
16
16
  class ExternalRequestSegment < Segment
17
- attr_reader :library, :uri, :procedure
18
-
19
17
  NR_SYNTHETICS_HEADER = 'X-NewRelic-Synthetics'.freeze
18
+ EXTERNAL_TRANSACTION_PREFIX = 'ExternalTransaction/'.freeze
19
+ SLASH = '/'.freeze
20
+ APP_DATA_KEY = 'NewRelicAppData'.freeze
20
21
 
22
+ attr_reader :library, :uri, :procedure
21
23
 
22
24
  def initialize library, uri, procedure, start_time = nil # :nodoc:
23
25
  @library = library
@@ -52,7 +54,7 @@ module NewRelic
52
54
 
53
55
  return unless record_metrics?
54
56
 
55
- insert_context_propagation_headers request
57
+ transaction.distributed_tracer.insert_headers request
56
58
  rescue => e
57
59
  NewRelic::Agent.logger.error "Error in add_request_headers", e
58
60
  end
@@ -98,10 +100,6 @@ module NewRelic
98
100
  @app_data && @app_data[1]
99
101
  end
100
102
 
101
- EXTERNAL_TRANSACTION_PREFIX = 'ExternalTransaction/'.freeze
102
- SLASH = '/'.freeze
103
- APP_DATA_KEY = 'NewRelicAppData'.freeze
104
-
105
103
  # Obtain an obfuscated +String+ suitable for delivery across public networks that identifies this application
106
104
  # and transaction to another application which is also running a New Relic agent. This +String+ can be processed
107
105
  # by +process_request_metadata+ on the receiving application.
@@ -123,14 +121,14 @@ module NewRelic
123
121
  NewRelicTransaction: [
124
122
  transaction.guid,
125
123
  false,
126
- transaction.cat_trip_id,
127
- transaction.cat_path_hash
124
+ transaction.distributed_tracer.cat_trip_id,
125
+ transaction.distributed_tracer.cat_path_hash
128
126
  ]
129
127
  }
130
128
 
131
129
  # flag cross app in the state so transaction knows to add bits to paylaod
132
130
  #
133
- transaction.is_cross_app_caller = true
131
+ transaction.distributed_tracer.is_cross_app_caller = true
134
132
 
135
133
  # add Synthetics header if we have it
136
134
  #
@@ -199,39 +197,6 @@ module NewRelic
199
197
  end
200
198
  end
201
199
 
202
- def insert_context_propagation_headers request
203
- return unless transaction
204
-
205
- if transaction.trace_context_enabled?
206
- insert_trace_context_headers request
207
- elsif transaction.nr_distributed_tracing_enabled?
208
- insert_distributed_trace_header request
209
- elsif CrossAppTracing.cross_app_enabled?
210
- insert_cross_app_header request
211
- end
212
- end
213
-
214
-
215
- def insert_cross_app_header request
216
- transaction.is_cross_app_caller = true
217
- txn_guid = transaction.guid
218
- trip_id = transaction && transaction.cat_trip_id
219
- path_hash = transaction && transaction.cat_path_hash
220
-
221
- CrossAppTracing.insert_request_headers request, txn_guid, trip_id, path_hash
222
- end
223
-
224
- NEWRELIC_TRACE_HEADER = "newrelic".freeze
225
-
226
- def insert_distributed_trace_header request
227
- payload = transaction.create_distributed_trace_payload
228
- request[NEWRELIC_TRACE_HEADER] = payload.http_safe if payload
229
- end
230
-
231
- def insert_trace_context_headers request
232
- transaction.insert_trace_context carrier: request
233
- end
234
-
235
200
  EXTERNAL_ALL = "External/all".freeze
236
201
 
237
202
  def add_unscoped_metrics
@@ -271,7 +236,6 @@ module NewRelic
271
236
  def record_span_event
272
237
  aggregator = ::NewRelic::Agent.agent.span_event_aggregator
273
238
  priority = transaction.priority
274
-
275
239
  aggregator.record(priority: priority) do
276
240
  SpanEventPrimitive.for_external_request_segment(self)
277
241
  end
@@ -3,7 +3,7 @@
3
3
  # See https://github.com/newrelic/rpm/blob/master/LICENSE for complete details.
4
4
 
5
5
  require 'new_relic/agent/transaction/segment'
6
- require 'new_relic/agent/cross_app_tracing'
6
+ require 'new_relic/agent/distributed_tracing/cross_app_tracing'
7
7
 
8
8
  module NewRelic
9
9
  module Agent
@@ -89,18 +89,10 @@ module NewRelic
89
89
  @name
90
90
  end
91
91
 
92
- NEWRELIC_TRACE_KEY = "newrelic".freeze
93
-
94
- def insert_distributed_trace_header
95
- return unless Agent.config[:'distributed_tracing.enabled']
96
- payload = transaction.create_distributed_trace_payload
97
- headers[NEWRELIC_TRACE_KEY] = payload.http_safe if payload
98
- end
99
-
100
92
  def transaction_assigned
101
93
  if headers && transaction && action == :produce && record_metrics?
102
- insert_distributed_trace_header
103
- transaction.add_message_cat_headers headers if CrossAppTracing.cross_app_enabled?
94
+ transaction.distributed_tracer.insert_distributed_trace_header headers
95
+ transaction.distributed_tracer.insert_cat_headers headers
104
96
  end
105
97
  rescue => e
106
98
  NewRelic::Agent.logger.error "Error during message header processing", e
@@ -121,13 +121,11 @@ module NewRelic
121
121
  }
122
122
  end
123
123
 
124
- EMPTY_HASH = {}.freeze
125
-
126
124
  def trace_tree attributes_hash
127
125
  [
128
126
  NewRelic::Coerce.float(self.start_time),
129
- EMPTY_HASH,
130
- EMPTY_HASH,
127
+ NewRelic::EMPTY_HASH,
128
+ NewRelic::EMPTY_HASH,
131
129
  self.root_node.to_array,
132
130
  attributes_hash
133
131
  ]
@@ -1,48 +1,74 @@
1
1
  # encoding: utf-8
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
- require 'new_relic/agent/trace_context'
5
- require 'new_relic/agent/distributed_trace_payload'
6
- require 'new_relic/agent/distributed_trace_intrinsics'
7
- require 'new_relic/agent/distributed_trace_metrics'
4
+ # frozen_string_literal: true
8
5
 
9
6
  module NewRelic
10
7
  module Agent
11
8
  class Transaction
12
- attr_accessor :trace_context_header_data
13
- attr_reader :trace_state_payload
14
-
15
9
  module TraceContext
16
- EMPTY_STRING = ''.freeze
17
- SUPPORTABILITY_PREFIX = "Supportability/TraceContext".freeze
18
- CREATE_PREFIX = "#{SUPPORTABILITY_PREFIX}/Create".freeze
19
- ACCEPT_PREFIX = "#{SUPPORTABILITY_PREFIX}/Accept".freeze
20
- TRACESTATE_PREFIX = "#{SUPPORTABILITY_PREFIX}/TraceState".freeze
21
-
22
- CREATE_SUCCESS_METRIC = "#{CREATE_PREFIX}/Success".freeze
23
- CREATE_EXCEPTION_METRIC = "#{CREATE_PREFIX}/Exception".freeze
24
-
25
- ACCEPT_SUCCESS_METRIC = "#{ACCEPT_PREFIX}/Success".freeze
26
- ACCEPT_EXCEPTION_METRIC = "#{ACCEPT_PREFIX}/Exception".freeze
27
- IGNORE_MULTIPLE_ACCEPT_METRIC = "#{ACCEPT_PREFIX}/Ignored/Multiple".freeze
28
- IGNORE_ACCEPT_AFTER_CREATE_METRIC = "#{ACCEPT_PREFIX}/Ignored/CreateBeforeAccept".freeze
29
-
30
- NO_NR_ENTRY_TRACESTATE_METRIC = "#{TRACESTATE_PREFIX}/NoNrEntry".freeze
31
- INVALID_TRACESTATE_PAYLOAD_METRIC = "#{TRACESTATE_PREFIX}/InvalidPayload".freeze
32
-
33
- def insert_trace_context \
34
- format: NewRelic::Agent::TraceContext::FORMAT_HTTP,
35
- carrier: nil
36
-
37
- return unless trace_context_enabled?
38
- NewRelic::Agent::TraceContext.insert \
10
+ include NewRelic::Coerce
11
+
12
+ module AccountHelpers
13
+ extend self
14
+
15
+ def trace_state_entry_key
16
+ @trace_state_entry_key ||= if Agent.config[:trusted_account_key]
17
+ "#{Agent.config[:trusted_account_key]}@nr".freeze
18
+ elsif Agent.config[:account_id]
19
+ "#{Agent.config[:account_id]}@nr".freeze
20
+ end
21
+ end
22
+ end
23
+
24
+ SUPPORTABILITY_PREFIX = "Supportability/TraceContext"
25
+ CREATE_PREFIX = "#{SUPPORTABILITY_PREFIX}/Create"
26
+ ACCEPT_PREFIX = "#{SUPPORTABILITY_PREFIX}/Accept"
27
+ TRACESTATE_PREFIX = "#{SUPPORTABILITY_PREFIX}/TraceState"
28
+
29
+ CREATE_SUCCESS_METRIC = "#{CREATE_PREFIX}/Success"
30
+ CREATE_EXCEPTION_METRIC = "#{CREATE_PREFIX}/Exception"
31
+
32
+ ACCEPT_SUCCESS_METRIC = "#{ACCEPT_PREFIX}/Success"
33
+ ACCEPT_EXCEPTION_METRIC = "#{ACCEPT_PREFIX}/Exception"
34
+ IGNORE_MULTIPLE_ACCEPT_METRIC = "#{ACCEPT_PREFIX}/Ignored/Multiple"
35
+ IGNORE_ACCEPT_AFTER_CREATE_METRIC = "#{ACCEPT_PREFIX}/Ignored/CreateBeforeAccept"
36
+
37
+ NO_NR_ENTRY_TRACESTATE_METRIC = "#{TRACESTATE_PREFIX}/NoNrEntry"
38
+ INVALID_TRACESTATE_PAYLOAD_METRIC = "#{TRACESTATE_PREFIX}/InvalidNrEntry"
39
+
40
+ attr_accessor :trace_context_header_data
41
+ attr_reader :trace_state_payload
42
+
43
+ def trace_parent_header_present? request
44
+ request[NewRelic::HTTP_TRACEPARENT_KEY]
45
+ end
46
+
47
+ def accept_trace_context_incoming_request request
48
+ header_data = NewRelic::Agent::DistributedTracing::TraceContext.parse(
49
+ format: NewRelic::FORMAT_RACK,
50
+ carrier: request,
51
+ trace_state_entry_key: AccountHelpers.trace_state_entry_key,
52
+ )
53
+ return if header_data.nil?
54
+
55
+ accept_trace_context header_data
56
+ end
57
+ private :accept_trace_context_incoming_request
58
+
59
+ def insert_trace_context_header header, format=NewRelic::FORMAT_NON_RACK
60
+ return unless Agent.config[:'distributed_tracing.enabled']
61
+
62
+ NewRelic::Agent::DistributedTracing::TraceContext.insert \
39
63
  format: format,
40
- carrier: carrier,
41
- trace_id: trace_id,
42
- parent_id: current_segment.guid,
43
- trace_flags: sampled? ? 0x1 : 0x0,
64
+ carrier: header,
65
+ trace_id: transaction.trace_id.rjust(32, '0').downcase,
66
+ parent_id: transaction.current_segment.guid,
67
+ trace_flags: transaction.sampled? ? 0x1 : 0x0,
44
68
  trace_state: create_trace_state
69
+
45
70
  @trace_context_inserted = true
71
+
46
72
  NewRelic::Agent.increment_metric CREATE_SUCCESS_METRIC
47
73
  true
48
74
  rescue Exception => e
@@ -52,37 +78,37 @@ module NewRelic
52
78
  end
53
79
 
54
80
  def create_trace_state
55
- entry_key = NewRelic::Agent::TraceContext::AccountHelpers.trace_state_entry_key
81
+ entry_key = AccountHelpers.trace_state_entry_key.dup
56
82
  payload = create_trace_state_payload
57
83
 
58
84
  if payload
59
- entry = NewRelic::Agent::TraceContext.create_trace_state_entry \
85
+ entry = NewRelic::Agent::DistributedTracing::TraceContext.create_trace_state_entry \
60
86
  entry_key,
61
87
  payload.to_s
62
88
  else
63
- entry = EMPTY_STRING
89
+ entry = NewRelic::EMPTY_STR
64
90
  end
65
91
 
66
92
  trace_context_header_data ? trace_context_header_data.trace_state(entry) : entry
67
93
  end
68
94
 
69
95
  def create_trace_state_payload
70
- unless trace_context_enabled?
96
+ unless Agent.config[:'distributed_tracing.enabled']
71
97
  NewRelic::Agent.logger.warn "Not configured to create WC3 trace context payload"
72
98
  return
73
99
  end
74
100
 
75
- if Agent.config[:'span_events.enabled']
76
- TraceContextPayload.create \
77
- parent_account_id: Agent.config[:account_id],
78
- parent_app_id: Agent.config[:primary_application_id],
79
- transaction_id: guid,
80
- sampled: sampled?,
81
- priority: priority,
82
- id: current_segment.guid
83
- elsif trace_context_header_data
84
- trace_context_header_data.trace_state_payload
85
- end
101
+
102
+ span_guid = Agent.config[:'span_events.enabled'] ? transaction.current_segment.guid : nil
103
+ transaction_guid = Agent.config[:'analytics_events.enabled'] ? transaction.guid : nil
104
+
105
+ TraceContextPayload.create \
106
+ parent_account_id: Agent.config[:account_id],
107
+ parent_app_id: Agent.config[:primary_application_id],
108
+ transaction_id: transaction_guid,
109
+ sampled: transaction.sampled?,
110
+ priority: float!(transaction.priority, NewRelic::PRIORITY_PRECISION),
111
+ id: span_guid
86
112
  end
87
113
 
88
114
  def assign_trace_state_payload
@@ -94,28 +120,24 @@ module NewRelic
94
120
  unless payload.valid?
95
121
  NewRelic::Agent.increment_metric INVALID_TRACESTATE_PAYLOAD_METRIC
96
122
  return false
97
- end
123
+ end
98
124
  @trace_state_payload = payload
99
125
  end
100
126
 
101
- def accept_trace_context trace_context_header_data
102
- unless trace_context_enabled?
103
- NewRelic::Agent.logger.warn "Not configured to accept WC3 trace context payload"
104
- return false
105
- end
106
- return false if ignore_trace_context?
107
-
108
- @trace_context_header_data = trace_context_header_data
109
- @trace_id = @trace_context_header_data.trace_id
110
- @parent_span_id = @trace_context_header_data.parent_id
127
+ def accept_trace_context header_data
128
+ return if ignore_trace_context?
129
+
130
+ @trace_context_header_data = header_data
131
+ transaction.trace_id = header_data.trace_id
132
+ transaction.parent_span_id = header_data.parent_id
111
133
 
112
134
  return false unless payload = assign_trace_state_payload
113
135
 
114
- @parent_transaction_id = payload.transaction_id
136
+ transaction.distributed_tracer.parent_transaction_id = payload.transaction_id
115
137
 
116
138
  unless payload.sampled.nil?
117
- self.sampled = payload.sampled
118
- self.priority = payload.priority if payload.priority
139
+ transaction.sampled = payload.sampled
140
+ transaction.priority = payload.priority if payload.priority
119
141
  end
120
142
  NewRelic::Agent.increment_metric ACCEPT_SUCCESS_METRIC
121
143
  true
@@ -125,14 +147,6 @@ module NewRelic
125
147
  false
126
148
  end
127
149
 
128
- def append_trace_context_info transaction_payload
129
- return unless trace_context_enabled?
130
- DistributedTraceIntrinsics.copy_from_transaction \
131
- self,
132
- trace_state_payload,
133
- transaction_payload
134
- end
135
-
136
150
  def ignore_trace_context?
137
151
  if trace_context_header_data
138
152
  NewRelic::Agent.increment_metric IGNORE_MULTIPLE_ACCEPT_METRIC
@@ -143,16 +157,11 @@ module NewRelic
143
157
  end
144
158
  false
145
159
  end
146
- end
147
-
148
- def trace_context_inserted?
149
- @trace_context_inserted ||= false
150
- end
151
160
 
152
- W3C_FORMAT = "w3c".freeze
161
+ def trace_context_inserted?
162
+ @trace_context_inserted ||= false
163
+ end
153
164
 
154
- def trace_context_enabled?
155
- Agent.config[:'distributed_tracing.enabled'] && (Agent.config[:'distributed_tracing.format'] == W3C_FORMAT) && Agent.instance.connected?
156
165
  end
157
166
  end
158
167
  end