newrelic_rpm 9.16.0 → 9.17.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.build_ignore +0 -1
- data/CHANGELOG.md +51 -3
- data/CONTRIBUTING.md +2 -2
- 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 +54 -3
- data/lib/new_relic/agent/configuration/default_source.rb +52 -11
- data/lib/new_relic/agent/configuration/yaml_source.rb +6 -1
- data/lib/new_relic/agent/database.rb +5 -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_record_helper.rb +5 -1
- data/lib/new_relic/agent/instrumentation/active_record_subscriber.rb +8 -4
- 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/instrumentation.rb +8 -9
- data/lib/new_relic/agent/instrumentation/dynamodb/instrumentation.rb +7 -1
- data/lib/new_relic/agent/instrumentation/grape/instrumentation.rb +0 -3
- data/lib/new_relic/agent/instrumentation/resque.rb +7 -1
- data/lib/new_relic/agent/instrumentation/sidekiq/extensions/delayed_class.rb +1 -1
- data/lib/new_relic/agent/local_log_decorator.rb +12 -2
- data/lib/new_relic/agent/new_relic_service.rb +8 -2
- 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.rb +2 -2
- data/lib/new_relic/dependency_detection.rb +1 -8
- data/lib/new_relic/version.rb +1 -1
- data/newrelic.yml +32 -26
- data/test/agent_helper.rb +7 -0
- metadata +12 -6
@@ -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
|
@@ -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 = {
|
@@ -116,10 +116,14 @@ module NewRelic
|
|
116
116
|
port_path_or_id = nil
|
117
117
|
database = nil
|
118
118
|
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
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]}")
|
123
127
|
end
|
124
128
|
|
125
129
|
segment = Tracer.start_datastore_segment(product: product,
|
@@ -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
|
@@ -63,10 +63,9 @@ module NewRelic::Agent::Instrumentation
|
|
63
63
|
def generate_segment(action, options = {})
|
64
64
|
function = function_name(options)
|
65
65
|
region = aws_region
|
66
|
-
account_id = aws_account_id
|
67
66
|
arn = aws_arn(function, region)
|
68
67
|
segment = NewRelic::Agent::Tracer.start_segment(name: "Lambda/#{action}/#{function}")
|
69
|
-
segment.add_agent_attribute('cloud.account.id',
|
68
|
+
segment.add_agent_attribute('cloud.account.id', nr_account_id)
|
70
69
|
segment.add_agent_attribute('cloud.platform', CLOUD_PLATFORM)
|
71
70
|
segment.add_agent_attribute('cloud.region', region)
|
72
71
|
segment.add_agent_attribute('cloud.resource_id', arn) if arn
|
@@ -77,18 +76,18 @@ module NewRelic::Agent::Instrumentation
|
|
77
76
|
(options.fetch(:function_name, nil) if options.respond_to?(:fetch)) || NewRelic::UNKNOWN
|
78
77
|
end
|
79
78
|
|
80
|
-
def aws_account_id
|
81
|
-
return unless self.respond_to?(:config)
|
82
|
-
|
83
|
-
config&.account_id || NewRelic::Agent.config[:'cloud.aws.account_id']
|
84
|
-
end
|
85
|
-
|
86
79
|
def aws_region
|
87
80
|
config&.region if self.respond_to?(:config)
|
88
81
|
end
|
89
82
|
|
90
83
|
def aws_arn(function, region)
|
91
|
-
NewRelic::Agent::Aws.create_arn(AWS_SERVICE, "function:#{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)
|
92
91
|
end
|
93
92
|
end
|
94
93
|
end
|
@@ -49,10 +49,16 @@ module NewRelic::Agent::Instrumentation
|
|
49
49
|
@nr_captured_request = yield
|
50
50
|
end
|
51
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
|
+
|
52
58
|
def get_arn(params)
|
53
59
|
return unless params[:table_name]
|
54
60
|
|
55
|
-
NewRelic::Agent::Aws.create_arn(PRODUCT.downcase, "table/#{params[:table_name]}", config&.region)
|
61
|
+
NewRelic::Agent::Aws.create_arn(PRODUCT.downcase, "table/#{params[:table_name]}", config&.region, nr_account_id)
|
56
62
|
end
|
57
63
|
end
|
58
64
|
end
|
@@ -56,10 +56,7 @@ module NewRelic::Agent::Instrumentation
|
|
56
56
|
|
57
57
|
def name_transaction(route, class_name, version)
|
58
58
|
txn_name = name_for_transaction(route, class_name, version)
|
59
|
-
segment_name = "Middleware/Grape/#{class_name}/call"
|
60
59
|
NewRelic::Agent::Transaction.set_default_transaction_name(txn_name, :grape)
|
61
|
-
txn = NewRelic::Agent::Transaction.tl_current
|
62
|
-
txn.segments.last.name = segment_name
|
63
60
|
end
|
64
61
|
|
65
62
|
def name_for_transaction(route, class_name, version)
|
@@ -19,7 +19,13 @@ DependencyDetection.defer do
|
|
19
19
|
end
|
20
20
|
|
21
21
|
executes do
|
22
|
-
if NewRelic::Agent.config[:'resque.use_ruby_dns'] &&
|
22
|
+
if NewRelic::Agent.config[:'resque.use_ruby_dns'] &&
|
23
|
+
NewRelic::Agent.config[:dispatcher] == :resque &&
|
24
|
+
# resolv-replace is no longer part of the language in Ruby 3.4.
|
25
|
+
# we don't believe this lib is still necessary for Ruby 3.4 users.
|
26
|
+
# however, if we receive customer feedback to the contrary, we can find
|
27
|
+
# an alternate approach.
|
28
|
+
Gem::Version.new(RUBY_VERSION) < Gem::Version.new('3.4')
|
23
29
|
NewRelic::Agent.logger.info('Requiring resolv-replace')
|
24
30
|
require 'resolv'
|
25
31
|
require 'resolv-replace'
|
@@ -6,7 +6,7 @@
|
|
6
6
|
# Delayed extensions are disabled by default in Sidekiq 5 and 6 and
|
7
7
|
# were removed entirely in Sidekiq 7.
|
8
8
|
#
|
9
|
-
# see https://github.com/
|
9
|
+
# see https://github.com/sidekiq/sidekiq/issues/5076 for the discussion
|
10
10
|
# of the removal, which includes mentions of alternatives
|
11
11
|
if defined?(Sidekiq::VERSION) && Sidekiq::VERSION < '7.0.0'
|
12
12
|
class Sidekiq::Extensions::DelayedClass
|
@@ -9,7 +9,7 @@ module NewRelic
|
|
9
9
|
extend self
|
10
10
|
|
11
11
|
def decorate(message)
|
12
|
-
return message
|
12
|
+
return message if !decorating_enabled? || message.nil?
|
13
13
|
|
14
14
|
metadata = NewRelic::Agent.linking_metadata
|
15
15
|
|
@@ -37,7 +37,17 @@ module NewRelic
|
|
37
37
|
def escape_entity_name(entity_name)
|
38
38
|
return unless entity_name
|
39
39
|
|
40
|
-
|
40
|
+
# TODO: OLD RUBIES 3.3
|
41
|
+
# URI version 1.0 marked URI::RFC3986_PARSER.escape as obsolete,
|
42
|
+
# which URI::DEFAULT_PARSER is an alias for.
|
43
|
+
# URI version 1.0+ will ship with Ruby 3.4
|
44
|
+
# Once we drop support for Rubies below 3.4, we can use the
|
45
|
+
# URI::RFC2396 parser exclusively.
|
46
|
+
if Gem::Version.new(URI::VERSION) >= Gem::Version.new('1.0')
|
47
|
+
URI::RFC2396_PARSER.escape(entity_name)
|
48
|
+
else
|
49
|
+
URI::DEFAULT_PARSER.escape(entity_name)
|
50
|
+
end
|
41
51
|
end
|
42
52
|
end
|
43
53
|
end
|
@@ -455,6 +455,8 @@ module NewRelic
|
|
455
455
|
end
|
456
456
|
|
457
457
|
def handle_error_response(response, endpoint)
|
458
|
+
NewRelic::Agent.agent.health_check.update_status(NewRelic::Agent::HealthCheck::HTTP_ERROR, [response.code, endpoint])
|
459
|
+
|
458
460
|
case response
|
459
461
|
when Net::HTTPRequestTimeOut,
|
460
462
|
Net::HTTPTooManyRequests,
|
@@ -637,9 +639,13 @@ module NewRelic
|
|
637
639
|
def send_request(opts)
|
638
640
|
request = prep_request(opts)
|
639
641
|
response = relay_request(request, opts)
|
640
|
-
return response if response.is_a?(Net::HTTPSuccess) || response.is_a?(Net::HTTPAccepted)
|
641
642
|
|
642
|
-
|
643
|
+
if response.is_a?(Net::HTTPSuccess) || response.is_a?(Net::HTTPAccepted)
|
644
|
+
NewRelic::Agent.agent.health_check.update_status(NewRelic::Agent::HealthCheck::HEALTHY)
|
645
|
+
response
|
646
|
+
else
|
647
|
+
handle_error_response(response, opts[:endpoint])
|
648
|
+
end
|
643
649
|
end
|
644
650
|
|
645
651
|
def log_response(response)
|
@@ -125,7 +125,16 @@ module NewRelic
|
|
125
125
|
|
126
126
|
# Returns [filename, method, line number]
|
127
127
|
def parse_backtrace_frame(frame)
|
128
|
-
|
128
|
+
# TODO: OLD RUBIES - Ruby 3.3
|
129
|
+
# The (?:`|') non-capturing group can be removed when the agent
|
130
|
+
# drops support for Ruby 3.3
|
131
|
+
# This group is used to capture the pre-Ruby 3.4.0 backtrace syntax.
|
132
|
+
# Example frame:
|
133
|
+
# Ruby 3.3.0 and below
|
134
|
+
# "irb.rb:69:in `catch'"
|
135
|
+
# Ruby 3.4.0+
|
136
|
+
# "irb.rb:69:in 'Kernel#catch'"
|
137
|
+
frame =~ /([^:]*)(\:(\d+))?\:in (?:`|')(.*)'/
|
129
138
|
[$1, $4, $3] # sic
|
130
139
|
end
|
131
140
|
end
|
@@ -15,6 +15,7 @@ module NewRelic
|
|
15
15
|
PRODUCE = 'Produce'.freeze
|
16
16
|
QUEUE = 'Queue'.freeze
|
17
17
|
PURGE = 'Purge'.freeze
|
18
|
+
STREAM = 'Stream'.freeze
|
18
19
|
TEMP = 'Temp'.freeze
|
19
20
|
TOPIC = 'Topic'.freeze
|
20
21
|
UNKNOWN = 'Unknown'.freeze
|
@@ -22,6 +23,7 @@ module NewRelic
|
|
22
23
|
DESTINATION_TYPES = [
|
23
24
|
:exchange,
|
24
25
|
:queue,
|
26
|
+
:stream,
|
25
27
|
:topic,
|
26
28
|
:temporary_queue,
|
27
29
|
:temporary_topic,
|
@@ -37,6 +39,7 @@ module NewRelic
|
|
37
39
|
TYPES = {
|
38
40
|
exchange: EXCHANGE,
|
39
41
|
temporary_queue: QUEUE,
|
42
|
+
stream: STREAM,
|
40
43
|
queue: QUEUE,
|
41
44
|
temporary_topic: TOPIC,
|
42
45
|
topic: TOPIC,
|
data/lib/new_relic/agent.rb
CHANGED
@@ -132,8 +132,8 @@ module NewRelic
|
|
132
132
|
def agent # :nodoc:
|
133
133
|
return @agent if @agent
|
134
134
|
|
135
|
-
NewRelic::Agent.logger.
|
136
|
-
NewRelic::Agent.logger.
|
135
|
+
NewRelic::Agent.logger.debug("Agent unavailable as it hasn't been started.")
|
136
|
+
NewRelic::Agent.logger.debug(caller.join("\n"))
|
137
137
|
nil
|
138
138
|
end
|
139
139
|
|