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
@@ -2,12 +2,30 @@
2
2
  # See https://github.com/newrelic/newrelic-ruby-agent/blob/main/LICENSE for complete details.
3
3
  # frozen_string_literal: true
4
4
 
5
- require 'new_relic/agent/instrumentation/notifications_subscriber'
5
+ require_relative 'notifications_subscriber'
6
6
 
7
7
  module NewRelic
8
8
  module Agent
9
9
  module Instrumentation
10
10
  class ActiveSupportSubscriber < NotificationsSubscriber
11
+ EVENT_NAME_TO_METHOD_NAME = {
12
+ 'cache_fetch_hit.active_support' => 'fetch_hit',
13
+ 'cache_generate.active_support' => 'generate',
14
+ 'cache_read.active_support' => 'read',
15
+ 'cache_write.active_support' => 'write',
16
+ 'cache_delete.active_support' => 'delete',
17
+ 'cache_exist?.active_support' => 'exist?',
18
+ 'cache_read_multi.active_support' => 'read_multi',
19
+ 'cache_write_multi.active_support' => 'write_multi',
20
+ 'cache_delete_multi.active_support' => 'delete_multi',
21
+ 'cache_delete_matched.active_support' => 'delete_matched',
22
+ 'cache_cleanup.active_support' => 'cleanup',
23
+ 'cache_increment.active_support' => 'increment',
24
+ 'cache_decrement.active_support' => 'decrement',
25
+ 'cache_prune.active_support' => 'prune',
26
+ 'message_serializer_fallback.active_support' => 'message_serializer_fallback'
27
+ }.freeze
28
+
11
29
  def add_segment_params(segment, payload)
12
30
  segment.params[:key] = payload[:key]
13
31
  segment.params[:store] = payload[:store]
@@ -18,22 +36,12 @@ module NewRelic
18
36
 
19
37
  def metric_name(name, payload)
20
38
  store = payload[:store]
21
- method = method_from_name(name)
39
+ method = method_name(name)
22
40
  "Ruby/ActiveSupport#{"/#{store}" if store}/#{method}"
23
41
  end
24
42
 
25
- PATTERN = /\Acache_([^\.]*)\.active_support\z/
26
-
27
- METHOD_NAME_MAPPING = Hash.new do |h, k|
28
- if PATTERN =~ k
29
- h[k] = $1
30
- else
31
- h[k] = NewRelic::UNKNOWN
32
- end
33
- end
34
-
35
- def method_from_name(name)
36
- METHOD_NAME_MAPPING[name]
43
+ def method_name(name)
44
+ EVENT_NAME_TO_METHOD_NAME.fetch(name, name.delete_prefix('cache_').delete_suffix('.active_support'))
37
45
  end
38
46
  end
39
47
  end
@@ -34,10 +34,7 @@ module NewRelic
34
34
  begin
35
35
  destination = exchange_name(name)
36
36
 
37
- tracing_enabled =
38
- NewRelic::Agent::CrossAppTracing.cross_app_enabled? ||
39
- NewRelic::Agent.config[:'distributed_tracing.enabled']
40
- opts[:headers] ||= {} if tracing_enabled
37
+ opts[:headers] ||= {} if NewRelic::Agent.config[:'distributed_tracing.enabled']
41
38
 
42
39
  segment = NewRelic::Agent::Messaging.start_amqp_publish_segment(
43
40
  library: LIBRARY,
@@ -14,7 +14,6 @@ DependencyDetection.defer do
14
14
  end
15
15
 
16
16
  executes do
17
- require 'new_relic/agent/distributed_tracing/cross_app_tracing'
18
17
  require 'new_relic/agent/messaging'
19
18
  require 'new_relic/agent/transaction/message_broker_segment'
20
19
  end
@@ -7,7 +7,7 @@ require_relative 'instrumentation'
7
7
  module NewRelic::Agent::Instrumentation
8
8
  module Curb
9
9
  module Chain
10
- def self.instrument! # rubocop:disable Metrics/AbcSize
10
+ def self.instrument!
11
11
  Curl::Easy.class_eval do
12
12
  include NewRelic::Agent::Instrumentation::Curb::Easy
13
13
 
@@ -69,7 +69,7 @@ module NewRelic::Agent::Instrumentation
69
69
  Curl::Multi.class_eval do
70
70
  include NewRelic::Agent::Instrumentation::Curb::Multi
71
71
 
72
- # Add CAT with callbacks if the request is serial
72
+ # Add tracing with callbacks if the request is serial
73
73
  def add_with_newrelic(curl)
74
74
  add_with_tracing(curl) { add_without_newrelic(curl) }
75
75
  end
@@ -70,7 +70,7 @@ module NewRelic
70
70
 
71
71
  INSTRUMENTATION_NAME = 'Curb'
72
72
 
73
- # Add CAT with callbacks if the request is serial
73
+ # Add tracing with callbacks if the request is serial
74
74
  def add_with_tracing(curl)
75
75
  if curl.respond_to?(:_nr_serial) && curl._nr_serial
76
76
  hook_pending_request(curl) if NewRelic::Agent::Tracer.tracing_enabled?
@@ -91,7 +91,7 @@ module NewRelic
91
91
  end
92
92
 
93
93
  # Instrument the specified +request+ (a Curl::Easy object)
94
- # and set up cross-application tracing if it's enabled.
94
+ # and set up distributed tracing headers.
95
95
  def hook_pending_request(request)
96
96
  wrapped_request, wrapped_response = wrap_request(request)
97
97
 
@@ -124,7 +124,6 @@ module NewRelic
124
124
  end
125
125
 
126
126
  # Install a callback that will record the response headers
127
- # to enable CAT linking
128
127
  def install_header_callback(request, wrapped_response)
129
128
  original_callback = request.on_header
130
129
  request._nr_original_on_header = original_callback
@@ -16,7 +16,6 @@ DependencyDetection.defer do
16
16
  end
17
17
 
18
18
  executes do
19
- require 'new_relic/agent/distributed_tracing/cross_app_tracing'
20
19
  require 'new_relic/agent/http_clients/curb_wrappers'
21
20
  end
22
21
 
@@ -4,7 +4,7 @@
4
4
 
5
5
  module ::Excon
6
6
  module Middleware
7
- class NewRelicCrossAppTracing
7
+ class NewRelicTracing
8
8
  TRACE_DATA_IVAR = :@newrelic_trace_data
9
9
  INSTRUMENTATION_NAME = 'Excon'
10
10
 
@@ -17,7 +17,7 @@ DependencyDetection.defer do
17
17
  # so we could safely subscribe and not be clobbered by future subscribers,
18
18
  # but alas, it does not yet.
19
19
 
20
- # TODO: MAJOR VERSION - update min version to 0.56.0
20
+ # We support and test 0.56.0 and above, but the instrumentation can still be installed and used with earlier versions.
21
21
  EXCON_MIN_VERSION = Gem::Version.new('0.19.0')
22
22
 
23
23
  depends_on do
@@ -34,7 +34,6 @@ DependencyDetection.defer do
34
34
  end
35
35
 
36
36
  def install_excon_instrumentation(excon_version)
37
- require 'new_relic/agent/distributed_tracing/cross_app_tracing'
38
37
  require 'new_relic/agent/http_clients/excon_wrappers'
39
38
 
40
39
  install_middleware_excon_instrumentation
@@ -46,7 +45,7 @@ DependencyDetection.defer do
46
45
  defaults = Excon.defaults
47
46
 
48
47
  if defaults[:middlewares]
49
- defaults[:middlewares] << Excon::Middleware::NewRelicCrossAppTracing
48
+ defaults[:middlewares] << Excon::Middleware::NewRelicTracing
50
49
  else
51
50
  NewRelic::Agent.logger.warn('Did not find :middlewares key in Excon.defaults, skipping Excon instrumentation')
52
51
  end
@@ -22,8 +22,7 @@ module NewRelic
22
22
 
23
23
  segment = request_segment(method)
24
24
  request_wrapper = NewRelic::Agent::Instrumentation::GRPC::Client::RequestWrapper.new(@host)
25
- # do not insert CAT headers for gRPC requests https://github.com/newrelic/newrelic-ruby-agent/issues/1730
26
- segment.add_request_headers(request_wrapper) unless CrossAppTracing.cross_app_enabled?
25
+ segment.add_request_headers(request_wrapper)
27
26
  metadata.merge!(request_wrapper.instance_variable_get(:@newrelic_metadata))
28
27
  grpc_message = nil
29
28
  grpc_status = 0
@@ -20,7 +20,6 @@ DependencyDetection.defer do
20
20
  end
21
21
 
22
22
  executes do
23
- require 'new_relic/agent/distributed_tracing/cross_app_tracing'
24
23
  require 'new_relic/agent/http_clients/httpclient_wrappers'
25
24
  end
26
25
 
@@ -14,7 +14,6 @@ DependencyDetection.defer do
14
14
  end
15
15
 
16
16
  executes do
17
- require 'new_relic/agent/distributed_tracing/cross_app_tracing'
18
17
  require 'new_relic/agent/http_clients/http_rb_wrappers'
19
18
  end
20
19
 
@@ -58,9 +58,7 @@ module NewRelic
58
58
  end.class_eval do
59
59
  include NewRelic::Agent::Instrumentation::Memcache::Tracer
60
60
 
61
- # TODO: MAJOR VERSION
62
61
  # Dalli - 3.1.0 renamed send_multiget to pipelined_get, but the method is otherwise the same
63
- # Once we no longer support Dalli < 3.1.0, remove this conditional logic
64
62
  if NewRelic::Helper.version_satisfied?(::Dalli::VERSION, '>=', '3.1.0')
65
63
  alias_method(:pipelined_get_without_newrelic_trace, :pipelined_get)
66
64
  def pipelined_get(keys)
@@ -84,9 +84,7 @@ module NewRelic::Agent::Instrumentation
84
84
  extend Helper
85
85
  include NewRelic::Agent::Instrumentation::Memcache::Tracer
86
86
 
87
- # TODO: MAJOR VERSION
88
87
  # Dalli - 3.1.0 renamed send_multiget to pipelined_get, but the method is otherwise the same
89
- # Once we no longer support Dalli < 3.1.0, remove this conditional logic
90
88
  if NewRelic::Helper.version_satisfied?(::Dalli::VERSION, '>=', '3.1.0')
91
89
  def pipelined_get(keys)
92
90
  send_multiget_with_newrelic_tracing(keys) { super }
@@ -20,9 +20,7 @@ module NewRelic::Agent::Instrumentation
20
20
  return false unless defined? ::Puma::Const::PUMA_VERSION
21
21
 
22
22
  version = Gem::Version.new(::Puma::Const::PUMA_VERSION)
23
- # TODO: MAJOR VERSION - update min_version to 3.9.0
24
- # min_version = Gem::Version.new('3.9.0')
25
- min_version = Gem::Version.new('2.12.0')
23
+ min_version = Gem::Version.new('3.9.0')
26
24
  version >= min_version
27
25
  end
28
26
 
@@ -18,7 +18,6 @@ DependencyDetection.defer do
18
18
  end
19
19
 
20
20
  executes do
21
- require 'new_relic/agent/distributed_tracing/cross_app_tracing'
22
21
  require 'new_relic/agent/http_clients/typhoeus_wrappers'
23
22
  end
24
23
 
@@ -29,14 +29,7 @@ module NewRelic
29
29
  end
30
30
 
31
31
  def attribute_name_exceptions
32
- # TODO: OLD RUBIES < 2.6
33
- # Hash#merge accepts multiple arguments in 2.6
34
- # Remove condition once support for Ruby <2.6 is dropped
35
- if NewRelic::Helper.version_satisfied?(RUBY_VERSION, '>=', '2.6.0')
36
- LlmEvent::ATTRIBUTE_NAME_EXCEPTIONS.merge(ResponseHeaders::ATTRIBUTE_NAME_EXCEPTIONS, ATTRIBUTE_NAME_EXCEPTIONS)
37
- else
38
- LlmEvent::ATTRIBUTE_NAME_EXCEPTIONS.merge(ResponseHeaders::ATTRIBUTE_NAME_EXCEPTIONS).merge(ATTRIBUTE_NAME_EXCEPTIONS)
39
- end
32
+ LlmEvent::ATTRIBUTE_NAME_EXCEPTIONS.merge(ResponseHeaders::ATTRIBUTE_NAME_EXCEPTIONS, ATTRIBUTE_NAME_EXCEPTIONS)
40
33
  end
41
34
 
42
35
  def event_name
@@ -22,14 +22,7 @@ module NewRelic
22
22
  end
23
23
 
24
24
  def attribute_name_exceptions
25
- # TODO: OLD RUBIES < 2.6
26
- # Hash#merge accepts multiple arguments in 2.6
27
- # Remove condition once support for Ruby <2.6 is dropped
28
- if NewRelic::Helper.version_satisfied?(RUBY_VERSION, '>=', '2.6.0')
29
- LlmEvent::ATTRIBUTE_NAME_EXCEPTIONS.merge(ResponseHeaders::ATTRIBUTE_NAME_EXCEPTIONS, ATTRIBUTE_NAME_EXCEPTIONS)
30
- else
31
- LlmEvent::ATTRIBUTE_NAME_EXCEPTIONS.merge(ResponseHeaders::ATTRIBUTE_NAME_EXCEPTIONS).merge(ATTRIBUTE_NAME_EXCEPTIONS)
32
- end
25
+ LlmEvent::ATTRIBUTE_NAME_EXCEPTIONS.merge(ResponseHeaders::ATTRIBUTE_NAME_EXCEPTIONS, ATTRIBUTE_NAME_EXCEPTIONS)
33
26
  end
34
27
 
35
28
  def event_name
@@ -16,6 +16,8 @@ module NewRelic
16
16
 
17
17
  RABBITMQ_TRANSPORT_TYPE = 'RabbitMQ'
18
18
 
19
+ REJECT_HEADERS = %w[newrelic traceparent tracestate NewRelicID NewRelicTransaction NewRelicSynthetics]
20
+
19
21
  ATTR_DESTINATION = AttributeFilter::DST_TRANSACTION_EVENTS |
20
22
  AttributeFilter::DST_TRANSACTION_TRACER |
21
23
  AttributeFilter::DST_ERROR_COLLECTOR
@@ -134,7 +136,7 @@ module NewRelic
134
136
  if headers
135
137
  NewRelic::Agent::DistributedTracing::accept_distributed_trace_headers(headers, library) # to handle the new w3c headers
136
138
  txn.distributed_tracer.consume_message_headers(headers, state, library) # to do the expected old things
137
- CrossAppTracing.reject_messaging_cat_headers(headers).each do |k, v|
139
+ reject_messaging_internal_headers(headers).each do |k, v|
138
140
  txn.add_agent_attribute(:"message.headers.#{k}", v, AttributeFilter::DST_NONE) unless v.nil?
139
141
  end
140
142
  end
@@ -193,8 +195,6 @@ module NewRelic
193
195
  correlation_id: nil,
194
196
  exchange_type: nil)
195
197
 
196
- raise ArgumentError, 'missing required argument: headers' if headers.nil? && CrossAppTracing.cross_app_enabled?
197
-
198
198
  # The following line needs else branch coverage
199
199
  original_headers = headers.nil? ? nil : headers.dup # rubocop:disable Style/SafeNavigation
200
200
 
@@ -265,8 +265,8 @@ module NewRelic
265
265
 
266
266
  if segment_parameters_enabled?
267
267
  if message_properties[:headers] && !message_properties[:headers].empty?
268
- non_cat_headers = CrossAppTracing.reject_messaging_cat_headers(message_properties[:headers])
269
- non_synth_headers = SyntheticsMonitor.reject_messaging_synthetics_header(non_cat_headers)
268
+ non_internal_headers = reject_messaging_internal_headers(message_properties[:headers])
269
+ non_synth_headers = SyntheticsMonitor.reject_messaging_synthetics_header(non_internal_headers)
270
270
  segment.params[:headers] = non_synth_headers unless non_synth_headers.empty?
271
271
  end
272
272
 
@@ -364,6 +364,13 @@ module NewRelic
364
364
 
365
365
  transaction_name
366
366
  end
367
+
368
+ # Filter out internal New Relic headers from message headers
369
+ def reject_messaging_internal_headers(headers)
370
+ return headers unless headers
371
+
372
+ headers.reject { |k, _v| REJECT_HEADERS.include?(k.to_s) }
373
+ end
367
374
  end
368
375
  end
369
376
  end
@@ -3,8 +3,7 @@
3
3
  # frozen_string_literal: true
4
4
 
5
5
  # This class serves as the base for objects wanting to monitor and respond to
6
- # incoming web requests. Examples include cross application tracing and
7
- # synthetics.
6
+ # incoming web requests. Examples include distributed tracing and synthetics.
8
7
  #
9
8
  # Subclasses are expected to define on_finished_configuring(events) which will
10
9
  # be called when the agent is fully configured. That method is expected to
@@ -7,6 +7,7 @@ module NewRelic
7
7
  class SyntheticsMonitor < InboundRequestMonitor
8
8
  SYNTHETICS_HEADER_KEY = 'HTTP_X_NEWRELIC_SYNTHETICS'
9
9
  SYNTHETICS_INFO_HEADER_KEY = 'HTTP_X_NEWRELIC_SYNTHETICS_INFO'
10
+ NON_HTTP_SYNTHETICS_HEADER_KEY = 'NewRelicSynthetics'
10
11
 
11
12
  SUPPORTED_VERSION = 1
12
13
  EXPECTED_PAYLOAD_LENGTH = 5
@@ -56,7 +57,7 @@ module NewRelic
56
57
  end
57
58
 
58
59
  def reject_messaging_synthetics_header(headers)
59
- headers.reject { |k, _| k == CrossAppTracing::NR_MESSAGE_BROKER_SYNTHETICS_HEADER }
60
+ headers.reject { |k, _| k == NON_HTTP_SYNTHETICS_HEADER_KEY }
60
61
  end
61
62
  end
62
63
  end
@@ -6,19 +6,16 @@ require_relative 'monitors/inbound_request_monitor'
6
6
 
7
7
  require_relative 'monitors/synthetics_monitor'
8
8
 
9
- require_relative 'monitors/cross_app_monitor'
10
9
  require_relative 'monitors/distributed_tracing_monitor'
11
10
 
12
11
  module NewRelic
13
12
  module Agent
14
13
  class Monitors
15
- attr_reader :cross_app_monitor
16
14
  attr_reader :synthetics_monitor
17
15
  attr_reader :distributed_tracing_monitor
18
16
 
19
17
  def initialize(events)
20
18
  @synthetics_monitor = NewRelic::Agent::SyntheticsMonitor.new(events)
21
- @cross_app_monitor = NewRelic::Agent::DistributedTracing::CrossAppMonitor.new(events)
22
19
  @distributed_tracing_monitor = NewRelic::Agent::DistributedTracing::Monitor.new(events)
23
20
  end
24
21
  end
@@ -23,20 +23,6 @@ module NewRelic
23
23
  Zlib::Deflate.deflate(data, Zlib::DEFAULT_COMPRESSION)
24
24
  end
25
25
  end
26
-
27
- module Gzip
28
- BINARY = 'BINARY'.freeze
29
-
30
- def self.encode(data, opts = nil)
31
- output = StringIO.new
32
- output.set_encoding(BINARY)
33
- gz = Zlib::GzipWriter.new(output, Zlib::DEFAULT_COMPRESSION, Zlib::DEFAULT_STRATEGY)
34
- gz.write(data)
35
- gz.close
36
- output.rewind
37
- output.string
38
- end
39
- end
40
26
  end
41
27
 
42
28
  module Base64CompressedJSON
@@ -7,7 +7,6 @@ require 'new_relic/agent/audit_logger'
7
7
  require 'new_relic/agent/new_relic_service/encoders'
8
8
  require 'new_relic/agent/new_relic_service/marshaller'
9
9
  require 'new_relic/agent/new_relic_service/json_marshaller'
10
- require 'new_relic/agent/new_relic_service/security_policy_settings'
11
10
 
12
11
  module NewRelic
13
12
  module Agent
@@ -18,13 +17,7 @@ module NewRelic
18
17
 
19
18
  # These include Errno connection errors, and all indicate that the
20
19
  # underlying TCP connection may be in a bad state.
21
- CONNECTION_ERRORS = [Net::OpenTimeout, Net::ReadTimeout, EOFError, SystemCallError, SocketError]
22
- # TODO: MAJOR VERSION - Net::WriteTimeout wasn't defined until Ruby 2.6.
23
- # Once support for Ruby 2.5 is dropped, we should simply include
24
- # Net::WriteTimeout in the connection errors array directly instead
25
- # of with a conditional
26
- CONNECTION_ERRORS << Net::WriteTimeout if defined?(Net::WriteTimeout)
27
- CONNECTION_ERRORS.freeze
20
+ CONNECTION_ERRORS = [Net::OpenTimeout, Net::ReadTimeout, EOFError, SystemCallError, SocketError, Net::WriteTimeout].freeze
28
21
 
29
22
  # The maximum number of times to attempt an HTTP request
30
23
  MAX_ATTEMPTS = 2
@@ -87,38 +80,19 @@ module NewRelic
87
80
 
88
81
  def connect(settings = {})
89
82
  @request_headers_map = nil
90
- security_policies = nil
91
- if response = preconnect
92
- if host = response['redirect_host']
93
- @collector = NewRelic::Control.instance.server_from_host(host)
94
- end
95
- if policies = response['security_policies']
96
- security_policies = SecurityPolicySettings.preliminary_settings(policies)
97
- settings.merge!(security_policies)
98
- end
83
+ if (response = preconnect) && (host = response['redirect_host'])
84
+ @collector = NewRelic::Control.instance.server_from_host(host)
99
85
  end
100
86
  response = invoke_remote(:connect, [settings])
101
87
  @request_headers_map = response['request_headers_map']
102
88
  self.agent_id = response['agent_run_id']
103
- response.merge!(security_policies) if security_policies
104
89
  response
105
90
  end
106
91
 
107
92
  def preconnect
108
- token = Agent.config[:security_policies_token]
109
-
110
- if token && !token.empty?
111
- response = invoke_remote(:preconnect, [{'security_policies_token' => token, 'high_security' => false}])
93
+ is_high_security = Agent.config[:high_security] ? true : false
112
94
 
113
- validator = SecurityPolicySettings::Validator.new(response)
114
- validator.validate_matching_agent_config!
115
-
116
- response
117
- elsif Agent.config[:high_security]
118
- invoke_remote(:preconnect, [{'high_security' => true}])
119
- else
120
- invoke_remote(:preconnect, [{'high_security' => false}])
121
- end
95
+ invoke_remote(:preconnect, [{'high_security' => is_high_security}])
122
96
  end
123
97
 
124
98
  def shutdown(time)
@@ -226,7 +200,7 @@ module NewRelic
226
200
  data = if encoding == 'deflate'
227
201
  Encoders::Compressed::Deflate.encode(data)
228
202
  else
229
- Encoders::Compressed::Gzip.encode(data)
203
+ Zlib.gzip(data)
230
204
  end
231
205
  end
232
206
  check_post_size(data, endpoint)
@@ -336,9 +310,7 @@ module NewRelic
336
310
  def setup_connection_timeouts(conn)
337
311
  conn.open_timeout = @request_timeout
338
312
  conn.read_timeout = @request_timeout
339
- # TODO: MAJOR VERSION - #write_timeout= requires Ruby 2.6+, so remove
340
- # the conditional check once support for Ruby 2.5 is dropped
341
- conn.write_timeout = @request_timeout if conn.respond_to?(:write_timeout=)
313
+ conn.write_timeout = @request_timeout
342
314
 
343
315
  if conn.respond_to?(:keep_alive_timeout) && NewRelic::Agent.config[:aggressive_keepalive]
344
316
  conn.keep_alive_timeout = NewRelic::Agent.config[:keep_alive_timeout]
@@ -463,6 +435,7 @@ module NewRelic
463
435
  Net::HTTPInternalServerError,
464
436
  Net::HTTPServiceUnavailable,
465
437
  Net::OpenTimeout,
438
+ Net::WriteTimeout,
466
439
  Net::ReadTimeout
467
440
  handle_server_connection_exception(response, endpoint)
468
441
  when Net::HTTPBadRequest,
@@ -484,20 +457,9 @@ module NewRelic
484
457
  when Net::HTTPGone
485
458
  handle_gone_response(response, endpoint)
486
459
  else
487
- # TODO: MAJOR VERSION - Net::WriteTimeout wasn't defined until
488
- # Ruby 2.6, so it can't be included in the case statement
489
- # as a constant and instead needs to be found here. Once
490
- # support for Ruby 2.5 is dropped, we should have
491
- # Net::WriteTimeout sit in the 'when' clause above alongside
492
- # Net::OpenTimeout and Net::ReadTimeout and this entire if/else
493
- # conditional can be removed.
494
- if response.respond_to?(:name) && response.name == 'Net::WriteTimeout'
495
- handle_server_connection_exception(response, endpoint)
496
- else
497
- record_endpoint_attempts_supportability_metrics(endpoint)
498
- record_error_response_supportability_metrics(response.code)
499
- raise UnrecoverableServerException, "#{response.code}: #{response.message}"
500
- end
460
+ record_endpoint_attempts_supportability_metrics(endpoint)
461
+ record_error_response_supportability_metrics(response.code)
462
+ raise UnrecoverableServerException, "#{response.code}: #{response.message}"
501
463
  end
502
464
  response
503
465
  end
@@ -8,6 +8,7 @@ module NewRelic
8
8
  module Trace
9
9
  class Span < ::OpenTelemetry::Trace::Span
10
10
  attr_accessor :finishable
11
+ attr_reader :status
11
12
 
12
13
  def finish(end_timestamp: nil)
13
14
  finishable&.finish
@@ -24,6 +25,46 @@ module NewRelic
24
25
  def record_exception(exception, attributes: nil)
25
26
  NewRelic::Agent.notice_error(exception, attributes: attributes)
26
27
  end
28
+
29
+ # @api private
30
+ def recording?
31
+ # in OTel, the recording? method checks for the end time on a span
32
+ # The closest method we have to this is finished? which exists on
33
+ # both transactions and segments.
34
+ !finishable&.finished?
35
+ end
36
+
37
+ # @api private
38
+ def name=(name)
39
+ if recording?
40
+ # overridden_name has slightly higher precedence than
41
+ # set_transaction_name, but still has a small chance of being
42
+ # overruled by other transaction naming operations if a
43
+ # @frozen_name has already been set. See Transaction#best_name.
44
+ if finishable.is_a?(NewRelic::Agent::Transaction)
45
+ finishable.overridden_name = name
46
+ # New Relic doesn't allow customers to rename segments
47
+ # so this method is just to deal with the OTel APIs that may
48
+ # try to rename a span after it's created.
49
+ elsif finishable.is_a?(NewRelic::Agent::Transaction::Segment)
50
+ finishable.instance_variable_set(:@name, name)
51
+ end
52
+ else
53
+ NewRelic::Agent.logger.warn('Calling name= on a finished OpenTelemetry Span')
54
+ end
55
+ end
56
+
57
+ # @api private
58
+ def status=(new_status)
59
+ # When OTel spans are inititalized they get an unset status
60
+ # During instrumentation, they may have this status overwrritten
61
+ # with an ok or error status. Error statuses may also have a description
62
+ @status = new_status
63
+ attrs = {'status.code' => new_status.code}
64
+ attrs['status.description'] = new_status.description unless new_status.description.empty?
65
+
66
+ NewRelic::Agent.add_custom_span_attributes(attrs)
67
+ end
27
68
  end
28
69
  end
29
70
  end
@@ -19,7 +19,9 @@ module NewRelic
19
19
  return if internal_span_kind_with_invalid_parent?(kind, parent_otel_context)
20
20
 
21
21
  nr_item = NewRelic::Agent::Tracer.start_transaction_or_segment(name: name, category: :otel)
22
+
22
23
  add_remote_context_to_txn(nr_item, parent_otel_context)
24
+
23
25
  nr_item
24
26
  else
25
27
  NewRelic::Agent::Tracer.start_segment(name: name)
@@ -27,6 +29,7 @@ module NewRelic
27
29
 
28
30
  otel_span = get_otel_span_from_finishable(finishable)
29
31
  otel_span.finishable = finishable
32
+ otel_span.status = ::OpenTelemetry::Trace::Status.unset
30
33
  add_remote_context_to_otel_span(otel_span, parent_otel_context)
31
34
  otel_span.add_attributes(attributes) if attributes
32
35
  otel_span
@@ -92,18 +95,24 @@ module NewRelic
92
95
  def set_nr_trace_state(distributed_tracer, otel_context)
93
96
  distributed_tracer.instance_variable_set(:@trace_state_payload, otel_context.tracestate)
94
97
  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)
98
+ trace_flags = parse_trace_flags(otel_context.trace_flags)
99
+
100
+ distributed_tracer.determine_sampling_decision(otel_context.tracestate, trace_flags)
96
101
  end
97
102
 
98
103
  def set_otel_trace_state(distributed_tracer, otel_context)
99
104
  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
105
  trace_flags = parse_trace_flags(otel_context.trace_flags)
106
- distributed_tracer.determine_sampling_decision(nr_payload, trace_flags)
106
+
107
+ if nr_entry
108
+ nr_payload = NewRelic::Agent::TraceContextPayload.from_s(nr_entry)
109
+
110
+ distributed_tracer.instance_variable_set(:@trace_state_payload, nr_payload)
111
+ distributed_tracer.parent_transaction_id = distributed_tracer.trace_state_payload.transaction_id
112
+ distributed_tracer.determine_sampling_decision(nr_payload, trace_flags)
113
+ else
114
+ distributed_tracer.determine_sampling_decision(NewRelic::Agent::TraceContextPayload::INVALID, trace_flags)
115
+ end
107
116
  end
108
117
 
109
118
  def parse_trace_flags(trace_flags)
@@ -6,11 +6,15 @@ module NewRelic
6
6
  module Agent
7
7
  class OpenTelemetryBridge
8
8
  def initialize
9
- # no-op without OpenTelemetry API & config
10
- return unless defined?(OpenTelemetry) &&
11
- NewRelic::Agent.config[:'opentelemetry.enabled']
12
-
13
- OpenTelemetryBridge.install
9
+ # currently, we only have support for traces
10
+ # this method should change when we add support for metrics and logs.
11
+ if defined?(OpenTelemetry) && Agent.config[:'opentelemetry.enabled'] && Agent.config[:'opentelemetry.traces.enabled']
12
+ OpenTelemetryBridge.install
13
+ NewRelic::Agent.record_metric('Supportability/Tracing/Ruby/OpenTelemetryBridge/enabled', 0.0)
14
+ # else
15
+ # This record metric calls happen before the agent is fully started, which causes us to log warnings every single time the agent runs.
16
+ # NewRelic::Agent.record_metric('Supportability/Tracing/Ruby/OpenTelemetryBridge/disabled', 0.0)
17
+ end
14
18
  end
15
19
 
16
20
  private