newrelic_rpm 6.15.0 → 7.0.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 +96 -22
- data/README.md +2 -2
- data/lib/new_relic/agent.rb +0 -6
- data/lib/new_relic/agent/autostart.rb +1 -2
- data/lib/new_relic/agent/configuration/default_source.rb +270 -104
- data/lib/new_relic/agent/configuration/manager.rb +2 -2
- data/lib/new_relic/agent/datastores/redis.rb +0 -4
- data/lib/new_relic/agent/distributed_tracing.rb +0 -66
- data/lib/new_relic/agent/instrumentation/active_record_notifications.rb +0 -16
- data/lib/new_relic/agent/instrumentation/bunny.rb +10 -152
- data/lib/new_relic/agent/instrumentation/bunny/chain.rb +45 -0
- data/lib/new_relic/agent/instrumentation/bunny/instrumentation.rb +152 -0
- data/lib/new_relic/agent/instrumentation/bunny/prepend.rb +35 -0
- data/lib/new_relic/agent/instrumentation/curb.rb +9 -241
- data/lib/new_relic/agent/instrumentation/curb/chain.rb +93 -0
- data/lib/new_relic/agent/instrumentation/curb/instrumentation.rb +222 -0
- data/lib/new_relic/agent/instrumentation/curb/prepend.rb +63 -0
- data/lib/new_relic/agent/instrumentation/delayed_job/chain.rb +38 -0
- data/lib/new_relic/agent/instrumentation/delayed_job/instrumentation.rb +53 -0
- data/lib/new_relic/agent/instrumentation/delayed_job/prepend.rb +34 -0
- data/lib/new_relic/agent/instrumentation/delayed_job_instrumentation.rb +8 -50
- data/lib/new_relic/agent/instrumentation/excon.rb +2 -1
- data/lib/new_relic/agent/instrumentation/grape.rb +13 -113
- data/lib/new_relic/agent/instrumentation/grape/chain.rb +25 -0
- data/lib/new_relic/agent/instrumentation/grape/instrumentation.rb +100 -0
- data/lib/new_relic/agent/instrumentation/grape/prepend.rb +17 -0
- data/lib/new_relic/agent/instrumentation/httpclient.rb +8 -30
- data/lib/new_relic/agent/instrumentation/httpclient/chain.rb +25 -0
- data/lib/new_relic/agent/instrumentation/httpclient/instrumentation.rb +38 -0
- data/lib/new_relic/agent/instrumentation/httpclient/prepend.rb +17 -0
- data/lib/new_relic/agent/instrumentation/httprb.rb +29 -0
- data/lib/new_relic/agent/instrumentation/httprb/chain.rb +22 -0
- data/lib/new_relic/agent/instrumentation/httprb/instrumentation.rb +30 -0
- data/lib/new_relic/agent/instrumentation/httprb/prepend.rb +15 -0
- data/lib/new_relic/agent/instrumentation/memcache.rb +54 -69
- data/lib/new_relic/agent/instrumentation/memcache/chain.rb +16 -0
- data/lib/new_relic/agent/instrumentation/memcache/dalli.rb +38 -121
- data/lib/new_relic/agent/instrumentation/memcache/helper.rb +56 -0
- data/lib/new_relic/agent/instrumentation/memcache/instrumentation.rb +88 -0
- data/lib/new_relic/agent/instrumentation/memcache/prepend.rb +88 -0
- data/lib/new_relic/agent/instrumentation/middleware_proxy.rb +2 -0
- data/lib/new_relic/agent/instrumentation/mongo.rb +7 -0
- data/lib/new_relic/agent/instrumentation/net_http.rb +39 -0
- data/lib/new_relic/agent/instrumentation/net_http/chain.rb +25 -0
- data/lib/new_relic/agent/instrumentation/{net_prepend.rb → net_http/instrumentation.rb} +3 -3
- data/lib/new_relic/agent/instrumentation/net_http/prepend.rb +21 -0
- data/lib/new_relic/agent/instrumentation/padrino.rb +18 -53
- data/lib/new_relic/agent/instrumentation/padrino/chain.rb +34 -0
- data/lib/new_relic/agent/instrumentation/padrino/instrumentation.rb +27 -0
- data/lib/new_relic/agent/instrumentation/padrino/prepend.rb +20 -0
- data/lib/new_relic/agent/instrumentation/rack.rb +29 -139
- data/lib/new_relic/agent/instrumentation/rack/chain.rb +57 -0
- data/lib/new_relic/agent/instrumentation/rack/helpers.rb +32 -0
- data/lib/new_relic/agent/instrumentation/rack/instrumentation.rb +73 -0
- data/lib/new_relic/agent/instrumentation/rack/prepend.rb +36 -0
- data/lib/new_relic/agent/instrumentation/rake.rb +13 -154
- data/lib/new_relic/agent/instrumentation/rake/chain.rb +25 -0
- data/lib/new_relic/agent/instrumentation/rake/instrumentation.rb +144 -0
- data/lib/new_relic/agent/instrumentation/rake/prepend.rb +14 -0
- data/lib/new_relic/agent/instrumentation/redis.rb +10 -109
- data/lib/new_relic/agent/instrumentation/redis/chain.rb +34 -0
- data/lib/new_relic/agent/instrumentation/redis/instrumentation.rb +65 -0
- data/lib/new_relic/agent/instrumentation/redis/prepend.rb +24 -0
- data/lib/new_relic/agent/instrumentation/resque.rb +8 -28
- data/lib/new_relic/agent/instrumentation/resque/chain.rb +22 -0
- data/lib/new_relic/agent/instrumentation/resque/instrumentation.rb +33 -0
- data/lib/new_relic/agent/instrumentation/resque/prepend.rb +16 -0
- data/lib/new_relic/agent/instrumentation/sinatra.rb +20 -158
- data/lib/new_relic/agent/instrumentation/sinatra/chain.rb +55 -0
- data/lib/new_relic/agent/instrumentation/sinatra/ignorer.rb +29 -34
- data/lib/new_relic/agent/instrumentation/sinatra/instrumentation.rb +118 -0
- data/lib/new_relic/agent/instrumentation/sinatra/prepend.rb +33 -0
- data/lib/new_relic/agent/instrumentation/typhoeus.rb +10 -89
- data/lib/new_relic/agent/instrumentation/typhoeus/chain.rb +22 -0
- data/lib/new_relic/agent/instrumentation/typhoeus/instrumentation.rb +82 -0
- data/lib/new_relic/agent/instrumentation/typhoeus/prepend.rb +14 -0
- data/lib/new_relic/agent/new_relic_service.rb +3 -12
- data/lib/new_relic/agent/sql_sampler.rb +1 -1
- data/lib/new_relic/agent/transaction.rb +1 -4
- data/lib/new_relic/control/frameworks/rails.rb +11 -9
- data/lib/new_relic/control/instance_methods.rb +1 -0
- data/lib/new_relic/dependency_detection.rb +116 -10
- data/lib/new_relic/noticed_error.rb +1 -5
- data/lib/new_relic/supportability_helper.rb +1 -2
- data/lib/new_relic/version.rb +2 -2
- data/newrelic_rpm.gemspec +1 -1
- metadata +53 -8
- data/cert/cacert.pem +0 -1177
- data/lib/new_relic/agent/instrumentation/http.rb +0 -49
- data/lib/new_relic/agent/instrumentation/net.rb +0 -70
@@ -0,0 +1,57 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# This file is distributed under New Relic's license terms.
|
3
|
+
# See https://github.com/newrelic/newrelic-ruby-agent/blob/main/LICENSE for complete details.
|
4
|
+
|
5
|
+
module NewRelic::Agent::Instrumentation
|
6
|
+
module Rack
|
7
|
+
module Chain
|
8
|
+
def self.instrument! builder_class
|
9
|
+
NewRelic::Agent::Instrumentation::RackBuilder.track_deferred_detection builder_class
|
10
|
+
|
11
|
+
builder_class.class_eval do
|
12
|
+
include ::NewRelic::Agent::Instrumentation::RackBuilder
|
13
|
+
|
14
|
+
def to_app_with_newrelic_deferred_dependency_detection
|
15
|
+
with_deferred_dependency_detection { to_app_without_newrelic }
|
16
|
+
end
|
17
|
+
|
18
|
+
alias_method :to_app_without_newrelic, :to_app
|
19
|
+
alias_method :to_app, :to_app_with_newrelic_deferred_dependency_detection
|
20
|
+
|
21
|
+
if ::NewRelic::Agent::Instrumentation::RackHelpers.middleware_instrumentation_enabled?
|
22
|
+
::NewRelic::Agent.logger.info "Installing #{builder_class} middleware instrumentation"
|
23
|
+
|
24
|
+
def run_with_newrelic(app, *args)
|
25
|
+
run_with_tracing(app) { |wrapped_app| run_without_newrelic(wrapped_app, *args) }
|
26
|
+
end
|
27
|
+
|
28
|
+
alias_method :run_without_newrelic, :run
|
29
|
+
alias_method :run, :run_with_newrelic
|
30
|
+
|
31
|
+
def use_with_newrelic(middleware_class, *args, &block)
|
32
|
+
use_with_tracing(middleware_class) { |wrapped_class| use_without_newrelic(wrapped_class, *args, &block) }
|
33
|
+
end
|
34
|
+
|
35
|
+
alias_method :use_without_newrelic, :use
|
36
|
+
alias_method :use, :use_with_newrelic
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
module URLMap
|
43
|
+
module Chain
|
44
|
+
def self.instrument! url_map_class
|
45
|
+
url_map_class.class_eval do
|
46
|
+
alias_method :initialize_without_newrelic, :initialize
|
47
|
+
|
48
|
+
def initialize(map = {})
|
49
|
+
traced_map = ::NewRelic::Agent::Instrumentation::RackURLMap.generate_traced_map(map)
|
50
|
+
initialize_without_newrelic(traced_map)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# This file is distributed under New Relic's license terms.
|
3
|
+
# See https://github.com/newrelic/newrelic-ruby-agent/blob/main/LICENSE for complete details.
|
4
|
+
|
5
|
+
module NewRelic::Agent::Instrumentation
|
6
|
+
module RackHelpers
|
7
|
+
def self.version_supported?
|
8
|
+
rack_version_supported? || puma_rack_version_supported?
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.rack_version_supported?
|
12
|
+
return false unless defined? ::Rack
|
13
|
+
|
14
|
+
version = Gem::Version.new(::Rack.release)
|
15
|
+
min_version = Gem::Version.new('1.1.0')
|
16
|
+
version >= min_version
|
17
|
+
end
|
18
|
+
|
19
|
+
def self.puma_rack_version_supported?
|
20
|
+
return false unless defined? ::Puma::Const::PUMA_VERSION
|
21
|
+
|
22
|
+
version = Gem::Version.new(::Puma::Const::PUMA_VERSION)
|
23
|
+
min_version = Gem::Version.new('2.12.0')
|
24
|
+
version >= min_version
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.middleware_instrumentation_enabled?
|
28
|
+
version_supported? && !::NewRelic::Agent.config[:disable_middleware_instrumentation]
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
@@ -0,0 +1,73 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# This file is distributed under New Relic's license terms.
|
3
|
+
# See https://github.com/newrelic/newrelic-ruby-agent/blob/main/LICENSE for complete details.
|
4
|
+
|
5
|
+
module NewRelic
|
6
|
+
module Agent
|
7
|
+
module Instrumentation
|
8
|
+
module RackBuilder
|
9
|
+
|
10
|
+
def self.track_deferred_detection builder_class
|
11
|
+
class << builder_class
|
12
|
+
attr_accessor :_nr_deferred_detection_ran
|
13
|
+
end
|
14
|
+
builder_class._nr_deferred_detection_ran = false
|
15
|
+
end
|
16
|
+
|
17
|
+
def deferred_dependency_check
|
18
|
+
return if self.class._nr_deferred_detection_ran
|
19
|
+
|
20
|
+
NewRelic::Agent.logger.info "Doing deferred dependency-detection before Rack startup"
|
21
|
+
DependencyDetection.detect!
|
22
|
+
self.class._nr_deferred_detection_ran = true
|
23
|
+
end
|
24
|
+
|
25
|
+
def check_for_late_instrumentation(app)
|
26
|
+
return if defined?(@checked_for_late_instrumentation) && @checked_for_late_instrumentation
|
27
|
+
@checked_for_late_instrumentation = true
|
28
|
+
if middleware_instrumentation_enabled?
|
29
|
+
if ::NewRelic::Agent::Instrumentation::MiddlewareProxy.needs_wrapping?(app)
|
30
|
+
::NewRelic::Agent.logger.info("We weren't able to instrument all of your Rack middlewares.",
|
31
|
+
"To correct this, ensure you 'require \"newrelic_rpm\"' before setting up your middleware stack.")
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
# We patch the #to_app method for a reason that actually has nothing to do with
|
37
|
+
# instrumenting rack itself. It happens to be a convenient and
|
38
|
+
# easy-to-hook point that happens late in the startup sequence of almost
|
39
|
+
# every application, making it a good place to do a final call to
|
40
|
+
# DependencyDetection.detect!, since all libraries are likely loaded at
|
41
|
+
# this point.
|
42
|
+
def with_deferred_dependency_detection
|
43
|
+
deferred_dependency_check
|
44
|
+
yield.tap{ |result| check_for_late_instrumentation(result) }
|
45
|
+
end
|
46
|
+
|
47
|
+
def middleware_instrumentation_enabled?
|
48
|
+
::NewRelic::Agent::Instrumentation::RackHelpers.middleware_instrumentation_enabled?
|
49
|
+
end
|
50
|
+
|
51
|
+
def run_with_tracing app
|
52
|
+
return yield(app) unless middleware_instrumentation_enabled?
|
53
|
+
yield ::NewRelic::Agent::Instrumentation::MiddlewareProxy.wrap(app, true)
|
54
|
+
end
|
55
|
+
|
56
|
+
def use_with_tracing middleware_class
|
57
|
+
return if middleware_class.nil?
|
58
|
+
return yield(middleware_class) unless middleware_instrumentation_enabled?
|
59
|
+
yield ::NewRelic::Agent::Instrumentation::MiddlewareProxy.for_class(middleware_class)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
module RackURLMap
|
64
|
+
def self.generate_traced_map(map)
|
65
|
+
map.inject({}) do |traced_map, (url, handler)|
|
66
|
+
traced_map[url] = NewRelic::Agent::Instrumentation::MiddlewareProxy.wrap(handler, true)
|
67
|
+
traced_map
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# This file is distributed under New Relic's license terms.
|
3
|
+
# See https://github.com/newrelic/newrelic-ruby-agent/blob/main/LICENSE for complete details.
|
4
|
+
|
5
|
+
module NewRelic::Agent::Instrumentation
|
6
|
+
module Rack
|
7
|
+
|
8
|
+
module URLMap
|
9
|
+
module Prepend
|
10
|
+
def initialize(map = {})
|
11
|
+
super ::NewRelic::Agent::Instrumentation::RackURLMap.generate_traced_map(map)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
module Prepend
|
17
|
+
include ::NewRelic::Agent::Instrumentation::RackBuilder
|
18
|
+
|
19
|
+
def self.prepended builder_class
|
20
|
+
NewRelic::Agent::Instrumentation::RackBuilder.track_deferred_detection builder_class
|
21
|
+
end
|
22
|
+
|
23
|
+
def to_app
|
24
|
+
with_deferred_dependency_detection { super }
|
25
|
+
end
|
26
|
+
|
27
|
+
def run(app, *args)
|
28
|
+
run_with_tracing(app) { |wrapped_app| super(wrapped_app, *args) }
|
29
|
+
end
|
30
|
+
|
31
|
+
def use(middleware_class, *args, &blk)
|
32
|
+
use_with_tracing(middleware_class) { |wrapped_class| super(wrapped_class, *args, &blk) }
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -2,17 +2,19 @@
|
|
2
2
|
# This file is distributed under New Relic's license terms.
|
3
3
|
# See https://github.com/newrelic/newrelic-ruby-agent/blob/main/LICENSE for complete details.
|
4
4
|
|
5
|
+
require_relative 'rake/instrumentation'
|
6
|
+
require_relative 'rake/chain'
|
7
|
+
require_relative 'rake/prepend'
|
8
|
+
|
5
9
|
DependencyDetection.defer do
|
6
10
|
# Why not :rake? newrelic-rake used that name, so avoid conflicting
|
7
11
|
named :rake_instrumentation
|
12
|
+
configure_with :rake
|
8
13
|
|
9
|
-
depends_on
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
::NewRelic::Agent.config[:'rake.tasks'].any? &&
|
14
|
-
::NewRelic::Agent::Instrumentation::RakeInstrumentation.should_install?
|
15
|
-
end
|
14
|
+
depends_on { defined?(::Rake) && defined?(::Rake::VERSION) }
|
15
|
+
depends_on { Gem::Version.new(::Rake::VERSION) >= Gem::Version.new("10.0.0") }
|
16
|
+
depends_on { ::NewRelic::Agent.config[:'rake.tasks'].any? }
|
17
|
+
depends_on { ::NewRelic::Agent::Instrumentation::Rake.safe_from_third_party_gem? }
|
16
18
|
|
17
19
|
executes do
|
18
20
|
::NewRelic::Agent.logger.info "Installing Rake instrumentation"
|
@@ -20,153 +22,10 @@ DependencyDetection.defer do
|
|
20
22
|
end
|
21
23
|
|
22
24
|
executes do
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
def invoke(*args)
|
28
|
-
unless NewRelic::Agent::Instrumentation::RakeInstrumentation.should_trace? name
|
29
|
-
return invoke_without_newrelic(*args)
|
30
|
-
end
|
31
|
-
|
32
|
-
begin
|
33
|
-
timeout = NewRelic::Agent.config[:'rake.connect_timeout']
|
34
|
-
NewRelic::Agent.instance.wait_on_connect(timeout)
|
35
|
-
rescue => e
|
36
|
-
NewRelic::Agent.logger.error("Exception in wait_on_connect", e)
|
37
|
-
return invoke_without_newrelic(*args)
|
38
|
-
end
|
39
|
-
|
40
|
-
NewRelic::Agent::Instrumentation::RakeInstrumentation.before_invoke_transaction(self)
|
41
|
-
|
42
|
-
NewRelic::Agent::Tracer.in_transaction(name: "OtherTransaction/Rake/invoke/#{name}", category: :rake) do
|
43
|
-
NewRelic::Agent::Instrumentation::RakeInstrumentation.record_attributes(args, self)
|
44
|
-
invoke_without_newrelic(*args)
|
45
|
-
end
|
46
|
-
end
|
47
|
-
end
|
48
|
-
end
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
module NewRelic
|
53
|
-
module Agent
|
54
|
-
module Instrumentation
|
55
|
-
module RakeInstrumentation
|
56
|
-
def self.should_install?
|
57
|
-
is_supported_version? && safe_from_third_party_gem?
|
58
|
-
end
|
59
|
-
|
60
|
-
def self.is_supported_version?
|
61
|
-
Gem::Version.new(::Rake::VERSION) >= Gem::Version.new("10.0.0")
|
62
|
-
end
|
63
|
-
|
64
|
-
def self.safe_from_third_party_gem?
|
65
|
-
if NewRelic::LanguageSupport.bundled_gem?("newrelic-rake")
|
66
|
-
::NewRelic::Agent.logger.info("Not installing New Relic supported Rake instrumentation because the third party newrelic-rake gem is present")
|
67
|
-
false
|
68
|
-
else
|
69
|
-
true
|
70
|
-
end
|
71
|
-
end
|
72
|
-
|
73
|
-
def self.should_trace?(name)
|
74
|
-
NewRelic::Agent.config[:'rake.tasks'].any? do |regex|
|
75
|
-
regex.match(name)
|
76
|
-
end
|
77
|
-
end
|
78
|
-
|
79
|
-
def self.instrument_execute_on_prereqs(task)
|
80
|
-
task.prerequisite_tasks.each do |child_task|
|
81
|
-
instrument_execute(child_task)
|
82
|
-
end
|
83
|
-
end
|
84
|
-
|
85
|
-
def self.instrument_execute(task)
|
86
|
-
return if task.instance_variable_get(:@__newrelic_instrumented_execute)
|
87
|
-
|
88
|
-
task.instance_variable_set(:@__newrelic_instrumented_execute, true)
|
89
|
-
task.instance_eval do
|
90
|
-
def execute(*args, &block)
|
91
|
-
NewRelic::Agent::MethodTracer.trace_execution_scoped("Rake/execute/#{self.name}") do
|
92
|
-
super
|
93
|
-
end
|
94
|
-
end
|
95
|
-
end
|
96
|
-
|
97
|
-
instrument_execute_on_prereqs(task)
|
98
|
-
end
|
99
|
-
|
100
|
-
def self.instrument_invoke_prerequisites_concurrently(task)
|
101
|
-
task.instance_eval do
|
102
|
-
def invoke_prerequisites_concurrently(*_)
|
103
|
-
NewRelic::Agent::MethodTracer.trace_execution_scoped("Rake/execute/multitask") do
|
104
|
-
prereqs = self.prerequisite_tasks.map(&:name).join(", ")
|
105
|
-
if txn = ::NewRelic::Agent::Tracer.current_transaction
|
106
|
-
txn.current_segment.params[:statement] = NewRelic::Agent::Database.truncate_query("Couldn't trace concurrent prereq tasks: #{prereqs}")
|
107
|
-
end
|
108
|
-
super
|
109
|
-
end
|
110
|
-
end
|
111
|
-
end
|
112
|
-
end
|
113
|
-
|
114
|
-
def self.before_invoke_transaction(task)
|
115
|
-
ensure_at_exit
|
116
|
-
|
117
|
-
# We can't represent overlapping operations yet, so if multitask just
|
118
|
-
# make one node and annotate with prereq task names
|
119
|
-
if task.application.options.always_multitask
|
120
|
-
instrument_invoke_prerequisites_concurrently(task)
|
121
|
-
else
|
122
|
-
instrument_execute_on_prereqs(task)
|
123
|
-
end
|
124
|
-
rescue => e
|
125
|
-
NewRelic::Agent.logger.error("Error during Rake task invoke", e)
|
126
|
-
end
|
127
|
-
|
128
|
-
def self.record_attributes(args, task)
|
129
|
-
command_line = task.application.top_level_tasks.join(" ")
|
130
|
-
NewRelic::Agent::Transaction.merge_untrusted_agent_attributes({ :command => command_line },
|
131
|
-
:'job.rake',
|
132
|
-
NewRelic::Agent::AttributeFilter::DST_NONE)
|
133
|
-
named_args = name_the_args(args, task.arg_names)
|
134
|
-
unless named_args.empty?
|
135
|
-
NewRelic::Agent::Transaction.merge_untrusted_agent_attributes(named_args,
|
136
|
-
:'job.rake.args',
|
137
|
-
NewRelic::Agent::AttributeFilter::DST_NONE)
|
138
|
-
end
|
139
|
-
rescue => e
|
140
|
-
NewRelic::Agent.logger.error("Error during Rake task attribute recording.", e)
|
141
|
-
end
|
142
|
-
|
143
|
-
# Expects literal args passed to the task and array of task names
|
144
|
-
# If names are present without matching args, still sets them with nils
|
145
|
-
def self.name_the_args(args, names)
|
146
|
-
unfulfilled_names_length = names.length - args.length
|
147
|
-
if unfulfilled_names_length > 0
|
148
|
-
args.concat(Array.new(unfulfilled_names_length))
|
149
|
-
end
|
150
|
-
|
151
|
-
result = {}
|
152
|
-
args.zip(names).each_with_index do |(value, key), index|
|
153
|
-
result[key || index.to_s] = value
|
154
|
-
end
|
155
|
-
result
|
156
|
-
end
|
157
|
-
|
158
|
-
def self.ensure_at_exit
|
159
|
-
return if @installed_at_exit
|
160
|
-
|
161
|
-
at_exit do
|
162
|
-
# The agent's default at_exit might not default to installing, but
|
163
|
-
# if we are running an instrumented rake task, we always want it.
|
164
|
-
NewRelic::Agent.shutdown
|
165
|
-
end
|
166
|
-
|
167
|
-
@installed_at_exit = true
|
168
|
-
end
|
169
|
-
end
|
25
|
+
if use_prepend?
|
26
|
+
prepend_instrument ::Rake::Task, NewRelic::Agent::Instrumentation::Rake::Prepend
|
27
|
+
else
|
28
|
+
chain_instrument NewRelic::Agent::Instrumentation::Rake::Chain
|
170
29
|
end
|
171
30
|
end
|
172
31
|
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# This file is distributed under New Relic's license terms.
|
3
|
+
# See https://github.com/newrelic/newrelic-ruby-agent/blob/main/LICENSE for complete details.
|
4
|
+
|
5
|
+
module NewRelic::Agent::Instrumentation
|
6
|
+
module Rake
|
7
|
+
module Chain
|
8
|
+
def self.instrument!
|
9
|
+
::Rake::Task.class_eval do
|
10
|
+
include NewRelic::Agent::Instrumentation::Rake::Tracer
|
11
|
+
alias_method :invoke_without_newrelic, :invoke
|
12
|
+
|
13
|
+
def invoke(*args)
|
14
|
+
invoke_with_newrelic_tracing(*args) { invoke_without_newrelic(*args) }
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
|
23
|
+
|
24
|
+
|
25
|
+
|
@@ -0,0 +1,144 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# This file is distributed under New Relic's license terms.
|
3
|
+
# See https://github.com/newrelic/newrelic-ruby-agent/blob/main/LICENSE for complete details.
|
4
|
+
# frozen_string_literal: true
|
5
|
+
|
6
|
+
module NewRelic
|
7
|
+
module Agent
|
8
|
+
module Instrumentation
|
9
|
+
module Rake
|
10
|
+
module Tracer
|
11
|
+
def invoke_with_newrelic_tracing(*args)
|
12
|
+
unless NewRelic::Agent::Instrumentation::Rake.should_trace? name
|
13
|
+
return yield
|
14
|
+
end
|
15
|
+
|
16
|
+
begin
|
17
|
+
timeout = NewRelic::Agent.config[:'rake.connect_timeout']
|
18
|
+
NewRelic::Agent.instance.wait_on_connect(timeout)
|
19
|
+
rescue => e
|
20
|
+
NewRelic::Agent.logger.error("Exception in wait_on_connect", e)
|
21
|
+
return yield
|
22
|
+
end
|
23
|
+
|
24
|
+
NewRelic::Agent::Instrumentation::Rake.before_invoke_transaction(self)
|
25
|
+
|
26
|
+
NewRelic::Agent::Tracer.in_transaction(name: "OtherTransaction/Rake/invoke/#{name}", category: :rake) do
|
27
|
+
NewRelic::Agent::Instrumentation::Rake.record_attributes(args, self)
|
28
|
+
yield
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
module_function
|
34
|
+
|
35
|
+
def should_install?
|
36
|
+
safe_from_third_party_gem?
|
37
|
+
end
|
38
|
+
|
39
|
+
def safe_from_third_party_gem?
|
40
|
+
return true unless NewRelic::LanguageSupport.bundled_gem?("newrelic-rake")
|
41
|
+
::NewRelic::Agent.logger.info("Not installing New Relic supported Rake instrumentation because the third party newrelic-rake gem is present")
|
42
|
+
false
|
43
|
+
end
|
44
|
+
|
45
|
+
def should_trace?(name)
|
46
|
+
NewRelic::Agent.config[:'rake.tasks'].any? do |regex|
|
47
|
+
regex.match(name)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def instrument_execute_on_prereqs(task)
|
52
|
+
task.prerequisite_tasks.each do |child_task|
|
53
|
+
instrument_execute(child_task)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def instrument_execute(task)
|
58
|
+
return if task.instance_variable_get(:@__newrelic_instrumented_execute)
|
59
|
+
|
60
|
+
task.instance_variable_set(:@__newrelic_instrumented_execute, true)
|
61
|
+
task.instance_eval do
|
62
|
+
def execute(*args, &block)
|
63
|
+
NewRelic::Agent::MethodTracer.trace_execution_scoped("Rake/execute/#{self.name}") do
|
64
|
+
super
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
instrument_execute_on_prereqs(task)
|
70
|
+
end
|
71
|
+
|
72
|
+
def instrument_invoke_prerequisites_concurrently(task)
|
73
|
+
task.instance_eval do
|
74
|
+
def invoke_prerequisites_concurrently(*_)
|
75
|
+
NewRelic::Agent::MethodTracer.trace_execution_scoped("Rake/execute/multitask") do
|
76
|
+
prereqs = self.prerequisite_tasks.map(&:name).join(", ")
|
77
|
+
if txn = ::NewRelic::Agent::Tracer.current_transaction
|
78
|
+
txn.current_segment.params[:statement] = NewRelic::Agent::Database.truncate_query("Couldn't trace concurrent prereq tasks: #{prereqs}")
|
79
|
+
end
|
80
|
+
super
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def before_invoke_transaction(task)
|
87
|
+
ensure_at_exit
|
88
|
+
|
89
|
+
# We can't represent overlapping operations yet, so if multitask just
|
90
|
+
# make one node and annotate with prereq task names
|
91
|
+
if task.application.options.always_multitask
|
92
|
+
instrument_invoke_prerequisites_concurrently(task)
|
93
|
+
else
|
94
|
+
instrument_execute_on_prereqs(task)
|
95
|
+
end
|
96
|
+
rescue => e
|
97
|
+
NewRelic::Agent.logger.error("Error during Rake task invoke", e)
|
98
|
+
end
|
99
|
+
|
100
|
+
def record_attributes(args, task)
|
101
|
+
command_line = task.application.top_level_tasks.join(" ")
|
102
|
+
NewRelic::Agent::Transaction.merge_untrusted_agent_attributes({ :command => command_line },
|
103
|
+
:'job.rake',
|
104
|
+
NewRelic::Agent::AttributeFilter::DST_NONE)
|
105
|
+
named_args = name_the_args(args, task.arg_names)
|
106
|
+
unless named_args.empty?
|
107
|
+
NewRelic::Agent::Transaction.merge_untrusted_agent_attributes(named_args,
|
108
|
+
:'job.rake.args',
|
109
|
+
NewRelic::Agent::AttributeFilter::DST_NONE)
|
110
|
+
end
|
111
|
+
rescue => e
|
112
|
+
NewRelic::Agent.logger.error("Error during Rake task attribute recording.", e)
|
113
|
+
end
|
114
|
+
|
115
|
+
# Expects literal args passed to the task and array of task names
|
116
|
+
# If names are present without matching args, still sets them with nils
|
117
|
+
def name_the_args(args, names)
|
118
|
+
unfulfilled_names_length = names.length - args.length
|
119
|
+
if unfulfilled_names_length > 0
|
120
|
+
args.concat(Array.new(unfulfilled_names_length))
|
121
|
+
end
|
122
|
+
|
123
|
+
result = {}
|
124
|
+
args.zip(names).each_with_index do |(value, key), index|
|
125
|
+
result[key || index.to_s] = value
|
126
|
+
end
|
127
|
+
result
|
128
|
+
end
|
129
|
+
|
130
|
+
def ensure_at_exit
|
131
|
+
return if @installed_at_exit
|
132
|
+
|
133
|
+
at_exit do
|
134
|
+
# The agent's default at_exit might not default to installing, but
|
135
|
+
# if we are running an instrumented rake task, we always want it.
|
136
|
+
NewRelic::Agent.shutdown
|
137
|
+
end
|
138
|
+
|
139
|
+
@installed_at_exit = true
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|