newrelic_rpm 8.11.0 → 8.13.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +1 -3
- data/.rubocop_todo.yml +14 -7
- data/Brewfile +1 -0
- data/CHANGELOG.md +78 -16
- data/README.md +1 -1
- data/bin/nrdebug +2 -0
- data/docker-compose.yml +22 -0
- data/lib/new_relic/agent/agent/shutdown.rb +1 -0
- data/lib/new_relic/agent/agent/special_startup.rb +2 -0
- data/lib/new_relic/agent/agent/startup.rb +1 -0
- data/lib/new_relic/agent/agent_logger.rb +1 -1
- data/lib/new_relic/agent/attributes.rb +1 -0
- data/lib/new_relic/agent/audit_logger.rb +2 -1
- data/lib/new_relic/agent/commands/thread_profiler_session.rb +1 -0
- data/lib/new_relic/agent/configuration/default_source.rb +1415 -1359
- data/lib/new_relic/agent/configuration/dotted_hash.rb +1 -0
- data/lib/new_relic/agent/configuration/environment_source.rb +3 -2
- data/lib/new_relic/agent/configuration/high_security_source.rb +1 -0
- data/lib/new_relic/agent/configuration/manager.rb +3 -0
- data/lib/new_relic/agent/configuration/security_policy_source.rb +10 -0
- data/lib/new_relic/agent/configuration/yaml_source.rb +1 -0
- data/lib/new_relic/agent/connect/request_builder.rb +1 -0
- data/lib/new_relic/agent/database/obfuscation_helpers.rb +1 -0
- data/lib/new_relic/agent/database.rb +7 -0
- data/lib/new_relic/agent/database_adapter.rb +2 -0
- data/lib/new_relic/agent/datastores/mongo/event_formatter.rb +3 -2
- data/lib/new_relic/agent/datastores/mongo/metric_translator.rb +1 -1
- data/lib/new_relic/agent/datastores/nosql_obfuscator.rb +41 -0
- data/lib/new_relic/agent/distributed_tracing/cross_app_tracing.rb +3 -0
- data/lib/new_relic/agent/distributed_tracing/distributed_trace_attributes.rb +3 -0
- data/lib/new_relic/agent/distributed_tracing/distributed_trace_metrics.rb +1 -0
- data/lib/new_relic/agent/distributed_tracing/distributed_trace_payload.rb +1 -0
- data/lib/new_relic/agent/distributed_tracing/trace_context.rb +1 -0
- data/lib/new_relic/agent/encoding_normalizer.rb +2 -0
- data/lib/new_relic/agent/error_collector.rb +3 -0
- data/lib/new_relic/agent/error_filter.rb +1 -0
- data/lib/new_relic/agent/error_trace_aggregator.rb +1 -0
- data/lib/new_relic/agent/event_aggregator.rb +1 -0
- data/lib/new_relic/agent/event_loop.rb +2 -0
- data/lib/new_relic/agent/http_clients/abstract.rb +2 -0
- data/lib/new_relic/agent/http_clients/http_rb_wrappers.rb +1 -1
- data/lib/new_relic/agent/http_clients/httpclient_wrappers.rb +1 -1
- data/lib/new_relic/agent/http_clients/typhoeus_wrappers.rb +1 -0
- data/lib/new_relic/agent/instrumentation/active_merchant.rb +1 -2
- data/lib/new_relic/agent/instrumentation/active_storage_subscriber.rb +2 -0
- data/lib/new_relic/agent/instrumentation/acts_as_solr.rb +1 -2
- data/lib/new_relic/agent/instrumentation/authlogic.rb +0 -2
- data/lib/new_relic/agent/instrumentation/controller_instrumentation.rb +1 -0
- data/lib/new_relic/agent/instrumentation/data_mapper.rb +0 -1
- data/lib/new_relic/agent/instrumentation/delayed_job_instrumentation.rb +1 -2
- data/lib/new_relic/agent/instrumentation/elasticsearch/chain.rb +29 -0
- data/lib/new_relic/agent/instrumentation/elasticsearch/instrumentation.rb +66 -0
- data/lib/new_relic/agent/instrumentation/elasticsearch/prepend.rb +13 -0
- data/lib/new_relic/agent/instrumentation/elasticsearch.rb +31 -0
- data/lib/new_relic/agent/instrumentation/excon.rb +17 -0
- data/lib/new_relic/agent/instrumentation/grape/instrumentation.rb +1 -0
- data/lib/new_relic/agent/instrumentation/logger/instrumentation.rb +4 -0
- data/lib/new_relic/agent/instrumentation/mongodb_command_subscriber.rb +2 -0
- data/lib/new_relic/agent/instrumentation/notifications_subscriber.rb +2 -0
- data/lib/new_relic/agent/instrumentation/rack/chain.rb +10 -2
- data/lib/new_relic/agent/instrumentation/rack/instrumentation.rb +3 -0
- data/lib/new_relic/agent/instrumentation/rack/prepend.rb +9 -2
- data/lib/new_relic/agent/instrumentation/rainbows_instrumentation.rb +0 -1
- data/lib/new_relic/agent/instrumentation/rake/instrumentation.rb +1 -0
- data/lib/new_relic/agent/instrumentation/redis/chain.rb +18 -6
- data/lib/new_relic/agent/instrumentation/redis/constants.rb +17 -0
- data/lib/new_relic/agent/instrumentation/redis/instrumentation.rb +28 -18
- data/lib/new_relic/agent/instrumentation/redis/middleware.rb +16 -0
- data/lib/new_relic/agent/instrumentation/redis/prepend.rb +6 -0
- data/lib/new_relic/agent/instrumentation/redis.rb +6 -0
- data/lib/new_relic/agent/instrumentation/sidekiq/client.rb +20 -0
- data/lib/new_relic/agent/instrumentation/sidekiq/extensions/delayed_class.rb +30 -0
- data/lib/new_relic/agent/instrumentation/sidekiq/server.rb +37 -0
- data/lib/new_relic/agent/instrumentation/sidekiq.rb +7 -70
- data/lib/new_relic/agent/instrumentation/sinatra.rb +1 -2
- data/lib/new_relic/agent/instrumentation/sunspot.rb +0 -2
- data/lib/new_relic/agent/instrumentation/thread/instrumentation.rb +1 -0
- data/lib/new_relic/agent/instrumentation/tilt/instrumentation.rb +1 -0
- data/lib/new_relic/agent/javascript_instrumentor.rb +1 -0
- data/lib/new_relic/agent/local_log_decorator.rb +1 -0
- data/lib/new_relic/agent/log_event_aggregator.rb +1 -0
- data/lib/new_relic/agent/messaging.rb +1 -0
- data/lib/new_relic/agent/method_tracer.rb +4 -0
- data/lib/new_relic/agent/method_tracer_helpers.rb +1 -1
- data/lib/new_relic/agent/monitors/distributed_tracing_monitor.rb +1 -0
- data/lib/new_relic/agent/new_relic_service.rb +2 -0
- data/lib/new_relic/agent/parameter_filtering.rb +7 -1
- data/lib/new_relic/agent/pipe_channel_manager.rb +2 -0
- data/lib/new_relic/agent/rules_engine.rb +1 -0
- data/lib/new_relic/agent/samplers/cpu_sampler.rb +1 -0
- data/lib/new_relic/agent/samplers/memory_sampler.rb +5 -0
- data/lib/new_relic/agent/span_event_primitive.rb +1 -0
- data/lib/new_relic/agent/stats.rb +1 -0
- data/lib/new_relic/agent/stats_engine/gc_profiler.rb +1 -0
- data/lib/new_relic/agent/system_info.rb +3 -0
- data/lib/new_relic/agent/threading/agent_thread.rb +1 -0
- data/lib/new_relic/agent/threading/backtrace_service.rb +1 -0
- data/lib/new_relic/agent/threading/thread_profile.rb +3 -0
- data/lib/new_relic/agent/tracer.rb +5 -1
- data/lib/new_relic/agent/transaction/abstract_segment.rb +3 -0
- data/lib/new_relic/agent/transaction/datastore_segment.rb +3 -0
- data/lib/new_relic/agent/transaction/distributed_tracer.rb +4 -0
- data/lib/new_relic/agent/transaction/distributed_tracing.rb +1 -0
- data/lib/new_relic/agent/transaction/external_request_segment.rb +1 -0
- data/lib/new_relic/agent/transaction/message_broker_segment.rb +1 -0
- data/lib/new_relic/agent/transaction/segment.rb +1 -0
- data/lib/new_relic/agent/transaction/trace.rb +4 -0
- data/lib/new_relic/agent/transaction/trace_node.rb +1 -0
- data/lib/new_relic/agent/transaction/transaction_sample_buffer.rb +2 -0
- data/lib/new_relic/agent/transaction.rb +10 -0
- data/lib/new_relic/agent/transaction_event_aggregator.rb +1 -0
- data/lib/new_relic/agent/transaction_time_aggregator.rb +1 -0
- data/lib/new_relic/agent/utilization/pcf.rb +1 -0
- data/lib/new_relic/agent/utilization/vendor.rb +2 -0
- data/lib/new_relic/agent/utilization_data.rb +3 -0
- data/lib/new_relic/agent.rb +4 -2
- data/lib/new_relic/cli/commands/install.rb +1 -0
- data/lib/new_relic/coerce.rb +6 -0
- data/lib/new_relic/collection_helper.rb +1 -0
- data/lib/new_relic/constants.rb +2 -0
- data/lib/new_relic/control/frameworks/rails.rb +5 -0
- data/lib/new_relic/control/instrumentation.rb +6 -8
- data/lib/new_relic/dependency_detection.rb +2 -0
- data/lib/new_relic/helper.rb +1 -0
- data/lib/new_relic/language_support.rb +1 -0
- data/lib/new_relic/latest_changes.rb +1 -0
- data/lib/new_relic/local_environment.rb +7 -1
- data/lib/new_relic/metric_spec.rb +2 -0
- data/lib/new_relic/rack/agent_middleware.rb +2 -0
- data/lib/new_relic/rack/browser_monitoring.rb +1 -0
- data/lib/new_relic/traced_thread.rb +1 -0
- data/lib/new_relic/version.rb +1 -1
- data/lib/tasks/helpers/format.rb +3 -0
- data/lib/tasks/helpers/prompt.rb +1 -1
- data/lib/tasks/instrumentation_generator/README.md +2 -2
- data/lib/tasks/instrumentation_generator/TODO.md +5 -5
- data/lib/tasks/instrumentation_generator/instrumentation.thor +27 -5
- data/lib/tasks/instrumentation_generator/templates/chain.tt +2 -1
- data/lib/tasks/instrumentation_generator/templates/chain_method.tt +3 -2
- data/lib/tasks/instrumentation_generator/templates/instrumentation.tt +2 -1
- data/lib/tasks/instrumentation_generator/templates/instrumentation_method.tt +1 -1
- data/lib/tasks/instrumentation_generator/templates/prepend.tt +1 -1
- data/lib/tasks/instrumentation_generator/templates/prepend_method.tt +1 -1
- data/lib/tasks/instrumentation_generator/templates/test.tt +1 -1
- data/newrelic.yml +13 -3
- data/newrelic_rpm.gemspec +7 -7
- data/test/agent_helper.rb +24 -0
- metadata +18 -79
- data/lib/new_relic/agent/datastores/mongo/obfuscator.rb +0 -43
@@ -0,0 +1,31 @@
|
|
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 'elasticsearch/instrumentation'
|
6
|
+
require_relative 'elasticsearch/chain'
|
7
|
+
require_relative 'elasticsearch/prepend'
|
8
|
+
|
9
|
+
DependencyDetection.defer do
|
10
|
+
named :elasticsearch
|
11
|
+
|
12
|
+
depends_on do
|
13
|
+
defined?(::Elasticsearch)
|
14
|
+
end
|
15
|
+
|
16
|
+
executes do
|
17
|
+
::NewRelic::Agent.logger.info('Installing Elasticsearch instrumentation')
|
18
|
+
|
19
|
+
to_instrument = if ::Gem::Version.create(::Elasticsearch::VERSION) < ::Gem::Version.create("8.0.0")
|
20
|
+
::Elasticsearch::Transport::Client
|
21
|
+
else
|
22
|
+
::Elastic::Transport::Client
|
23
|
+
end
|
24
|
+
|
25
|
+
if use_prepend?
|
26
|
+
prepend_instrument to_instrument, NewRelic::Agent::Instrumentation::Elasticsearch::Prepend
|
27
|
+
else
|
28
|
+
chain_instrument NewRelic::Agent::Instrumentation::Elasticsearch
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -17,6 +17,7 @@ DependencyDetection.defer do
|
|
17
17
|
# so we could safely subscribe and not be clobbered by future subscribers,
|
18
18
|
# but alas, it does not yet.
|
19
19
|
|
20
|
+
# TODO: MAJOR VERSION - update min version to 0.56.0
|
20
21
|
EXCON_MIN_VERSION = Gem::Version.new("0.19.0")
|
21
22
|
|
22
23
|
depends_on do
|
@@ -32,6 +33,22 @@ DependencyDetection.defer do
|
|
32
33
|
end
|
33
34
|
end
|
34
35
|
|
36
|
+
executes do
|
37
|
+
next unless Gem::Version.new(::Excon::VERSION) < Gem::Version.new('0.56.0')
|
38
|
+
|
39
|
+
deprecation_msg = 'Instrumentation for Excon versions below 0.56.0 is deprecated.' \
|
40
|
+
'They will stop being monitored in version 9.0.0. ' \
|
41
|
+
'Please upgrade your Excon version to continue receiving full support. '
|
42
|
+
|
43
|
+
::NewRelic::Agent.logger.log_once(
|
44
|
+
:warn,
|
45
|
+
:deprecated_excon_version,
|
46
|
+
deprecation_msg
|
47
|
+
)
|
48
|
+
|
49
|
+
::NewRelic::Agent.record_metric("Supportability/Deprecated/Excon", 1)
|
50
|
+
end
|
51
|
+
|
35
52
|
def install_excon_instrumentation(excon_version)
|
36
53
|
require 'new_relic/agent/distributed_tracing/cross_app_tracing'
|
37
54
|
require 'new_relic/agent/http_clients/excon_wrappers'
|
@@ -15,21 +15,25 @@ module NewRelic
|
|
15
15
|
# and AuditLogger without them having to know the inner details.
|
16
16
|
def self.mark_skip_instrumenting(logger)
|
17
17
|
return if logger.frozen?
|
18
|
+
|
18
19
|
logger.instance_variable_set(:@skip_instrumenting, true)
|
19
20
|
end
|
20
21
|
|
21
22
|
def self.clear_skip_instrumenting(logger)
|
22
23
|
return if logger.frozen?
|
24
|
+
|
23
25
|
logger.instance_variable_set(:@skip_instrumenting, false)
|
24
26
|
end
|
25
27
|
|
26
28
|
def mark_skip_instrumenting
|
27
29
|
return if frozen?
|
30
|
+
|
28
31
|
@skip_instrumenting = true
|
29
32
|
end
|
30
33
|
|
31
34
|
def clear_skip_instrumenting
|
32
35
|
return if frozen?
|
36
|
+
|
33
37
|
@skip_instrumenting = false
|
34
38
|
end
|
35
39
|
|
@@ -14,6 +14,7 @@ module NewRelic
|
|
14
14
|
def started(event)
|
15
15
|
begin
|
16
16
|
return unless NewRelic::Agent::Tracer.tracing_enabled?
|
17
|
+
|
17
18
|
segments[event.operation_id] = start_segment(event)
|
18
19
|
rescue Exception => e
|
19
20
|
log_notification_error('started', e)
|
@@ -33,6 +34,7 @@ module NewRelic
|
|
33
34
|
def completed(event)
|
34
35
|
begin
|
35
36
|
return unless NewRelic::Agent::Tracer.tracing_enabled?
|
37
|
+
|
36
38
|
segment = segments.delete(event.operation_id)
|
37
39
|
return unless segment
|
38
40
|
|
@@ -76,6 +76,7 @@ module NewRelic
|
|
76
76
|
# defensive.
|
77
77
|
return if defined?(exception_object)
|
78
78
|
return unless defined?(::ActiveSupport::VERSION)
|
79
|
+
|
79
80
|
if ::ActiveSupport::VERSION::STRING < "5.0.0"
|
80
81
|
# Earlier versions of Rails did not add the exception itself to the
|
81
82
|
# payload accessible via :exception_object, so we create a stand-in
|
@@ -85,6 +86,7 @@ module NewRelic
|
|
85
86
|
def exception_object(payload)
|
86
87
|
exception_class, message = payload[:exception]
|
87
88
|
return nil unless exception_class
|
89
|
+
|
88
90
|
NewRelic::Agent::NoticeableError.new(exception_class, message)
|
89
91
|
end
|
90
92
|
else
|
@@ -21,8 +21,16 @@ module NewRelic::Agent::Instrumentation
|
|
21
21
|
if ::NewRelic::Agent::Instrumentation::RackHelpers.middleware_instrumentation_enabled?
|
22
22
|
::NewRelic::Agent.logger.info("Installing #{builder_class} middleware instrumentation")
|
23
23
|
|
24
|
-
def run_with_newrelic(app, *args)
|
25
|
-
|
24
|
+
def run_with_newrelic(app = nil, *args, &block)
|
25
|
+
app_or_block = app || block
|
26
|
+
run_with_tracing(app_or_block) do |wrapped|
|
27
|
+
# Rack::Builder#run for Rack v3+ supports a block, and does not
|
28
|
+
# support args. Whether a block or an app is provided, that
|
29
|
+
# callable object will be wrapped into a MiddlewareProxy
|
30
|
+
# instance. That proxy instance must then be passed to
|
31
|
+
# run_without_newrelic as the app argument.
|
32
|
+
block ? run_without_newrelic(wrapped, &nil) : run_without_newrelic(wrapped, *args)
|
33
|
+
end
|
26
34
|
end
|
27
35
|
|
28
36
|
alias_method(:run_without_newrelic, :run)
|
@@ -23,6 +23,7 @@ module NewRelic
|
|
23
23
|
|
24
24
|
def check_for_late_instrumentation(app)
|
25
25
|
return if defined?(@checked_for_late_instrumentation) && @checked_for_late_instrumentation
|
26
|
+
|
26
27
|
@checked_for_late_instrumentation = true
|
27
28
|
if middleware_instrumentation_enabled?
|
28
29
|
if ::NewRelic::Agent::Instrumentation::MiddlewareProxy.needs_wrapping?(app)
|
@@ -49,12 +50,14 @@ module NewRelic
|
|
49
50
|
|
50
51
|
def run_with_tracing(app)
|
51
52
|
return yield(app) unless middleware_instrumentation_enabled?
|
53
|
+
|
52
54
|
yield(::NewRelic::Agent::Instrumentation::MiddlewareProxy.wrap(app, true))
|
53
55
|
end
|
54
56
|
|
55
57
|
def use_with_tracing(middleware_class)
|
56
58
|
return if middleware_class.nil?
|
57
59
|
return yield(middleware_class) unless middleware_instrumentation_enabled?
|
60
|
+
|
58
61
|
yield(::NewRelic::Agent::Instrumentation::MiddlewareProxy.for_class(middleware_class))
|
59
62
|
end
|
60
63
|
end
|
@@ -23,8 +23,15 @@ module NewRelic::Agent::Instrumentation
|
|
23
23
|
with_deferred_dependency_detection { super }
|
24
24
|
end
|
25
25
|
|
26
|
-
def run(app, *args)
|
27
|
-
|
26
|
+
def run(app = nil, *args, &block)
|
27
|
+
app_or_block = app || block
|
28
|
+
run_with_tracing(app_or_block) do |wrapped|
|
29
|
+
# Rack::Builder#run for Rack v3+ supports a block, and does not
|
30
|
+
# support args. Whether a block or an app is provided, that callable
|
31
|
+
# object will be wrapped into a MiddlewareProxy instance. That
|
32
|
+
# proxy instance must then be passed to super as the app argument.
|
33
|
+
block ? super(wrapped, &nil) : super(wrapped, *args)
|
34
|
+
end
|
28
35
|
end
|
29
36
|
|
30
37
|
def use(middleware_class, *args, &blk)
|
@@ -37,6 +37,7 @@ module NewRelic
|
|
37
37
|
|
38
38
|
def safe_from_third_party_gem?
|
39
39
|
return true unless NewRelic::LanguageSupport.bundled_gem?("newrelic-rake")
|
40
|
+
|
40
41
|
::NewRelic::Agent.logger.info("Not installing New Relic supported Rake instrumentation because the third party newrelic-rake gem is present")
|
41
42
|
false
|
42
43
|
end
|
@@ -9,16 +9,28 @@ module NewRelic::Agent::Instrumentation
|
|
9
9
|
::Redis::Client.class_eval do
|
10
10
|
include NewRelic::Agent::Instrumentation::Redis
|
11
11
|
|
12
|
-
|
12
|
+
if method_defined?(:call_v)
|
13
|
+
alias_method(:call_v_without_new_relic, :call_v)
|
13
14
|
|
14
|
-
|
15
|
-
|
15
|
+
def call_v(*args, &block)
|
16
|
+
call_with_tracing(args[0]) { call_v_without_new_relic(*args, &block) }
|
17
|
+
end
|
16
18
|
end
|
17
19
|
|
18
|
-
|
20
|
+
if method_defined?(:call)
|
21
|
+
alias_method(:call_without_new_relic, :call)
|
19
22
|
|
20
|
-
|
21
|
-
|
23
|
+
def call(*args, &block)
|
24
|
+
call_with_tracing(args[0]) { call_without_new_relic(*args, &block) }
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
if method_defined?(:call_pipeline)
|
29
|
+
alias_method(:call_pipeline_without_new_relic, :call_pipeline)
|
30
|
+
|
31
|
+
def call_pipeline(*args, &block)
|
32
|
+
call_pipeline_with_tracing(args[0]) { call_pipeline_without_new_relic(*args, &block) }
|
33
|
+
end
|
22
34
|
end
|
23
35
|
|
24
36
|
alias_method(:connect_without_new_relic, :connect)
|
@@ -0,0 +1,17 @@
|
|
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::Redis
|
6
|
+
class Constants
|
7
|
+
PRODUCT_NAME = 'Redis'
|
8
|
+
CONNECT = 'connect'
|
9
|
+
UNKNOWN = 'unknown'
|
10
|
+
LOCALHOST = 'localhost'
|
11
|
+
MULTI_OPERATION = 'multi'
|
12
|
+
PIPELINE_OPERATION = 'pipeline'
|
13
|
+
HAS_REDIS_CLIENT = defined?(::Redis) &&
|
14
|
+
Gem::Version.new(::Redis::VERSION) >= Gem::Version.new('5.0.0') &&
|
15
|
+
!!defined?(::RedisClient)
|
16
|
+
end
|
17
|
+
end
|
@@ -2,42 +2,48 @@
|
|
2
2
|
# See https://github.com/newrelic/newrelic-ruby-agent/blob/main/LICENSE for complete details.
|
3
3
|
# frozen_string_literal: true
|
4
4
|
|
5
|
+
require_relative 'constants'
|
6
|
+
|
5
7
|
module NewRelic::Agent::Instrumentation
|
6
8
|
module Redis
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
LOCALHOST = "localhost"
|
11
|
-
MULTI_OPERATION = 'multi'
|
12
|
-
PIPELINE_OPERATION = 'pipeline'
|
9
|
+
def connect_with_tracing
|
10
|
+
with_tracing(Constants::CONNECT, database: db) { yield }
|
11
|
+
end
|
13
12
|
|
14
13
|
def call_with_tracing(command, &block)
|
15
14
|
operation = command[0]
|
16
15
|
statement = ::NewRelic::Agent::Datastores::Redis.format_command(command)
|
17
16
|
|
18
|
-
with_tracing(operation, statement) { yield }
|
17
|
+
with_tracing(operation, statement: statement, database: db) { yield }
|
19
18
|
end
|
20
19
|
|
20
|
+
# Used for Redis 4.x and 3.x
|
21
21
|
def call_pipeline_with_tracing(pipeline)
|
22
|
-
operation = pipeline.is_a?(::Redis::Pipeline::Multi) ? MULTI_OPERATION : PIPELINE_OPERATION
|
22
|
+
operation = pipeline.is_a?(::Redis::Pipeline::Multi) ? Constants::MULTI_OPERATION : Constants::PIPELINE_OPERATION
|
23
23
|
statement = ::NewRelic::Agent::Datastores::Redis.format_pipeline_commands(pipeline.commands)
|
24
24
|
|
25
|
-
with_tracing(operation, statement) { yield }
|
25
|
+
with_tracing(operation, statement: statement, database: db) { yield }
|
26
26
|
end
|
27
27
|
|
28
|
-
|
29
|
-
|
28
|
+
# Used for Redis 5.x+
|
29
|
+
def call_pipelined_with_tracing(pipeline)
|
30
|
+
operation = pipeline.flatten.include?('MULTI') ? Constants::MULTI_OPERATION : Constants::PIPELINE_OPERATION
|
31
|
+
statement = ::NewRelic::Agent::Datastores::Redis.format_pipeline_commands(pipeline)
|
32
|
+
|
33
|
+
# call_pipelined isn't invoked on the client object, so use client.db to
|
34
|
+
# access the client instance var on self
|
35
|
+
with_tracing(operation, statement: statement, database: client.db) { yield }
|
30
36
|
end
|
31
37
|
|
32
38
|
private
|
33
39
|
|
34
|
-
def with_tracing(operation, statement
|
40
|
+
def with_tracing(operation, statement: nil, database: nil)
|
35
41
|
segment = NewRelic::Agent::Tracer.start_datastore_segment(
|
36
|
-
product: PRODUCT_NAME,
|
42
|
+
product: Constants::PRODUCT_NAME,
|
37
43
|
operation: operation,
|
38
44
|
host: _nr_hostname,
|
39
45
|
port_path_or_id: _nr_port_path_or_id,
|
40
|
-
database_name:
|
46
|
+
database_name: database
|
41
47
|
)
|
42
48
|
begin
|
43
49
|
segment.notice_nosql_statement(statement) if statement
|
@@ -48,17 +54,21 @@ module NewRelic::Agent::Instrumentation
|
|
48
54
|
end
|
49
55
|
|
50
56
|
def _nr_hostname
|
51
|
-
|
57
|
+
_nr_client.path ? Constants::LOCALHOST : _nr_client.host
|
52
58
|
rescue => e
|
53
59
|
NewRelic::Agent.logger.debug("Failed to retrieve Redis host: #{e}")
|
54
|
-
UNKNOWN
|
60
|
+
Constants::UNKNOWN
|
55
61
|
end
|
56
62
|
|
57
63
|
def _nr_port_path_or_id
|
58
|
-
|
64
|
+
_nr_client.path || _nr_client.port
|
59
65
|
rescue => e
|
60
66
|
NewRelic::Agent.logger.debug("Failed to retrieve Redis port_path_or_id: #{e}")
|
61
|
-
UNKNOWN
|
67
|
+
Constants::UNKNOWN
|
68
|
+
end
|
69
|
+
|
70
|
+
def _nr_client
|
71
|
+
@nr_client ||= self.is_a?(::Redis::Client) ? self : client
|
62
72
|
end
|
63
73
|
end
|
64
74
|
end
|
@@ -0,0 +1,16 @@
|
|
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 RedisClient
|
7
|
+
module Middleware
|
8
|
+
# This module is used to instrument Redis 5.x+
|
9
|
+
include NewRelic::Agent::Instrumentation::Redis
|
10
|
+
|
11
|
+
def call_pipelined(*args, &block)
|
12
|
+
call_pipelined_with_tracing(args[0]) { super }
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -7,6 +7,12 @@ module NewRelic::Agent::Instrumentation
|
|
7
7
|
module Prepend
|
8
8
|
include NewRelic::Agent::Instrumentation::Redis
|
9
9
|
|
10
|
+
# Defined in version 5.x+
|
11
|
+
def call_v(*args, &block)
|
12
|
+
call_with_tracing(args[0]) { super }
|
13
|
+
end
|
14
|
+
|
15
|
+
# Defined in version 4.x, 3.x
|
10
16
|
def call(*args, &block)
|
11
17
|
call_with_tracing(args[0]) { super }
|
12
18
|
end
|
@@ -7,7 +7,9 @@ require 'new_relic/agent/datastores/redis'
|
|
7
7
|
|
8
8
|
require_relative 'redis/instrumentation'
|
9
9
|
require_relative 'redis/chain'
|
10
|
+
require_relative 'redis/constants'
|
10
11
|
require_relative 'redis/prepend'
|
12
|
+
require_relative 'redis/middleware'
|
11
13
|
|
12
14
|
DependencyDetection.defer do
|
13
15
|
# Why not :redis? newrelic-redis used that name, so avoid conflicting
|
@@ -29,6 +31,10 @@ DependencyDetection.defer do
|
|
29
31
|
|
30
32
|
executes do
|
31
33
|
NewRelic::Agent.logger.info('Installing Redis Instrumentation')
|
34
|
+
if NewRelic::Agent::Instrumentation::Redis::Constants::HAS_REDIS_CLIENT
|
35
|
+
::RedisClient.register(NewRelic::Agent::Instrumentation::RedisClient::Middleware)
|
36
|
+
end
|
37
|
+
|
32
38
|
if use_prepend?
|
33
39
|
prepend_instrument ::Redis::Client, NewRelic::Agent::Instrumentation::Redis::Prepend
|
34
40
|
else
|
@@ -0,0 +1,20 @@
|
|
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::Sidekiq
|
6
|
+
class Client
|
7
|
+
include Sidekiq::ClientMiddleware if defined?(Sidekiq::ClientMiddleware)
|
8
|
+
|
9
|
+
def call(_worker_class, job, *_)
|
10
|
+
job[NewRelic::NEWRELIC_KEY] ||= distributed_tracing_headers if ::NewRelic::Agent.config[:'distributed_tracing.enabled']
|
11
|
+
yield
|
12
|
+
end
|
13
|
+
|
14
|
+
def distributed_tracing_headers
|
15
|
+
headers = {}
|
16
|
+
::NewRelic::Agent::DistributedTracing.insert_distributed_trace_headers(headers)
|
17
|
+
headers
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,30 @@
|
|
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
|
+
# TODO: remove this class once Sidekiq v6 is no longer supported.
|
6
|
+
# Delayed extensions are disabled by default in Sidekiq 5 and 6 and
|
7
|
+
# were removed entirely in Sidekiq 7.
|
8
|
+
#
|
9
|
+
# see https://github.com/mperham/sidekiq/issues/5076 for the discussion
|
10
|
+
# of the removal, which includes mentions of alternatives
|
11
|
+
if defined?(Sidekiq::VERSION) && Sidekiq::VERSION < '7.0.0'
|
12
|
+
class Sidekiq::Extensions::DelayedClass
|
13
|
+
def newrelic_trace_args(msg, queue)
|
14
|
+
(target, method_name, _args) = if YAML.respond_to?(:unsafe_load)
|
15
|
+
YAML.unsafe_load(msg['args'][0])
|
16
|
+
else
|
17
|
+
YAML.load(msg['args'][0])
|
18
|
+
end
|
19
|
+
|
20
|
+
{
|
21
|
+
:name => method_name,
|
22
|
+
:class_name => target.name,
|
23
|
+
:category => 'OtherTransaction/SidekiqJob'
|
24
|
+
}
|
25
|
+
rescue => e
|
26
|
+
NewRelic::Agent.logger.error("Failure during deserializing YAML for Sidekiq::Extensions::DelayedClass", e)
|
27
|
+
NewRelic::Agent::Instrumentation::Sidekiq::Server.default_trace_args(msg)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
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::Sidekiq
|
6
|
+
class Server
|
7
|
+
include NewRelic::Agent::Instrumentation::ControllerInstrumentation
|
8
|
+
include Sidekiq::ServerMiddleware if defined?(Sidekiq::ServerMiddleware)
|
9
|
+
|
10
|
+
# Client middleware has additional parameters, and our tests use the
|
11
|
+
# middleware client-side to work inline.
|
12
|
+
def call(worker, msg, queue, *_)
|
13
|
+
trace_args = if worker.respond_to?(:newrelic_trace_args)
|
14
|
+
worker.newrelic_trace_args(msg, queue)
|
15
|
+
else
|
16
|
+
self.class.default_trace_args(msg)
|
17
|
+
end
|
18
|
+
trace_headers = msg.delete(NewRelic::NEWRELIC_KEY)
|
19
|
+
|
20
|
+
perform_action_with_newrelic_trace(trace_args) do
|
21
|
+
NewRelic::Agent::Transaction.merge_untrusted_agent_attributes(msg['args'], :'job.sidekiq.args',
|
22
|
+
NewRelic::Agent::AttributeFilter::DST_NONE)
|
23
|
+
|
24
|
+
::NewRelic::Agent::DistributedTracing::accept_distributed_trace_headers(trace_headers, "Other") if ::NewRelic::Agent.config[:'distributed_tracing.enabled']
|
25
|
+
yield
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.default_trace_args(msg)
|
30
|
+
{
|
31
|
+
:name => 'perform',
|
32
|
+
:class_name => msg['class'],
|
33
|
+
:category => 'OtherTransaction/SidekiqJob'
|
34
|
+
}
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -1,6 +1,9 @@
|
|
1
1
|
# This file is distributed under New Relic's license terms.
|
2
2
|
# See https://github.com/newrelic/newrelic-ruby-agent/blob/main/LICENSE for complete details.
|
3
3
|
# frozen_string_literal: true
|
4
|
+
require_relative 'sidekiq/client'
|
5
|
+
require_relative 'sidekiq/server'
|
6
|
+
require_relative 'sidekiq/extensions/delayed_class'
|
4
7
|
|
5
8
|
DependencyDetection.defer do
|
6
9
|
@name = :sidekiq
|
@@ -14,83 +17,18 @@ DependencyDetection.defer do
|
|
14
17
|
end
|
15
18
|
|
16
19
|
executes do
|
17
|
-
module NewRelic::SidekiqInstrumentation
|
18
|
-
class Server
|
19
|
-
include NewRelic::Agent::Instrumentation::ControllerInstrumentation
|
20
|
-
|
21
|
-
# Client middleware has additional parameters, and our tests use the
|
22
|
-
# middleware client-side to work inline.
|
23
|
-
def call(worker, msg, queue, *_)
|
24
|
-
trace_args = if worker.respond_to?(:newrelic_trace_args)
|
25
|
-
worker.newrelic_trace_args(msg, queue)
|
26
|
-
else
|
27
|
-
self.class.default_trace_args(msg)
|
28
|
-
end
|
29
|
-
trace_headers = msg.delete(NewRelic::NEWRELIC_KEY)
|
30
|
-
|
31
|
-
perform_action_with_newrelic_trace(trace_args) do
|
32
|
-
NewRelic::Agent::Transaction.merge_untrusted_agent_attributes(msg['args'], :'job.sidekiq.args',
|
33
|
-
NewRelic::Agent::AttributeFilter::DST_NONE)
|
34
|
-
|
35
|
-
::NewRelic::Agent::DistributedTracing::accept_distributed_trace_headers(trace_headers, "Other") if ::NewRelic::Agent.config[:'distributed_tracing.enabled']
|
36
|
-
yield
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
def self.default_trace_args(msg)
|
41
|
-
{
|
42
|
-
:name => 'perform',
|
43
|
-
:class_name => msg['class'],
|
44
|
-
:category => 'OtherTransaction/SidekiqJob'
|
45
|
-
}
|
46
|
-
end
|
47
|
-
end
|
48
|
-
|
49
|
-
class Client
|
50
|
-
def call(_worker_class, job, *_)
|
51
|
-
job[NewRelic::NEWRELIC_KEY] ||= distributed_tracing_headers if ::NewRelic::Agent.config[:'distributed_tracing.enabled']
|
52
|
-
yield
|
53
|
-
end
|
54
|
-
|
55
|
-
def distributed_tracing_headers
|
56
|
-
headers = {}
|
57
|
-
::NewRelic::Agent::DistributedTracing.insert_distributed_trace_headers(headers)
|
58
|
-
headers
|
59
|
-
end
|
60
|
-
end
|
61
|
-
end
|
62
|
-
|
63
|
-
class Sidekiq::Extensions::DelayedClass
|
64
|
-
def newrelic_trace_args(msg, queue)
|
65
|
-
(target, method_name, _args) = if YAML.respond_to?(:unsafe_load)
|
66
|
-
YAML.unsafe_load(msg['args'][0])
|
67
|
-
else
|
68
|
-
YAML.load(msg['args'][0])
|
69
|
-
end
|
70
|
-
|
71
|
-
{
|
72
|
-
:name => method_name,
|
73
|
-
:class_name => target.name,
|
74
|
-
:category => 'OtherTransaction/SidekiqJob'
|
75
|
-
}
|
76
|
-
rescue => e
|
77
|
-
NewRelic::Agent.logger.error("Failure during deserializing YAML for Sidekiq::Extensions::DelayedClass", e)
|
78
|
-
NewRelic::SidekiqInstrumentation::Server.default_trace_args(msg)
|
79
|
-
end
|
80
|
-
end
|
81
|
-
|
82
20
|
Sidekiq.configure_client do |config|
|
83
21
|
config.client_middleware do |chain|
|
84
|
-
chain.add(NewRelic::
|
22
|
+
chain.add(NewRelic::Agent::Instrumentation::Sidekiq::Client)
|
85
23
|
end
|
86
24
|
end
|
87
25
|
|
88
26
|
Sidekiq.configure_server do |config|
|
89
27
|
config.client_middleware do |chain|
|
90
|
-
chain.add(NewRelic::
|
28
|
+
chain.add(NewRelic::Agent::Instrumentation::Sidekiq::Client)
|
91
29
|
end
|
92
30
|
config.server_middleware do |chain|
|
93
|
-
chain.add(NewRelic::
|
31
|
+
chain.add(NewRelic::Agent::Instrumentation::Sidekiq::Server)
|
94
32
|
end
|
95
33
|
|
96
34
|
if config.respond_to?(:error_handlers)
|
@@ -103,6 +41,7 @@ DependencyDetection.defer do
|
|
103
41
|
|
104
42
|
executes do
|
105
43
|
next unless Gem::Version.new(Sidekiq::VERSION) < Gem::Version.new('5.0.0')
|
44
|
+
|
106
45
|
deprecation_msg = 'Instrumentation for Sidekiq versions below 5.0.0 is deprecated.' \
|
107
46
|
'They will stop being monitored in version 9.0.0. ' \
|
108
47
|
'Please upgrade your Sidekiq version to continue receiving full support. '
|
@@ -112,7 +51,5 @@ DependencyDetection.defer do
|
|
112
51
|
:deprecated_sidekiq_version,
|
113
52
|
deprecation_msg
|
114
53
|
)
|
115
|
-
|
116
|
-
::NewRelic::Agent.record_metric("Supportability/Deprecated/Sidekiq", 1)
|
117
54
|
end
|
118
55
|
end
|
@@ -45,6 +45,7 @@ DependencyDetection.defer do
|
|
45
45
|
|
46
46
|
executes do
|
47
47
|
next unless Gem::Version.new(Sinatra::VERSION) < Gem::Version.new('2.0.0')
|
48
|
+
|
48
49
|
deprecation_msg = 'The Ruby Agent is dropping support for Sinatra versions below 2.0.0 ' \
|
49
50
|
'in version 9.0.0. Please upgrade your Sinatra version to continue receiving full compatibility. ' \
|
50
51
|
|
@@ -53,7 +54,5 @@ DependencyDetection.defer do
|
|
53
54
|
:deprecated_sinatra_version,
|
54
55
|
deprecation_msg
|
55
56
|
)
|
56
|
-
|
57
|
-
::NewRelic::Agent.record_metric("Supportability/Deprecated/Sinatra", 1)
|
58
57
|
end
|
59
58
|
end
|
@@ -14,6 +14,7 @@ module NewRelic
|
|
14
14
|
# So here we are only grabbing the file name and name of directory it is in
|
15
15
|
def create_filename_for_metric(file)
|
16
16
|
return file unless defined?(::Sinatra) && defined?(::Sinatra::Base)
|
17
|
+
|
17
18
|
file.split('/')[-2..-1].join('/')
|
18
19
|
rescue NoMethodError
|
19
20
|
file
|