newrelic_rpm 9.18.0 → 9.19.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: cb30bae7fc944221b3f08c8635e18c84c02b04f2fe36bc70814c3fed471dd8f8
4
- data.tar.gz: 01fc3c88893c0fc0d8f3e92cc394767eac9ee134f2c58d3656e8d6e6b5a95d8f
3
+ metadata.gz: 3a2b588c4be509b5a02bb0516a47e9329cab3bcf79c97f614d4349291db0876f
4
+ data.tar.gz: 30f1dcd2997242e38836aa3325badb71656aaa3aa074857a2edad75f6e21972b
5
5
  SHA512:
6
- metadata.gz: 99dc8ccbe8653343313da890dd8f6fc445638239c346fd104f3792519f33096f0ea2ec2faf96d03de72d050d38887c5c1a61caa3c7f66196d71bd5d0e057cf40
7
- data.tar.gz: bb47acdc604c90a7bf8c7ddd0dafbb1377d8de51b3841cdcb2fef377a8b789cd523f522478d0387ec84ab4b6b85d7dc8e2f5ae7881501ee38c7c5d5acc6564fb
6
+ metadata.gz: 6915cfd19ea57029473609dd02b4e9bd110aaa3766f13af648705a0132d4608f33051ad0e44f6c03f72b037eb99c64f1992c92408d1caedd3381538e906c4b0d
7
+ data.tar.gz: 87c1d548bd4a78eb26706eae9f1932c9fb394c05f16e8d4603ce8b690e4df255fdd8748f7f2b09501a7e73770961ec20f6df07435255db293bb4e7395400094c
data/CHANGELOG.md CHANGED
@@ -1,5 +1,23 @@
1
1
  # New Relic Ruby Agent Release Notes
2
2
 
3
+ ## v9.19.0
4
+
5
+ - **Feature: Add Thread ID as attribute to all spans**
6
+
7
+ The agent will now record the Thread ID as an attribute on each span. [PR#3122](https://github.com/newrelic/newrelic-ruby-agent/pull/3122)
8
+
9
+ - **Feature: Add support for W3C TraceContext Trace Flag**
10
+
11
+ Previously, the agent would not use the trace flag field of the traceparent header for sampling decisions. This could lead to fragmented traces in the UI. While the default behavior remains unchanged, two new configuration options, `distributed_tracing.sampler.remote_parent_sampled` and `distributed_tracing.sampler.remote_parent_not_sampled`, have been introduced to allow more control over the way sampling decisions are made. [PR#3135](https://github.com/newrelic/newrelic-ruby-agent/pull/3135)
12
+
13
+ - **Bugfix: Include request.uri in Transaction events by default**
14
+
15
+ [The New Relic data dictionary expects Transaction events to have the `request.uri` attribute.](https://docs.newrelic.com/attribute-dictionary/?event=Transaction&attribute=request.uri) The Ruby agent now fulfills this expectation. If you would like to exclude `request.uri` from Transaction events, you can do so by setting `transaction_events.attributes.exclude` to `'request.uri'`. [PR#3103](https://github.com/newrelic/newrelic-ruby-agent/pull/3103)
16
+
17
+ - **Bugfix: Fix error in Active Job instrumentation when using perform_all_later**
18
+
19
+ Previously, when Active Job's `perform_all_later` method was called and the agent was running, a `NoMethodError` would be raised with the message `undefined method 'queue_name' for nil`. The error has been fixed and the name of the segment will reflect the first job in the queue. Our thanks goes to [@tan-linx](https://github.com/tan-linx) for bringing this to our attention and providing a fix. [PR#3110](https://github.com/newrelic/newrelic-ruby-agent/pull/3110)
20
+
3
21
  ## v9.18.0
4
22
 
5
23
  - **Feature: Add elasticsearch.capture_cluster_name configuration option**
@@ -38,6 +38,7 @@ require 'new_relic/agent/adaptive_sampler'
38
38
  require 'new_relic/agent/serverless_handler'
39
39
  require 'new_relic/agent/connect/request_builder'
40
40
  require 'new_relic/agent/connect/response_handler'
41
+ require 'new_relic/agent/opentelemetry_bridge'
41
42
 
42
43
  require 'new_relic/agent/agent_helpers/connect'
43
44
  require 'new_relic/agent/agent_helpers/harvest'
@@ -100,6 +101,7 @@ module NewRelic
100
101
  @adaptive_sampler = AdaptiveSampler.new(Agent.config[:sampling_target],
101
102
  Agent.config[:sampling_target_period_in_seconds])
102
103
  @serverless_handler = ServerlessHandler.new
104
+ @opentelemetry_bridge = OpenTelemetryBridge.new
103
105
  end
104
106
 
105
107
  def init_event_handlers
@@ -762,7 +762,12 @@ module NewRelic
762
762
  DESCRIPTION
763
763
  },
764
764
  :'error_collector.ignore_messages' => {
765
+ # we have to keep the hash rocket in the actual default so the
766
+ # class name key is treated like a string rather than a symbol.
767
+ # however, this isn't valid yaml, so document something that is
768
+ # valid yaml
765
769
  :default => {'ThreadError' => ['queue empty']},
770
+ :documentation_default => {'ThreadError': ['queue empty']},
766
771
  :public => true,
767
772
  :type => Hash,
768
773
  :allowed_from_server => true,
@@ -1458,6 +1463,20 @@ module NewRelic
1458
1463
  :allowed_from_server => true,
1459
1464
  :description => 'Distributed tracing lets you see the path that a request takes through your distributed system. Enabling distributed tracing changes the behavior of some New Relic features, so carefully consult the [transition guide](/docs/transition-guide-distributed-tracing) before you enable this feature.'
1460
1465
  },
1466
+ :'distributed_tracing.sampler.remote_parent_sampled' => {
1467
+ :default => 'default',
1468
+ :public => true,
1469
+ :type => String,
1470
+ :allowed_from_server => true,
1471
+ :description => 'This setting controls the behavior of transaction sampling when a remote parent is sampled and the trace flag is set in the traceparent. Available values are `default`, `always_on`, and `always_off`.'
1472
+ },
1473
+ :'distributed_tracing.sampler.remote_parent_not_sampled' => {
1474
+ :default => 'default',
1475
+ :public => true,
1476
+ :type => String,
1477
+ :allowed_from_server => true,
1478
+ :description => 'This setting controls the behavior of transaction sampling when a remote parent is not sampled and the trace flag is not set in the traceparent. Available values are `default`, `always_on`, and `always_off`.'
1479
+ },
1461
1480
  # Elasticsearch
1462
1481
  :'elasticsearch.capture_cluster_name' => {
1463
1482
  :default => true,
@@ -2490,6 +2509,14 @@ module NewRelic
2490
2509
  :allowed_from_server => true,
2491
2510
  :description => 'Number of seconds betwixt connections to the New Relic span event collection services.'
2492
2511
  },
2512
+ # TODO: Sync with the other agents to see what the config should be named, how it should be enabled, how it should be described
2513
+ :'opentelemetry_bridge.enabled' => {
2514
+ :default => false,
2515
+ :public => false,
2516
+ :type => Boolean,
2517
+ :allowed_from_server => false,
2518
+ :description => 'Enables the creation of Transaction Trace segments and timeslice metrics from OpenTelemetry Spans. This will help drive New Relic UI experience for opentelemetry spans. **WARNING**: This is not feature complete and is not intended to be enabled yet.'
2519
+ },
2493
2520
  :force_reconnect => {
2494
2521
  :default => false,
2495
2522
  :public => false,
@@ -8,7 +8,7 @@ module NewRelic
8
8
  module Agent
9
9
  module Instrumentation
10
10
  class ActiveJobSubscriber < NotificationsSubscriber
11
- PAYLOAD_KEYS = %i[adapter db_runtime error job wait]
11
+ PAYLOAD_KEYS = %i[adapter db_runtime error job wait jobs]
12
12
 
13
13
  def add_segment_params(segment, payload)
14
14
  PAYLOAD_KEYS.each do |key|
@@ -16,8 +16,12 @@ module NewRelic
16
16
  end
17
17
  end
18
18
 
19
+ # NOTE: For `enqueue_all.active_job`, only the first job is used to determine the queue.
20
+ # Therefore, this assumes all jobs given as arguments for perform_all_later share the same queue.
19
21
  def metric_name(name, payload)
20
- queue = payload[:job].queue_name
22
+ job = payload[:job] || payload[:jobs].first
23
+
24
+ queue = job.queue_name
21
25
  method = method_from_name(name)
22
26
  "Ruby/ActiveJob/#{queue}/#{method}"
23
27
  end
@@ -0,0 +1,23 @@
1
+ # This file is distributed under New Relic's license terms.
2
+ # See https://github.com/newrelic/newrelic-ruby-agent/blob/main/LICENSE for complete details.
3
+ # frozen_string_literal: true
4
+
5
+ module NewRelic
6
+ module Agent
7
+ module OpenTelemetry
8
+ module Trace
9
+ class Span < ::OpenTelemetry::Trace::Span
10
+ attr_reader :context
11
+
12
+ def initialize(segment:, transaction:)
13
+ @context = ::OpenTelemetry::Trace::SpanContext.new(
14
+ trace_id: transaction.trace_id,
15
+ span_id: segment.guid,
16
+ trace_flags: 1
17
+ )
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,38 @@
1
+ # This file is distributed under New Relic's license terms.
2
+ # See https://github.com/newrelic/newrelic-ruby-agent/blob/main/LICENSE for complete details.
3
+ # frozen_string_literal: true
4
+
5
+ module NewRelic
6
+ module Agent
7
+ module OpenTelemetry
8
+ module Trace
9
+ class Tracer < ::OpenTelemetry::Trace::Tracer
10
+ def initialize(name = nil, version = nil)
11
+ @name = name || ''
12
+ @version = version || ''
13
+ end
14
+
15
+ def in_span(name, attributes: nil, links: nil, start_timestamp: nil, kind: nil)
16
+ case kind
17
+ when :internal
18
+ begin
19
+ return yield unless NewRelic::Agent::Tracer.current_transaction
20
+
21
+ segment = NewRelic::Agent::Tracer.start_segment(name: name)
22
+ span = Span.new(segment: segment, transaction: segment.transaction)
23
+
24
+ ::OpenTelemetry::Trace.with_span(span) do
25
+ yield
26
+ end
27
+ ensure
28
+ segment&.finish
29
+ end
30
+ else
31
+ NewRelic::Agent.logger.debug("Span kind: #{kind} is not supported yet")
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,18 @@
1
+ # This file is distributed under New Relic's license terms.
2
+ # See https://github.com/newrelic/newrelic-ruby-agent/blob/main/LICENSE for complete details.
3
+ # frozen_string_literal: true
4
+
5
+ module NewRelic
6
+ module Agent
7
+ module OpenTelemetry
8
+ module Trace
9
+ class TracerProvider < ::OpenTelemetry::Trace::TracerProvider
10
+ # TODO: Add a registration mechanism for tracers like exists in the SDK
11
+ def tracer(name = nil, version = nil)
12
+ @tracer ||= Tracer.new(name, version)
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,15 @@
1
+ # This file is distributed under New Relic's license terms.
2
+ # See https://github.com/newrelic/newrelic-ruby-agent/blob/main/LICENSE for complete details.
3
+ # frozen_string_literal: true
4
+
5
+ module NewRelic
6
+ module Agent
7
+ module OpenTelemetry
8
+ module Trace
9
+ require_relative 'trace/tracer_provider'
10
+ require_relative 'trace/tracer'
11
+ require_relative 'trace/span'
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,26 @@
1
+ # This file is distributed under New Relic's license terms.
2
+ # See https://github.com/newrelic/newrelic-ruby-agent/blob/main/LICENSE for complete details.
3
+ # frozen_string_literal: true
4
+
5
+ module NewRelic
6
+ module Agent
7
+ class OpenTelemetryBridge
8
+ def initialize
9
+ # no-op without OpenTelemetry API & config
10
+ return unless defined?(OpenTelemetry) &&
11
+ NewRelic::Agent.config[:'opentelemetry_bridge.enabled']
12
+
13
+ OpenTelemetryBridge.install
14
+ end
15
+
16
+ private
17
+
18
+ def self.install
19
+ require 'opentelemetry' # requires the opentelemetry-api gem
20
+ require_relative 'opentelemetry/trace'
21
+
22
+ ::OpenTelemetry.tracer_provider = NewRelic::Agent::OpenTelemetry::Trace::TracerProvider.new
23
+ end
24
+ end
25
+ end
26
+ end
@@ -44,6 +44,7 @@ module NewRelic
44
44
  TRUSTED_PARENT_KEY = 'trustedParentId'
45
45
  TRACING_VENDORS_KEY = 'tracingVendors'
46
46
  TRANSACTION_NAME_KEY = 'transaction.name'
47
+ THREAD_ID_KEY = 'thread.id'
47
48
 
48
49
  # Strings for static values of the event structure
49
50
  EVENT_TYPE = 'Span'
@@ -135,7 +136,8 @@ module NewRelic
135
136
  PRIORITY_KEY => segment.transaction.priority,
136
137
  TIMESTAMP_KEY => milliseconds_since_epoch(segment),
137
138
  DURATION_KEY => segment.duration,
138
- NAME_KEY => segment.name
139
+ NAME_KEY => segment.name,
140
+ THREAD_ID_KEY => segment.thread_id
139
141
  }
140
142
 
141
143
  # with infinite-tracing, transactions may or may not be sampled!
@@ -19,7 +19,7 @@ module NewRelic
19
19
  # after its parent. We will use the optimized exclusive duration
20
20
  # calculation in all other cases.
21
21
  #
22
- attr_reader :start_time, :end_time, :duration, :exclusive_duration, :guid, :starting_segment_key
22
+ attr_reader :start_time, :end_time, :duration, :exclusive_duration, :guid, :starting_segment_key, :thread_id
23
23
  attr_accessor :name, :parent, :children_time, :transaction, :transaction_name, :llm_event
24
24
  attr_writer :record_metrics, :record_scoped_metric, :record_on_finish
25
25
  attr_reader :noticed_error
@@ -30,6 +30,7 @@ module NewRelic
30
30
  def initialize(name = nil, start_time = nil)
31
31
  @name = name
32
32
  @starting_segment_key = NewRelic::Agent::Tracer.current_segment_key
33
+ @thread_id = Thread.current.object_id
33
34
  @transaction_name = nil
34
35
  @transaction = nil
35
36
  @guid = NewRelic::Agent::GuidGenerator.generate_guid
@@ -43,12 +43,7 @@ module NewRelic
43
43
  end
44
44
 
45
45
  if request_path
46
- destinations = if allow_other_headers?
47
- default_destinations
48
- else
49
- AttributeFilter::DST_TRANSACTION_TRACER | AttributeFilter::DST_ERROR_COLLECTOR
50
- end
51
- txn.add_agent_attribute(:'request.uri', request_path, destinations)
46
+ txn.add_agent_attribute(:'request.uri', request_path, default_destinations)
52
47
  end
53
48
 
54
49
  if accept
@@ -136,10 +136,8 @@ module NewRelic
136
136
 
137
137
  transaction.distributed_tracer.parent_transaction_id = payload.transaction_id
138
138
 
139
- unless payload.sampled.nil?
140
- transaction.sampled = payload.sampled
141
- transaction.priority = payload.priority if payload.priority
142
- end
139
+ determine_sampling_decision(payload, header_data)
140
+
143
141
  NewRelic::Agent.increment_metric(ACCEPT_SUCCESS_METRIC)
144
142
  true
145
143
  rescue => e
@@ -148,6 +146,37 @@ module NewRelic
148
146
  false
149
147
  end
150
148
 
149
+ def determine_sampling_decision(payload, header_data)
150
+ if header_data.trace_parent['trace_flags'] == '01'
151
+ set_priority_and_sampled(NewRelic::Agent.config[:'distributed_tracing.sampler.remote_parent_sampled'], payload)
152
+ elsif header_data.trace_parent['trace_flags'] == '00'
153
+ set_priority_and_sampled(NewRelic::Agent.config[:'distributed_tracing.sampler.remote_parent_not_sampled'], payload)
154
+ else
155
+ use_nr_tracestate_sampled(payload)
156
+ end
157
+ rescue
158
+ use_nr_tracestate_sampled(payload)
159
+ end
160
+
161
+ def use_nr_tracestate_sampled(payload)
162
+ unless payload.sampled.nil?
163
+ transaction.sampled = payload.sampled
164
+ transaction.priority = payload.priority if payload.priority
165
+ end
166
+ end
167
+
168
+ def set_priority_and_sampled(config, payload)
169
+ if config == 'always_on'
170
+ transaction.sampled = true
171
+ transaction.priority = 2.0
172
+ elsif config == 'always_off'
173
+ transaction.sampled = false
174
+ transaction.priority = 0
175
+ else # default
176
+ use_nr_tracestate_sampled(payload)
177
+ end
178
+ end
179
+
151
180
  def ignore_trace_context?
152
181
  if trace_context_header_data
153
182
  NewRelic::Agent.increment_metric(IGNORE_MULTIPLE_ACCEPT_METRIC)
@@ -6,7 +6,7 @@
6
6
  module NewRelic
7
7
  module VERSION # :nodoc:
8
8
  MAJOR = 9
9
- MINOR = 18
9
+ MINOR = 19
10
10
  TINY = 0
11
11
 
12
12
  STRING = "#{MAJOR}.#{MINOR}.#{TINY}"
data/newrelic.yml CHANGED
@@ -359,6 +359,16 @@ common: &default_settings
359
359
  # enable this feature.
360
360
  # distributed_tracing.enabled: true
361
361
 
362
+ # This setting controls the behavior of transaction sampling when a remote
363
+ # parent is not sampled and the trace flag is not set in the traceparent.
364
+ # Available values are default, always_on, and always_off.
365
+ # distributed_tracing.sampler.remote_parent_not_sampled: default
366
+
367
+ # This setting controls the behavior of transaction sampling when a remote
368
+ # parent is sampled and the trace flag is set in the traceparent. Available
369
+ # values are default, always_on, and always_off.
370
+ # distributed_tracing.sampler.remote_parent_sampled: default
371
+
362
372
  # If true, the agent captures the Elasticsearch cluster name in transaction
363
373
  # traces.
364
374
  # elasticsearch.capture_cluster_name: true
@@ -409,7 +419,7 @@ common: &default_settings
409
419
  # classes specified here occurs, if its error message contains one of the
410
420
  # strings corresponding to it here, that error will be ignored.
411
421
  # This option can't be set via environment variable.
412
- # error_collector.ignore_messages: {"ThreadError" => ["queue empty"]}
422
+ # error_collector.ignore_messages: {ThreadError: ["queue empty"]}
413
423
 
414
424
  # A comma separated list of status codes, possibly including ranges. Errors
415
425
  # associated with these status codes, where applicable, will be ignored.
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: newrelic_rpm
3
3
  version: !ruby/object:Gem::Version
4
- version: 9.18.0
4
+ version: 9.19.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tanna McClure
@@ -10,7 +10,7 @@ authors:
10
10
  - Hannah Ramadan
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2025-04-02 00:00:00.000000000 Z
13
+ date: 2025-04-30 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: bundler
@@ -614,6 +614,11 @@ files:
614
614
  - lib/new_relic/agent/noticeable_error.rb
615
615
  - lib/new_relic/agent/null_logger.rb
616
616
  - lib/new_relic/agent/obfuscator.rb
617
+ - lib/new_relic/agent/opentelemetry/trace.rb
618
+ - lib/new_relic/agent/opentelemetry/trace/span.rb
619
+ - lib/new_relic/agent/opentelemetry/trace/tracer.rb
620
+ - lib/new_relic/agent/opentelemetry/trace/tracer_provider.rb
621
+ - lib/new_relic/agent/opentelemetry_bridge.rb
617
622
  - lib/new_relic/agent/parameter_filtering.rb
618
623
  - lib/new_relic/agent/payload_metric_mapping.rb
619
624
  - lib/new_relic/agent/pipe_channel_manager.rb