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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +136 -0
- data/README.md +0 -7
- data/lib/new_relic/agent/agent.rb +9 -4
- data/lib/new_relic/agent/configuration/default_source.rb +103 -181
- data/lib/new_relic/agent/configuration/environment_source.rb +7 -38
- data/lib/new_relic/agent/configuration/manager.rb +141 -59
- data/lib/new_relic/agent/configuration/sampler_config_validator.rb +54 -0
- data/lib/new_relic/agent/configuration/server_source.rb +0 -1
- data/lib/new_relic/agent/connect/response_handler.rb +0 -11
- data/lib/new_relic/agent/datastores.rb +13 -17
- data/lib/new_relic/agent/distributed_tracing.rb +0 -3
- data/lib/new_relic/agent/health_check.rb +1 -0
- data/lib/new_relic/agent/instrumentation/active_job.rb +1 -1
- data/lib/new_relic/agent/instrumentation/active_job_subscriber.rb +2 -1
- data/lib/new_relic/agent/instrumentation/active_record_helper.rb +1 -4
- data/lib/new_relic/agent/instrumentation/active_support.rb +8 -1
- data/lib/new_relic/agent/instrumentation/active_support_subscriber.rb +22 -14
- data/lib/new_relic/agent/instrumentation/bunny/instrumentation.rb +1 -4
- data/lib/new_relic/agent/instrumentation/bunny.rb +0 -1
- data/lib/new_relic/agent/instrumentation/curb/chain.rb +2 -2
- data/lib/new_relic/agent/instrumentation/curb/instrumentation.rb +2 -3
- data/lib/new_relic/agent/instrumentation/curb.rb +0 -1
- data/lib/new_relic/agent/instrumentation/excon/middleware.rb +1 -1
- data/lib/new_relic/agent/instrumentation/excon.rb +2 -3
- data/lib/new_relic/agent/instrumentation/grpc/client/instrumentation.rb +1 -2
- data/lib/new_relic/agent/instrumentation/httpclient.rb +0 -1
- data/lib/new_relic/agent/instrumentation/httprb.rb +0 -1
- data/lib/new_relic/agent/instrumentation/memcache/dalli.rb +0 -2
- data/lib/new_relic/agent/instrumentation/memcache/prepend.rb +0 -2
- data/lib/new_relic/agent/instrumentation/rack/helpers.rb +1 -3
- data/lib/new_relic/agent/instrumentation/typhoeus.rb +0 -1
- data/lib/new_relic/agent/llm/chat_completion_summary.rb +1 -8
- data/lib/new_relic/agent/llm/embedding.rb +1 -8
- data/lib/new_relic/agent/messaging.rb +12 -5
- data/lib/new_relic/agent/monitors/inbound_request_monitor.rb +1 -2
- data/lib/new_relic/agent/monitors/synthetics_monitor.rb +2 -1
- data/lib/new_relic/agent/monitors.rb +0 -3
- data/lib/new_relic/agent/new_relic_service/encoders.rb +0 -14
- data/lib/new_relic/agent/new_relic_service.rb +11 -49
- data/lib/new_relic/agent/opentelemetry/trace/span.rb +41 -0
- data/lib/new_relic/agent/opentelemetry/trace/tracer.rb +16 -7
- data/lib/new_relic/agent/opentelemetry_bridge.rb +9 -5
- data/lib/new_relic/agent/serverless_handler.rb +2 -2
- data/lib/new_relic/agent/span_event_primitive.rb +1 -1
- data/lib/new_relic/agent/sql_sampler.rb +0 -31
- data/lib/new_relic/agent/stats_engine.rb +1 -0
- data/lib/new_relic/agent/transaction/distributed_tracer.rb +12 -56
- data/lib/new_relic/agent/transaction/distributed_tracing.rb +11 -19
- data/lib/new_relic/agent/transaction/external_request_segment.rb +1 -131
- data/lib/new_relic/agent/transaction/message_broker_segment.rb +0 -2
- data/lib/new_relic/agent/transaction/trace_context.rb +33 -11
- data/lib/new_relic/agent/transaction.rb +35 -4
- data/lib/new_relic/agent/transaction_error_primitive.rb +0 -8
- data/lib/new_relic/agent/transaction_event_primitive.rb +0 -14
- data/lib/new_relic/agent/utilization/gcp.rb +2 -0
- data/lib/new_relic/agent.rb +11 -3
- data/lib/new_relic/cli/command.rb +2 -11
- data/lib/new_relic/control/instance_methods.rb +2 -15
- data/lib/new_relic/control/private_instance_methods.rb +2 -4
- data/lib/new_relic/control/server_methods.rb +0 -6
- data/lib/new_relic/helper.rb +21 -2
- data/lib/new_relic/language_support.rb +3 -34
- data/lib/new_relic/supportability_helper.rb +0 -4
- data/lib/new_relic/version.rb +2 -2
- data/lib/tasks/helpers/newrelicyml.rb +2 -2
- data/lib/tasks/helpers/version_bump.rb +1 -2
- data/newrelic.yml +25 -28
- data/newrelic_rpm.gemspec +10 -9
- metadata +27 -26
- data/bin/newrelic +0 -8
- data/lib/new_relic/agent/configuration/security_policy_source.rb +0 -246
- data/lib/new_relic/agent/distributed_tracing/cross_app_payload.rb +0 -44
- data/lib/new_relic/agent/distributed_tracing/cross_app_tracing.rb +0 -253
- data/lib/new_relic/agent/external.rb +0 -112
- data/lib/new_relic/agent/monitors/cross_app_monitor.rb +0 -117
- data/lib/new_relic/agent/new_relic_service/security_policy_settings.rb +0 -61
- data/lib/new_relic/cli/commands/deployments.rb +0 -206
- data/lib/new_relic/recipes/capistrano3.rb +0 -23
- data/lib/new_relic/recipes/capistrano_legacy.rb +0 -95
- data/lib/new_relic/recipes/helpers/send_deployment.rb +0 -70
- data/lib/new_relic/recipes.rb +0 -24
- 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
|
-
|
|
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 =
|
|
39
|
+
method = method_name(name)
|
|
22
40
|
"Ruby/ActiveSupport#{"/#{store}" if store}/#{method}"
|
|
23
41
|
end
|
|
24
42
|
|
|
25
|
-
|
|
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
|
-
|
|
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,
|
|
@@ -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!
|
|
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
|
|
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
|
|
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
|
|
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
|
|
@@ -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
|
-
#
|
|
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::
|
|
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
|
-
|
|
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
|
|
@@ -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
|
-
|
|
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
|
|
|
@@ -29,14 +29,7 @@ module NewRelic
|
|
|
29
29
|
end
|
|
30
30
|
|
|
31
31
|
def attribute_name_exceptions
|
|
32
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
269
|
-
non_synth_headers = SyntheticsMonitor.reject_messaging_synthetics_header(
|
|
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
|
|
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 ==
|
|
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
|
-
|
|
91
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
488
|
-
|
|
489
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
#
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
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
|