newrelic_rpm 9.19.0 → 9.20.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 (93) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +38 -0
  3. data/lib/new_relic/agent/configuration/default_source.rb +85 -85
  4. data/lib/new_relic/agent/configuration/manager.rb +5 -2
  5. data/lib/new_relic/agent/configuration/yaml_source.rb +2 -2
  6. data/lib/new_relic/agent/database.rb +1 -1
  7. data/lib/new_relic/agent/database_adapter.rb +1 -1
  8. data/lib/new_relic/agent/datastores/redis.rb +1 -1
  9. data/lib/new_relic/agent/distributed_tracing/cross_app_tracing.rb +1 -1
  10. data/lib/new_relic/agent/distributed_tracing.rb +2 -0
  11. data/lib/new_relic/agent/external.rb +2 -0
  12. data/lib/new_relic/agent/instrumentation/action_dispatch.rb +1 -1
  13. data/lib/new_relic/agent/instrumentation/action_dispatch_subscriber.rb +1 -1
  14. data/lib/new_relic/agent/instrumentation/action_mailbox.rb +1 -1
  15. data/lib/new_relic/agent/instrumentation/action_mailer.rb +1 -1
  16. data/lib/new_relic/agent/instrumentation/active_job.rb +1 -1
  17. data/lib/new_relic/agent/instrumentation/active_record.rb +6 -4
  18. data/lib/new_relic/agent/instrumentation/active_record_helper.rb +2 -2
  19. data/lib/new_relic/agent/instrumentation/active_record_notifications.rb +11 -9
  20. data/lib/new_relic/agent/instrumentation/active_record_prepend.rb +2 -2
  21. data/lib/new_relic/agent/instrumentation/async_http.rb +1 -1
  22. data/lib/new_relic/agent/instrumentation/aws_sdk_kinesis/instrumentation.rb +1 -1
  23. data/lib/new_relic/agent/instrumentation/concurrent_ruby.rb +1 -1
  24. data/lib/new_relic/agent/instrumentation/controller_instrumentation.rb +4 -0
  25. data/lib/new_relic/agent/instrumentation/curb.rb +1 -1
  26. data/lib/new_relic/agent/instrumentation/elasticsearch/chain.rb +1 -2
  27. data/lib/new_relic/agent/instrumentation/elasticsearch.rb +1 -1
  28. data/lib/new_relic/agent/instrumentation/ethon.rb +1 -1
  29. data/lib/new_relic/agent/instrumentation/excon.rb +1 -1
  30. data/lib/new_relic/agent/instrumentation/fiber/chain.rb +1 -1
  31. data/lib/new_relic/agent/instrumentation/fiber/prepend.rb +1 -1
  32. data/lib/new_relic/agent/instrumentation/httpclient.rb +1 -4
  33. data/lib/new_relic/agent/instrumentation/httpx/instrumentation.rb +1 -1
  34. data/lib/new_relic/agent/instrumentation/httpx.rb +1 -1
  35. data/lib/new_relic/agent/instrumentation/logstasher.rb +1 -1
  36. data/lib/new_relic/agent/instrumentation/memcache/dalli.rb +1 -1
  37. data/lib/new_relic/agent/instrumentation/memcache/helper.rb +2 -2
  38. data/lib/new_relic/agent/instrumentation/memcache/instrumentation.rb +1 -1
  39. data/lib/new_relic/agent/instrumentation/memcache/prepend.rb +1 -1
  40. data/lib/new_relic/agent/instrumentation/mongodb_command_subscriber.rb +1 -1
  41. data/lib/new_relic/agent/instrumentation/net_http.rb +2 -1
  42. data/lib/new_relic/agent/instrumentation/rake.rb +1 -1
  43. data/lib/new_relic/agent/instrumentation/rdkafka/chain.rb +2 -2
  44. data/lib/new_relic/agent/instrumentation/rdkafka/prepend.rb +2 -2
  45. data/lib/new_relic/agent/instrumentation/redis/constants.rb +2 -2
  46. data/lib/new_relic/agent/instrumentation/resque.rb +2 -2
  47. data/lib/new_relic/agent/instrumentation/roda.rb +1 -1
  48. data/lib/new_relic/agent/instrumentation/ruby_kafka/prepend.rb +1 -1
  49. data/lib/new_relic/agent/instrumentation/ruby_openai.rb +2 -2
  50. data/lib/new_relic/agent/instrumentation/sidekiq/extensions/delayed_class.rb +1 -1
  51. data/lib/new_relic/agent/instrumentation/stripe.rb +1 -1
  52. data/lib/new_relic/agent/instrumentation/typhoeus/instrumentation.rb +2 -2
  53. data/lib/new_relic/agent/llm/chat_completion_summary.rb +1 -1
  54. data/lib/new_relic/agent/llm/embedding.rb +1 -1
  55. data/lib/new_relic/agent/local_log_decorator.rb +1 -1
  56. data/lib/new_relic/agent/logging.rb +1 -1
  57. data/lib/new_relic/agent/messaging.rb +5 -0
  58. data/lib/new_relic/agent/method_tracer.rb +3 -0
  59. data/lib/new_relic/agent/monitors/inbound_request_monitor.rb +1 -1
  60. data/lib/new_relic/agent/monitors/synthetics_monitor.rb +1 -1
  61. data/lib/new_relic/agent/new_relic_service/json_marshaller.rb +2 -2
  62. data/lib/new_relic/agent/opentelemetry/context/propagation/trace_propagator.rb +66 -0
  63. data/lib/new_relic/agent/opentelemetry/context/propagation.rb +15 -0
  64. data/lib/new_relic/agent/opentelemetry/context.rb +13 -0
  65. data/lib/new_relic/agent/opentelemetry/trace/span.rb +15 -7
  66. data/lib/new_relic/agent/opentelemetry/trace/tracer.rb +106 -15
  67. data/lib/new_relic/agent/opentelemetry/transaction_patch.rb +69 -0
  68. data/lib/new_relic/agent/opentelemetry_bridge.rb +7 -1
  69. data/lib/new_relic/agent/parameter_filtering.rb +1 -1
  70. data/lib/new_relic/agent/samplers/cpu_sampler.rb +1 -1
  71. data/lib/new_relic/agent/samplers/memory_sampler.rb +1 -1
  72. data/lib/new_relic/agent/span_event_primitive.rb +5 -0
  73. data/lib/new_relic/agent/tracer.rb +1 -1
  74. data/lib/new_relic/agent/transaction/datastore_segment.rb +1 -1
  75. data/lib/new_relic/agent/transaction/distributed_tracer.rb +3 -3
  76. data/lib/new_relic/agent/transaction/message_broker_segment.rb +1 -1
  77. data/lib/new_relic/agent/transaction/trace_context.rb +4 -4
  78. data/lib/new_relic/agent/transaction_time_aggregator.rb +1 -1
  79. data/lib/new_relic/agent/utilization/ecs.rb +22 -0
  80. data/lib/new_relic/agent/utilization/ecs_v4.rb +22 -0
  81. data/lib/new_relic/agent/utilization_data.rb +25 -0
  82. data/lib/new_relic/agent/vm/c_ruby_vm.rb +3 -3
  83. data/lib/new_relic/agent.rb +28 -0
  84. data/lib/new_relic/constants.rb +1 -0
  85. data/lib/new_relic/control/instrumentation.rb +1 -1
  86. data/lib/new_relic/dependency_detection.rb +0 -1
  87. data/lib/new_relic/helper.rb +7 -0
  88. data/lib/new_relic/version.rb +1 -1
  89. data/lib/sequel/extensions/new_relic_instrumentation.rb +1 -1
  90. data/lib/tasks/helpers/newrelicyml.rb +2 -0
  91. data/newrelic.yml +14 -14
  92. data/newrelic_rpm.gemspec +1 -1
  93. metadata +11 -6
@@ -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 Context
9
+ module Propagation
10
+ require_relative 'propagation/trace_propagator'
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,13 @@
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 Context
9
+ require_relative 'context/propagation'
10
+ end
11
+ end
12
+ end
13
+ end
@@ -7,14 +7,22 @@ module NewRelic
7
7
  module OpenTelemetry
8
8
  module Trace
9
9
  class Span < ::OpenTelemetry::Trace::Span
10
- attr_reader :context
10
+ attr_accessor :finishable
11
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
- )
12
+ def finish(end_timestamp: nil)
13
+ finishable&.finish
14
+ end
15
+
16
+ def set_attribute(key, value)
17
+ NewRelic::Agent.add_custom_span_attributes(key => value)
18
+ end
19
+
20
+ def add_attributes(attributes)
21
+ NewRelic::Agent.add_custom_span_attributes(attributes)
22
+ end
23
+
24
+ def record_exception(exception, attributes: nil)
25
+ NewRelic::Agent.notice_error(exception, attributes: attributes)
18
26
  end
19
27
  end
20
28
  end
@@ -12,25 +12,116 @@ module NewRelic
12
12
  @version = version || ''
13
13
  end
14
14
 
15
+ def start_span(name, with_parent: nil, attributes: nil, links: nil, start_timestamp: nil, kind: nil)
16
+ parent_otel_context = ::OpenTelemetry::Trace.current_span(with_parent).context
17
+
18
+ finishable = if can_start_transaction?(parent_otel_context)
19
+ return if internal_span_kind_with_invalid_parent?(kind, parent_otel_context)
20
+
21
+ nr_item = NewRelic::Agent::Tracer.start_transaction_or_segment(name: name, category: :otel)
22
+ add_remote_context_to_txn(nr_item, parent_otel_context)
23
+ nr_item
24
+ else
25
+ NewRelic::Agent::Tracer.start_segment(name: name)
26
+ end
27
+
28
+ otel_span = get_otel_span_from_finishable(finishable)
29
+ otel_span.finishable = finishable
30
+ add_remote_context_to_otel_span(otel_span, parent_otel_context)
31
+ otel_span.add_attributes(attributes) if attributes
32
+ otel_span
33
+ end
34
+
15
35
  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
36
+ span = start_span(name, attributes: attributes, links: links, start_timestamp: start_timestamp, kind: kind)
37
+ begin
38
+ yield
39
+ rescue => e
40
+ # TODO: Update for segment errors if finishable is a segment
41
+ NewRelic::Agent.notice_error(e)
42
+ raise
43
+ end
44
+ ensure
45
+ span&.finish
46
+ end
47
+
48
+ private
49
+
50
+ def get_otel_span_from_finishable(finishable)
51
+ case finishable
52
+ when NewRelic::Agent::Transaction
53
+ finishable.segments.first.instance_variable_get(:@otel_span)
54
+ when NewRelic::Agent::Transaction::Segment
55
+ finishable.instance_variable_get(:@otel_span)
30
56
  else
31
- NewRelic::Agent.logger.debug("Span kind: #{kind} is not supported yet")
57
+ NewRelic::Agent.logger.warn('Tracer#get_otel_span_from_finishable failed to get span from finishable - finishable is not a transaction or segment')
58
+ nil
32
59
  end
33
60
  end
61
+
62
+ def can_start_transaction?(parent_otel_context)
63
+ parent_otel_context.remote? || !parent_otel_context.valid?
64
+ end
65
+
66
+ def internal_span_kind_with_invalid_parent?(kind, parent_otel_context)
67
+ !parent_otel_context.valid? && kind == :internal
68
+ end
69
+
70
+ def transaction_and_remote_parent?(txn, parent_otel_context)
71
+ txn.is_a?(NewRelic::Agent::Transaction) && parent_otel_context.remote?
72
+ end
73
+
74
+ def add_remote_context_to_txn(txn, parent_otel_context)
75
+ return unless transaction_and_remote_parent?(txn, parent_otel_context)
76
+
77
+ txn.trace_id = parent_otel_context.trace_id
78
+ txn.parent_span_id = parent_otel_context.span_id
79
+
80
+ set_tracestate(txn.distributed_tracer, parent_otel_context)
81
+ end
82
+
83
+ def set_tracestate(distributed_tracer, otel_context)
84
+ case otel_context.tracestate
85
+ when ::OpenTelemetry::Trace::Tracestate
86
+ set_otel_trace_state(distributed_tracer, otel_context)
87
+ when NewRelic::Agent::TraceContextPayload
88
+ set_nr_trace_state(distributed_tracer, otel_context)
89
+ end
90
+ end
91
+
92
+ def set_nr_trace_state(distributed_tracer, otel_context)
93
+ distributed_tracer.instance_variable_set(:@trace_state_payload, otel_context.tracestate)
94
+ distributed_tracer.parent_transaction_id = distributed_tracer.trace_state_payload.transaction_id
95
+ distributed_tracer.determine_sampling_decision(otel_context.tracestate, otel_context.trace_flags)
96
+ end
97
+
98
+ def set_otel_trace_state(distributed_tracer, otel_context)
99
+ nr_entry = otel_context.tracestate.value(Transaction::TraceContext::AccountHelpers.trace_state_entry_key)
100
+ return unless nr_entry
101
+
102
+ nr_payload = NewRelic::Agent::TraceContextPayload.from_s(nr_entry)
103
+ distributed_tracer.instance_variable_set(:@trace_state_payload, nr_payload)
104
+ distributed_tracer.parent_transaction_id = distributed_tracer.trace_state_payload.transaction_id
105
+ trace_flags = parse_trace_flags(otel_context.trace_flags)
106
+ distributed_tracer.determine_sampling_decision(nr_payload, trace_flags)
107
+ end
108
+
109
+ def parse_trace_flags(trace_flags)
110
+ case trace_flags
111
+ when String
112
+ trace_flags
113
+ when Integer
114
+ trace_flags.to_s
115
+ when ::OpenTelemetry::Trace::TraceFlags
116
+ trace_flags.sampled? ? '01' : '00'
117
+ end
118
+ end
119
+
120
+ def add_remote_context_to_otel_span(otel_span, parent_otel_context)
121
+ return unless transaction_and_remote_parent?(otel_span.finishable, parent_otel_context)
122
+
123
+ otel_span.context.instance_variable_set(:@trace_id, otel_span.finishable.trace_id)
124
+ end
34
125
  end
35
126
  end
36
127
  end
@@ -0,0 +1,69 @@
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 TransactionPatch
9
+ attr_accessor :opentelemetry_context
10
+
11
+ def initialize(_category, _options)
12
+ @opentelemetry_context = {}
13
+ super
14
+ end
15
+
16
+ def set_current_segment(new_segment)
17
+ @current_segment_lock.synchronize do
18
+ unless opentelemetry_context.empty?
19
+ ::OpenTelemetry::Context.detach(opentelemetry_context[otel_current_span_key])
20
+ end
21
+
22
+ span = find_or_create_span(new_segment)
23
+ ctx = ::OpenTelemetry::Context.current.set_value(otel_current_span_key, span)
24
+ token = ::OpenTelemetry::Context.attach(ctx)
25
+
26
+ opentelemetry_context[otel_current_span_key] = token
27
+ end
28
+
29
+ super
30
+ end
31
+
32
+ def remove_current_segment_by_thread_id(id)
33
+ # make sure the context is fully detached when the transaction ends
34
+ @current_segment_lock.synchronize do
35
+ ::OpenTelemetry::Context.detach(opentelemetry_context[otel_current_span_key])
36
+ opentelemetry_context.delete(id)
37
+ end
38
+
39
+ super
40
+ end
41
+
42
+ private
43
+
44
+ def find_or_create_span(segment)
45
+ if segment.instance_variable_defined?(:@otel_span)
46
+ segment.instance_variable_get(:@otel_span)
47
+ else
48
+ span = Trace::Span.new(span_context: span_context_from_segment(segment))
49
+ segment.instance_variable_set(:@otel_span, span)
50
+ span
51
+ end
52
+ end
53
+
54
+ def span_context_from_segment(segment)
55
+ ::OpenTelemetry::Trace::SpanContext.new(
56
+ trace_id: segment.transaction.trace_id,
57
+ span_id: segment.guid,
58
+ remote: false
59
+ )
60
+ end
61
+
62
+ def otel_current_span_key
63
+ # CURRENT_SPAN_KEY is a private constant
64
+ ::OpenTelemetry::Trace.const_get(:CURRENT_SPAN_KEY)
65
+ end
66
+ end
67
+ end
68
+ end
69
+ end
@@ -18,8 +18,14 @@ module NewRelic
18
18
  def self.install
19
19
  require 'opentelemetry' # requires the opentelemetry-api gem
20
20
  require_relative 'opentelemetry/trace'
21
+ require_relative 'opentelemetry/transaction_patch'
22
+ require_relative 'opentelemetry/context'
21
23
 
22
- ::OpenTelemetry.tracer_provider = NewRelic::Agent::OpenTelemetry::Trace::TracerProvider.new
24
+ # TODO: Add a warning if SDK gem is installed
25
+
26
+ ::OpenTelemetry.tracer_provider = OpenTelemetry::Trace::TracerProvider.new
27
+ Transaction.prepend(OpenTelemetry::TransactionPatch)
28
+ ::OpenTelemetry.propagation = OpenTelemetry::Context::Propagation::TracePropagator.new
23
29
  end
24
30
  end
25
31
  end
@@ -9,7 +9,7 @@ module NewRelic
9
9
 
10
10
  ACTION_DISPATCH_PARAMETER_FILTER ||= 'action_dispatch.parameter_filter'.freeze
11
11
 
12
- if defined?(Rails) && Gem::Version.new(::Rails::VERSION::STRING) >= Gem::Version.new('5.0.0')
12
+ if defined?(Rails) && NewRelic::Helper.version_satisfied?(::Rails::VERSION::STRING, '>=', '5.0.0')
13
13
  Rails.application.config.to_prepare do
14
14
  RAILS_FILTER_CLASS ||= if defined?(ActiveSupport::ParameterFilter)
15
15
  ActiveSupport::ParameterFilter
@@ -42,7 +42,7 @@ module NewRelic
42
42
  # Process.times on JRuby < 1.7.0 reports wall clock elapsed time,
43
43
  # not actual cpu time used, so this sampler can only be used on JRuby >= 1.7.0.
44
44
  if defined?(JRuby)
45
- return JRUBY_VERSION >= '1.7.0'
45
+ return NewRelic::Helper.version_satisfied?(JRUBY_VERSION, '>=', '1.7.0')
46
46
  end
47
47
 
48
48
  true
@@ -50,7 +50,7 @@ module NewRelic
50
50
  begin
51
51
  NewRelic::Helper.run_command('uname -s').downcase
52
52
  rescue NewRelic::CommandRunFailedError, NewRelic::CommandExecutableNotFoundError
53
- 'unknown'
53
+ NewRelic::UNKNOWN_LOWER
54
54
  end
55
55
  else
56
56
  RUBY_PLATFORM.downcase
@@ -40,6 +40,7 @@ module NewRelic
40
40
  SERVER_ADDRESS_KEY = 'server.address'
41
41
  SERVER_PORT_KEY = 'server.port'
42
42
  SPAN_KIND_KEY = 'span.kind'
43
+ STACKTRACE_KEY = 'code.stacktrace'
43
44
  ENTRY_POINT_KEY = 'nr.entryPoint'
44
45
  TRUSTED_PARENT_KEY = 'trustedParentId'
45
46
  TRACING_VENDORS_KEY = 'tracingVendors'
@@ -122,6 +123,10 @@ module NewRelic
122
123
  agent_attributes[DB_STATEMENT_KEY] = truncate(segment.nosql_statement, DB_STATEMENT_MAX_BYTES)
123
124
  end
124
125
 
126
+ if segment.params[:backtrace]
127
+ agent_attributes[STACKTRACE_KEY] = segment.params[:backtrace]
128
+ end
129
+
125
130
  [intrinsics, custom_attributes(segment), agent_attributes.merge(agent_attributes(segment))]
126
131
  end
127
132
 
@@ -247,7 +247,7 @@ module NewRelic
247
247
  log_error('start_segment', exception)
248
248
  end
249
249
 
250
- UNKNOWN = 'Unknown'.freeze
250
+ UNKNOWN = NewRelic::UNKNOWN
251
251
  OTHER = 'other'.freeze
252
252
 
253
253
  # Creates and starts a datastore segment used to time
@@ -11,7 +11,7 @@ module NewRelic
11
11
  module Agent
12
12
  class Transaction
13
13
  class DatastoreSegment < Segment
14
- UNKNOWN = 'unknown'.freeze
14
+ UNKNOWN = NewRelic::UNKNOWN_LOWER
15
15
 
16
16
  attr_reader :product, :operation, :collection, :sql_statement, :nosql_statement, :host, :port_path_or_id
17
17
  attr_accessor :database_name, :record_sql
@@ -35,7 +35,7 @@ module NewRelic
35
35
  end
36
36
 
37
37
  def caller_transport_type
38
- @caller_transport_type ||= 'Unknown'
38
+ @caller_transport_type ||= NewRelic::UNKNOWN
39
39
  end
40
40
 
41
41
  def accept_transport_type_from_api(value)
@@ -127,7 +127,7 @@ module NewRelic
127
127
  def consume_message_synthetics_headers(headers)
128
128
  synthetics_header = headers[CrossAppTracing::NR_MESSAGE_BROKER_SYNTHETICS_HEADER]
129
129
  if synthetics_header and
130
- incoming_payload = ::JSON.load(deobfuscate(synthetics_header)) and
130
+ incoming_payload = ::JSON.parse(deobfuscate(synthetics_header)) and
131
131
  SyntheticsMonitor.is_valid_payload?(incoming_payload) and
132
132
  SyntheticsMonitor.is_supported_version?(incoming_payload) and
133
133
  SyntheticsMonitor.is_trusted?(incoming_payload)
@@ -167,7 +167,7 @@ module NewRelic
167
167
  return unless CrossAppTracing.trusted_valid_cross_app_id?(decoded_id)
168
168
 
169
169
  txn_header = headers[CrossAppTracing::NR_MESSAGE_BROKER_TXN_HEADER]
170
- txn_info = ::JSON.load(deobfuscate(txn_header))
170
+ txn_info = ::JSON.parse(deobfuscate(txn_header))
171
171
  payload = CrossAppPayload.new(decoded_id, transaction, txn_info)
172
172
 
173
173
  @cross_app_payload = payload
@@ -18,7 +18,7 @@ module NewRelic
18
18
  STREAM = 'Stream'.freeze
19
19
  TEMP = 'Temp'.freeze
20
20
  TOPIC = 'Topic'.freeze
21
- UNKNOWN = 'Unknown'.freeze
21
+ UNKNOWN = NewRelic::UNKNOWN
22
22
 
23
23
  DESTINATION_TYPES = [
24
24
  :exchange,
@@ -136,7 +136,7 @@ module NewRelic
136
136
 
137
137
  transaction.distributed_tracer.parent_transaction_id = payload.transaction_id
138
138
 
139
- determine_sampling_decision(payload, header_data)
139
+ determine_sampling_decision(payload, header_data.trace_parent['trace_flags'])
140
140
 
141
141
  NewRelic::Agent.increment_metric(ACCEPT_SUCCESS_METRIC)
142
142
  true
@@ -146,10 +146,10 @@ module NewRelic
146
146
  false
147
147
  end
148
148
 
149
- def determine_sampling_decision(payload, header_data)
150
- if header_data.trace_parent['trace_flags'] == '01'
149
+ def determine_sampling_decision(payload, trace_flags)
150
+ if trace_flags == '01'
151
151
  set_priority_and_sampled(NewRelic::Agent.config[:'distributed_tracing.sampler.remote_parent_sampled'], payload)
152
- elsif header_data.trace_parent['trace_flags'] == '00'
152
+ elsif trace_flags == '00'
153
153
  set_priority_and_sampled(NewRelic::Agent.config[:'distributed_tracing.sampler.remote_parent_not_sampled'], payload)
154
154
  else
155
155
  use_nr_tracestate_sampled(payload)
@@ -150,7 +150,7 @@ module NewRelic
150
150
  # rubocop:disable Style/SafeNavigation
151
151
  transaction_name = transaction_name = Tracer.current_transaction &&
152
152
  Tracer.current_transaction.best_name ||
153
- 'unknown'
153
+ NewRelic::UNKNOWN_LOWER
154
154
  # rubocop:enable Style/SafeNavigation
155
155
  NewRelic::Agent.logger.warn("Unable to calculate elapsed transaction time for #{transaction_name}")
156
156
  end
@@ -0,0 +1,22 @@
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
+ require 'new_relic/agent/utilization/vendor'
6
+
7
+ module NewRelic
8
+ module Agent
9
+ module Utilization
10
+ class ECS < Vendor
11
+ vendor_name 'ecs'
12
+ endpoint ENV['ECS_CONTAINER_METADATA_URI'] || ''
13
+ headers 'Metadata' => 'true'
14
+ keys %w[DockerId]
15
+
16
+ def transform_key(key)
17
+ 'ecs' + key
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,22 @@
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
+ require 'new_relic/agent/utilization/vendor'
6
+
7
+ module NewRelic
8
+ module Agent
9
+ module Utilization
10
+ class ECSV4 < Vendor
11
+ vendor_name 'ecs_v4'
12
+ endpoint ENV['ECS_CONTAINER_METADATA_URI_V4'] || ''
13
+ headers 'Metadata' => 'true'
14
+ keys %w[DockerId]
15
+
16
+ def transform_key(key)
17
+ 'ecs' + key
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -6,6 +6,8 @@ require 'new_relic/agent/utilization/aws'
6
6
  require 'new_relic/agent/utilization/gcp'
7
7
  require 'new_relic/agent/utilization/azure'
8
8
  require 'new_relic/agent/utilization/pcf'
9
+ require 'new_relic/agent/utilization/ecs'
10
+ require 'new_relic/agent/utilization/ecs_v4'
9
11
 
10
12
  module NewRelic
11
13
  module Agent
@@ -84,10 +86,32 @@ module NewRelic
84
86
  result
85
87
  end
86
88
 
89
+ def append_ecs_info(collector_hash)
90
+ return unless Agent.config[:'utilization.detect_aws']
91
+
92
+ Thread.new do
93
+ # try v4 first, and only try unversioned endpoint if v4 fails
94
+ ecs = Utilization::ECSV4.new
95
+ if ecs.detect
96
+ collector_hash[:vendors] ||= {}
97
+ collector_hash[:vendors][:ecs] = ecs.metadata
98
+ else
99
+ ecs = Utilization::ECS.new
100
+ if ecs.detect
101
+ collector_hash[:vendors] ||= {}
102
+ collector_hash[:vendors][:ecs] = ecs.metadata
103
+ end
104
+ end
105
+ end
106
+ end
107
+
87
108
  def append_vendor_info(collector_hash)
88
109
  threads = []
89
110
  complete = false
90
111
 
112
+ # ecs needs be checked even if AWS check succeeds
113
+ ecs_thread = append_ecs_info(collector_hash)
114
+
91
115
  VENDORS.each_pair do |klass, config_option|
92
116
  next unless Agent.config[config_option]
93
117
 
@@ -106,6 +130,7 @@ module NewRelic
106
130
  while complete == false && threads.any?(&:alive?)
107
131
  sleep 0.01
108
132
  end
133
+ ecs_thread&.join
109
134
  end
110
135
 
111
136
  def append_docker_info(collector_hash)
@@ -61,7 +61,7 @@ module NewRelic
61
61
  end
62
62
 
63
63
  def gather_constant_cache_invalidations
64
- RubyVM.stat[RUBY_VERSION >= '3.2.0' ? :constant_cache_invalidations : :global_constant_state]
64
+ RubyVM.stat[NewRelic::Helper.version_satisfied?(RUBY_VERSION, '>=', '3.2.0') ? :constant_cache_invalidations : :global_constant_state]
65
65
  end
66
66
 
67
67
  def gather_constant_cache_misses
@@ -86,9 +86,9 @@ module NewRelic
86
86
  when :gc_total_time
87
87
  NewRelic::LanguageSupport.gc_profiler_enabled?
88
88
  when :method_cache_invalidations
89
- RUBY_VERSION < '3.0.0'
89
+ NewRelic::Helper.version_satisfied?(RUBY_VERSION, '<', '3.0.0')
90
90
  when :constant_cache_misses
91
- RUBY_VERSION >= '3.2.0'
91
+ NewRelic::Helper.version_satisfied?(RUBY_VERSION, '>=', '3.2.0')
92
92
  else
93
93
  false
94
94
  end