newrelic_rpm 9.7.0 → 9.16.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +376 -2
- data/README.md +17 -18
- data/Rakefile +1 -1
- data/lib/boot/strap.rb +101 -0
- data/lib/new_relic/agent/agent.rb +4 -1
- data/lib/new_relic/agent/agent_helpers/connect.rb +10 -8
- data/lib/new_relic/agent/agent_helpers/start_worker_thread.rb +1 -1
- data/lib/new_relic/agent/agent_helpers/startup.rb +2 -1
- data/lib/new_relic/agent/agent_logger.rb +3 -1
- data/lib/new_relic/agent/aws.rb +68 -0
- data/lib/new_relic/agent/configuration/default_source.rb +519 -23
- data/lib/new_relic/agent/configuration/environment_source.rb +14 -2
- data/lib/new_relic/agent/configuration/high_security_source.rb +1 -0
- data/lib/new_relic/agent/configuration/manager.rb +51 -8
- data/lib/new_relic/agent/configuration/security_policy_source.rb +11 -0
- data/lib/new_relic/agent/configuration/yaml_source.rb +2 -0
- data/lib/new_relic/agent/connect/request_builder.rb +1 -1
- data/lib/new_relic/agent/custom_event_aggregator.rb +27 -1
- data/lib/new_relic/agent/database/obfuscation_helpers.rb +11 -11
- data/lib/new_relic/agent/database/obfuscator.rb +1 -0
- data/lib/new_relic/agent/database.rb +39 -0
- data/lib/new_relic/agent/distributed_tracing/distributed_trace_payload.rb +1 -5
- data/lib/new_relic/agent/error_collector.rb +39 -10
- data/lib/new_relic/agent/harvester.rb +1 -1
- data/lib/new_relic/agent/instrumentation/active_merchant.rb +0 -13
- data/lib/new_relic/agent/instrumentation/active_record.rb +1 -8
- data/lib/new_relic/agent/instrumentation/active_record_helper.rb +3 -0
- data/lib/new_relic/agent/instrumentation/active_record_subscriber.rb +1 -12
- data/lib/new_relic/agent/instrumentation/active_support_broadcast_logger/instrumentation.rb +7 -3
- data/lib/new_relic/agent/instrumentation/active_support_broadcast_logger.rb +0 -2
- data/lib/new_relic/agent/instrumentation/active_support_logger.rb +0 -2
- data/lib/new_relic/agent/instrumentation/async_http.rb +4 -3
- data/lib/new_relic/agent/instrumentation/aws_sdk_lambda/chain.rb +33 -0
- data/lib/new_relic/agent/instrumentation/aws_sdk_lambda/instrumentation.rb +93 -0
- data/lib/new_relic/agent/instrumentation/aws_sdk_lambda/prepend.rb +23 -0
- data/lib/new_relic/agent/instrumentation/aws_sdk_lambda.rb +23 -0
- data/lib/new_relic/agent/instrumentation/aws_sqs/chain.rb +37 -0
- data/lib/new_relic/agent/instrumentation/aws_sqs/instrumentation.rb +67 -0
- data/lib/new_relic/agent/instrumentation/aws_sqs/prepend.rb +21 -0
- data/lib/new_relic/agent/instrumentation/aws_sqs.rb +23 -0
- data/lib/new_relic/agent/instrumentation/bunny/instrumentation.rb +14 -0
- data/lib/new_relic/agent/instrumentation/bunny.rb +3 -4
- data/lib/new_relic/agent/instrumentation/concurrent_ruby.rb +1 -2
- data/lib/new_relic/agent/instrumentation/curb.rb +3 -4
- data/lib/new_relic/agent/instrumentation/delayed_job_instrumentation.rb +0 -23
- data/lib/new_relic/agent/instrumentation/dynamodb/chain.rb +27 -0
- data/lib/new_relic/agent/instrumentation/dynamodb/instrumentation.rb +64 -0
- data/lib/new_relic/agent/instrumentation/dynamodb/prepend.rb +19 -0
- data/lib/new_relic/agent/instrumentation/dynamodb.rb +23 -0
- data/lib/new_relic/agent/instrumentation/elasticsearch/instrumentation.rb +58 -8
- data/lib/new_relic/agent/instrumentation/elasticsearch.rb +0 -2
- data/lib/new_relic/agent/instrumentation/ethon.rb +0 -4
- data/lib/new_relic/agent/instrumentation/excon.rb +0 -16
- data/lib/new_relic/agent/instrumentation/fiber.rb +0 -2
- data/lib/new_relic/agent/instrumentation/grape.rb +1 -1
- data/lib/new_relic/agent/instrumentation/grpc/client/instrumentation.rb +0 -1
- data/lib/new_relic/agent/instrumentation/grpc_server.rb +1 -1
- 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/httpx.rb +0 -4
- data/lib/new_relic/agent/instrumentation/logger.rb +1 -3
- data/lib/new_relic/agent/instrumentation/logstasher/chain.rb +21 -0
- data/lib/new_relic/agent/instrumentation/logstasher/instrumentation.rb +24 -0
- data/lib/new_relic/agent/instrumentation/logstasher/prepend.rb +13 -0
- data/lib/new_relic/agent/instrumentation/logstasher.rb +25 -0
- data/lib/new_relic/agent/instrumentation/memcache.rb +0 -1
- data/lib/new_relic/agent/instrumentation/net_http/instrumentation.rb +6 -0
- 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 +23 -0
- data/lib/new_relic/agent/instrumentation/padrino.rb +3 -3
- data/lib/new_relic/agent/instrumentation/rack/instrumentation.rb +3 -0
- data/lib/new_relic/agent/instrumentation/rails_notifications/action_controller.rb +9 -5
- data/lib/new_relic/agent/instrumentation/rake.rb +0 -1
- data/lib/new_relic/agent/instrumentation/rdkafka/chain.rb +72 -0
- data/lib/new_relic/agent/instrumentation/rdkafka/instrumentation.rb +70 -0
- data/lib/new_relic/agent/instrumentation/rdkafka/prepend.rb +67 -0
- data/lib/new_relic/agent/instrumentation/rdkafka.rb +25 -0
- data/lib/new_relic/agent/instrumentation/redis/cluster_middleware.rb +26 -0
- data/lib/new_relic/agent/instrumentation/redis/instrumentation.rb +14 -11
- data/lib/new_relic/agent/instrumentation/redis/middleware.rb +3 -0
- data/lib/new_relic/agent/instrumentation/redis.rb +11 -5
- data/lib/new_relic/agent/instrumentation/resque.rb +0 -4
- data/lib/new_relic/agent/instrumentation/roda.rb +4 -4
- 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 +60 -0
- data/lib/new_relic/agent/instrumentation/ruby_kafka.rb +25 -0
- data/lib/new_relic/agent/instrumentation/ruby_openai/chain.rb +36 -0
- data/lib/new_relic/agent/instrumentation/ruby_openai/instrumentation.rb +196 -0
- data/lib/new_relic/agent/instrumentation/ruby_openai/prepend.rb +20 -0
- data/lib/new_relic/agent/instrumentation/ruby_openai.rb +35 -0
- data/lib/new_relic/agent/instrumentation/sidekiq.rb +0 -14
- data/lib/new_relic/agent/instrumentation/sinatra.rb +3 -19
- data/lib/new_relic/agent/instrumentation/stripe_subscriber.rb +22 -1
- data/lib/new_relic/agent/instrumentation/thread.rb +0 -2
- data/lib/new_relic/agent/instrumentation/tilt.rb +0 -4
- data/lib/new_relic/agent/instrumentation/typhoeus.rb +0 -1
- data/lib/new_relic/agent/instrumentation/view_component/instrumentation.rb +13 -6
- data/lib/new_relic/agent/instrumentation/view_component.rb +0 -2
- data/lib/new_relic/agent/javascript_instrumentor.rb +2 -3
- data/lib/new_relic/agent/llm/chat_completion_message.rb +25 -0
- data/lib/new_relic/agent/llm/chat_completion_summary.rb +66 -0
- data/lib/new_relic/agent/llm/embedding.rb +60 -0
- data/lib/new_relic/agent/llm/llm_event.rb +95 -0
- data/lib/new_relic/agent/llm/response_headers.rb +80 -0
- data/lib/new_relic/agent/llm.rb +49 -0
- data/lib/new_relic/agent/local_log_decorator.rb +8 -1
- data/lib/new_relic/agent/log_event_aggregator.rb +120 -44
- data/lib/new_relic/agent/messaging.rb +11 -5
- data/lib/new_relic/agent/new_relic_service.rb +12 -2
- data/lib/new_relic/agent/serverless_handler.rb +400 -0
- 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/span_event_primitive.rb +8 -10
- data/lib/new_relic/agent/system_info.rb +14 -0
- data/lib/new_relic/agent/threading/agent_thread.rb +1 -2
- data/lib/new_relic/agent/tracer.rb +5 -5
- data/lib/new_relic/agent/transaction/abstract_segment.rb +1 -1
- data/lib/new_relic/agent/transaction/external_request_segment.rb +0 -10
- 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/transaction/tracing.rb +2 -2
- data/lib/new_relic/agent/transaction.rb +2 -6
- data/lib/new_relic/agent/transaction_error_primitive.rb +23 -19
- data/lib/new_relic/agent.rb +198 -10
- data/lib/new_relic/constants.rb +2 -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 +1 -3
- data/lib/new_relic/control/instance_methods.rb +8 -0
- data/lib/new_relic/control/private_instance_methods.rb +4 -0
- data/lib/new_relic/control/security_interface.rb +57 -0
- data/lib/new_relic/control.rb +1 -1
- data/lib/new_relic/dependency_detection.rb +10 -5
- data/lib/new_relic/environment_report.rb +2 -2
- data/lib/new_relic/helper.rb +15 -0
- data/lib/new_relic/language_support.rb +3 -1
- data/lib/new_relic/local_environment.rb +14 -10
- data/lib/new_relic/rack/browser_monitoring.rb +28 -12
- data/lib/new_relic/supportability_helper.rb +2 -0
- data/lib/new_relic/thread_local_storage.rb +31 -0
- data/lib/new_relic/version.rb +2 -2
- data/lib/sequel/extensions/new_relic_instrumentation.rb +3 -2
- data/lib/tasks/config.rake +8 -3
- data/lib/tasks/gha.rake +31 -0
- data/lib/tasks/helpers/config.html.erb +3 -2
- data/lib/tasks/helpers/format.rb +1 -1
- data/lib/tasks/helpers/newrelicyml.rb +76 -13
- data/lib/tasks/instrumentation_generator/instrumentation.thor +31 -22
- data/lib/tasks/instrumentation_generator/templates/chain.tt +0 -1
- data/lib/tasks/instrumentation_generator/templates/chain_method.tt +0 -1
- data/lib/tasks/instrumentation_generator/templates/dependency_detection.tt +11 -8
- data/lib/tasks/instrumentation_generator/templates/newrelic.yml.tt +1 -1
- data/newrelic.yml +387 -143
- data/newrelic_rpm.gemspec +2 -0
- data/test/agent_helper.rb +17 -2
- metadata +80 -3
@@ -0,0 +1,93 @@
|
|
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 'json'
|
6
|
+
|
7
|
+
module NewRelic::Agent::Instrumentation
|
8
|
+
module AwsSdkLambda
|
9
|
+
INSTRUMENTATION_NAME = 'aws_sdk_lambda'
|
10
|
+
AWS_SERVICE = 'lambda'
|
11
|
+
CLOUD_PLATFORM = 'aws_lambda'
|
12
|
+
WRAPPED_RESPONSE = Struct.new(:status_code, :has_status_code?)
|
13
|
+
|
14
|
+
def invoke_with_new_relic(*args)
|
15
|
+
with_tracing(:invoke, *args) { yield }
|
16
|
+
end
|
17
|
+
|
18
|
+
def invoke_async_with_new_relic(*args)
|
19
|
+
with_tracing(:invoke_async, *args) { yield }
|
20
|
+
end
|
21
|
+
|
22
|
+
def invoke_with_response_stream_with_new_relic(*args)
|
23
|
+
with_tracing(:invoke_with_response_stream, *args) { yield }
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def with_tracing(action, *args)
|
29
|
+
segment = generate_segment(action, *args)
|
30
|
+
|
31
|
+
# prevent additional instrumentation for things like Net::HTTP from
|
32
|
+
# creating any segments that may appear as redundant / confusing
|
33
|
+
NewRelic::Agent.disable_all_tracing do
|
34
|
+
response = NewRelic::Agent::Tracer.capture_segment_error(segment) { yield }
|
35
|
+
process_response(response, segment)
|
36
|
+
response
|
37
|
+
end
|
38
|
+
ensure
|
39
|
+
segment&.finish
|
40
|
+
end
|
41
|
+
|
42
|
+
def process_response(response, segment)
|
43
|
+
process_function_error(response) if response.respond_to?(:function_error)
|
44
|
+
rescue => e
|
45
|
+
NewRelic::Agent.logger.error("Error processing aws-sdk-lambda invocation response: #{e}")
|
46
|
+
end
|
47
|
+
|
48
|
+
# notice error that was raised / unhandled by the function
|
49
|
+
def process_function_error(response)
|
50
|
+
function_error = response.function_error
|
51
|
+
return unless function_error
|
52
|
+
|
53
|
+
msg = "[#{function_error}]"
|
54
|
+
payload = response.payload&.string if response.respond_to?(:payload)
|
55
|
+
payload_hash = JSON.parse(payload) if payload
|
56
|
+
msg = "#{msg} #{payload_hash['errorType']} - #{payload_hash['errorMessage']}" if payload_hash
|
57
|
+
e = StandardError.new(msg)
|
58
|
+
e.set_backtrace(payload_hash['stackTrace']) if payload_hash
|
59
|
+
|
60
|
+
NewRelic::Agent.notice_error(e)
|
61
|
+
end
|
62
|
+
|
63
|
+
def generate_segment(action, options = {})
|
64
|
+
function = function_name(options)
|
65
|
+
region = aws_region
|
66
|
+
arn = aws_arn(function, region)
|
67
|
+
segment = NewRelic::Agent::Tracer.start_segment(name: "Lambda/#{action}/#{function}")
|
68
|
+
segment.add_agent_attribute('cloud.account.id', nr_account_id)
|
69
|
+
segment.add_agent_attribute('cloud.platform', CLOUD_PLATFORM)
|
70
|
+
segment.add_agent_attribute('cloud.region', region)
|
71
|
+
segment.add_agent_attribute('cloud.resource_id', arn) if arn
|
72
|
+
segment
|
73
|
+
end
|
74
|
+
|
75
|
+
def function_name(options = {})
|
76
|
+
(options.fetch(:function_name, nil) if options.respond_to?(:fetch)) || NewRelic::UNKNOWN
|
77
|
+
end
|
78
|
+
|
79
|
+
def aws_region
|
80
|
+
config&.region if self.respond_to?(:config)
|
81
|
+
end
|
82
|
+
|
83
|
+
def aws_arn(function, region)
|
84
|
+
NewRelic::Agent::Aws.create_arn(AWS_SERVICE, "function:#{function}", region, nr_account_id)
|
85
|
+
end
|
86
|
+
|
87
|
+
def nr_account_id
|
88
|
+
return @nr_account_id if defined?(@nr_account_id)
|
89
|
+
|
90
|
+
@nr_account_id = NewRelic::Agent::Aws.get_account_id(config)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# This file is distributed under New Relic's license terms.
|
2
|
+
# See https://github.com/newrelic/newrelic-ruby-agent/blob/main/LICENSE for complete details.
|
3
|
+
# frozen_string_literal: true
|
4
|
+
|
5
|
+
require_relative 'instrumentation'
|
6
|
+
|
7
|
+
module NewRelic::Agent::Instrumentation
|
8
|
+
module AwsSdkLambda::Prepend
|
9
|
+
include NewRelic::Agent::Instrumentation::AwsSdkLambda
|
10
|
+
|
11
|
+
def invoke(*args)
|
12
|
+
invoke_with_new_relic(*args) { super }
|
13
|
+
end
|
14
|
+
|
15
|
+
def invoke_async(*args)
|
16
|
+
invoke_async_with_new_relic(*args) { super }
|
17
|
+
end
|
18
|
+
|
19
|
+
def invoke_with_response_stream(*args)
|
20
|
+
invoke_with_response_stream_with_new_relic(*args) { super }
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# This file is distributed under New Relic's license terms.
|
2
|
+
# See https://github.com/newrelic/newrelic-ruby-agent/blob/main/LICENSE for complete details.
|
3
|
+
# frozen_string_literal: true
|
4
|
+
|
5
|
+
DependencyDetection.defer do
|
6
|
+
named :aws_sdk_lambda
|
7
|
+
|
8
|
+
depends_on do
|
9
|
+
defined?(Aws::Lambda::Client)
|
10
|
+
end
|
11
|
+
|
12
|
+
executes do
|
13
|
+
require_relative 'aws_sdk_lambda/instrumentation'
|
14
|
+
|
15
|
+
if use_prepend?
|
16
|
+
require_relative 'aws_sdk_lambda/prepend'
|
17
|
+
prepend_instrument Aws::Lambda::Client, NewRelic::Agent::Instrumentation::AwsSdkLambda::Prepend
|
18
|
+
else
|
19
|
+
require_relative 'aws_sdk_lambda/chain'
|
20
|
+
chain_instrument NewRelic::Agent::Instrumentation::AwsSdkLambda::Chain
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,37 @@
|
|
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 AwsSqs::Chain
|
7
|
+
def self.instrument!
|
8
|
+
::Aws::SQS::Client.class_eval do
|
9
|
+
include NewRelic::Agent::Instrumentation::AwsSqs
|
10
|
+
|
11
|
+
alias_method(:send_message_without_new_relic, :send_message)
|
12
|
+
|
13
|
+
def send_message(*args)
|
14
|
+
send_message_with_new_relic(*args) do
|
15
|
+
send_message_without_new_relic(*args)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
alias_method(:send_message_batch_without_new_relic, :send_message_batch)
|
20
|
+
|
21
|
+
def send_message_batch(*args)
|
22
|
+
send_message_batch_with_new_relic(*args) do
|
23
|
+
send_message_batch_without_new_relic(*args)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
alias_method(:receive_message_without_new_relic, :receive_message)
|
28
|
+
|
29
|
+
def receive_message(*args)
|
30
|
+
receive_message_with_new_relic(*args) do
|
31
|
+
receive_message_without_new_relic(*args)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
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
|
+
module NewRelic::Agent::Instrumentation
|
6
|
+
module AwsSqs
|
7
|
+
MESSAGING_LIBRARY = 'SQS'
|
8
|
+
|
9
|
+
def send_message_with_new_relic(*args)
|
10
|
+
with_tracing(:produce, args) do
|
11
|
+
yield
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def send_message_batch_with_new_relic(*args)
|
16
|
+
with_tracing(:produce, args) do
|
17
|
+
yield
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def receive_message_with_new_relic(*args)
|
22
|
+
with_tracing(:consume, args) do
|
23
|
+
yield
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def with_tracing(action, params)
|
28
|
+
segment = nil
|
29
|
+
begin
|
30
|
+
info = get_url_info(params[0])
|
31
|
+
segment = NewRelic::Agent::Tracer.start_message_broker_segment(
|
32
|
+
action: action,
|
33
|
+
library: MESSAGING_LIBRARY,
|
34
|
+
destination_type: :queue,
|
35
|
+
destination_name: info[:queue_name]
|
36
|
+
)
|
37
|
+
add_aws_attributes(segment, info)
|
38
|
+
rescue => e
|
39
|
+
NewRelic::Agent.logger.error('Error starting message broker segment in Aws::SQS::Client', e)
|
40
|
+
end
|
41
|
+
NewRelic::Agent::Tracer.capture_segment_error(segment) do
|
42
|
+
yield
|
43
|
+
end
|
44
|
+
ensure
|
45
|
+
segment&.finish
|
46
|
+
end
|
47
|
+
|
48
|
+
private
|
49
|
+
|
50
|
+
def add_aws_attributes(segment, info)
|
51
|
+
return unless segment
|
52
|
+
|
53
|
+
segment.add_agent_attribute('messaging.system', 'aws_sqs')
|
54
|
+
segment.add_agent_attribute('cloud.region', config&.region)
|
55
|
+
segment.add_agent_attribute('cloud.account.id', info[:account_id])
|
56
|
+
segment.add_agent_attribute('messaging.destination.name', info[:queue_name])
|
57
|
+
end
|
58
|
+
|
59
|
+
def get_url_info(params)
|
60
|
+
split = params[:queue_url].split('/')
|
61
|
+
{
|
62
|
+
queue_name: split.last,
|
63
|
+
account_id: split[-2]
|
64
|
+
}
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
@@ -0,0 +1,21 @@
|
|
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 AwsSqs::Prepend
|
7
|
+
include NewRelic::Agent::Instrumentation::AwsSqs
|
8
|
+
|
9
|
+
def send_message(*args)
|
10
|
+
send_message_with_new_relic(*args) { super }
|
11
|
+
end
|
12
|
+
|
13
|
+
def send_message_batch(*args)
|
14
|
+
send_message_batch_with_new_relic(*args) { super }
|
15
|
+
end
|
16
|
+
|
17
|
+
def receive_message(*args)
|
18
|
+
receive_message_with_new_relic(*args) { super }
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# This file is distributed under New Relic's license terms.
|
2
|
+
# See https://github.com/newrelic/newrelic-ruby-agent/blob/main/LICENSE for complete details.
|
3
|
+
# frozen_string_literal: true
|
4
|
+
|
5
|
+
require_relative 'aws_sqs/instrumentation'
|
6
|
+
require_relative 'aws_sqs/chain'
|
7
|
+
require_relative 'aws_sqs/prepend'
|
8
|
+
|
9
|
+
DependencyDetection.defer do
|
10
|
+
named :aws_sqs
|
11
|
+
|
12
|
+
depends_on do
|
13
|
+
defined?(Aws::SQS::Client)
|
14
|
+
end
|
15
|
+
|
16
|
+
executes do
|
17
|
+
if use_prepend?
|
18
|
+
prepend_instrument Aws::SQS::Client, NewRelic::Agent::Instrumentation::AwsSqs::Prepend
|
19
|
+
else
|
20
|
+
chain_instrument NewRelic::Agent::Instrumentation::AwsSqs::Chain
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -48,6 +48,12 @@ module NewRelic
|
|
48
48
|
correlation_id: opts[:correlation_id],
|
49
49
|
exchange_type: type
|
50
50
|
)
|
51
|
+
if segment
|
52
|
+
segment.add_agent_attribute('server.address', channel&.connection&.hostname)
|
53
|
+
segment.add_agent_attribute('server.port', channel&.connection&.port)
|
54
|
+
segment.add_agent_attribute('messaging.destination.name', destination) # for produce, this is exchange name
|
55
|
+
segment.add_agent_attribute('messaging.rabbitmq.destination.routing_key', opts[:routing_key])
|
56
|
+
end
|
51
57
|
rescue => e
|
52
58
|
NewRelic::Agent.logger.error('Error starting message broker segment in Bunny::Exchange#publish', e)
|
53
59
|
yield
|
@@ -94,6 +100,14 @@ module NewRelic
|
|
94
100
|
queue_name: name,
|
95
101
|
start_time: t0
|
96
102
|
)
|
103
|
+
if segment
|
104
|
+
segment.add_agent_attribute('server.address', channel&.connection&.hostname)
|
105
|
+
segment.add_agent_attribute('server.port', channel&.connection&.port)
|
106
|
+
segment.add_agent_attribute('messaging.destination.name', name) # for consume, this is queue name
|
107
|
+
segment.add_agent_attribute('messaging.destination_publish.name', exch_name)
|
108
|
+
segment.add_agent_attribute('message.queueName', name)
|
109
|
+
segment.add_agent_attribute('messaging.rabbitmq.destination.routing_key', delivery_info&.routing_key)
|
110
|
+
end
|
97
111
|
rescue => e
|
98
112
|
NewRelic::Agent.logger.error('Error starting message broker segment in Bunny::Queue#pop', e)
|
99
113
|
else
|
@@ -14,7 +14,6 @@ DependencyDetection.defer do
|
|
14
14
|
end
|
15
15
|
|
16
16
|
executes do
|
17
|
-
NewRelic::Agent.logger.info('Installing Bunny instrumentation')
|
18
17
|
require 'new_relic/agent/distributed_tracing/cross_app_tracing'
|
19
18
|
require 'new_relic/agent/messaging'
|
20
19
|
require 'new_relic/agent/transaction/message_broker_segment'
|
@@ -22,9 +21,9 @@ DependencyDetection.defer do
|
|
22
21
|
|
23
22
|
executes do
|
24
23
|
if use_prepend?
|
25
|
-
prepend_instrument Bunny::Exchange, NewRelic::Agent::Instrumentation::Bunny::Prepend::Exchange
|
26
|
-
prepend_instrument Bunny::Queue, NewRelic::Agent::Instrumentation::Bunny::Prepend::Queue
|
27
|
-
prepend_instrument Bunny::Consumer, NewRelic::Agent::Instrumentation::Bunny::Prepend::Consumer
|
24
|
+
prepend_instrument Bunny::Exchange, NewRelic::Agent::Instrumentation::Bunny::Prepend::Exchange, 'Bunny::Exchange'
|
25
|
+
prepend_instrument Bunny::Queue, NewRelic::Agent::Instrumentation::Bunny::Prepend::Queue, 'Bunny::Queue'
|
26
|
+
prepend_instrument Bunny::Consumer, NewRelic::Agent::Instrumentation::Bunny::Prepend::Consumer, 'Bunny::Consumer'
|
28
27
|
else
|
29
28
|
chain_instrument NewRelic::Agent::Instrumentation::Bunny::Chain
|
30
29
|
end
|
@@ -11,12 +11,11 @@ DependencyDetection.defer do
|
|
11
11
|
|
12
12
|
depends_on do
|
13
13
|
defined?(Concurrent) &&
|
14
|
+
defined?(Concurrent::VERSION) &&
|
14
15
|
Gem::Version.new(Concurrent::VERSION) >= Gem::Version.new('1.1.5')
|
15
16
|
end
|
16
17
|
|
17
18
|
executes do
|
18
|
-
NewRelic::Agent.logger.info('Installing concurrent-ruby instrumentation')
|
19
|
-
|
20
19
|
if use_prepend?
|
21
20
|
prepend_instrument(Concurrent::ThreadPoolExecutor, NewRelic::Agent::Instrumentation::ConcurrentRuby::Prepend)
|
22
21
|
|
@@ -16,17 +16,16 @@ DependencyDetection.defer do
|
|
16
16
|
end
|
17
17
|
|
18
18
|
executes do
|
19
|
-
NewRelic::Agent.logger.info('Installing Curb instrumentation')
|
20
19
|
require 'new_relic/agent/distributed_tracing/cross_app_tracing'
|
21
20
|
require 'new_relic/agent/http_clients/curb_wrappers'
|
22
21
|
end
|
23
22
|
|
24
23
|
executes do
|
25
24
|
if use_prepend?
|
26
|
-
prepend_instrument Curl::Easy, NewRelic::Agent::Instrumentation::Curb::Easy::Prepend
|
27
|
-
prepend_instrument Curl::Multi, NewRelic::Agent::Instrumentation::Curb::Multi::Prepend
|
25
|
+
prepend_instrument Curl::Easy, NewRelic::Agent::Instrumentation::Curb::Easy::Prepend, 'Curb::Easy'
|
26
|
+
prepend_instrument Curl::Multi, NewRelic::Agent::Instrumentation::Curb::Multi::Prepend, 'Curb::Multi'
|
28
27
|
else
|
29
|
-
chain_instrument NewRelic::Agent::Instrumentation::Curb::Chain
|
28
|
+
chain_instrument NewRelic::Agent::Instrumentation::Curb::Chain, NewRelic::Agent::Instrumentation::Curb::Multi::INSTRUMENTATION_NAME
|
30
29
|
end
|
31
30
|
end
|
32
31
|
end
|
@@ -82,10 +82,6 @@ DependencyDetection.defer do
|
|
82
82
|
defined?(Delayed) && defined?(Delayed::Worker)
|
83
83
|
end
|
84
84
|
|
85
|
-
executes do
|
86
|
-
NewRelic::Agent.logger.info('Installing DelayedJob instrumentation [part 1/2]')
|
87
|
-
end
|
88
|
-
|
89
85
|
executes do
|
90
86
|
if use_prepend?
|
91
87
|
prepend_instrument Delayed::Worker, NewRelic::Agent::Instrumentation::DelayedJob::Prepend
|
@@ -93,23 +89,4 @@ DependencyDetection.defer do
|
|
93
89
|
chain_instrument NewRelic::Agent::Instrumentation::DelayedJob::Chain
|
94
90
|
end
|
95
91
|
end
|
96
|
-
|
97
|
-
executes do
|
98
|
-
next unless delayed_job_version < Gem::Version.new('4.1.0')
|
99
|
-
|
100
|
-
deprecation_msg = 'Instrumentation for DelayedJob versions below 4.1.0 is deprecated.' \
|
101
|
-
'It will stop being monitored in version 9.0.0. ' \
|
102
|
-
'Please upgrade your DelayedJob version to continue receiving full support. ' \
|
103
|
-
|
104
|
-
NewRelic::Agent.logger.log_once(
|
105
|
-
:warn,
|
106
|
-
:deprecated_delayed_job_version,
|
107
|
-
deprecation_msg
|
108
|
-
)
|
109
|
-
end
|
110
|
-
|
111
|
-
def delayed_job_version
|
112
|
-
# the following line needs else branch coverage
|
113
|
-
Gem.loaded_specs['delayed_job'].version if Gem.loaded_specs['delayed_job'] # rubocop:disable Style/SafeNavigation
|
114
|
-
end
|
115
92
|
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
|
+
module NewRelic::Agent::Instrumentation
|
6
|
+
module DynamoDB::Chain
|
7
|
+
def self.instrument!
|
8
|
+
::Aws::DynamoDB::Client.class_eval do
|
9
|
+
include NewRelic::Agent::Instrumentation::DynamoDB
|
10
|
+
|
11
|
+
NewRelic::Agent::Instrumentation::DynamoDB::INSTRUMENTED_METHODS.each do |method_name|
|
12
|
+
alias_method("#{method_name}_without_new_relic".to_sym, method_name.to_sym)
|
13
|
+
|
14
|
+
define_method(method_name) do |*args|
|
15
|
+
instrument_method_with_new_relic(method_name, *args) { send("#{method_name}_without_new_relic".to_sym, *args) }
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
alias_method(:build_request_without_new_relic, :build_request)
|
20
|
+
|
21
|
+
def build_request(*args)
|
22
|
+
build_request_with_new_relic(*args) { build_request_without_new_relic(*args) }
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,64 @@
|
|
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 DynamoDB
|
7
|
+
INSTRUMENTED_METHODS = %w[
|
8
|
+
create_table
|
9
|
+
delete_item
|
10
|
+
delete_table
|
11
|
+
get_item
|
12
|
+
put_item
|
13
|
+
query
|
14
|
+
scan
|
15
|
+
update_item
|
16
|
+
].freeze
|
17
|
+
|
18
|
+
PRODUCT = 'DynamoDB'
|
19
|
+
DEFAULT_HOST = 'dynamodb.amazonaws.com'
|
20
|
+
|
21
|
+
def instrument_method_with_new_relic(method_name, *args)
|
22
|
+
return yield unless NewRelic::Agent::Tracer.tracing_enabled?
|
23
|
+
|
24
|
+
NewRelic::Agent.record_instrumentation_invocation(PRODUCT)
|
25
|
+
|
26
|
+
segment = NewRelic::Agent::Tracer.start_datastore_segment(
|
27
|
+
product: PRODUCT,
|
28
|
+
operation: method_name,
|
29
|
+
host: config&.endpoint&.host || DEFAULT_HOST,
|
30
|
+
port_path_or_id: config&.endpoint&.port,
|
31
|
+
collection: args[0][:table_name]
|
32
|
+
)
|
33
|
+
|
34
|
+
arn = get_arn(args[0])
|
35
|
+
segment&.add_agent_attribute('cloud.resource_id', arn) if arn
|
36
|
+
|
37
|
+
@nr_captured_request = nil # clear request just in case
|
38
|
+
begin
|
39
|
+
NewRelic::Agent::Tracer.capture_segment_error(segment) { yield }
|
40
|
+
ensure
|
41
|
+
segment&.add_agent_attribute('aws.operation', method_name)
|
42
|
+
segment&.add_agent_attribute('aws.requestId', @nr_captured_request&.context&.http_response&.headers&.[]('x-amzn-requestid'))
|
43
|
+
segment&.add_agent_attribute('aws.region', config&.region)
|
44
|
+
segment&.finish
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def build_request_with_new_relic(*args)
|
49
|
+
@nr_captured_request = yield
|
50
|
+
end
|
51
|
+
|
52
|
+
def nr_account_id
|
53
|
+
return @nr_account_id if defined?(@nr_account_id)
|
54
|
+
|
55
|
+
@nr_account_id = NewRelic::Agent::Aws.get_account_id(config)
|
56
|
+
end
|
57
|
+
|
58
|
+
def get_arn(params)
|
59
|
+
return unless params[:table_name]
|
60
|
+
|
61
|
+
NewRelic::Agent::Aws.create_arn(PRODUCT.downcase, "table/#{params[:table_name]}", config&.region, nr_account_id)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,19 @@
|
|
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 DynamoDB::Prepend
|
7
|
+
include NewRelic::Agent::Instrumentation::DynamoDB
|
8
|
+
|
9
|
+
INSTRUMENTED_METHODS.each do |method_name|
|
10
|
+
define_method(method_name) do |*args|
|
11
|
+
instrument_method_with_new_relic(method_name, *args) { super(*args) }
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def build_request(*args)
|
16
|
+
build_request_with_new_relic(*args) { super }
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# This file is distributed under New Relic's license terms.
|
2
|
+
# See https://github.com/newrelic/newrelic-ruby-agent/blob/main/LICENSE for complete details.
|
3
|
+
# frozen_string_literal: true
|
4
|
+
|
5
|
+
require_relative 'dynamodb/instrumentation'
|
6
|
+
require_relative 'dynamodb/chain'
|
7
|
+
require_relative 'dynamodb/prepend'
|
8
|
+
|
9
|
+
DependencyDetection.defer do
|
10
|
+
named :dynamodb
|
11
|
+
|
12
|
+
depends_on do
|
13
|
+
defined?(Aws::DynamoDB::Client)
|
14
|
+
end
|
15
|
+
|
16
|
+
executes do
|
17
|
+
if use_prepend?
|
18
|
+
prepend_instrument Aws::DynamoDB::Client, NewRelic::Agent::Instrumentation::DynamoDB::Prepend
|
19
|
+
else
|
20
|
+
chain_instrument NewRelic::Agent::Instrumentation::DynamoDB::Chain
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -8,9 +8,61 @@ module NewRelic::Agent::Instrumentation
|
|
8
8
|
module Elasticsearch
|
9
9
|
PRODUCT_NAME = 'Elasticsearch'
|
10
10
|
OPERATION = 'perform_request'
|
11
|
+
|
12
|
+
# Pattern to use with client caller location strings. Look for a location
|
13
|
+
# that contains '/lib/elasticsearch/api/' and is NOT followed by the
|
14
|
+
# string held in the OPERATION constant
|
15
|
+
OPERATION_PATTERN = %r{/lib/elasticsearch/api/(?!.+#{OPERATION})}.freeze
|
16
|
+
|
17
|
+
# Use the OPERATION_PATTERN pattern to find the appropriate caller location
|
18
|
+
# that will contain the client instance method (example: 'search') and
|
19
|
+
# return that method name.
|
20
|
+
#
|
21
|
+
# A Ruby caller location matching the OPERATION_PATTERN will contain an
|
22
|
+
# elasticsearch client instance method name (such as "search"), and that
|
23
|
+
# method name will be used as the operation name.
|
24
|
+
#
|
25
|
+
# With Ruby < 3.4 the method name is listed as:
|
26
|
+
#
|
27
|
+
# `search'
|
28
|
+
#
|
29
|
+
# with an opening backtick and a closing single tick. And only the
|
30
|
+
# method name itself is listed.
|
31
|
+
#
|
32
|
+
# With Ruby 3.4+ the method name is listed as:
|
33
|
+
#
|
34
|
+
# 'Elasticsearch::API::Actions#search'
|
35
|
+
#
|
36
|
+
# with opening and closing single ticks and the class defining the
|
37
|
+
# instance method listed.
|
38
|
+
#
|
39
|
+
# (?:) = ?: prevents capturing
|
40
|
+
# (?:`|') = allow ` or '
|
41
|
+
# (?:.+#) = allow the class name and '#' prefix to exist but ignore it
|
42
|
+
# ([^']+)' = after the opening ` or ', capturing everything up to the
|
43
|
+
# closing '. [^']+ = one or more characters that are not '
|
44
|
+
#
|
45
|
+
# Example Ruby 3.3.1 input:
|
46
|
+
#
|
47
|
+
# /Users/fallwith/.rubies/ruby-3.3.1/lib/ruby/gems/3.3.0/gems/elasticsearch-api-7.17.10/lib/elasticsearch/api/actions/index.rb:74:in `index'
|
48
|
+
#
|
49
|
+
# Example Ruby 3.4.0-preview1 input:
|
50
|
+
#
|
51
|
+
# /Users/fallwith/.rubies/ruby-3.4.0-preview1/lib/ruby/gems/3.4.0+0/gems/elasticsearch-api-7.17.10/lib/elasticsearch/api/actions/index.rb:74:in 'Elasticsearch::API::Actions#index'
|
52
|
+
#
|
53
|
+
# Example output for both Rubies:
|
54
|
+
#
|
55
|
+
# index
|
56
|
+
|
57
|
+
INSTANCE_METHOD_PATTERN = /:in (?:`|')(?:.+#)?([^']+)'\z/.freeze
|
58
|
+
|
11
59
|
INSTRUMENTATION_NAME = NewRelic::Agent.base_name(name)
|
12
60
|
|
13
|
-
|
61
|
+
# We need the positional arguments `params` and `body`
|
62
|
+
# to capture the nosql statement
|
63
|
+
# *args protects the instrumented method if new arguments are added to
|
64
|
+
# perform_request
|
65
|
+
def perform_request_with_tracing(_method, _path, params = {}, body = nil, _headers = nil, *_args)
|
14
66
|
return yield unless NewRelic::Agent::Tracer.tracing_enabled?
|
15
67
|
|
16
68
|
NewRelic::Agent.record_instrumentation_invocation(INSTRUMENTATION_NAME)
|
@@ -22,6 +74,7 @@ module NewRelic::Agent::Instrumentation
|
|
22
74
|
port_path_or_id: nr_hosts[:port],
|
23
75
|
database_name: nr_cluster_name
|
24
76
|
)
|
77
|
+
|
25
78
|
begin
|
26
79
|
NewRelic::Agent::Tracer.capture_segment_error(segment) { yield }
|
27
80
|
ensure
|
@@ -35,13 +88,10 @@ module NewRelic::Agent::Instrumentation
|
|
35
88
|
private
|
36
89
|
|
37
90
|
def nr_operation
|
38
|
-
|
39
|
-
|
40
|
-
string.include?('lib/elasticsearch/api') && !string.include?(OPERATION)
|
41
|
-
end
|
42
|
-
return nil unless operation_index
|
91
|
+
location = caller_locations.detect { |loc| loc.to_s.match?(OPERATION_PATTERN) }
|
92
|
+
return unless location && location.to_s =~ INSTANCE_METHOD_PATTERN
|
43
93
|
|
44
|
-
|
94
|
+
Regexp.last_match(1)
|
45
95
|
end
|
46
96
|
|
47
97
|
def nr_reported_query(query)
|
@@ -52,7 +102,7 @@ module NewRelic::Agent::Instrumentation
|
|
52
102
|
end
|
53
103
|
|
54
104
|
def nr_cluster_name
|
55
|
-
return @nr_cluster_name if @nr_cluster_name
|
105
|
+
return @nr_cluster_name if defined?(@nr_cluster_name)
|
56
106
|
return if nr_hosts.empty?
|
57
107
|
|
58
108
|
NewRelic::Agent.disable_all_tracing do
|
@@ -14,8 +14,6 @@ DependencyDetection.defer do
|
|
14
14
|
end
|
15
15
|
|
16
16
|
executes do
|
17
|
-
NewRelic::Agent.logger.info('Installing Elasticsearch instrumentation')
|
18
|
-
|
19
17
|
to_instrument = if Gem::Version.create(Elasticsearch::VERSION) < Gem::Version.create('8.0.0')
|
20
18
|
Elasticsearch::Transport::Client
|
21
19
|
else
|
@@ -21,10 +21,6 @@ DependencyDetection.defer do
|
|
21
21
|
defined?(Ethon) && Gem::Version.new(Ethon::VERSION) >= Gem::Version.new('0.12.0')
|
22
22
|
end
|
23
23
|
|
24
|
-
executes do
|
25
|
-
NewRelic::Agent.logger.info('Installing ethon instrumentation')
|
26
|
-
end
|
27
|
-
|
28
24
|
executes do
|
29
25
|
if use_prepend?
|
30
26
|
# NOTE: by default prepend_instrument will go with the module name that
|