newrelic_rpm 9.12.0 → 9.17.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 +217 -1
- data/CONTRIBUTING.md +2 -2
- data/README.md +16 -20
- data/lib/boot/strap.rb +4 -3
- data/lib/new_relic/agent/agent.rb +4 -0
- data/lib/new_relic/agent/agent_helpers/connect.rb +3 -0
- data/lib/new_relic/agent/agent_helpers/harvest.rb +3 -0
- data/lib/new_relic/agent/agent_helpers/shutdown.rb +3 -0
- data/lib/new_relic/agent/agent_helpers/start_worker_thread.rb +1 -0
- data/lib/new_relic/agent/agent_helpers/startup.rb +7 -0
- data/lib/new_relic/agent/aws.rb +6 -0
- data/lib/new_relic/agent/configuration/default_source.rb +363 -31
- 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/configuration/yaml_source.rb +6 -1
- data/lib/new_relic/agent/database/obfuscation_helpers.rb +11 -11
- data/lib/new_relic/agent/database.rb +41 -1
- data/lib/new_relic/agent/distributed_tracing.rb +2 -2
- data/lib/new_relic/agent/health_check.rb +136 -0
- 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 +5 -1
- data/lib/new_relic/agent/instrumentation/active_record_subscriber.rb +9 -16
- 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 +1 -2
- data/lib/new_relic/agent/instrumentation/aws_sdk_firehose/chain.rb +21 -0
- data/lib/new_relic/agent/instrumentation/aws_sdk_firehose/instrumentation.rb +66 -0
- data/lib/new_relic/agent/instrumentation/aws_sdk_firehose/prepend.rb +15 -0
- data/lib/new_relic/agent/instrumentation/aws_sdk_firehose.rb +22 -0
- data/lib/new_relic/agent/instrumentation/aws_sdk_kinesis/chain.rb +21 -0
- data/lib/new_relic/agent/instrumentation/aws_sdk_kinesis/instrumentation.rb +91 -0
- data/lib/new_relic/agent/instrumentation/aws_sdk_kinesis/prepend.rb +15 -0
- data/lib/new_relic/agent/instrumentation/aws_sdk_kinesis.rb +22 -0
- 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.rb +0 -2
- data/lib/new_relic/agent/instrumentation/bunny.rb +3 -4
- data/lib/new_relic/agent/instrumentation/concurrent_ruby.rb +0 -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/instrumentation.rb +1 -1
- data/lib/new_relic/agent/instrumentation/dynamodb.rb +0 -2
- 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/instrumentation.rb +0 -3
- data/lib/new_relic/agent/instrumentation/grape.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.rb +0 -2
- data/lib/new_relic/agent/instrumentation/memcache.rb +0 -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 +23 -0
- data/lib/new_relic/agent/instrumentation/padrino.rb +3 -3
- 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.rb +7 -6
- data/lib/new_relic/agent/instrumentation/resque.rb +7 -5
- 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/sidekiq/extensions/delayed_class.rb +1 -1
- 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/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 +11 -5
- 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/local_log_decorator.rb +12 -2
- data/lib/new_relic/agent/log_event_aggregator.rb +28 -2
- data/lib/new_relic/agent/messaging.rb +11 -5
- data/lib/new_relic/agent/new_relic_service.rb +8 -2
- 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/span_event_primitive.rb +4 -2
- data/lib/new_relic/agent/system_info.rb +14 -0
- data/lib/new_relic/agent/threading/backtrace_node.rb +10 -1
- data/lib/new_relic/agent/transaction/message_broker_segment.rb +3 -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 +95 -2
- 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/dependency_detection.rb +11 -13
- 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 +1 -4
- data/lib/new_relic/version.rb +1 -1
- data/lib/sequel/extensions/new_relic_instrumentation.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 +11 -8
- data/newrelic.yml +224 -79
- data/test/agent_helper.rb +8 -1
- metadata +32 -6
@@ -7,17 +7,17 @@ module NewRelic
|
|
7
7
|
module Database
|
8
8
|
module ObfuscationHelpers
|
9
9
|
COMPONENTS_REGEX_MAP = {
|
10
|
-
:
|
11
|
-
:
|
12
|
-
:
|
13
|
-
:
|
14
|
-
:
|
15
|
-
:
|
16
|
-
:
|
17
|
-
:
|
18
|
-
:
|
19
|
-
:
|
20
|
-
}
|
10
|
+
single_quotes: /'(?:[^']|'')*?(?:\\'.*|'(?!'))/,
|
11
|
+
double_quotes: /"(?:[^"]|"")*?(?:\\".*|"(?!"))/,
|
12
|
+
dollar_quotes: /(\$(?!\d)[^$]*?\$).*?(?:\1|$)/,
|
13
|
+
uuids: /\{?(?:[0-9a-fA-F]-*){32}\}?/,
|
14
|
+
numeric_literals: /-?\b(?:[0-9]+\.)?[0-9]+([eE][+-]?[0-9]+)?\b/,
|
15
|
+
boolean_literals: /\b(?:true|false|null)\b/i,
|
16
|
+
hexadecimal_literals: /0x[0-9a-fA-F]+/,
|
17
|
+
comments: /(?:#|--).*?(?=\r|\n|$)/i,
|
18
|
+
multi_line_comments: %r{/\*.*?\*/}m,
|
19
|
+
oracle_quoted_strings: /q'\[.*?(?:\]'|$)|q'\{.*?(?:\}'|$)|q'<.*?(?:>'|$)|q'\(.*?(?:\)'|$)/
|
20
|
+
}.freeze
|
21
21
|
|
22
22
|
DIALECT_COMPONENTS = {
|
23
23
|
:fallback => COMPONENTS_REGEX_MAP.keys,
|
@@ -90,6 +90,42 @@ module NewRelic
|
|
90
90
|
ConnectionManager.instance.get_connection(config, &connector)
|
91
91
|
end
|
92
92
|
|
93
|
+
def explain_this(statement, use_execute = false)
|
94
|
+
if supports_with_connection?
|
95
|
+
explain_this_using_with_connection(statement)
|
96
|
+
else
|
97
|
+
explain_this_using_adapter_connection(statement, use_execute)
|
98
|
+
end
|
99
|
+
rescue => e
|
100
|
+
NewRelic::Agent.logger.error("Couldn't fetch the explain plan for statement: #{e}")
|
101
|
+
end
|
102
|
+
|
103
|
+
def explain_this_using_with_connection(statement)
|
104
|
+
::ActiveRecord::Base.with_connection do |conn|
|
105
|
+
conn.exec_query("EXPLAIN #{statement.sql}", "Explain #{statement.name}", statement.binds)
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
def explain_this_using_adapter_connection(statement, use_execute)
|
110
|
+
connection = get_connection(statement.config) do
|
111
|
+
::ActiveRecord::Base.send(:"#{statement.config[:adapter]}_connection", statement.config)
|
112
|
+
end
|
113
|
+
|
114
|
+
if use_execute
|
115
|
+
connection.execute("EXPLAIN #{statement.sql}")
|
116
|
+
else
|
117
|
+
connection.exec_query("EXPLAIN #{statement.sql}", "Explain #{statement.name}", statement.binds)
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
# ActiveRecord v7.2.0 introduced with_connection
|
122
|
+
def supports_with_connection?
|
123
|
+
return @supports_with_connection if defined?(@supports_with_connection)
|
124
|
+
|
125
|
+
@supports_with_connection = defined?(::ActiveRecord::VERSION::STRING) &&
|
126
|
+
Gem::Version.new(ActiveRecord::VERSION::STRING) >= Gem::Version.new('7.2.0')
|
127
|
+
end
|
128
|
+
|
93
129
|
def close_connections
|
94
130
|
ConnectionManager.instance.close_connections
|
95
131
|
end
|
@@ -241,9 +277,11 @@ module NewRelic
|
|
241
277
|
MYSQL_PREFIX = 'mysql'.freeze
|
242
278
|
MYSQL2_PREFIX = 'mysql2'.freeze
|
243
279
|
SQLITE_PREFIX = 'sqlite'.freeze
|
280
|
+
TRILOGY_PREFIX = 'trilogy'.freeze
|
281
|
+
REDSHIFT_PREFIX = 'redshift'.freeze
|
244
282
|
|
245
283
|
def symbolized_adapter(adapter)
|
246
|
-
if adapter.start_with?(POSTGRES_PREFIX) || adapter == POSTGIS_PREFIX
|
284
|
+
if adapter.start_with?(POSTGRES_PREFIX) || adapter == POSTGIS_PREFIX || adapter == REDSHIFT_PREFIX
|
247
285
|
:postgres
|
248
286
|
elsif adapter == MYSQL_PREFIX
|
249
287
|
:mysql
|
@@ -253,6 +291,8 @@ module NewRelic
|
|
253
291
|
:mysql2
|
254
292
|
elsif adapter.start_with?(SQLITE_PREFIX)
|
255
293
|
:sqlite
|
294
|
+
elsif adapter == TRILOGY_PREFIX
|
295
|
+
:trilogy
|
256
296
|
else
|
257
297
|
adapter.to_sym
|
258
298
|
end
|
@@ -45,7 +45,7 @@ module NewRelic
|
|
45
45
|
record_api_supportability_metric(:insert_distributed_trace_headers)
|
46
46
|
|
47
47
|
unless Agent.config[:'distributed_tracing.enabled']
|
48
|
-
NewRelic::Agent.logger.
|
48
|
+
NewRelic::Agent.logger.debug('Not configured to insert distributed trace headers')
|
49
49
|
return nil
|
50
50
|
end
|
51
51
|
|
@@ -99,7 +99,7 @@ module NewRelic
|
|
99
99
|
record_api_supportability_metric(:accept_distributed_trace_headers)
|
100
100
|
|
101
101
|
unless Agent.config[:'distributed_tracing.enabled']
|
102
|
-
NewRelic::Agent.logger.
|
102
|
+
NewRelic::Agent.logger.debug('Not configured to accept distributed trace headers')
|
103
103
|
return nil
|
104
104
|
end
|
105
105
|
|
@@ -0,0 +1,136 @@
|
|
1
|
+
# This file is distributed under New Relic's license terms.
|
2
|
+
# See https://github.com/newrelic/newrelic-ruby-agent/blob/main/LICENSE for complete details.
|
3
|
+
# frozen_string_literal: true
|
4
|
+
|
5
|
+
module NewRelic
|
6
|
+
module Agent
|
7
|
+
class HealthCheck
|
8
|
+
def initialize
|
9
|
+
@start_time = nano_time
|
10
|
+
@continue = true
|
11
|
+
@status = HEALTHY
|
12
|
+
# the following assignments may set @continue = false if they are invalid
|
13
|
+
set_enabled
|
14
|
+
set_delivery_location
|
15
|
+
set_frequency
|
16
|
+
end
|
17
|
+
|
18
|
+
HEALTHY = {healthy: true, last_error: 'NR-APM-000', message: 'Healthy'}.freeze
|
19
|
+
INVALID_LICENSE_KEY = {healthy: false, last_error: 'NR-APM-001', message: 'Invalid license key (HTTP status code 401)'}.freeze
|
20
|
+
MISSING_LICENSE_KEY = {healthy: false, last_error: 'NR-APM-002', message: 'License key missing in configuration'}.freeze
|
21
|
+
FORCED_DISCONNECT = {healthy: false, last_error: 'NR-APM-003', message: 'Forced disconnect received from New Relic (HTTP status code 410)'}.freeze
|
22
|
+
HTTP_ERROR = {healthy: false, last_error: 'NR-APM-004', message: 'HTTP error response code [%s] recevied from New Relic while sending data type [%s]'}.freeze
|
23
|
+
MISSING_APP_NAME = {healthy: false, last_error: 'NR-APM-005', message: 'Missing application name in agent configuration'}.freeze
|
24
|
+
APP_NAME_EXCEEDED = {healthy: false, last_error: 'NR-APM-006', message: 'The maximum number of configured app names (3) exceeded'}.freeze
|
25
|
+
PROXY_CONFIG_ERROR = {healthy: false, last_error: 'NR-APM-007', message: 'HTTP Proxy configuration error; response code [%s]'}.freeze
|
26
|
+
AGENT_DISABLED = {healthy: false, last_error: 'NR-APM-008', message: 'Agent is disabled via configuration'}.freeze
|
27
|
+
FAILED_TO_CONNECT = {healthy: false, last_error: 'NR-APM-009', message: 'Failed to connect to New Relic data collector'}.freeze
|
28
|
+
FAILED_TO_PARSE_CONFIG = {healthy: false, last_error: 'NR-APM-010', message: 'Agent config file is not able to be parsed'}.freeze
|
29
|
+
SHUTDOWN = {healthy: true, last_error: 'NR-APM-099', message: 'Agent has shutdown'}.freeze
|
30
|
+
|
31
|
+
def create_and_run_health_check_loop
|
32
|
+
return unless health_checks_enabled? && @continue
|
33
|
+
|
34
|
+
NewRelic::Agent.logger.debug('Agent Control health check conditions met. Starting health checks.')
|
35
|
+
NewRelic::Agent.record_metric('Supportability/AgentControl/Health/enabled', 1)
|
36
|
+
|
37
|
+
Thread.new do
|
38
|
+
while @continue
|
39
|
+
begin
|
40
|
+
sleep @frequency
|
41
|
+
write_file
|
42
|
+
@continue = false if @status == SHUTDOWN
|
43
|
+
rescue StandardError => e
|
44
|
+
NewRelic::Agent.logger.error("Aborting Agent Control health check. Error raised: #{e}")
|
45
|
+
@continue = false
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def update_status(status, options = [])
|
52
|
+
return unless @continue
|
53
|
+
|
54
|
+
@status = status.dup
|
55
|
+
update_message(options) unless options.empty?
|
56
|
+
end
|
57
|
+
|
58
|
+
def healthy?
|
59
|
+
@status == HEALTHY
|
60
|
+
end
|
61
|
+
|
62
|
+
private
|
63
|
+
|
64
|
+
def set_enabled
|
65
|
+
@enabled = if ENV['NEW_RELIC_AGENT_CONTROL_ENABLED'] == 'true'
|
66
|
+
true
|
67
|
+
else
|
68
|
+
NewRelic::Agent.logger.debug('NEW_RELIC_AGENT_CONTROL_ENABLED not true, disabling health checks')
|
69
|
+
@continue = false
|
70
|
+
false
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def set_delivery_location
|
75
|
+
@delivery_location = if ENV['NEW_RELIC_AGENT_CONTROL_HEALTH_DELIVERY_LOCATION']
|
76
|
+
# The spec states file paths for the delivery location will begin with file://
|
77
|
+
# This does not create a valid path in Ruby, so remove the prefix when present
|
78
|
+
ENV['NEW_RELIC_AGENT_CONTROL_HEALTH_DELIVERY_LOCATION']&.gsub('file://', '')
|
79
|
+
else
|
80
|
+
# The spec default is 'file:///newrelic/apm/health', but since we're just going to remove it anyway...
|
81
|
+
'/newrelic/apm/health'
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def set_frequency
|
86
|
+
@frequency = ENV['NEW_RELIC_AGENT_CONTROL_HEALTH_FREQUENCY'] ? ENV['NEW_RELIC_AGENT_CONTROL_HEALTH_FREQUENCY'].to_i : 5
|
87
|
+
|
88
|
+
if @frequency <= 0
|
89
|
+
NewRelic::Agent.logger.debug('NEW_RELIC_AGENT_CONTROL_HEALTH_FREQUENCY zero or less, disabling health checks')
|
90
|
+
@continue = false
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def contents
|
95
|
+
<<~CONTENTS
|
96
|
+
healthy: #{@status[:healthy]}
|
97
|
+
status: #{@status[:message]}#{last_error}
|
98
|
+
start_time_unix_nano: #{@start_time}
|
99
|
+
status_time_unix_nano: #{nano_time}
|
100
|
+
CONTENTS
|
101
|
+
end
|
102
|
+
|
103
|
+
def last_error
|
104
|
+
@status[:healthy] ? '' : "\nlast_error: #{@status[:last_error]}"
|
105
|
+
end
|
106
|
+
|
107
|
+
def nano_time
|
108
|
+
Process.clock_gettime(Process::CLOCK_REALTIME, :nanosecond)
|
109
|
+
end
|
110
|
+
|
111
|
+
def file_name
|
112
|
+
"health-#{NewRelic::Agent::GuidGenerator.generate_guid(32)}.yml"
|
113
|
+
end
|
114
|
+
|
115
|
+
def write_file
|
116
|
+
@file ||= "#{@delivery_location}/#{file_name}"
|
117
|
+
|
118
|
+
File.write(@file, contents)
|
119
|
+
rescue StandardError => e
|
120
|
+
NewRelic::Agent.logger.error("Agent Control health check raised an error while writing a file: #{e}")
|
121
|
+
@continue = false
|
122
|
+
end
|
123
|
+
|
124
|
+
def health_checks_enabled?
|
125
|
+
@enabled && @delivery_location && @frequency > 0
|
126
|
+
end
|
127
|
+
|
128
|
+
def update_message(options)
|
129
|
+
@status[:message] = sprintf(@status[:message], *options)
|
130
|
+
rescue StandardError => e
|
131
|
+
NewRelic::Agent.logger.debug("Error raised while updating Agent Control health check message: #{e}." \
|
132
|
+
"options = #{options}, @status[:message] = #{@status[:message]}")
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
@@ -35,17 +35,4 @@ DependencyDetection.defer do
|
|
35
35
|
end
|
36
36
|
end
|
37
37
|
end
|
38
|
-
|
39
|
-
executes do
|
40
|
-
next unless Gem::Version.new(ActiveMerchant::VERSION) < Gem::Version.new('1.65.0')
|
41
|
-
|
42
|
-
deprecation_msg = 'The Ruby agent is dropping support for ActiveMerchant versions below 1.65.0 ' \
|
43
|
-
'in version 9.0.0. Please upgrade your ActiveMerchant version to continue receiving full support. ' \
|
44
|
-
|
45
|
-
NewRelic::Agent.logger.log_once(
|
46
|
-
:warn,
|
47
|
-
:deprecated_active_merchant_version,
|
48
|
-
deprecation_msg
|
49
|
-
)
|
50
|
-
end
|
51
38
|
end
|
@@ -9,14 +9,7 @@ module NewRelic
|
|
9
9
|
module Instrumentation
|
10
10
|
module ActiveRecord
|
11
11
|
EXPLAINER = lambda do |statement|
|
12
|
-
|
13
|
-
::ActiveRecord::Base.send("#{statement.config[:adapter]}_connection",
|
14
|
-
statement.config)
|
15
|
-
end
|
16
|
-
# the following line needs else branch coverage
|
17
|
-
if connection && connection.respond_to?(:execute) # rubocop:disable Style/SafeNavigation
|
18
|
-
return connection.execute("EXPLAIN #{statement.sql}")
|
19
|
-
end
|
12
|
+
NewRelic::Agent::Database.explain_this(statement, true)
|
20
13
|
end
|
21
14
|
|
22
15
|
def self.insert_instrumentation
|
@@ -170,6 +170,9 @@ module NewRelic
|
|
170
170
|
|
171
171
|
'sqlite3' => 'SQLite',
|
172
172
|
|
173
|
+
# https://rubygems.org/gems/trilogy
|
174
|
+
'trilogy' => 'MySQL',
|
175
|
+
|
173
176
|
# https://rubygems.org/gems/activerecord-jdbcpostgresql-adapter
|
174
177
|
'jdbcmysql' => 'MySQL',
|
175
178
|
|
@@ -222,7 +225,8 @@ module NewRelic
|
|
222
225
|
|
223
226
|
'postgresql' => :postgres,
|
224
227
|
'jdbcpostgresql' => :postgres,
|
225
|
-
'postgis' => :postgres
|
228
|
+
'postgis' => :postgres,
|
229
|
+
'redshift' => :postgres
|
226
230
|
}.freeze
|
227
231
|
|
228
232
|
DATASTORE_DEFAULT_PORTS = {
|
@@ -70,18 +70,7 @@ module NewRelic
|
|
70
70
|
end
|
71
71
|
|
72
72
|
def get_explain_plan(statement)
|
73
|
-
|
74
|
-
::ActiveRecord::Base.send("#{statement.config[:adapter]}_connection",
|
75
|
-
statement.config)
|
76
|
-
end
|
77
|
-
# the following line needs else branch coverage
|
78
|
-
if connection && connection.respond_to?(:exec_query) # rubocop:disable Style/SafeNavigation
|
79
|
-
return connection.exec_query("EXPLAIN #{statement.sql}",
|
80
|
-
"Explain #{statement.name}",
|
81
|
-
statement.binds)
|
82
|
-
end
|
83
|
-
rescue => e
|
84
|
-
NewRelic::Agent.logger.debug("Couldn't fetch the explain plan for #{statement} due to #{e}")
|
73
|
+
NewRelic::Agent::Database.explain_this(statement)
|
85
74
|
end
|
86
75
|
|
87
76
|
def active_record_config(payload)
|
@@ -127,10 +116,14 @@ module NewRelic
|
|
127
116
|
port_path_or_id = nil
|
128
117
|
database = nil
|
129
118
|
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
119
|
+
begin
|
120
|
+
if ActiveRecordHelper::InstanceIdentification.supported_adapter?(config)
|
121
|
+
host = ActiveRecordHelper::InstanceIdentification.host(config)
|
122
|
+
port_path_or_id = ActiveRecordHelper::InstanceIdentification.port_path_or_id(config)
|
123
|
+
database = config && config[:database]
|
124
|
+
end
|
125
|
+
rescue
|
126
|
+
NewRelic::Agent.logger.debug("Failed to retrieve ActiveRecord host, port, and database details for adapter: #{config && config[:adapter]}")
|
134
127
|
end
|
135
128
|
|
136
129
|
segment = Tracer.start_datastore_segment(product: product,
|
@@ -12,8 +12,6 @@ DependencyDetection.defer do
|
|
12
12
|
depends_on { defined?(ActiveSupport::BroadcastLogger) }
|
13
13
|
|
14
14
|
executes do
|
15
|
-
NewRelic::Agent.logger.info('Installing ActiveSupport::BroadcastLogger instrumentation')
|
16
|
-
|
17
15
|
if use_prepend?
|
18
16
|
prepend_instrument ActiveSupport::BroadcastLogger, NewRelic::Agent::Instrumentation::ActiveSupportBroadcastLogger::Prepend
|
19
17
|
else
|
@@ -14,8 +14,6 @@ DependencyDetection.defer do
|
|
14
14
|
end
|
15
15
|
|
16
16
|
executes do
|
17
|
-
NewRelic::Agent.logger.info('Installing ActiveSupport::Logger instrumentation')
|
18
|
-
|
19
17
|
if use_prepend?
|
20
18
|
# the only method currently instrumented is a class method
|
21
19
|
prepend_instrument ActiveSupport::Logger.singleton_class, NewRelic::Agent::Instrumentation::ActiveSupportLogger::Prepend
|
@@ -16,9 +16,8 @@ DependencyDetection.defer do
|
|
16
16
|
end
|
17
17
|
|
18
18
|
executes do
|
19
|
-
NewRelic::Agent.logger.info('Installing async_http instrumentation')
|
20
|
-
|
21
19
|
require 'async/http/internet'
|
20
|
+
|
22
21
|
if use_prepend?
|
23
22
|
prepend_instrument Async::HTTP::Internet, NewRelic::Agent::Instrumentation::AsyncHttp::Prepend
|
24
23
|
else
|
@@ -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 Firehose::Chain
|
7
|
+
def self.instrument!
|
8
|
+
::Aws::Firehose::Client.class_eval do
|
9
|
+
include NewRelic::Agent::Instrumentation::Firehose
|
10
|
+
|
11
|
+
NewRelic::Agent::Instrumentation::Firehose::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
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
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
|
+
module NewRelic::Agent::Instrumentation
|
6
|
+
module Firehose
|
7
|
+
INSTRUMENTED_METHODS = %w[
|
8
|
+
create_delivery_stream
|
9
|
+
delete_delivery_stream
|
10
|
+
describe_delivery_stream
|
11
|
+
list_delivery_streams
|
12
|
+
list_tags_for_delivery_stream
|
13
|
+
put_record
|
14
|
+
put_record_batch
|
15
|
+
start_delivery_stream_encryption
|
16
|
+
stop_delivery_stream_encryption
|
17
|
+
tag_delivery_stream
|
18
|
+
untag_delivery_stream
|
19
|
+
update_destination
|
20
|
+
].freeze
|
21
|
+
|
22
|
+
FIREHOSE = 'Firehose'
|
23
|
+
AWS_KINESIS_DELIVERY_STREAMS = 'aws_kinesis_delivery_streams'
|
24
|
+
|
25
|
+
def instrument_method_with_new_relic(method_name, *args)
|
26
|
+
return yield unless NewRelic::Agent::Tracer.tracing_enabled?
|
27
|
+
|
28
|
+
NewRelic::Agent.record_instrumentation_invocation(FIREHOSE)
|
29
|
+
|
30
|
+
params = args[0]
|
31
|
+
segment = NewRelic::Agent::Tracer.start_segment(name: get_segment_name(method_name, params))
|
32
|
+
arn = get_arn(params) if params
|
33
|
+
segment&.add_agent_attribute('cloud.resource_id', arn) if arn
|
34
|
+
|
35
|
+
begin
|
36
|
+
NewRelic::Agent::Tracer.capture_segment_error(segment) { yield }
|
37
|
+
ensure
|
38
|
+
segment&.add_agent_attribute('cloud.platform', AWS_KINESIS_DELIVERY_STREAMS)
|
39
|
+
segment&.finish
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def get_segment_name(method_name, params)
|
44
|
+
stream_name = params&.dig(:delivery_stream_name)
|
45
|
+
return "#{FIREHOSE}/#{method_name}/#{stream_name}" if stream_name
|
46
|
+
|
47
|
+
"#{FIREHOSE}/#{method_name}"
|
48
|
+
rescue => e
|
49
|
+
NewRelic::Agent.logger.warn("Failed to create segment name: #{e}")
|
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
|
+
stream_arn = params&.dig(:delivery_stream_arn)
|
60
|
+
return stream_arn if stream_arn
|
61
|
+
|
62
|
+
stream_name = params&.dig(:delivery_stream_name)
|
63
|
+
NewRelic::Agent::Aws.create_arn(FIREHOSE.downcase, "deliverystream/#{stream_name}", config&.region, nr_account_id) if stream_name
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# This file is distributed under New Relic's license terms.
|
2
|
+
# See https://github.com/newrelic/newrelic-ruby-agent/blob/main/LICENSE for complete details.
|
3
|
+
# frozen_string_literal: true
|
4
|
+
|
5
|
+
module NewRelic::Agent::Instrumentation
|
6
|
+
module Firehose::Prepend
|
7
|
+
include NewRelic::Agent::Instrumentation::Firehose
|
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
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# This file is distributed under New Relic's license terms.
|
2
|
+
# See https://github.com/newrelic/newrelic-ruby-agent/blob/main/LICENSE for complete details.
|
3
|
+
# frozen_string_literal: true
|
4
|
+
|
5
|
+
require_relative 'aws_sdk_firehose/instrumentation'
|
6
|
+
require_relative 'aws_sdk_firehose/chain'
|
7
|
+
require_relative 'aws_sdk_firehose/prepend'
|
8
|
+
|
9
|
+
DependencyDetection.defer do
|
10
|
+
named :aws_sdk_firehose
|
11
|
+
|
12
|
+
depends_on do
|
13
|
+
defined?(Aws::Firehose::Client)
|
14
|
+
end
|
15
|
+
executes do
|
16
|
+
if use_prepend?
|
17
|
+
prepend_instrument Aws::Firehose::Client, NewRelic::Agent::Instrumentation::Firehose::Prepend
|
18
|
+
else
|
19
|
+
chain_instrument NewRelic::Agent::Instrumentation::Firehose::Chain
|
20
|
+
end
|
21
|
+
end
|
22
|
+
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 Kinesis::Chain
|
7
|
+
def self.instrument!
|
8
|
+
::Aws::Kinesis::Client.class_eval do
|
9
|
+
include NewRelic::Agent::Instrumentation::Kinesis
|
10
|
+
|
11
|
+
NewRelic::Agent::Instrumentation::Kinesis::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
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,91 @@
|
|
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 Kinesis
|
7
|
+
INSTRUMENTED_METHODS = %w[
|
8
|
+
add_tags_to_stream
|
9
|
+
create_stream
|
10
|
+
decrease_stream_retention_period
|
11
|
+
delete_stream
|
12
|
+
describe_limits
|
13
|
+
describe_stream
|
14
|
+
disable_enhanced_monitoring
|
15
|
+
enable_enhanced_monitoring
|
16
|
+
get_records
|
17
|
+
get_shard_iterator
|
18
|
+
increase_stream_retention_period
|
19
|
+
list_streams
|
20
|
+
list_tags_for_stream
|
21
|
+
merge_shards
|
22
|
+
put_record
|
23
|
+
put_records
|
24
|
+
remove_tags_from_stream
|
25
|
+
split_shard
|
26
|
+
update_shard_count
|
27
|
+
].freeze
|
28
|
+
|
29
|
+
KINESIS = 'Kinesis'
|
30
|
+
AWS_KINESIS_DATA_STREAMS = 'aws_kinesis_data_streams'
|
31
|
+
MESSAGE_BROKER_SEGMENT_METHODS = %w[put_record put_records get_records].freeze
|
32
|
+
|
33
|
+
def instrument_method_with_new_relic(method_name, *args)
|
34
|
+
return yield unless NewRelic::Agent::Tracer.tracing_enabled?
|
35
|
+
|
36
|
+
NewRelic::Agent.record_instrumentation_invocation(KINESIS)
|
37
|
+
params = args[0]
|
38
|
+
arn = get_arn(params) if params
|
39
|
+
|
40
|
+
if MESSAGE_BROKER_SEGMENT_METHODS.include?(method_name)
|
41
|
+
stream_name = get_stream_name(params, arn)
|
42
|
+
segment = NewRelic::Agent::Tracer.start_message_broker_segment(
|
43
|
+
action: method_name == 'get_records' ? :consume : :produce,
|
44
|
+
library: KINESIS,
|
45
|
+
destination_type: :stream,
|
46
|
+
destination_name: stream_name
|
47
|
+
)
|
48
|
+
else
|
49
|
+
segment = NewRelic::Agent::Tracer.start_segment(name: get_segment_name(method_name, params))
|
50
|
+
end
|
51
|
+
|
52
|
+
segment&.add_agent_attribute('cloud.resource_id', arn) if arn
|
53
|
+
|
54
|
+
begin
|
55
|
+
NewRelic::Agent::Tracer.capture_segment_error(segment) { yield }
|
56
|
+
ensure
|
57
|
+
segment&.add_agent_attribute('cloud.platform', AWS_KINESIS_DATA_STREAMS)
|
58
|
+
segment&.finish
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def get_segment_name(method_name, params)
|
63
|
+
stream_name = params&.dig(:stream_name)
|
64
|
+
return "#{KINESIS}/#{method_name}/#{stream_name}" if stream_name
|
65
|
+
|
66
|
+
"#{KINESIS}/#{method_name}"
|
67
|
+
rescue => e
|
68
|
+
NewRelic::Agent.logger.warn("Failed to create segment name: #{e}")
|
69
|
+
end
|
70
|
+
|
71
|
+
def get_stream_name(params, arn)
|
72
|
+
params&.dig(:stream_name) || arn.split('/').last || 'unknown'
|
73
|
+
rescue => e
|
74
|
+
NewRelic::Agent.logger.warn("Failed to get stream name: #{e}")
|
75
|
+
end
|
76
|
+
|
77
|
+
def nr_account_id
|
78
|
+
return @nr_account_id if defined?(@nr_account_id)
|
79
|
+
|
80
|
+
@nr_account_id = NewRelic::Agent::Aws.get_account_id(config)
|
81
|
+
end
|
82
|
+
|
83
|
+
def get_arn(params)
|
84
|
+
stream_arn = params&.dig(:stream_arn)
|
85
|
+
return stream_arn if stream_arn
|
86
|
+
|
87
|
+
stream_name = params&.dig(:stream_name)
|
88
|
+
NewRelic::Agent::Aws.create_arn(KINESIS.downcase, "stream/#{stream_name}", config&.region, nr_account_id) if stream_name
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# This file is distributed under New Relic's license terms.
|
2
|
+
# See https://github.com/newrelic/newrelic-ruby-agent/blob/main/LICENSE for complete details.
|
3
|
+
# frozen_string_literal: true
|
4
|
+
|
5
|
+
module NewRelic::Agent::Instrumentation
|
6
|
+
module Kinesis::Prepend
|
7
|
+
include NewRelic::Agent::Instrumentation::Kinesis
|
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
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# This file is distributed under New Relic's license terms.
|
2
|
+
# See https://github.com/newrelic/newrelic-ruby-agent/blob/main/LICENSE for complete details.
|
3
|
+
# frozen_string_literal: true
|
4
|
+
|
5
|
+
require_relative 'aws_sdk_kinesis/instrumentation'
|
6
|
+
require_relative 'aws_sdk_kinesis/chain'
|
7
|
+
require_relative 'aws_sdk_kinesis/prepend'
|
8
|
+
|
9
|
+
DependencyDetection.defer do
|
10
|
+
named :aws_sdk_kinesis
|
11
|
+
|
12
|
+
depends_on do
|
13
|
+
defined?(Aws::Kinesis::Client)
|
14
|
+
end
|
15
|
+
executes do
|
16
|
+
if use_prepend?
|
17
|
+
prepend_instrument Aws::Kinesis::Client, NewRelic::Agent::Instrumentation::Kinesis::Prepend
|
18
|
+
else
|
19
|
+
chain_instrument NewRelic::Agent::Instrumentation::Kinesis::Chain
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|