newrelic_rpm 9.23.0 → 10.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (83) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +136 -0
  3. data/README.md +0 -7
  4. data/lib/new_relic/agent/agent.rb +9 -4
  5. data/lib/new_relic/agent/configuration/default_source.rb +103 -181
  6. data/lib/new_relic/agent/configuration/environment_source.rb +7 -38
  7. data/lib/new_relic/agent/configuration/manager.rb +141 -59
  8. data/lib/new_relic/agent/configuration/sampler_config_validator.rb +54 -0
  9. data/lib/new_relic/agent/configuration/server_source.rb +0 -1
  10. data/lib/new_relic/agent/connect/response_handler.rb +0 -11
  11. data/lib/new_relic/agent/datastores.rb +13 -17
  12. data/lib/new_relic/agent/distributed_tracing.rb +0 -3
  13. data/lib/new_relic/agent/health_check.rb +1 -0
  14. data/lib/new_relic/agent/instrumentation/active_job.rb +1 -1
  15. data/lib/new_relic/agent/instrumentation/active_job_subscriber.rb +2 -1
  16. data/lib/new_relic/agent/instrumentation/active_record_helper.rb +1 -4
  17. data/lib/new_relic/agent/instrumentation/active_support.rb +8 -1
  18. data/lib/new_relic/agent/instrumentation/active_support_subscriber.rb +22 -14
  19. data/lib/new_relic/agent/instrumentation/bunny/instrumentation.rb +1 -4
  20. data/lib/new_relic/agent/instrumentation/bunny.rb +0 -1
  21. data/lib/new_relic/agent/instrumentation/curb/chain.rb +2 -2
  22. data/lib/new_relic/agent/instrumentation/curb/instrumentation.rb +2 -3
  23. data/lib/new_relic/agent/instrumentation/curb.rb +0 -1
  24. data/lib/new_relic/agent/instrumentation/excon/middleware.rb +1 -1
  25. data/lib/new_relic/agent/instrumentation/excon.rb +2 -3
  26. data/lib/new_relic/agent/instrumentation/grpc/client/instrumentation.rb +1 -2
  27. data/lib/new_relic/agent/instrumentation/httpclient.rb +0 -1
  28. data/lib/new_relic/agent/instrumentation/httprb.rb +0 -1
  29. data/lib/new_relic/agent/instrumentation/memcache/dalli.rb +0 -2
  30. data/lib/new_relic/agent/instrumentation/memcache/prepend.rb +0 -2
  31. data/lib/new_relic/agent/instrumentation/rack/helpers.rb +1 -3
  32. data/lib/new_relic/agent/instrumentation/typhoeus.rb +0 -1
  33. data/lib/new_relic/agent/llm/chat_completion_summary.rb +1 -8
  34. data/lib/new_relic/agent/llm/embedding.rb +1 -8
  35. data/lib/new_relic/agent/messaging.rb +12 -5
  36. data/lib/new_relic/agent/monitors/inbound_request_monitor.rb +1 -2
  37. data/lib/new_relic/agent/monitors/synthetics_monitor.rb +2 -1
  38. data/lib/new_relic/agent/monitors.rb +0 -3
  39. data/lib/new_relic/agent/new_relic_service/encoders.rb +0 -14
  40. data/lib/new_relic/agent/new_relic_service.rb +11 -49
  41. data/lib/new_relic/agent/opentelemetry/trace/span.rb +41 -0
  42. data/lib/new_relic/agent/opentelemetry/trace/tracer.rb +16 -7
  43. data/lib/new_relic/agent/opentelemetry_bridge.rb +9 -5
  44. data/lib/new_relic/agent/serverless_handler.rb +2 -2
  45. data/lib/new_relic/agent/span_event_primitive.rb +1 -1
  46. data/lib/new_relic/agent/sql_sampler.rb +0 -31
  47. data/lib/new_relic/agent/stats_engine.rb +1 -0
  48. data/lib/new_relic/agent/transaction/distributed_tracer.rb +12 -56
  49. data/lib/new_relic/agent/transaction/distributed_tracing.rb +11 -19
  50. data/lib/new_relic/agent/transaction/external_request_segment.rb +1 -131
  51. data/lib/new_relic/agent/transaction/message_broker_segment.rb +0 -2
  52. data/lib/new_relic/agent/transaction/trace_context.rb +33 -11
  53. data/lib/new_relic/agent/transaction.rb +35 -4
  54. data/lib/new_relic/agent/transaction_error_primitive.rb +0 -8
  55. data/lib/new_relic/agent/transaction_event_primitive.rb +0 -14
  56. data/lib/new_relic/agent/utilization/gcp.rb +2 -0
  57. data/lib/new_relic/agent.rb +11 -3
  58. data/lib/new_relic/cli/command.rb +2 -11
  59. data/lib/new_relic/control/instance_methods.rb +2 -15
  60. data/lib/new_relic/control/private_instance_methods.rb +2 -4
  61. data/lib/new_relic/control/server_methods.rb +0 -6
  62. data/lib/new_relic/helper.rb +21 -2
  63. data/lib/new_relic/language_support.rb +3 -34
  64. data/lib/new_relic/supportability_helper.rb +0 -4
  65. data/lib/new_relic/version.rb +2 -2
  66. data/lib/tasks/helpers/newrelicyml.rb +2 -2
  67. data/lib/tasks/helpers/version_bump.rb +1 -2
  68. data/newrelic.yml +25 -28
  69. data/newrelic_rpm.gemspec +10 -9
  70. metadata +27 -26
  71. data/bin/newrelic +0 -8
  72. data/lib/new_relic/agent/configuration/security_policy_source.rb +0 -246
  73. data/lib/new_relic/agent/distributed_tracing/cross_app_payload.rb +0 -44
  74. data/lib/new_relic/agent/distributed_tracing/cross_app_tracing.rb +0 -253
  75. data/lib/new_relic/agent/external.rb +0 -112
  76. data/lib/new_relic/agent/monitors/cross_app_monitor.rb +0 -117
  77. data/lib/new_relic/agent/new_relic_service/security_policy_settings.rb +0 -61
  78. data/lib/new_relic/cli/commands/deployments.rb +0 -206
  79. data/lib/new_relic/recipes/capistrano3.rb +0 -23
  80. data/lib/new_relic/recipes/capistrano_legacy.rb +0 -95
  81. data/lib/new_relic/recipes/helpers/send_deployment.rb +0 -70
  82. data/lib/new_relic/recipes.rb +0 -24
  83. data/recipes/newrelic.rb +0 -10
@@ -144,7 +144,7 @@ module NewRelic
144
144
  def payload_v1 # New Relic serverless payload v1
145
145
  payload_hash = {'metadata' => metadata, 'data' => @payloads}
146
146
  json = NewRelic::Agent.agent.service.marshaller.dump(payload_hash)
147
- gzipped = NewRelic::Agent::NewRelicService::Encoders::Compressed::Gzip.encode(json)
147
+ gzipped = Zlib.gzip(json)
148
148
  base64_encoded = NewRelic::Base64.strict_encode64(gzipped)
149
149
  array = [PAYLOAD_VERSION, LAMBDA_MARKER, base64_encoded]
150
150
  ::JSON.dump(array)
@@ -152,7 +152,7 @@ module NewRelic
152
152
 
153
153
  def payload_v2 # New Relic serverless payload v2
154
154
  json = NewRelic::Agent.agent.service.marshaller.dump(@payloads)
155
- gzipped = NewRelic::Agent::NewRelicService::Encoders::Compressed::Gzip.encode(json)
155
+ gzipped = Zlib.gzip(json)
156
156
  base64_encoded = NewRelic::Base64.strict_encode64(gzipped)
157
157
  array = [PAYLOAD_VERSION, LAMBDA_MARKER, metadata, base64_encoded]
158
158
  ::JSON.dump(array)
@@ -92,7 +92,7 @@ module NewRelic
92
92
  [intrinsics, custom_attributes(segment), agent_attributes.merge(agent_attributes(segment))]
93
93
  end
94
94
 
95
- def for_datastore_segment(segment) # rubocop:disable Metrics/AbcSize
95
+ def for_datastore_segment(segment)
96
96
  intrinsics = intrinsics_for(segment)
97
97
 
98
98
  intrinsics[COMPONENT_KEY] = segment.product
@@ -122,37 +122,6 @@ module NewRelic
122
122
  @sql_traces.delete(shortest_key)
123
123
  end
124
124
 
125
- # Records an SQL query, potentially creating a new slow SQL trace, or
126
- # aggregating the query into an existing slow SQL trace.
127
- #
128
- # This method should be used only by gem authors wishing to extend
129
- # the Ruby agent to instrument new database interfaces - it should
130
- # generally not be called directly from application code.
131
- #
132
- # @param sql [String] the SQL query being recorded
133
- # @param metric_name [String] is the metric name under which this query will be recorded
134
- # @param config [Object] is the driver configuration for the connection
135
- # @param duration [Float] number of seconds the query took to execute
136
- # @param explainer [Proc] for internal use only - 3rd-party clients must
137
- # not pass this parameter.
138
- #
139
- # @api public
140
- # @deprecated Use {Datastores.notice_sql} instead.
141
- #
142
- def notice_sql(sql, metric_name, config, duration, state = nil, explainer = nil, binds = nil, name = nil) # THREAD_LOCAL_ACCESS sometimes
143
- state ||= Tracer.state
144
- data = state.sql_sampler_transaction_data
145
- return unless data
146
-
147
- if state.is_sql_recorded?
148
- if duration > Agent.config[:'slow_sql.explain_threshold']
149
- backtrace = caller.join("\n")
150
- statement = Database::Statement.new(sql, config, explainer, binds, name)
151
- data.sql_data << SlowSql.new(statement, metric_name, duration, backtrace)
152
- end
153
- end
154
- end
155
-
156
125
  PRIORITY = 'priority'.freeze
157
126
 
158
127
  def distributed_trace_attributes(state)
@@ -4,6 +4,7 @@
4
4
 
5
5
  require 'new_relic/agent/stats_engine/gc_profiler'
6
6
  require 'new_relic/agent/stats_engine/stats_hash'
7
+ require 'new_relic/agent/tracer'
7
8
  require 'new_relic/language_support'
8
9
 
9
10
  module NewRelic
@@ -4,13 +4,11 @@
4
4
 
5
5
  require 'new_relic/agent/transaction/trace_context'
6
6
  require 'new_relic/agent/transaction/distributed_tracing'
7
- require 'new_relic/agent/distributed_tracing/cross_app_tracing'
8
7
 
9
8
  module NewRelic
10
9
  module Agent
11
10
  class Transaction
12
11
  class DistributedTracer
13
- include NewRelic::Agent::CrossAppTracing
14
12
  include DistributedTracing
15
13
  include TraceContext
16
14
 
@@ -55,12 +53,10 @@ module NewRelic
55
53
  end
56
54
 
57
55
  def record_metrics
58
- record_cross_app_metrics
59
56
  DistributedTraceMetrics.record_metrics_for_transaction(transaction)
60
57
  end
61
58
 
62
59
  def append_payload(payload)
63
- append_cat_info(payload)
64
60
  DistributedTraceAttributes.copy_from_transaction( \
65
61
  transaction,
66
62
  trace_state_payload || distributed_trace_payload,
@@ -78,14 +74,12 @@ module NewRelic
78
74
 
79
75
  insert_trace_context_header(headers)
80
76
  insert_distributed_trace_header(headers)
81
- insert_cross_app_header(headers)
82
77
  log_request_headers(headers)
83
78
  end
84
79
 
85
80
  def consume_message_headers(headers, tracer_state, transport_type)
86
81
  log_request_headers(headers, 'INCOMING')
87
82
  consume_message_distributed_tracing_headers(headers, transport_type)
88
- consume_message_cross_app_tracing_headers(headers, tracer_state)
89
83
  consume_message_synthetics_headers(headers)
90
84
  rescue => e
91
85
  NewRelic::Agent.logger.error('Error in consume_message_headers', e)
@@ -94,8 +88,6 @@ module NewRelic
94
88
  def assign_intrinsics
95
89
  if dt_enabled?
96
90
  DistributedTraceAttributes.copy_to_attributes(transaction.payload, transaction.attributes)
97
- elsif is_cross_app?
98
- assign_cross_app_intrinsics
99
91
  end
100
92
  end
101
93
 
@@ -107,17 +99,6 @@ module NewRelic
107
99
  headers[NewRelic::NEWRELIC_KEY] = payload.http_safe if payload
108
100
  end
109
101
 
110
- def insert_cat_headers(headers)
111
- return unless CrossAppTracing.cross_app_enabled?
112
-
113
- @is_cross_app_caller = true
114
- insert_message_headers(headers,
115
- transaction.guid,
116
- cat_trip_id,
117
- cat_path_hash,
118
- transaction.raw_synthetics_header)
119
- end
120
-
121
102
  private
122
103
 
123
104
  def dt_enabled?
@@ -125,15 +106,18 @@ module NewRelic
125
106
  end
126
107
 
127
108
  def consume_message_synthetics_headers(headers)
128
- synthetics_header = headers[CrossAppTracing::NR_MESSAGE_BROKER_SYNTHETICS_HEADER]
129
- if synthetics_header and
130
- incoming_payload = ::JSON.parse(deobfuscate(synthetics_header)) and
131
- SyntheticsMonitor.is_valid_payload?(incoming_payload) and
132
- SyntheticsMonitor.is_supported_version?(incoming_payload) and
133
- SyntheticsMonitor.is_trusted?(incoming_payload)
134
-
135
- transaction.raw_synthetics_header = synthetics_header
136
- transaction.synthetics_payload = incoming_payload
109
+ synthetics_header = headers[SyntheticsMonitor::NON_HTTP_SYNTHETICS_HEADER_KEY]
110
+ if synthetics_header
111
+ require 'new_relic/agent/obfuscator'
112
+ obfuscator = ::NewRelic::Agent::Obfuscator.new(Agent.config[:encoding_key])
113
+ incoming_payload = ::JSON.parse(obfuscator.deobfuscate(synthetics_header))
114
+ if SyntheticsMonitor.is_valid_payload?(incoming_payload) &&
115
+ SyntheticsMonitor.is_supported_version?(incoming_payload) &&
116
+ SyntheticsMonitor.is_trusted?(incoming_payload)
117
+
118
+ transaction.raw_synthetics_header = synthetics_header
119
+ transaction.synthetics_payload = incoming_payload
120
+ end
137
121
  end
138
122
  rescue => e
139
123
  NewRelic::Agent.logger.error('Error in consume_message_synthetics_header', e)
@@ -151,34 +135,6 @@ module NewRelic
151
135
 
152
136
  accept_distributed_trace_payload(payload)
153
137
  end
154
-
155
- def consume_message_cross_app_tracing_headers(headers, tracer_state)
156
- return unless CrossAppTracing.cross_app_enabled?
157
- return unless CrossAppTracing.message_has_crossapp_request_header?(headers)
158
-
159
- accept_cross_app_payload(headers, tracer_state)
160
- CrossAppTracing.assign_intrinsic_transaction_attributes(tracer_state)
161
- end
162
-
163
- def accept_cross_app_payload(headers, tracer_state)
164
- encoded_id = headers[CrossAppTracing::NR_MESSAGE_BROKER_ID_HEADER]
165
- decoded_id = encoded_id.nil? ? EMPTY_STRING : deobfuscate(encoded_id)
166
-
167
- return unless CrossAppTracing.trusted_valid_cross_app_id?(decoded_id)
168
-
169
- txn_header = headers[CrossAppTracing::NR_MESSAGE_BROKER_TXN_HEADER]
170
- txn_info = ::JSON.parse(deobfuscate(txn_header))
171
- payload = CrossAppPayload.new(decoded_id, transaction, txn_info)
172
-
173
- @cross_app_payload = payload
174
- rescue => e
175
- NewRelic::Agent.logger.debug("Failure deserializing encoded header in #{self.class}, #{e.class}, #{e.message}")
176
- nil
177
- end
178
-
179
- def deobfuscate(message)
180
- CrossAppTracing.obfuscator.deobfuscate(message)
181
- end
182
138
  end
183
139
  end
184
140
  end
@@ -161,29 +161,21 @@ module NewRelic
161
161
  transaction.parent_span_id = payload.id
162
162
 
163
163
  unless payload.sampled.nil?
164
- if payload.sampled == true
165
- set_priority_and_sampled_newrelic_header(NewRelic::Agent.config[:'distributed_tracing.sampler.remote_parent_sampled'], payload)
166
- elsif payload.sampled == false
167
- set_priority_and_sampled_newrelic_header(NewRelic::Agent.config[:'distributed_tracing.sampler.remote_parent_not_sampled'], payload)
164
+ if payload.sampled
165
+ set_priority_and_sampled(
166
+ NewRelic::Agent.config[:'distributed_tracing.sampler.remote_parent_sampled'],
167
+ NewRelic::Agent.config[:'distributed_tracing.sampler.remote_parent_sampled.trace_id_ratio_based.ratio'],
168
+ payload
169
+ )
168
170
  else
169
- transaction.sampled = payload.sampled
170
- transaction.priority = payload.priority if payload.priority
171
+ set_priority_and_sampled(
172
+ NewRelic::Agent.config[:'distributed_tracing.sampler.remote_parent_not_sampled'],
173
+ NewRelic::Agent.config[:'distributed_tracing.sampler.remote_parent_not_sampled.trace_id_ratio_based.ratio'],
174
+ payload
175
+ )
171
176
  end
172
177
  end
173
178
  end
174
-
175
- def set_priority_and_sampled_newrelic_header(config, payload)
176
- if config == 'always_on'
177
- transaction.sampled = true
178
- transaction.priority = 2.0
179
- elsif config == 'always_off'
180
- transaction.sampled = false
181
- transaction.priority = 0
182
- else # case for 'default' value
183
- transaction.sampled = payload.sampled
184
- transaction.priority = payload.priority if payload.priority
185
- end
186
- end
187
179
  end
188
180
  end
189
181
  end
@@ -64,119 +64,6 @@ module NewRelic
64
64
  NewRelic::Agent.logger.error('Error in add_request_headers', e)
65
65
  end
66
66
 
67
- # This method extracts app data from an external response if present. If
68
- # a valid cross-app ID is found, the name of the segment is updated to
69
- # reflect the cross-process ID and transaction name.
70
- #
71
- # @param [Hash] response a hash of response headers
72
- #
73
- # @api public
74
- def read_response_headers(response)
75
- return unless record_metrics? && CrossAppTracing.cross_app_enabled?
76
- return unless CrossAppTracing.response_has_crossapp_header?(response)
77
-
78
- unless data = CrossAppTracing.extract_appdata(response)
79
- NewRelic::Agent.logger.debug("Couldn't extract_appdata from external segment response")
80
- return
81
- end
82
-
83
- if CrossAppTracing.valid_cross_app_id?(data[0])
84
- @app_data = data
85
- update_segment_name
86
- else
87
- NewRelic::Agent.logger.debug('External segment response has invalid cross_app_id')
88
- end
89
- rescue => e
90
- NewRelic::Agent.logger.error('Error in read_response_headers', e)
91
- end
92
-
93
- def cross_app_request? # :nodoc:
94
- !!@app_data
95
- end
96
-
97
- def cross_process_id # :nodoc:
98
- @app_data && @app_data[0]
99
- end
100
-
101
- def transaction_guid # :nodoc:
102
- @app_data && @app_data[5]
103
- end
104
-
105
- def cross_process_transaction_name # :nodoc:
106
- @app_data && @app_data[1]
107
- end
108
-
109
- # Obtain an obfuscated +String+ suitable for delivery across public networks that identifies this application
110
- # and transaction to another application which is also running a New Relic agent. This +String+ can be processed
111
- # by +process_request_metadata+ on the receiving application.
112
- #
113
- # @return [String] obfuscated request metadata to send
114
- #
115
- # @api public
116
- #
117
- def get_request_metadata
118
- NewRelic::Agent.record_api_supportability_metric(:get_request_metadata)
119
- return unless CrossAppTracing.cross_app_enabled?
120
-
121
- if transaction
122
-
123
- # build hash of CAT metadata
124
- #
125
- rmd = {
126
- NewRelicID: NewRelic::Agent.config[:cross_process_id],
127
- NewRelicTransaction: [
128
- transaction.guid,
129
- false,
130
- transaction.distributed_tracer.cat_trip_id,
131
- transaction.distributed_tracer.cat_path_hash
132
- ]
133
- }
134
-
135
- # flag cross app in the state so transaction knows to add bits to payload
136
- #
137
- transaction.distributed_tracer.is_cross_app_caller = true
138
-
139
- # add Synthetics header if we have it
140
- #
141
- rmd[:NewRelicSynthetics] = transaction.raw_synthetics_header if transaction.raw_synthetics_header
142
-
143
- # obfuscate the generated request metadata JSON
144
- #
145
- obfuscator.obfuscate(::JSON.dump(rmd))
146
-
147
- end
148
- rescue => e
149
- NewRelic::Agent.logger.error('error during get_request_metadata', e)
150
- end
151
-
152
- # Process obfuscated +String+ sent from a called application that is also running a New Relic agent and
153
- # save information in current transaction for inclusion in a trace. This +String+ is generated by
154
- # +get_response_metadata+ on the receiving application.
155
- #
156
- # @param response_metadata [String] received obfuscated response metadata
157
- #
158
- # @api public
159
- #
160
- def process_response_metadata(response_metadata)
161
- NewRelic::Agent.record_api_supportability_metric(:process_response_metadata)
162
- if transaction
163
- app_data = ::JSON.parse(obfuscator.deobfuscate(response_metadata))[APP_DATA_KEY]
164
-
165
- # validate cross app id
166
- #
167
- if Array === app_data and CrossAppTracing.trusted_valid_cross_app_id?(app_data[0])
168
- @app_data = app_data
169
- update_segment_name
170
- else
171
- NewRelic::Agent.logger.error('error processing response metadata: invalid/non-trusted ID')
172
- end
173
- end
174
-
175
- nil
176
- rescue => e
177
- NewRelic::Agent.logger.error('error during process_response_metadata', e)
178
- end
179
-
180
67
  def record_metrics
181
68
  add_unscoped_metrics
182
69
  super
@@ -184,7 +71,6 @@ module NewRelic
184
71
 
185
72
  def process_response_headers(response) # :nodoc:
186
73
  set_http_status_code(response)
187
- read_response_headers(response)
188
74
  end
189
75
 
190
76
  private
@@ -206,10 +92,6 @@ module NewRelic
206
92
 
207
93
  def segment_complete
208
94
  params[:uri] = uri.to_s
209
- if cross_app_request?
210
- params[:transaction_guid] = transaction_guid
211
- end
212
-
213
95
  super
214
96
  end
215
97
 
@@ -223,10 +105,6 @@ module NewRelic
223
105
  @unscoped_metrics = [EXTERNAL_ALL,
224
106
  "External/#{host}/all",
225
107
  suffixed_rollup_metric]
226
-
227
- if cross_app_request?
228
- @unscoped_metrics << "ExternalApp/#{host}/#{cross_process_id}/all"
229
- end
230
108
  end
231
109
 
232
110
  def suffixed_rollup_metric
@@ -238,15 +116,7 @@ module NewRelic
238
116
  end
239
117
 
240
118
  def update_segment_name
241
- if @app_data
242
- @name = "ExternalTransaction/#{host}/#{cross_process_id}/#{cross_process_transaction_name}"
243
- else
244
- @name = "External/#{host}/#{library}/#{procedure}"
245
- end
246
- end
247
-
248
- def obfuscator
249
- CrossAppTracing.obfuscator
119
+ @name = "External/#{host}/#{library}/#{procedure}"
250
120
  end
251
121
 
252
122
  def record_span_event
@@ -3,7 +3,6 @@
3
3
  # frozen_string_literal: true
4
4
 
5
5
  require 'new_relic/agent/transaction/segment'
6
- require 'new_relic/agent/distributed_tracing/cross_app_tracing'
7
6
 
8
7
  module NewRelic
9
8
  module Agent
@@ -89,7 +88,6 @@ module NewRelic
89
88
  def transaction_assigned
90
89
  if headers && transaction && action == :produce && record_metrics?
91
90
  transaction.distributed_tracer.insert_distributed_trace_header(headers)
92
- transaction.distributed_tracer.insert_cat_headers(headers)
93
91
  transaction.distributed_tracer.log_request_headers(headers)
94
92
  end
95
93
  rescue => e
@@ -154,32 +154,54 @@ module NewRelic
154
154
 
155
155
  def determine_sampling_decision(payload, trace_flags)
156
156
  if trace_flags == '01'
157
- set_priority_and_sampled(NewRelic::Agent.config[:'distributed_tracing.sampler.remote_parent_sampled'], payload)
157
+ set_priority_and_sampled(
158
+ NewRelic::Agent.config[:'distributed_tracing.sampler.remote_parent_sampled'],
159
+ NewRelic::Agent.config[:'distributed_tracing.sampler.remote_parent_sampled.trace_id_ratio_based.ratio'],
160
+ payload,
161
+ trace_flags
162
+ )
158
163
  elsif trace_flags == '00'
159
- set_priority_and_sampled(NewRelic::Agent.config[:'distributed_tracing.sampler.remote_parent_not_sampled'], payload)
164
+ set_priority_and_sampled(
165
+ NewRelic::Agent.config[:'distributed_tracing.sampler.remote_parent_not_sampled'],
166
+ NewRelic::Agent.config[:'distributed_tracing.sampler.remote_parent_not_sampled.trace_id_ratio_based.ratio'],
167
+ payload,
168
+ trace_flags
169
+ )
160
170
  else
161
- use_nr_tracestate_sampled(payload)
171
+ use_nr_tracestate_sampled(payload, trace_flags)
162
172
  end
163
173
  rescue
164
- use_nr_tracestate_sampled(payload)
174
+ use_nr_tracestate_sampled(payload, trace_flags)
165
175
  end
166
176
 
167
- def use_nr_tracestate_sampled(payload)
168
- unless payload.sampled.nil?
177
+ def use_nr_tracestate_sampled(payload, trace_flags)
178
+ if payload.sampled.nil?
179
+ if trace_flags == '01'
180
+ transaction.sampled = NewRelic::Agent.instance.adaptive_sampler_remote_parent_sampled.sampled?
181
+ elsif trace_flags == '00'
182
+ transaction.sampled = NewRelic::Agent.instance.adaptive_sampler_remote_parent_not_sampled.sampled?
183
+ end
184
+
185
+ transaction.priority = transaction.default_priority
186
+ else
169
187
  transaction.sampled = payload.sampled
170
188
  transaction.priority = payload.priority if payload.priority
171
189
  end
172
190
  end
173
191
 
174
- def set_priority_and_sampled(config, payload)
175
- if config == 'always_on'
192
+ def set_priority_and_sampled(sampler, ratio, payload, trace_flags = nil)
193
+ case sampler
194
+ when 'adaptive'
195
+ use_nr_tracestate_sampled(payload, trace_flags)
196
+ when 'always_on'
176
197
  transaction.sampled = true
177
198
  transaction.priority = 2.0
178
- elsif config == 'always_off'
199
+ when 'always_off'
179
200
  transaction.sampled = false
180
201
  transaction.priority = 0
181
- else # default
182
- use_nr_tracestate_sampled(payload)
202
+ when 'trace_id_ratio_based'
203
+ transaction.sampled = transaction.trace_ratio_sampled?(ratio)
204
+ transaction.priority = transaction.default_priority
183
205
  end
184
206
  end
185
207
 
@@ -211,7 +211,7 @@ module NewRelic
211
211
  end
212
212
  end
213
213
 
214
- def initialize(category, options) # rubocop:disable Metrics/AbcSize
214
+ def initialize(category, options)
215
215
  @nesting_max_depth = 0
216
216
  @current_segment_by_thread = {}
217
217
  @current_segment_lock = Mutex.new
@@ -294,11 +294,31 @@ module NewRelic
294
294
  return false unless Agent.config[:'distributed_tracing.enabled']
295
295
 
296
296
  if @sampled.nil?
297
- @sampled = NewRelic::Agent.instance.adaptive_sampler.sampled?
297
+ @sampled = case NewRelic::Agent.config[:'distributed_tracing.sampler.root']
298
+ when 'adaptive'
299
+ NewRelic::Agent.instance.adaptive_sampler.sampled?
300
+ when 'always_on'
301
+ true
302
+ when 'always_off'
303
+ false
304
+ when 'trace_id_ratio_based'
305
+ trace_ratio_sampled?(NewRelic::Agent.config[:'distributed_tracing.sampler.root.trace_id_ratio_based.ratio'])
306
+ end
298
307
  end
299
308
  @sampled
300
309
  end
301
310
 
311
+ def trace_ratio_sampled?(ratio)
312
+ # In the opentelemetry-sdk TraceIdRatioBased sampler, the algorithm
313
+ # looks like this:
314
+ # ratio == 1.0 || trace_id[8, 8].unpack1('Q>') < (ratio * (2**64 - 1)).ceil
315
+ # OTel stores their trace ids as binary strings
316
+ # ex. Array(trace_id).pack('H*')
317
+ # Since we don't store our trace ids as binary strings, this way is
318
+ # faster, but still gets the same result.
319
+ ratio == 1.0 || Integer(trace_id[16, 16], 16) < (ratio * (2**64 - 1)).ceil
320
+ end
321
+
302
322
  def trace_id
303
323
  @trace_id ||= NewRelic::Agent::GuidGenerator.generate_guid(32)
304
324
  end
@@ -307,8 +327,19 @@ module NewRelic
307
327
  @trace_id = value
308
328
  end
309
329
 
330
+ def default_priority
331
+ (sampled? ? rand + 1.0 : rand).round(NewRelic::PRIORITY_PRECISION)
332
+ end
333
+
310
334
  def priority
311
- @priority ||= (sampled? ? rand + 1.0 : rand).round(NewRelic::PRIORITY_PRECISION)
335
+ @priority ||= case NewRelic::Agent.config[:'distributed_tracing.sampler.root']
336
+ when 'adaptive', 'trace_id_ratio_based'
337
+ default_priority
338
+ when 'always_on'
339
+ 2.0
340
+ when 'always_off'
341
+ 0
342
+ end
312
343
  end
313
344
 
314
345
  def referer
@@ -689,7 +720,7 @@ module NewRelic
689
720
  end
690
721
 
691
722
  def include_guid?
692
- distributed_tracer.is_cross_app? || is_synthetics_request?
723
+ is_synthetics_request?
693
724
  end
694
725
 
695
726
  def is_synthetics_request?
@@ -26,8 +26,6 @@ module NewRelic
26
26
  NAME_KEY = 'transactionName'
27
27
  DURATION_KEY = 'duration'
28
28
  SAMPLED_KEY = 'sampled'
29
- CAT_GUID_KEY = 'nr.transactionGuid'
30
- CAT_REFERRING_TRANSACTION_GUID_KEY = 'nr.referringTransactionGuid'
31
29
  SYNTHETICS_RESOURCE_ID_KEY = 'nr.syntheticsResourceId'
32
30
  SYNTHETICS_JOB_ID_KEY = 'nr.syntheticsJobId'
33
31
  SYNTHETICS_MONITOR_ID_KEY = 'nr.syntheticsMonitorId'
@@ -69,7 +67,6 @@ module NewRelic
69
67
  attrs[SAMPLED_KEY] = payload[:sampled] if payload.key?(:sampled)
70
68
  attrs[PRIORITY_KEY] = payload[:priority]
71
69
  append_synthetics(payload, attrs)
72
- append_cat(payload, attrs)
73
70
  DistributedTraceAttributes.copy_to_hash(payload, attrs)
74
71
  PayloadMetricMapping.append_mapped_metrics(payload[:metrics], attrs)
75
72
  else
@@ -95,11 +92,6 @@ module NewRelic
95
92
  sample[new_key] = v
96
93
  end
97
94
  end
98
-
99
- def append_cat(payload, sample)
100
- sample[CAT_GUID_KEY] = payload[:guid] if payload[:guid]
101
- sample[CAT_REFERRING_TRANSACTION_GUID_KEY] = payload[:referring_transaction_guid] if payload[:referring_transaction_guid]
102
- end
103
95
  end
104
96
  end
105
97
  end
@@ -30,10 +30,6 @@ module NewRelic
30
30
  SAMPLED_KEY = 'sampled'
31
31
  PRIORITY_KEY = 'priority'
32
32
  GUID_KEY = 'nr.guid'
33
- REFERRING_TRANSACTION_GUID_KEY = 'nr.referringTransactionGuid'
34
- CAT_PATH_HASH_KEY = 'nr.pathHash'
35
- CAT_REFERRING_PATH_HASH_KEY = 'nr.referringPathHash'
36
- CAT_ALTERNATE_PATH_HASHES_KEY = 'nr.alternatePathHashes'
37
33
  APDEX_PERF_ZONE_KEY = 'nr.apdexPerfZone'
38
34
  SYNTHETICS_RESOURCE_ID_KEY = 'nr.syntheticsResourceId'
39
35
  SYNTHETICS_JOB_ID_KEY = 'nr.syntheticsJobId'
@@ -69,9 +65,6 @@ module NewRelic
69
65
 
70
66
  def append_optional_attributes(sample, payload)
71
67
  optionally_append(GUID_KEY, :guid, sample, payload)
72
- optionally_append(REFERRING_TRANSACTION_GUID_KEY, :referring_transaction_guid, sample, payload)
73
- optionally_append(CAT_PATH_HASH_KEY, :cat_path_hash, sample, payload)
74
- optionally_append(CAT_REFERRING_PATH_HASH_KEY, :cat_referring_path_hash, sample, payload)
75
68
  optionally_append(APDEX_PERF_ZONE_KEY, :apdex_perf_zone, sample, payload)
76
69
  optionally_append(SYNTHETICS_RESOURCE_ID_KEY, :synthetics_resource_id, sample, payload)
77
70
  optionally_append(SYNTHETICS_JOB_ID_KEY, :synthetics_job_id, sample, payload)
@@ -79,7 +72,6 @@ module NewRelic
79
72
  optionally_append(SYNTHETICS_TYPE_KEY, :synthetics_type, sample, payload)
80
73
  optionally_append(SYNTHETICS_INITIATOR_KEY, :synthetics_initiator, sample, payload)
81
74
  append_synthetics_info_attributes(sample, payload)
82
- append_cat_alternate_path_hashes(sample, payload)
83
75
  end
84
76
 
85
77
  def append_synthetics_info_attributes(sample, payload)
@@ -93,12 +85,6 @@ module NewRelic
93
85
  end
94
86
  end
95
87
 
96
- def append_cat_alternate_path_hashes(sample, payload)
97
- if payload.include?(:cat_alternate_path_hashes)
98
- sample[CAT_ALTERNATE_PATH_HASHES_KEY] = payload[:cat_alternate_path_hashes].sort.join(COMMA)
99
- end
100
- end
101
-
102
88
  def optionally_append(sample_key, payload_key, sample, payload)
103
89
  if payload.include?(payload_key)
104
90
  sample[sample_key] = string(payload[payload_key])
@@ -25,6 +25,8 @@ module NewRelic
25
25
  end
26
26
 
27
27
  def trim_leading(value)
28
+ return nil unless value.is_a?(String)
29
+
28
30
  value.split(NewRelic::SLASH).last
29
31
  end
30
32
  end