newrelic_rpm 9.12.0 → 9.14.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +120 -0
- data/README.md +16 -20
- data/lib/new_relic/agent/configuration/default_source.rb +112 -3
- data/lib/new_relic/agent/configuration/environment_source.rb +5 -1
- data/lib/new_relic/agent/configuration/manager.rb +23 -0
- data/lib/new_relic/agent/database/obfuscation_helpers.rb +11 -11
- data/lib/new_relic/agent/instrumentation/active_merchant.rb +0 -13
- data/lib/new_relic/agent/instrumentation/delayed_job_instrumentation.rb +0 -19
- data/lib/new_relic/agent/instrumentation/dynamodb/instrumentation.rb +3 -2
- data/lib/new_relic/agent/instrumentation/excon.rb +0 -16
- data/lib/new_relic/agent/instrumentation/grape.rb +3 -1
- data/lib/new_relic/agent/instrumentation/opensearch/chain.rb +21 -0
- data/lib/new_relic/agent/instrumentation/opensearch/instrumentation.rb +66 -0
- data/lib/new_relic/agent/instrumentation/opensearch/prepend.rb +13 -0
- data/lib/new_relic/agent/instrumentation/opensearch.rb +25 -0
- data/lib/new_relic/agent/instrumentation/rdkafka/chain.rb +71 -0
- data/lib/new_relic/agent/instrumentation/rdkafka/instrumentation.rb +70 -0
- data/lib/new_relic/agent/instrumentation/rdkafka/prepend.rb +66 -0
- data/lib/new_relic/agent/instrumentation/rdkafka.rb +27 -0
- data/lib/new_relic/agent/instrumentation/redis.rb +7 -5
- data/lib/new_relic/agent/instrumentation/ruby_kafka/chain.rb +55 -0
- data/lib/new_relic/agent/instrumentation/ruby_kafka/instrumentation.rb +67 -0
- data/lib/new_relic/agent/instrumentation/ruby_kafka/prepend.rb +50 -0
- data/lib/new_relic/agent/instrumentation/ruby_kafka.rb +27 -0
- data/lib/new_relic/agent/instrumentation/sidekiq.rb +0 -14
- data/lib/new_relic/agent/instrumentation/sinatra.rb +0 -13
- data/lib/new_relic/agent/instrumentation/view_component/instrumentation.rb +4 -1
- data/lib/new_relic/agent/javascript_instrumentor.rb +2 -3
- data/lib/new_relic/agent/messaging.rb +11 -5
- data/lib/new_relic/agent/serverless_handler.rb +241 -12
- data/lib/new_relic/agent/serverless_handler_event_sources.json +155 -0
- data/lib/new_relic/agent/serverless_handler_event_sources.rb +49 -0
- data/lib/new_relic/agent/system_info.rb +14 -0
- data/lib/new_relic/agent/transaction/request_attributes.rb +13 -1
- data/lib/new_relic/agent/transaction/trace_context.rb +1 -1
- data/lib/new_relic/agent.rb +93 -0
- data/lib/new_relic/control/frameworks/grape.rb +14 -0
- data/lib/new_relic/control/frameworks/padrino.rb +14 -0
- data/lib/new_relic/control/frameworks/rails4.rb +4 -2
- data/lib/new_relic/environment_report.rb +6 -2
- data/lib/new_relic/language_support.rb +7 -1
- data/lib/new_relic/local_environment.rb +1 -4
- data/lib/new_relic/version.rb +1 -1
- data/lib/tasks/helpers/newrelicyml.rb +73 -11
- data/lib/tasks/instrumentation_generator/instrumentation.thor +1 -1
- data/lib/tasks/instrumentation_generator/templates/dependency_detection.tt +3 -3
- data/newrelic.yml +118 -54
- metadata +19 -3
@@ -0,0 +1,66 @@
|
|
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::Agent::Instrumentation
|
6
|
+
module OpenSearch
|
7
|
+
PRODUCT_NAME = 'OpenSearch'
|
8
|
+
OPERATION = 'perform_request'
|
9
|
+
OPERATION_PATTERN = %r{/lib/opensearch/api/(?!.+#{OPERATION})}
|
10
|
+
INSTANCE_METHOD_PATTERN = /:in (?:`|')(?:.+#)?([^']+)'\z/
|
11
|
+
INSTRUMENTATION_NAME = NewRelic::Agent.base_name(name)
|
12
|
+
|
13
|
+
def perform_request_with_tracing(_method, _path, params = NewRelic::EMPTY_HASH, body = nil, _headers = nil, _opts = nil, &_block)
|
14
|
+
return yield unless NewRelic::Agent::Tracer.tracing_enabled?
|
15
|
+
|
16
|
+
segment = NewRelic::Agent::Tracer.start_datastore_segment(
|
17
|
+
product: PRODUCT_NAME,
|
18
|
+
operation: nr_operation || OPERATION,
|
19
|
+
host: nr_hosts[:host],
|
20
|
+
port_path_or_id: nr_hosts[:port],
|
21
|
+
database_name: nr_cluster_name
|
22
|
+
)
|
23
|
+
begin
|
24
|
+
NewRelic::Agent::Tracer.capture_segment_error(segment) { yield }
|
25
|
+
ensure
|
26
|
+
if segment
|
27
|
+
segment.notice_nosql_statement(nr_reported_query(body || params))
|
28
|
+
segment.finish
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
# See Elasticsearch instrumentation for explanation on Ruby 3.4 changes to match instance method
|
36
|
+
def nr_operation
|
37
|
+
location = caller_locations.detect { |loc| loc.to_s.match?(OPERATION_PATTERN) }
|
38
|
+
return unless location && location.to_s =~ INSTANCE_METHOD_PATTERN
|
39
|
+
|
40
|
+
Regexp.last_match(1)
|
41
|
+
end
|
42
|
+
|
43
|
+
def nr_reported_query(query)
|
44
|
+
return unless NewRelic::Agent.config[:'opensearch.capture_queries']
|
45
|
+
return query unless NewRelic::Agent.config[:'opensearch.obfuscate_queries']
|
46
|
+
|
47
|
+
NewRelic::Agent::Datastores::NosqlObfuscator.obfuscate_statement(query)
|
48
|
+
end
|
49
|
+
|
50
|
+
def nr_cluster_name
|
51
|
+
return @nr_cluster_name if defined?(@nr_cluster_name)
|
52
|
+
return if nr_hosts.empty?
|
53
|
+
|
54
|
+
NewRelic::Agent.disable_all_tracing do
|
55
|
+
@nr_cluster_name ||= perform_request('GET', '/').body['cluster_name']
|
56
|
+
end
|
57
|
+
rescue StandardError => e
|
58
|
+
NewRelic::Agent.logger.error('Failed to get cluster name for OpenSearch', e)
|
59
|
+
nil
|
60
|
+
end
|
61
|
+
|
62
|
+
def nr_hosts
|
63
|
+
@nr_hosts ||= (transport.hosts.first || NewRelic::EMPTY_HASH)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
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::Agent::Instrumentation
|
6
|
+
module OpenSearch::Prepend
|
7
|
+
include NewRelic::Agent::Instrumentation::OpenSearch
|
8
|
+
|
9
|
+
def perform_request(*args)
|
10
|
+
perform_request_with_tracing(*args) { super }
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,25 @@
|
|
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_relative 'opensearch/instrumentation'
|
6
|
+
require_relative 'opensearch/chain'
|
7
|
+
require_relative 'opensearch/prepend'
|
8
|
+
|
9
|
+
DependencyDetection.defer do
|
10
|
+
named :opensearch
|
11
|
+
|
12
|
+
depends_on do
|
13
|
+
defined?(OpenSearch)
|
14
|
+
end
|
15
|
+
|
16
|
+
executes do
|
17
|
+
NewRelic::Agent.logger.info('Installing opensearch-ruby instrumentation')
|
18
|
+
|
19
|
+
if use_prepend?
|
20
|
+
prepend_instrument OpenSearch::Transport::Client, NewRelic::Agent::Instrumentation::OpenSearch::Prepend
|
21
|
+
else
|
22
|
+
chain_instrument NewRelic::Agent::Instrumentation::OpenSearch::Chain
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,71 @@
|
|
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_relative 'instrumentation'
|
6
|
+
|
7
|
+
module NewRelic::Agent::Instrumentation
|
8
|
+
module Rdkafka::Chain
|
9
|
+
def self.instrument!
|
10
|
+
::Rdkafka::Producer.class_eval do
|
11
|
+
include NewRelic::Agent::Instrumentation::Rdkafka
|
12
|
+
|
13
|
+
alias_method(:produce_without_new_relic, :produce)
|
14
|
+
|
15
|
+
def produce(**kwargs)
|
16
|
+
produce_with_new_relic(kwargs) do |headers|
|
17
|
+
kwargs[:headers] = headers
|
18
|
+
produce_without_new_relic(**kwargs)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
::Rdkafka::Consumer.class_eval do
|
24
|
+
include NewRelic::Agent::Instrumentation::Rdkafka
|
25
|
+
|
26
|
+
alias_method(:each_without_new_relic, :each)
|
27
|
+
|
28
|
+
def each(**kwargs)
|
29
|
+
each_without_new_relic(**kwargs) do |message|
|
30
|
+
each_with_new_relic(message) do
|
31
|
+
yield(message)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
::Rdkafka::Config.class_eval do
|
38
|
+
include NewRelic::Agent::Instrumentation::RdkafkaConfig
|
39
|
+
|
40
|
+
alias_method(:producer_without_new_relic, :producer)
|
41
|
+
alias_method(:consumer_without_new_relic, :consumer)
|
42
|
+
|
43
|
+
if Gem::Version.new(::Rdkafka::VERSION) >= Gem::Version.new('0.16.0')
|
44
|
+
def producer(**kwargs)
|
45
|
+
producer_without_new_relic(**kwargs).tap do |producer|
|
46
|
+
set_nr_config(producer)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def consumer(**kwargs)
|
51
|
+
consumer_without_new_relic(**kwargs).tap do |consumer|
|
52
|
+
set_nr_config(consumer)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
else
|
56
|
+
def producer
|
57
|
+
producer_without_new_relic.tap do |producer|
|
58
|
+
set_nr_config(producer)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def consumer
|
63
|
+
consumer_without_new_relic.tap do |consumer|
|
64
|
+
set_nr_config(consumer)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,70 @@
|
|
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/messaging'
|
6
|
+
|
7
|
+
module NewRelic::Agent::Instrumentation
|
8
|
+
module Rdkafka
|
9
|
+
MESSAGING_LIBRARY = 'Kafka'
|
10
|
+
PRODUCE = 'Produce'
|
11
|
+
CONSUME = 'Consume'
|
12
|
+
|
13
|
+
INSTRUMENTATION_NAME = 'Rdkafka'
|
14
|
+
|
15
|
+
def produce_with_new_relic(*args)
|
16
|
+
NewRelic::Agent.record_instrumentation_invocation(INSTRUMENTATION_NAME)
|
17
|
+
|
18
|
+
topic_name = args[0][:topic]
|
19
|
+
segment = NewRelic::Agent::Tracer.start_message_broker_segment(
|
20
|
+
action: :produce,
|
21
|
+
library: MESSAGING_LIBRARY,
|
22
|
+
destination_type: :topic,
|
23
|
+
destination_name: topic_name
|
24
|
+
)
|
25
|
+
create_kafka_metrics(action: PRODUCE, topic: topic_name)
|
26
|
+
|
27
|
+
headers = args[0][:headers] || {}
|
28
|
+
::NewRelic::Agent::DistributedTracing.insert_distributed_trace_headers(headers)
|
29
|
+
|
30
|
+
NewRelic::Agent::Tracer.capture_segment_error(segment) { yield(headers) }
|
31
|
+
ensure
|
32
|
+
segment&.finish
|
33
|
+
end
|
34
|
+
|
35
|
+
def each_with_new_relic(message)
|
36
|
+
NewRelic::Agent.record_instrumentation_invocation(INSTRUMENTATION_NAME)
|
37
|
+
|
38
|
+
headers = message&.headers || {}
|
39
|
+
topic_name = message&.topic
|
40
|
+
|
41
|
+
NewRelic::Agent::Messaging.wrap_message_broker_consume_transaction(
|
42
|
+
library: MESSAGING_LIBRARY,
|
43
|
+
destination_type: :topic,
|
44
|
+
destination_name: topic_name,
|
45
|
+
headers: headers,
|
46
|
+
action: :consume
|
47
|
+
) do
|
48
|
+
create_kafka_metrics(action: CONSUME, topic: topic_name)
|
49
|
+
yield
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def create_kafka_metrics(action:, topic:)
|
54
|
+
hosts = []
|
55
|
+
# both 'bootstrap.servers' and 'metadata.broker.list' are valid ways to specify the Kafka server
|
56
|
+
hosts << @nr_config[:'bootstrap.servers'] if @nr_config[:'bootstrap.servers']
|
57
|
+
hosts << @nr_config[:'metadata.broker.list'] if @nr_config[:'metadata.broker.list']
|
58
|
+
hosts.each do |host|
|
59
|
+
NewRelic::Agent.record_metric("MessageBroker/Kafka/Nodes/#{host}/#{action}/#{topic}", 1)
|
60
|
+
NewRelic::Agent.record_metric("MessageBroker/Kafka/Nodes/#{host}", 1)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
module RdkafkaConfig
|
66
|
+
def set_nr_config(producer_or_consumer)
|
67
|
+
producer_or_consumer.instance_variable_set(:@nr_config, self)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,66 @@
|
|
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_relative 'instrumentation'
|
6
|
+
|
7
|
+
module NewRelic::Agent::Instrumentation
|
8
|
+
module RdkafkaProducer
|
9
|
+
module Prepend
|
10
|
+
include NewRelic::Agent::Instrumentation::Rdkafka
|
11
|
+
|
12
|
+
def produce(**kwargs)
|
13
|
+
produce_with_new_relic(kwargs) do |headers|
|
14
|
+
kwargs[:headers] = headers
|
15
|
+
super
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
module RdkafkaConsumer
|
22
|
+
module Prepend
|
23
|
+
include NewRelic::Agent::Instrumentation::Rdkafka
|
24
|
+
|
25
|
+
def each
|
26
|
+
super do |message|
|
27
|
+
each_with_new_relic(message) do
|
28
|
+
yield(message)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
module RdkafkaConfig
|
36
|
+
module Prepend
|
37
|
+
include NewRelic::Agent::Instrumentation::RdkafkaConfig
|
38
|
+
|
39
|
+
if defined?(::Rdkafka) && Gem::Version.new(::Rdkafka::VERSION) >= Gem::Version.new('0.16.0')
|
40
|
+
def producer(**kwargs)
|
41
|
+
super.tap do |producer|
|
42
|
+
set_nr_config(producer)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def consumer(**kwargs)
|
47
|
+
super.tap do |consumer|
|
48
|
+
set_nr_config(consumer)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
else # older versions
|
52
|
+
def producer
|
53
|
+
super.tap do |producer|
|
54
|
+
set_nr_config(producer)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def consumer
|
59
|
+
super.tap do |consumer|
|
60
|
+
set_nr_config(consumer)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,27 @@
|
|
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
|
+
DependencyDetection.defer do
|
6
|
+
named :rdkafka
|
7
|
+
|
8
|
+
depends_on do
|
9
|
+
defined?(Rdkafka)
|
10
|
+
end
|
11
|
+
|
12
|
+
executes do
|
13
|
+
NewRelic::Agent.logger.info('Installing rdkafka instrumentation')
|
14
|
+
|
15
|
+
require_relative 'rdkafka/instrumentation'
|
16
|
+
require_relative 'rdkafka/chain'
|
17
|
+
require_relative 'rdkafka/prepend'
|
18
|
+
|
19
|
+
if use_prepend?
|
20
|
+
prepend_instrument Rdkafka::Config, NewRelic::Agent::Instrumentation::RdkafkaConfig::Prepend
|
21
|
+
prepend_instrument Rdkafka::Producer, NewRelic::Agent::Instrumentation::RdkafkaProducer::Prepend
|
22
|
+
prepend_instrument Rdkafka::Consumer, NewRelic::Agent::Instrumentation::RdkafkaConsumer::Prepend
|
23
|
+
else
|
24
|
+
chain_instrument NewRelic::Agent::Instrumentation::Rdkafka::Chain
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -36,14 +36,16 @@ DependencyDetection.defer do
|
|
36
36
|
RedisClient.register(NewRelic::Agent::Instrumentation::RedisClient::Middleware)
|
37
37
|
|
38
38
|
if defined?(Redis::Cluster::Client)
|
39
|
-
|
39
|
+
RedisClient.register(NewRelic::Agent::Instrumentation::RedisClient::ClusterMiddleware)
|
40
40
|
end
|
41
41
|
end
|
42
42
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
43
|
+
unless defined?(Redis::Cluster::Client)
|
44
|
+
if use_prepend?
|
45
|
+
prepend_instrument Redis::Client, NewRelic::Agent::Instrumentation::Redis::Prepend
|
46
|
+
else
|
47
|
+
chain_instrument NewRelic::Agent::Instrumentation::Redis::Chain
|
48
|
+
end
|
47
49
|
end
|
48
50
|
end
|
49
51
|
end
|
@@ -0,0 +1,55 @@
|
|
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::Agent::Instrumentation
|
6
|
+
module RubyKafka::Chain
|
7
|
+
def self.instrument!
|
8
|
+
::Kafka::Producer.class_eval do
|
9
|
+
include NewRelic::Agent::Instrumentation::RubyKafka
|
10
|
+
|
11
|
+
alias_method(:produce_without_new_relic, :produce)
|
12
|
+
|
13
|
+
def produce(value, **kwargs)
|
14
|
+
produce_with_new_relic(value, **kwargs) do |headers|
|
15
|
+
kwargs[:headers] = headers
|
16
|
+
produce_without_new_relic(value, **kwargs)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
::Kafka::Consumer.class_eval do
|
22
|
+
include NewRelic::Agent::Instrumentation::RubyKafka
|
23
|
+
|
24
|
+
alias_method(:each_message_without_new_relic, :each_message)
|
25
|
+
|
26
|
+
def each_message(*args)
|
27
|
+
each_message_without_new_relic(*args) do |message|
|
28
|
+
each_message_with_new_relic(message) do
|
29
|
+
yield(message)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
::Kafka::Client.class_eval do
|
36
|
+
include NewRelic::Agent::Instrumentation::RubyKafkaConfig
|
37
|
+
|
38
|
+
alias_method(:producer_without_new_relic, :producer)
|
39
|
+
alias_method(:consumer_without_new_relic, :consumer)
|
40
|
+
|
41
|
+
def producer(**kwargs)
|
42
|
+
producer_without_new_relic(**kwargs).tap do |producer|
|
43
|
+
set_nr_config(producer)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def consumer(**kwargs)
|
48
|
+
consumer_without_new_relic(**kwargs).tap do |consumer|
|
49
|
+
set_nr_config(consumer)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,67 @@
|
|
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/messaging'
|
6
|
+
|
7
|
+
module NewRelic::Agent::Instrumentation
|
8
|
+
module RubyKafka
|
9
|
+
MESSAGING_LIBRARY = 'Kafka'
|
10
|
+
PRODUCE = 'Produce'
|
11
|
+
CONSUME = 'Consume'
|
12
|
+
|
13
|
+
INSTRUMENTATION_NAME = 'ruby-kafka'
|
14
|
+
|
15
|
+
def produce_with_new_relic(value, **kwargs)
|
16
|
+
NewRelic::Agent.record_instrumentation_invocation(INSTRUMENTATION_NAME)
|
17
|
+
|
18
|
+
topic_name = kwargs[:topic]
|
19
|
+
segment = NewRelic::Agent::Tracer.start_message_broker_segment(
|
20
|
+
action: :produce,
|
21
|
+
library: MESSAGING_LIBRARY,
|
22
|
+
destination_type: :topic,
|
23
|
+
destination_name: topic_name
|
24
|
+
)
|
25
|
+
create_kafka_metrics(action: PRODUCE, topic: topic_name)
|
26
|
+
|
27
|
+
headers = kwargs[:headers] || {}
|
28
|
+
::NewRelic::Agent::DistributedTracing.insert_distributed_trace_headers(headers)
|
29
|
+
|
30
|
+
NewRelic::Agent::Tracer.capture_segment_error(segment) { yield(headers) }
|
31
|
+
ensure
|
32
|
+
segment&.finish
|
33
|
+
end
|
34
|
+
|
35
|
+
def each_message_with_new_relic(message)
|
36
|
+
NewRelic::Agent.record_instrumentation_invocation(INSTRUMENTATION_NAME)
|
37
|
+
|
38
|
+
headers = message&.headers || {}
|
39
|
+
topic_name = message&.topic
|
40
|
+
|
41
|
+
NewRelic::Agent::Messaging.wrap_message_broker_consume_transaction(
|
42
|
+
library: MESSAGING_LIBRARY,
|
43
|
+
destination_type: :topic,
|
44
|
+
destination_name: topic_name,
|
45
|
+
headers: headers,
|
46
|
+
action: :consume
|
47
|
+
) do
|
48
|
+
create_kafka_metrics(action: CONSUME, topic: topic_name)
|
49
|
+
yield
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def create_kafka_metrics(action:, topic:)
|
54
|
+
@nr_config.each do |seed_broker|
|
55
|
+
host = "#{seed_broker&.host}:#{seed_broker&.port}"
|
56
|
+
NewRelic::Agent.record_metric("MessageBroker/Kafka/Nodes/#{host}/#{action}/#{topic}", 1)
|
57
|
+
NewRelic::Agent.record_metric("MessageBroker/Kafka/Nodes/#{host}", 1)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
module RubyKafkaConfig
|
63
|
+
def set_nr_config(producer_or_consumer)
|
64
|
+
producer_or_consumer.instance_variable_set(:@nr_config, @seed_brokers)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,50 @@
|
|
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::Agent::Instrumentation
|
6
|
+
module RubyKafkaProducer
|
7
|
+
module Prepend
|
8
|
+
include NewRelic::Agent::Instrumentation::RubyKafka
|
9
|
+
|
10
|
+
def produce(value, **kwargs)
|
11
|
+
produce_with_new_relic(value, **kwargs) do |headers|
|
12
|
+
kwargs[:headers] = headers
|
13
|
+
super
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
module RubyKafkaConsumer
|
20
|
+
module Prepend
|
21
|
+
include NewRelic::Agent::Instrumentation::RubyKafka
|
22
|
+
|
23
|
+
def each_message(*args)
|
24
|
+
super do |message|
|
25
|
+
each_message_with_new_relic(message) do
|
26
|
+
yield(message)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
module RubyKafkaClient
|
34
|
+
module Prepend
|
35
|
+
include NewRelic::Agent::Instrumentation::RubyKafkaConfig
|
36
|
+
|
37
|
+
def producer(**kwargs)
|
38
|
+
super.tap do |producer|
|
39
|
+
set_nr_config(producer)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def consumer(**kwargs)
|
44
|
+
super.tap do |consumer|
|
45
|
+
set_nr_config(consumer)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,27 @@
|
|
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_relative 'ruby_kafka/instrumentation'
|
6
|
+
require_relative 'ruby_kafka/chain'
|
7
|
+
require_relative 'ruby_kafka/prepend'
|
8
|
+
|
9
|
+
DependencyDetection.defer do
|
10
|
+
named :'ruby_kafka'
|
11
|
+
|
12
|
+
depends_on do
|
13
|
+
defined?(Kafka)
|
14
|
+
end
|
15
|
+
|
16
|
+
executes do
|
17
|
+
NewRelic::Agent.logger.info('Installing ruby-kafka instrumentation')
|
18
|
+
|
19
|
+
if use_prepend?
|
20
|
+
prepend_instrument Kafka::Producer, NewRelic::Agent::Instrumentation::RubyKafkaProducer::Prepend
|
21
|
+
prepend_instrument Kafka::Consumer, NewRelic::Agent::Instrumentation::RubyKafkaConsumer::Prepend
|
22
|
+
prepend_instrument Kafka::Client, NewRelic::Agent::Instrumentation::RubyKafkaClient::Prepend
|
23
|
+
else
|
24
|
+
chain_instrument NewRelic::Agent::Instrumentation::RubyKafka::Chain
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -41,18 +41,4 @@ DependencyDetection.defer do
|
|
41
41
|
end
|
42
42
|
end
|
43
43
|
end
|
44
|
-
|
45
|
-
executes do
|
46
|
-
next unless Gem::Version.new(Sidekiq::VERSION) < Gem::Version.new('5.0.0')
|
47
|
-
|
48
|
-
deprecation_msg = 'Instrumentation for Sidekiq versions below 5.0.0 is deprecated ' \
|
49
|
-
'and will be dropped entirely in a future major New Relic Ruby agent release.' \
|
50
|
-
'Please upgrade your Sidekiq version to continue receiving full support. '
|
51
|
-
|
52
|
-
NewRelic::Agent.logger.log_once(
|
53
|
-
:warn,
|
54
|
-
:deprecated_sidekiq_version,
|
55
|
-
deprecation_msg
|
56
|
-
)
|
57
|
-
end
|
58
44
|
end
|
@@ -42,17 +42,4 @@ DependencyDetection.defer do
|
|
42
42
|
chain_instrument NewRelic::Agent::Instrumentation::Sinatra::Build::Chain
|
43
43
|
end
|
44
44
|
end
|
45
|
-
|
46
|
-
executes do
|
47
|
-
next unless Gem::Version.new(Sinatra::VERSION) < Gem::Version.new('2.0.0')
|
48
|
-
|
49
|
-
deprecation_msg = 'The Ruby agent is dropping support for Sinatra versions below 2.0.0 ' \
|
50
|
-
'in version 9.0.0. Please upgrade your Sinatra version to continue receiving full compatibility. ' \
|
51
|
-
|
52
|
-
NewRelic::Agent.logger.log_once(
|
53
|
-
:warn,
|
54
|
-
:deprecated_sinatra_version,
|
55
|
-
deprecation_msg
|
56
|
-
)
|
57
|
-
end
|
58
45
|
end
|
@@ -11,7 +11,10 @@ module NewRelic::Agent::Instrumentation
|
|
11
11
|
|
12
12
|
begin
|
13
13
|
segment = NewRelic::Agent::Tracer.start_segment(
|
14
|
-
name: metric_name(
|
14
|
+
name: metric_name(
|
15
|
+
self.class.respond_to?(:identifier) ? self.class.identifier : nil,
|
16
|
+
self.class.name
|
17
|
+
)
|
15
18
|
)
|
16
19
|
yield
|
17
20
|
rescue => e
|
@@ -164,9 +164,8 @@ module NewRelic
|
|
164
164
|
|
165
165
|
def add_ssl_for_http(data)
|
166
166
|
ssl_for_http = NewRelic::Agent.config[:'browser_monitoring.ssl_for_http']
|
167
|
-
|
168
|
-
|
169
|
-
end
|
167
|
+
|
168
|
+
data[SSL_FOR_HTTP_KEY] = ssl_for_http if ssl_for_http
|
170
169
|
end
|
171
170
|
|
172
171
|
def add_attributes(data, txn)
|
@@ -117,7 +117,8 @@ module NewRelic
|
|
117
117
|
queue_name: nil,
|
118
118
|
exchange_type: nil,
|
119
119
|
reply_to: nil,
|
120
|
-
correlation_id: nil
|
120
|
+
correlation_id: nil,
|
121
|
+
action: nil)
|
121
122
|
|
122
123
|
state = Tracer.state
|
123
124
|
return yield if state.current_transaction
|
@@ -125,12 +126,12 @@ module NewRelic
|
|
125
126
|
txn = nil
|
126
127
|
|
127
128
|
begin
|
128
|
-
txn_name = transaction_name(library, destination_type, destination_name)
|
129
|
+
txn_name = transaction_name(library, destination_type, destination_name, action)
|
129
130
|
|
130
131
|
txn = Tracer.start_transaction(name: txn_name, category: :message)
|
131
|
-
|
132
132
|
if headers
|
133
|
-
|
133
|
+
NewRelic::Agent::DistributedTracing::accept_distributed_trace_headers(headers, library) # to handle the new w3c headers
|
134
|
+
txn.distributed_tracer.consume_message_headers(headers, state, library) # to do the expected old things
|
134
135
|
CrossAppTracing.reject_messaging_cat_headers(headers).each do |k, v|
|
135
136
|
txn.add_agent_attribute(:"message.headers.#{k}", v, AttributeFilter::DST_NONE) unless v.nil?
|
136
137
|
end
|
@@ -327,12 +328,17 @@ module NewRelic
|
|
327
328
|
NewRelic::Agent.config[:'message_tracer.segment_parameters.enabled']
|
328
329
|
end
|
329
330
|
|
330
|
-
def transaction_name(library, destination_type, destination_name)
|
331
|
+
def transaction_name(library, destination_type, destination_name, action = nil)
|
331
332
|
transaction_name = Transaction::MESSAGE_PREFIX + library
|
332
333
|
transaction_name << NewRelic::SLASH
|
333
334
|
transaction_name << Transaction::MessageBrokerSegment::TYPES[destination_type]
|
334
335
|
transaction_name << NewRelic::SLASH
|
335
336
|
|
337
|
+
if action == :consume
|
338
|
+
transaction_name << 'Consume'
|
339
|
+
transaction_name << NewRelic::SLASH
|
340
|
+
end
|
341
|
+
|
336
342
|
case destination_type
|
337
343
|
when :queue
|
338
344
|
transaction_name << Transaction::MessageBrokerSegment::NAMED
|