newrelic_rpm 6.13.0 → 7.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (147) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/CHANGELOG.md +231 -0
  4. data/CONTRIBUTING.md +13 -2
  5. data/README.md +2 -2
  6. data/lib/new_relic/agent.rb +5 -8
  7. data/lib/new_relic/agent/agent.rb +4 -5
  8. data/lib/new_relic/agent/audit_logger.rb +10 -0
  9. data/lib/new_relic/agent/autostart.rb +1 -2
  10. data/lib/new_relic/agent/configuration/default_source.rb +412 -220
  11. data/lib/new_relic/agent/configuration/manager.rb +2 -2
  12. data/lib/new_relic/agent/database_adapter.rb +33 -0
  13. data/lib/new_relic/agent/datastores/redis.rb +0 -4
  14. data/lib/new_relic/agent/distributed_tracing.rb +0 -66
  15. data/lib/new_relic/agent/distributed_tracing/cross_app_tracing.rb +2 -2
  16. data/lib/new_relic/agent/http_clients/uri_util.rb +1 -1
  17. data/lib/new_relic/agent/instrumentation/action_view_subscriber.rb +4 -5
  18. data/lib/new_relic/agent/instrumentation/active_record_helper.rb +21 -68
  19. data/lib/new_relic/agent/instrumentation/active_record_notifications.rb +0 -16
  20. data/lib/new_relic/agent/instrumentation/active_record_prepend.rb +23 -57
  21. data/lib/new_relic/agent/instrumentation/active_record_subscriber.rb +1 -3
  22. data/lib/new_relic/agent/instrumentation/acts_as_solr.rb +0 -15
  23. data/lib/new_relic/agent/instrumentation/bunny.rb +10 -196
  24. data/lib/new_relic/agent/instrumentation/bunny/chain.rb +45 -0
  25. data/lib/new_relic/agent/instrumentation/bunny/instrumentation.rb +152 -0
  26. data/lib/new_relic/agent/instrumentation/bunny/prepend.rb +35 -0
  27. data/lib/new_relic/agent/instrumentation/controller_instrumentation.rb +1 -0
  28. data/lib/new_relic/agent/instrumentation/curb.rb +9 -259
  29. data/lib/new_relic/agent/instrumentation/curb/chain.rb +93 -0
  30. data/lib/new_relic/agent/instrumentation/curb/instrumentation.rb +222 -0
  31. data/lib/new_relic/agent/instrumentation/curb/prepend.rb +63 -0
  32. data/lib/new_relic/agent/instrumentation/delayed_job/chain.rb +38 -0
  33. data/lib/new_relic/agent/instrumentation/delayed_job/instrumentation.rb +53 -0
  34. data/lib/new_relic/agent/instrumentation/delayed_job/prepend.rb +34 -0
  35. data/lib/new_relic/agent/instrumentation/delayed_job_instrumentation.rb +8 -84
  36. data/lib/new_relic/agent/instrumentation/excon.rb +2 -1
  37. data/lib/new_relic/agent/instrumentation/grape.rb +13 -113
  38. data/lib/new_relic/agent/instrumentation/grape/chain.rb +25 -0
  39. data/lib/new_relic/agent/instrumentation/grape/instrumentation.rb +100 -0
  40. data/lib/new_relic/agent/instrumentation/grape/prepend.rb +17 -0
  41. data/lib/new_relic/agent/instrumentation/httpclient.rb +8 -30
  42. data/lib/new_relic/agent/instrumentation/httpclient/chain.rb +25 -0
  43. data/lib/new_relic/agent/instrumentation/httpclient/instrumentation.rb +38 -0
  44. data/lib/new_relic/agent/instrumentation/httpclient/prepend.rb +17 -0
  45. data/lib/new_relic/agent/instrumentation/httprb.rb +29 -0
  46. data/lib/new_relic/agent/instrumentation/httprb/chain.rb +22 -0
  47. data/lib/new_relic/agent/instrumentation/httprb/instrumentation.rb +30 -0
  48. data/lib/new_relic/agent/instrumentation/httprb/prepend.rb +15 -0
  49. data/lib/new_relic/agent/instrumentation/memcache.rb +54 -69
  50. data/lib/new_relic/agent/instrumentation/memcache/chain.rb +16 -0
  51. data/lib/new_relic/agent/instrumentation/memcache/dalli.rb +38 -121
  52. data/lib/new_relic/agent/instrumentation/memcache/helper.rb +56 -0
  53. data/lib/new_relic/agent/instrumentation/memcache/instrumentation.rb +88 -0
  54. data/lib/new_relic/agent/instrumentation/memcache/prepend.rb +88 -0
  55. data/lib/new_relic/agent/instrumentation/middleware_proxy.rb +4 -10
  56. data/lib/new_relic/agent/instrumentation/mongo.rb +7 -0
  57. data/lib/new_relic/agent/instrumentation/net_http.rb +44 -0
  58. data/lib/new_relic/agent/instrumentation/net_http/chain.rb +25 -0
  59. data/lib/new_relic/agent/instrumentation/net_http/instrumentation.rb +40 -0
  60. data/lib/new_relic/agent/instrumentation/net_http/prepend.rb +21 -0
  61. data/lib/new_relic/agent/instrumentation/notifications_subscriber.rb +1 -1
  62. data/lib/new_relic/agent/instrumentation/padrino.rb +18 -75
  63. data/lib/new_relic/agent/instrumentation/padrino/chain.rb +34 -0
  64. data/lib/new_relic/agent/instrumentation/padrino/instrumentation.rb +27 -0
  65. data/lib/new_relic/agent/instrumentation/padrino/prepend.rb +20 -0
  66. data/lib/new_relic/agent/instrumentation/rack.rb +29 -160
  67. data/lib/new_relic/agent/instrumentation/rack/chain.rb +57 -0
  68. data/lib/new_relic/agent/instrumentation/rack/helpers.rb +32 -0
  69. data/lib/new_relic/agent/instrumentation/rack/instrumentation.rb +73 -0
  70. data/lib/new_relic/agent/instrumentation/rack/prepend.rb +36 -0
  71. data/lib/new_relic/agent/instrumentation/rake.rb +13 -188
  72. data/lib/new_relic/agent/instrumentation/rake/chain.rb +25 -0
  73. data/lib/new_relic/agent/instrumentation/rake/instrumentation.rb +144 -0
  74. data/lib/new_relic/agent/instrumentation/rake/prepend.rb +14 -0
  75. data/lib/new_relic/agent/instrumentation/redis.rb +12 -186
  76. data/lib/new_relic/agent/instrumentation/redis/chain.rb +34 -0
  77. data/lib/new_relic/agent/instrumentation/redis/instrumentation.rb +65 -0
  78. data/lib/new_relic/agent/instrumentation/redis/prepend.rb +24 -0
  79. data/lib/new_relic/agent/instrumentation/resque.rb +21 -32
  80. data/lib/new_relic/agent/instrumentation/resque/chain.rb +22 -0
  81. data/lib/new_relic/agent/instrumentation/resque/helper.rb +19 -0
  82. data/lib/new_relic/agent/instrumentation/resque/instrumentation.rb +35 -0
  83. data/lib/new_relic/agent/instrumentation/resque/prepend.rb +16 -0
  84. data/lib/new_relic/agent/instrumentation/sidekiq.rb +1 -1
  85. data/lib/new_relic/agent/instrumentation/sinatra.rb +20 -198
  86. data/lib/new_relic/agent/instrumentation/sinatra/chain.rb +55 -0
  87. data/lib/new_relic/agent/instrumentation/sinatra/ignorer.rb +29 -34
  88. data/lib/new_relic/agent/instrumentation/sinatra/instrumentation.rb +124 -0
  89. data/lib/new_relic/agent/instrumentation/sinatra/prepend.rb +33 -0
  90. data/lib/new_relic/agent/instrumentation/typhoeus.rb +10 -89
  91. data/lib/new_relic/agent/instrumentation/typhoeus/chain.rb +22 -0
  92. data/lib/new_relic/agent/instrumentation/typhoeus/instrumentation.rb +82 -0
  93. data/lib/new_relic/agent/instrumentation/typhoeus/prepend.rb +14 -0
  94. data/lib/new_relic/agent/javascript_instrumentor.rb +12 -7
  95. data/lib/new_relic/agent/method_tracer.rb +6 -16
  96. data/lib/new_relic/agent/new_relic_service.rb +16 -13
  97. data/lib/new_relic/agent/samplers/memory_sampler.rb +1 -1
  98. data/lib/new_relic/agent/span_event_primitive.rb +10 -8
  99. data/lib/new_relic/agent/sql_sampler.rb +3 -3
  100. data/lib/new_relic/agent/stats_engine/gc_profiler.rb +1 -1
  101. data/lib/new_relic/agent/transaction.rb +1 -4
  102. data/lib/new_relic/agent/transaction/abstract_segment.rb +1 -1
  103. data/lib/new_relic/agent/transaction/distributed_tracer.rb +12 -6
  104. data/lib/new_relic/agent/transaction/message_broker_segment.rb +1 -0
  105. data/lib/new_relic/agent/vm/mri_vm.rb +6 -4
  106. data/lib/new_relic/cli/commands/deployments.rb +0 -1
  107. data/lib/new_relic/constants.rb +4 -0
  108. data/lib/new_relic/control/frameworks/rails.rb +11 -9
  109. data/lib/new_relic/control/instance_methods.rb +1 -0
  110. data/lib/new_relic/dependency_detection.rb +119 -9
  111. data/lib/new_relic/environment_report.rb +1 -7
  112. data/lib/new_relic/noticed_error.rb +1 -5
  113. data/lib/new_relic/supportability_helper.rb +3 -2
  114. data/lib/new_relic/version.rb +2 -2
  115. data/lib/tasks/config.html.erb +14 -25
  116. data/lib/tasks/config.rake +8 -7
  117. data/newrelic_rpm.gemspec +2 -2
  118. data/test/agent_helper.rb +1 -0
  119. metadata +55 -32
  120. data/.github/ISSUE_TEMPLATE/bug_report.md +0 -31
  121. data/.github/ISSUE_TEMPLATE/config.yml +0 -5
  122. data/.github/ISSUE_TEMPLATE/feature_request.md +0 -24
  123. data/.github/actions/annotate/README.md +0 -79
  124. data/.github/actions/annotate/action.yml +0 -6
  125. data/.github/actions/annotate/dist/index.js +0 -433
  126. data/.github/actions/annotate/index.js +0 -25
  127. data/.github/actions/annotate/package-lock.json +0 -172
  128. data/.github/actions/annotate/package.json +0 -30
  129. data/.github/actions/annotate/pre-commit +0 -5
  130. data/.github/actions/build-ruby/README.md +0 -79
  131. data/.github/actions/build-ruby/action.yml +0 -15
  132. data/.github/actions/build-ruby/dist/index.js +0 -52683
  133. data/.github/actions/build-ruby/index.js +0 -514
  134. data/.github/actions/build-ruby/package-lock.json +0 -581
  135. data/.github/actions/build-ruby/package.json +0 -32
  136. data/.github/actions/build-ruby/pre-commit +0 -5
  137. data/.github/pull_request_template.md +0 -16
  138. data/.github/workflows/ci.yml +0 -212
  139. data/.github/workflows/pr_review_checklist.yml +0 -22
  140. data/.github/workflows/release.yml +0 -78
  141. data/.github/workflows/scripts/rubygems-authenticate.py +0 -13
  142. data/.github/workflows/scripts/rubygems-publish.rb +0 -32
  143. data/.github/workflows/snyk.yml +0 -27
  144. data/.github/workflows/stale.yml +0 -21
  145. data/cert/cacert.pem +0 -1177
  146. data/lib/new_relic/agent/instrumentation/http.rb +0 -49
  147. data/lib/new_relic/agent/instrumentation/net.rb +0 -87
@@ -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
@@ -0,0 +1,14 @@
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 Prepend
8
+ include NewRelic::Agent::Instrumentation::Rake::Tracer
9
+ def invoke(*args)
10
+ invoke_with_newrelic_tracing(*args) { super }
11
+ end
12
+ end
13
+ end
14
+ end
@@ -5,43 +5,21 @@
5
5
  require 'new_relic/agent/datastores'
6
6
  require 'new_relic/agent/datastores/redis'
7
7
 
8
- module NewRelic
9
- module Agent
10
- module Instrumentation
11
- module Redis
12
- extend self
13
-
14
- UNKNOWN = "unknown".freeze
15
- LOCALHOST = "localhost".freeze
16
-
17
- def host_for(client)
18
- client.path ? LOCALHOST : client.host
19
- rescue => e
20
- NewRelic::Agent.logger.debug "Failed to retrieve Redis host: #{e}"
21
- UNKNOWN
22
- end
23
-
24
- def port_path_or_id_for(client)
25
- client.path || client.port
26
- rescue => e
27
- NewRelic::Agent.logger.debug "Failed to retrieve Redis port_path_or_id: #{e}"
28
- UNKNOWN
29
- end
30
- end
31
- end
32
- end
33
- end
8
+ require_relative 'redis/instrumentation'
9
+ require_relative 'redis/chain'
10
+ require_relative 'redis/prepend'
34
11
 
35
12
  DependencyDetection.defer do
36
13
  # Why not :redis? newrelic-redis used that name, so avoid conflicting
37
14
  named :redis_instrumentation
38
-
15
+ configure_with :redis
16
+
39
17
  depends_on do
40
- defined? ::Redis
18
+ defined?(::Redis) && defined?(::Redis::VERSION)
41
19
  end
42
20
 
43
- depends_on do
44
- NewRelic::Agent.config[:disable_redis] == false
21
+ conflicts_with_prepend do
22
+ defined?(::PrometheusExporter)
45
23
  end
46
24
 
47
25
  depends_on do
@@ -51,162 +29,10 @@ DependencyDetection.defer do
51
29
 
52
30
  executes do
53
31
  NewRelic::Agent.logger.info 'Installing Redis Instrumentation'
54
-
55
- Redis::Client.class_eval do
56
- alias_method :call_without_new_relic, :call
57
-
58
- if RUBY_VERSION < "2.7.0"
59
- def call(*args, &block)
60
- operation = args[0][0]
61
- statement = ::NewRelic::Agent::Datastores::Redis.format_command(args[0])
62
-
63
- hostname = NewRelic::Agent::Instrumentation::Redis.host_for(self)
64
- port_path_or_id = NewRelic::Agent::Instrumentation::Redis.port_path_or_id_for(self)
65
-
66
- segment = NewRelic::Agent::Tracer.start_datastore_segment(
67
- product: NewRelic::Agent::Datastores::Redis::PRODUCT_NAME,
68
- operation: operation,
69
- host: hostname,
70
- port_path_or_id: port_path_or_id,
71
- database_name: db
72
- )
73
- begin
74
- segment.notice_nosql_statement(statement) if statement
75
- NewRelic::Agent::Tracer.capture_segment_error segment do
76
- call_without_new_relic(*args, &block)
77
- end
78
- ensure
79
- segment.finish if segment
80
- end
81
- end
82
- else
83
- def call(*args, **kwargs, &block)
84
- operation = args[0][0]
85
- statement = ::NewRelic::Agent::Datastores::Redis.format_command(args[0])
86
-
87
- hostname = NewRelic::Agent::Instrumentation::Redis.host_for(self)
88
- port_path_or_id = NewRelic::Agent::Instrumentation::Redis.port_path_or_id_for(self)
89
-
90
- segment = NewRelic::Agent::Tracer.start_datastore_segment(
91
- product: NewRelic::Agent::Datastores::Redis::PRODUCT_NAME,
92
- operation: operation,
93
- host: hostname,
94
- port_path_or_id: port_path_or_id,
95
- database_name: db
96
- )
97
- begin
98
- segment.notice_nosql_statement(statement) if statement
99
- NewRelic::Agent::Tracer.capture_segment_error segment do
100
- call_without_new_relic(*args, **kwargs, &block)
101
- end
102
- ensure
103
- segment.finish if segment
104
- end
105
- end
106
- end
107
-
108
-
109
-
110
- alias_method :call_pipeline_without_new_relic, :call_pipeline
111
-
112
- if RUBY_VERSION < "2.7.0"
113
- def call_pipeline(*args, &block)
114
- pipeline = args[0]
115
- operation = pipeline.is_a?(::Redis::Pipeline::Multi) ? NewRelic::Agent::Datastores::Redis::MULTI_OPERATION : NewRelic::Agent::Datastores::Redis::PIPELINE_OPERATION
116
- statement = ::NewRelic::Agent::Datastores::Redis.format_pipeline_commands(pipeline.commands)
117
-
118
- hostname = NewRelic::Agent::Instrumentation::Redis.host_for(self)
119
- port_path_or_id = NewRelic::Agent::Instrumentation::Redis.port_path_or_id_for(self)
120
-
121
- segment = NewRelic::Agent::Tracer.start_datastore_segment(
122
- product: NewRelic::Agent::Datastores::Redis::PRODUCT_NAME,
123
- operation: operation,
124
- host: hostname,
125
- port_path_or_id: port_path_or_id,
126
- database_name: db
127
- )
128
- begin
129
- segment.notice_nosql_statement(statement)
130
- NewRelic::Agent::Tracer.capture_segment_error segment do
131
- call_pipeline_without_new_relic(*args, &block)
132
- end
133
- ensure
134
- segment.finish if segment
135
- end
136
- end
137
- else
138
- def call_pipeline(*args, **kwargs, &block)
139
- pipeline = args[0]
140
- operation = pipeline.is_a?(::Redis::Pipeline::Multi) ? NewRelic::Agent::Datastores::Redis::MULTI_OPERATION : NewRelic::Agent::Datastores::Redis::PIPELINE_OPERATION
141
- statement = ::NewRelic::Agent::Datastores::Redis.format_pipeline_commands(pipeline.commands)
142
-
143
- hostname = NewRelic::Agent::Instrumentation::Redis.host_for(self)
144
- port_path_or_id = NewRelic::Agent::Instrumentation::Redis.port_path_or_id_for(self)
145
-
146
- segment = NewRelic::Agent::Tracer.start_datastore_segment(
147
- product: NewRelic::Agent::Datastores::Redis::PRODUCT_NAME,
148
- operation: operation,
149
- host: hostname,
150
- port_path_or_id: port_path_or_id,
151
- database_name: db
152
- )
153
- begin
154
- segment.notice_nosql_statement(statement)
155
- NewRelic::Agent::Tracer.capture_segment_error segment do
156
- call_pipeline_without_new_relic(*args, **kwargs, &block)
157
- end
158
- ensure
159
- segment.finish if segment
160
- end
161
- end
162
- end
163
-
164
- alias_method :connect_without_new_relic, :connect
165
-
166
- if RUBY_VERSION < "2.7.0"
167
- def connect(*args, &block)
168
- hostname = NewRelic::Agent::Instrumentation::Redis.host_for(self)
169
- port_path_or_id = NewRelic::Agent::Instrumentation::Redis.port_path_or_id_for(self)
170
-
171
- segment = NewRelic::Agent::Tracer.start_datastore_segment(
172
- product: NewRelic::Agent::Datastores::Redis::PRODUCT_NAME,
173
- operation: NewRelic::Agent::Datastores::Redis::CONNECT,
174
- host: hostname,
175
- port_path_or_id: port_path_or_id,
176
- database_name: db
177
- )
178
-
179
- begin
180
- NewRelic::Agent::Tracer.capture_segment_error segment do
181
- connect_without_new_relic(*args, &block)
182
- end
183
- ensure
184
- segment.finish if segment
185
- end
186
- end
187
- else
188
- def connect(*args, **kwargs, &block)
189
- hostname = NewRelic::Agent::Instrumentation::Redis.host_for(self)
190
- port_path_or_id = NewRelic::Agent::Instrumentation::Redis.port_path_or_id_for(self)
191
-
192
- segment = NewRelic::Agent::Tracer.start_datastore_segment(
193
- product: NewRelic::Agent::Datastores::Redis::PRODUCT_NAME,
194
- operation: NewRelic::Agent::Datastores::Redis::CONNECT,
195
- host: hostname,
196
- port_path_or_id: port_path_or_id,
197
- database_name: db
198
- )
199
-
200
- begin
201
- NewRelic::Agent::Tracer.capture_segment_error segment do
202
- connect_without_new_relic(*args, **kwargs, &block)
203
- end
204
- ensure
205
- segment.finish if segment
206
- end
207
- end
208
- end
209
-
32
+ if use_prepend?
33
+ prepend_instrument ::Redis::Client, NewRelic::Agent::Instrumentation::Redis::Prepend
34
+ else
35
+ chain_instrument NewRelic::Agent::Instrumentation::Redis::Chain
210
36
  end
211
37
  end
212
38
  end
@@ -0,0 +1,34 @@
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::Agent::Instrumentation
7
+ module Redis
8
+ module Chain
9
+ def self.instrument!
10
+ ::Redis::Client.class_eval do
11
+ include NewRelic::Agent::Instrumentation::Redis
12
+
13
+ alias_method :call_without_new_relic, :call
14
+
15
+ def call(*args, &block)
16
+ call_with_tracing(args[0]) { call_without_new_relic(*args, &block) }
17
+ end
18
+
19
+ alias_method :call_pipeline_without_new_relic, :call_pipeline
20
+
21
+ def call_pipeline(*args, &block)
22
+ call_pipeline_with_tracing(args[0]) { call_pipeline_without_new_relic(*args, &block) }
23
+ end
24
+
25
+ alias_method :connect_without_new_relic, :connect
26
+
27
+ def connect(*args, &block)
28
+ connect_with_tracing { connect_without_new_relic(*args, &block) }
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,65 @@
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::Agent::Instrumentation
7
+ module Redis
8
+ PRODUCT_NAME = 'Redis'
9
+ CONNECT = 'connect'
10
+ UNKNOWN = "unknown"
11
+ LOCALHOST = "localhost"
12
+ MULTI_OPERATION = 'multi'
13
+ PIPELINE_OPERATION = 'pipeline'
14
+
15
+ def call_with_tracing command, &block
16
+ operation = command[0]
17
+ statement = ::NewRelic::Agent::Datastores::Redis.format_command(command)
18
+
19
+ with_tracing(operation, statement) { yield }
20
+ end
21
+
22
+ def call_pipeline_with_tracing pipeline
23
+ operation = pipeline.is_a?(::Redis::Pipeline::Multi) ? MULTI_OPERATION : PIPELINE_OPERATION
24
+ statement = ::NewRelic::Agent::Datastores::Redis.format_pipeline_commands(pipeline.commands)
25
+
26
+ with_tracing(operation, statement) { yield }
27
+ end
28
+
29
+ def connect_with_tracing
30
+ with_tracing(CONNECT) { yield }
31
+ end
32
+
33
+ private
34
+
35
+ def with_tracing operation, statement=nil
36
+ segment = NewRelic::Agent::Tracer.start_datastore_segment(
37
+ product: PRODUCT_NAME,
38
+ operation: operation,
39
+ host: _nr_hostname,
40
+ port_path_or_id: _nr_port_path_or_id,
41
+ database_name: db
42
+ )
43
+ begin
44
+ segment.notice_nosql_statement(statement) if statement
45
+ NewRelic::Agent::Tracer.capture_segment_error(segment) { yield }
46
+ ensure
47
+ segment.finish if segment
48
+ end
49
+ end
50
+
51
+ def _nr_hostname
52
+ self.path ? LOCALHOST : self.host
53
+ rescue => e
54
+ NewRelic::Agent.logger.debug "Failed to retrieve Redis host: #{e}"
55
+ UNKNOWN
56
+ end
57
+
58
+ def _nr_port_path_or_id
59
+ self.path || self.port
60
+ rescue => e
61
+ NewRelic::Agent.logger.debug "Failed to retrieve Redis port_path_or_id: #{e}"
62
+ UNKNOWN
63
+ end
64
+ end
65
+ end