newrelic_rpm 9.9.0 → 9.21.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.
Files changed (219) hide show
  1. checksums.yaml +4 -4
  2. data/.build_ignore +1 -0
  3. data/CHANGELOG.md +463 -1
  4. data/CONTRIBUTING.md +2 -2
  5. data/README.md +16 -17
  6. data/Rakefile +1 -1
  7. data/lib/boot/strap.rb +102 -0
  8. data/lib/new_relic/agent/agent.rb +6 -0
  9. data/lib/new_relic/agent/agent_helpers/connect.rb +3 -0
  10. data/lib/new_relic/agent/agent_helpers/harvest.rb +3 -0
  11. data/lib/new_relic/agent/agent_helpers/shutdown.rb +3 -0
  12. data/lib/new_relic/agent/agent_helpers/start_worker_thread.rb +1 -0
  13. data/lib/new_relic/agent/agent_helpers/startup.rb +7 -0
  14. data/lib/new_relic/agent/agent_logger.rb +1 -0
  15. data/lib/new_relic/agent/aws.rb +68 -0
  16. data/lib/new_relic/agent/configuration/default_source.rb +603 -105
  17. data/lib/new_relic/agent/configuration/environment_source.rb +5 -1
  18. data/lib/new_relic/agent/configuration/manager.rb +28 -2
  19. data/lib/new_relic/agent/configuration/yaml_source.rb +7 -2
  20. data/lib/new_relic/agent/database/obfuscation_helpers.rb +11 -11
  21. data/lib/new_relic/agent/database/obfuscator.rb +1 -0
  22. data/lib/new_relic/agent/database.rb +41 -1
  23. data/lib/new_relic/agent/database_adapter.rb +1 -1
  24. data/lib/new_relic/agent/datastores/redis.rb +1 -1
  25. data/lib/new_relic/agent/distributed_tracing/cross_app_tracing.rb +1 -1
  26. data/lib/new_relic/agent/distributed_tracing.rb +4 -2
  27. data/lib/new_relic/agent/error_collector.rb +37 -10
  28. data/lib/new_relic/agent/external.rb +2 -0
  29. data/lib/new_relic/agent/health_check.rb +136 -0
  30. data/lib/new_relic/agent/http_clients/uri_util.rb +1 -1
  31. data/lib/new_relic/agent/instrumentation/action_dispatch.rb +1 -1
  32. data/lib/new_relic/agent/instrumentation/action_dispatch_subscriber.rb +1 -1
  33. data/lib/new_relic/agent/instrumentation/action_mailbox.rb +1 -1
  34. data/lib/new_relic/agent/instrumentation/action_mailer.rb +1 -1
  35. data/lib/new_relic/agent/instrumentation/active_job.rb +1 -1
  36. data/lib/new_relic/agent/instrumentation/active_job_subscriber.rb +6 -2
  37. data/lib/new_relic/agent/instrumentation/active_merchant.rb +0 -13
  38. data/lib/new_relic/agent/instrumentation/active_record.rb +7 -12
  39. data/lib/new_relic/agent/instrumentation/active_record_helper.rb +7 -3
  40. data/lib/new_relic/agent/instrumentation/active_record_notifications.rb +11 -9
  41. data/lib/new_relic/agent/instrumentation/active_record_prepend.rb +2 -2
  42. data/lib/new_relic/agent/instrumentation/active_record_subscriber.rb +9 -16
  43. data/lib/new_relic/agent/instrumentation/active_support_broadcast_logger.rb +0 -2
  44. data/lib/new_relic/agent/instrumentation/active_support_logger.rb +0 -2
  45. data/lib/new_relic/agent/instrumentation/async_http.rb +2 -3
  46. data/lib/new_relic/agent/instrumentation/aws_sdk_firehose/chain.rb +21 -0
  47. data/lib/new_relic/agent/instrumentation/aws_sdk_firehose/instrumentation.rb +66 -0
  48. data/lib/new_relic/agent/instrumentation/aws_sdk_firehose/prepend.rb +15 -0
  49. data/lib/new_relic/agent/instrumentation/aws_sdk_firehose.rb +22 -0
  50. data/lib/new_relic/agent/instrumentation/aws_sdk_kinesis/chain.rb +21 -0
  51. data/lib/new_relic/agent/instrumentation/aws_sdk_kinesis/instrumentation.rb +91 -0
  52. data/lib/new_relic/agent/instrumentation/aws_sdk_kinesis/prepend.rb +15 -0
  53. data/lib/new_relic/agent/instrumentation/aws_sdk_kinesis.rb +22 -0
  54. data/lib/new_relic/agent/instrumentation/aws_sdk_lambda/chain.rb +33 -0
  55. data/lib/new_relic/agent/instrumentation/aws_sdk_lambda/instrumentation.rb +93 -0
  56. data/lib/new_relic/agent/instrumentation/aws_sdk_lambda/prepend.rb +23 -0
  57. data/lib/new_relic/agent/instrumentation/aws_sdk_lambda.rb +23 -0
  58. data/lib/new_relic/agent/instrumentation/aws_sqs/chain.rb +37 -0
  59. data/lib/new_relic/agent/instrumentation/aws_sqs/instrumentation.rb +67 -0
  60. data/lib/new_relic/agent/instrumentation/aws_sqs/prepend.rb +21 -0
  61. data/lib/new_relic/agent/instrumentation/aws_sqs.rb +23 -0
  62. data/lib/new_relic/agent/instrumentation/bunny/instrumentation.rb +14 -0
  63. data/lib/new_relic/agent/instrumentation/bunny.rb +3 -4
  64. data/lib/new_relic/agent/instrumentation/concurrent_ruby.rb +1 -3
  65. data/lib/new_relic/agent/instrumentation/controller_instrumentation.rb +4 -0
  66. data/lib/new_relic/agent/instrumentation/curb.rb +4 -5
  67. data/lib/new_relic/agent/instrumentation/delayed_job_instrumentation.rb +0 -23
  68. data/lib/new_relic/agent/instrumentation/dynamodb/chain.rb +27 -0
  69. data/lib/new_relic/agent/instrumentation/dynamodb/instrumentation.rb +64 -0
  70. data/lib/new_relic/agent/instrumentation/dynamodb/prepend.rb +19 -0
  71. data/lib/new_relic/agent/instrumentation/dynamodb.rb +23 -0
  72. data/lib/new_relic/agent/instrumentation/elasticsearch/chain.rb +1 -2
  73. data/lib/new_relic/agent/instrumentation/elasticsearch/instrumentation.rb +53 -7
  74. data/lib/new_relic/agent/instrumentation/elasticsearch.rb +1 -3
  75. data/lib/new_relic/agent/instrumentation/ethon.rb +1 -5
  76. data/lib/new_relic/agent/instrumentation/excon.rb +1 -17
  77. data/lib/new_relic/agent/instrumentation/fiber/chain.rb +1 -1
  78. data/lib/new_relic/agent/instrumentation/fiber/prepend.rb +1 -1
  79. data/lib/new_relic/agent/instrumentation/fiber.rb +0 -2
  80. data/lib/new_relic/agent/instrumentation/grape/instrumentation.rb +0 -3
  81. data/lib/new_relic/agent/instrumentation/grape.rb +1 -1
  82. data/lib/new_relic/agent/instrumentation/grpc/client/instrumentation.rb +0 -1
  83. data/lib/new_relic/agent/instrumentation/httpclient.rb +1 -5
  84. data/lib/new_relic/agent/instrumentation/httprb.rb +0 -1
  85. data/lib/new_relic/agent/instrumentation/httpx/instrumentation.rb +1 -1
  86. data/lib/new_relic/agent/instrumentation/httpx.rb +1 -5
  87. data/lib/new_relic/agent/instrumentation/logger.rb +1 -3
  88. data/lib/new_relic/agent/instrumentation/logstasher/chain.rb +21 -0
  89. data/lib/new_relic/agent/instrumentation/logstasher/instrumentation.rb +24 -0
  90. data/lib/new_relic/agent/instrumentation/logstasher/prepend.rb +13 -0
  91. data/lib/new_relic/agent/instrumentation/logstasher.rb +25 -0
  92. data/lib/new_relic/agent/instrumentation/memcache/dalli.rb +1 -1
  93. data/lib/new_relic/agent/instrumentation/memcache/helper.rb +2 -2
  94. data/lib/new_relic/agent/instrumentation/memcache/instrumentation.rb +1 -1
  95. data/lib/new_relic/agent/instrumentation/memcache/prepend.rb +1 -1
  96. data/lib/new_relic/agent/instrumentation/memcache.rb +0 -1
  97. data/lib/new_relic/agent/instrumentation/mongodb_command_subscriber.rb +1 -1
  98. data/lib/new_relic/agent/instrumentation/net_http/instrumentation.rb +3 -3
  99. data/lib/new_relic/agent/instrumentation/net_http.rb +2 -1
  100. data/lib/new_relic/agent/instrumentation/notifications_subscriber.rb +0 -2
  101. data/lib/new_relic/agent/instrumentation/opensearch/chain.rb +21 -0
  102. data/lib/new_relic/agent/instrumentation/opensearch/instrumentation.rb +66 -0
  103. data/lib/{tasks/instrumentation_generator/templates/instrumentation.tt → new_relic/agent/instrumentation/opensearch/prepend.rb} +4 -4
  104. data/lib/new_relic/agent/instrumentation/opensearch.rb +23 -0
  105. data/lib/new_relic/agent/instrumentation/padrino.rb +3 -3
  106. data/lib/new_relic/agent/instrumentation/rack/instrumentation.rb +3 -0
  107. data/lib/new_relic/agent/instrumentation/rails_notifications/action_controller.rb +9 -5
  108. data/lib/new_relic/agent/instrumentation/rake.rb +1 -2
  109. data/lib/new_relic/agent/instrumentation/rdkafka/chain.rb +72 -0
  110. data/lib/new_relic/agent/instrumentation/rdkafka/instrumentation.rb +70 -0
  111. data/lib/new_relic/agent/instrumentation/rdkafka/prepend.rb +67 -0
  112. data/lib/new_relic/agent/instrumentation/rdkafka.rb +25 -0
  113. data/lib/new_relic/agent/instrumentation/redis/cluster_middleware.rb +26 -0
  114. data/lib/new_relic/agent/instrumentation/redis/constants.rb +2 -2
  115. data/lib/new_relic/agent/instrumentation/redis/instrumentation.rb +14 -11
  116. data/lib/new_relic/agent/instrumentation/redis/middleware.rb +3 -0
  117. data/lib/new_relic/agent/instrumentation/redis.rb +11 -5
  118. data/lib/new_relic/agent/instrumentation/resque.rb +8 -6
  119. data/lib/new_relic/agent/instrumentation/roda.rb +5 -5
  120. data/lib/new_relic/agent/instrumentation/ruby_kafka/chain.rb +55 -0
  121. data/lib/new_relic/agent/instrumentation/ruby_kafka/instrumentation.rb +67 -0
  122. data/lib/new_relic/agent/instrumentation/ruby_kafka/prepend.rb +60 -0
  123. data/lib/new_relic/agent/instrumentation/ruby_kafka.rb +25 -0
  124. data/lib/new_relic/agent/instrumentation/ruby_openai.rb +2 -2
  125. data/lib/new_relic/agent/instrumentation/sidekiq/extensions/delay_extensions.rb +24 -0
  126. data/lib/new_relic/agent/instrumentation/sidekiq/extensions/delayed_class.rb +2 -2
  127. data/lib/new_relic/agent/instrumentation/sidekiq.rb +9 -15
  128. data/lib/new_relic/agent/instrumentation/sinatra.rb +3 -19
  129. data/lib/new_relic/agent/instrumentation/stripe.rb +1 -1
  130. data/lib/new_relic/agent/instrumentation/stripe_subscriber.rb +22 -1
  131. data/lib/new_relic/agent/instrumentation/thread.rb +0 -2
  132. data/lib/new_relic/agent/instrumentation/tilt.rb +0 -4
  133. data/lib/new_relic/agent/instrumentation/typhoeus/instrumentation.rb +2 -2
  134. data/lib/new_relic/agent/instrumentation/typhoeus.rb +0 -1
  135. data/lib/new_relic/agent/instrumentation/view_component/instrumentation.rb +11 -5
  136. data/lib/new_relic/agent/instrumentation/view_component.rb +0 -2
  137. data/lib/new_relic/agent/javascript_instrumentor.rb +2 -3
  138. data/lib/new_relic/agent/llm/chat_completion_summary.rb +1 -1
  139. data/lib/new_relic/agent/llm/embedding.rb +1 -1
  140. data/lib/new_relic/agent/local_log_decorator.rb +20 -3
  141. data/lib/new_relic/agent/log_event_aggregator.rb +119 -28
  142. data/lib/new_relic/agent/logging.rb +1 -1
  143. data/lib/new_relic/agent/messaging.rb +16 -5
  144. data/lib/new_relic/agent/method_tracer.rb +3 -0
  145. data/lib/new_relic/agent/monitors/inbound_request_monitor.rb +1 -1
  146. data/lib/new_relic/agent/monitors/synthetics_monitor.rb +1 -1
  147. data/lib/new_relic/agent/new_relic_service/json_marshaller.rb +2 -2
  148. data/lib/new_relic/agent/new_relic_service.rb +8 -2
  149. data/lib/new_relic/agent/opentelemetry/context/propagation/trace_propagator.rb +66 -0
  150. data/lib/new_relic/agent/opentelemetry/context/propagation.rb +15 -0
  151. data/lib/{tasks/instrumentation_generator/templates/Envfile.tt → new_relic/agent/opentelemetry/context.rb} +9 -5
  152. data/lib/new_relic/agent/opentelemetry/trace/span.rb +31 -0
  153. data/lib/new_relic/agent/opentelemetry/trace/tracer.rb +129 -0
  154. data/lib/new_relic/agent/opentelemetry/trace/tracer_provider.rb +18 -0
  155. data/lib/new_relic/agent/opentelemetry/trace.rb +15 -0
  156. data/lib/new_relic/agent/opentelemetry/transaction_patch.rb +69 -0
  157. data/lib/new_relic/agent/opentelemetry_bridge.rb +32 -0
  158. data/lib/new_relic/agent/parameter_filtering.rb +1 -1
  159. data/lib/new_relic/agent/samplers/cpu_sampler.rb +1 -1
  160. data/lib/new_relic/agent/samplers/memory_sampler.rb +1 -1
  161. data/lib/new_relic/agent/serverless_handler.rb +247 -12
  162. data/lib/new_relic/agent/serverless_handler_event_sources.json +155 -0
  163. data/lib/new_relic/agent/serverless_handler_event_sources.rb +49 -0
  164. data/lib/new_relic/agent/span_event_primitive.rb +16 -11
  165. data/lib/new_relic/agent/system_info.rb +14 -0
  166. data/lib/new_relic/agent/threading/backtrace_node.rb +10 -1
  167. data/lib/new_relic/agent/tracer.rb +1 -1
  168. data/lib/new_relic/agent/transaction/abstract_segment.rb +2 -1
  169. data/lib/new_relic/agent/transaction/datastore_segment.rb +1 -1
  170. data/lib/new_relic/agent/transaction/distributed_tracer.rb +3 -3
  171. data/lib/new_relic/agent/transaction/external_request_segment.rb +0 -10
  172. data/lib/new_relic/agent/transaction/message_broker_segment.rb +4 -1
  173. data/lib/new_relic/agent/transaction/request_attributes.rb +14 -7
  174. data/lib/new_relic/agent/transaction/trace_context.rb +34 -5
  175. data/lib/new_relic/agent/transaction/tracing.rb +3 -3
  176. data/lib/new_relic/agent/transaction.rb +4 -7
  177. data/lib/new_relic/agent/transaction_time_aggregator.rb +1 -1
  178. data/lib/new_relic/agent/utilization/ecs.rb +22 -0
  179. data/lib/new_relic/agent/utilization/ecs_v4.rb +22 -0
  180. data/lib/new_relic/agent/utilization_data.rb +40 -5
  181. data/lib/new_relic/agent/vm/c_ruby_vm.rb +3 -3
  182. data/lib/new_relic/agent.rb +124 -2
  183. data/lib/new_relic/constants.rb +1 -0
  184. data/lib/new_relic/control/frameworks/grape.rb +14 -0
  185. data/lib/new_relic/control/frameworks/padrino.rb +14 -0
  186. data/lib/new_relic/control/frameworks/rails4.rb +1 -3
  187. data/lib/new_relic/control/instance_methods.rb +6 -0
  188. data/lib/new_relic/control/instrumentation.rb +1 -1
  189. data/lib/new_relic/control/private_instance_methods.rb +4 -0
  190. data/lib/new_relic/control/security_interface.rb +57 -0
  191. data/lib/new_relic/control.rb +1 -1
  192. data/lib/new_relic/dependency_detection.rb +11 -14
  193. data/lib/new_relic/environment_report.rb +2 -2
  194. data/lib/new_relic/helper.rb +22 -0
  195. data/lib/new_relic/language_support.rb +3 -1
  196. data/lib/new_relic/local_environment.rb +1 -4
  197. data/lib/new_relic/rack/browser_monitoring.rb +20 -8
  198. data/lib/new_relic/version.rb +1 -1
  199. data/lib/sequel/extensions/new_relic_instrumentation.rb +3 -2
  200. data/lib/tasks/config.rake +7 -3
  201. data/lib/tasks/gha.rake +31 -0
  202. data/lib/tasks/helpers/config.html.erb +3 -2
  203. data/lib/tasks/helpers/format.rb +1 -1
  204. data/lib/tasks/helpers/newrelicyml.rb +80 -13
  205. data/newrelic.yml +425 -162
  206. data/newrelic_rpm.gemspec +3 -1
  207. data/test/agent_helper.rb +24 -2
  208. metadata +91 -22
  209. data/lib/tasks/instrumentation_generator/README.md +0 -63
  210. data/lib/tasks/instrumentation_generator/TODO.md +0 -33
  211. data/lib/tasks/instrumentation_generator/instrumentation.thor +0 -121
  212. data/lib/tasks/instrumentation_generator/templates/chain.tt +0 -21
  213. data/lib/tasks/instrumentation_generator/templates/chain_method.tt +0 -7
  214. data/lib/tasks/instrumentation_generator/templates/dependency_detection.tt +0 -29
  215. data/lib/tasks/instrumentation_generator/templates/instrumentation_method.tt +0 -3
  216. data/lib/tasks/instrumentation_generator/templates/newrelic.yml.tt +0 -19
  217. data/lib/tasks/instrumentation_generator/templates/prepend.tt +0 -13
  218. data/lib/tasks/instrumentation_generator/templates/prepend_method.tt +0 -3
  219. data/lib/tasks/instrumentation_generator/templates/test.tt +0 -15
@@ -14,8 +14,6 @@ DependencyDetection.defer do
14
14
  end
15
15
 
16
16
  executes do
17
- NewRelic::Agent.logger.info('Installing Fiber instrumentation')
18
-
19
17
  if use_prepend?
20
18
  prepend_instrument Fiber, NewRelic::Agent::Instrumentation::MonitoredFiber::Prepend
21
19
  else
@@ -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,7 @@ DependencyDetection.defer do
19
19
 
20
20
  depends_on do
21
21
  begin
22
- if defined?(Bundler) && Bundler.rubygems.all_specs.map(&:name).include?('newrelic-grape')
22
+ if NewRelic::Helper.rubygems_specs.map(&:name).include?('newrelic-grape')
23
23
  NewRelic::Agent.logger.info('Not installing New Relic supported Grape instrumentation because the third party newrelic-grape gem is present')
24
24
  false
25
25
  else
@@ -50,7 +50,6 @@ module NewRelic
50
50
  attributes_hash.each do |attr, value|
51
51
  segment.add_agent_attribute(attr, value)
52
52
  end
53
- segment.record_agent_attributes = true
54
53
  end
55
54
 
56
55
  def grpc_status_and_message_from_exception(exception)
@@ -16,14 +16,10 @@ DependencyDetection.defer do
16
16
  end
17
17
 
18
18
  depends_on do
19
- minimum_supported_version = Gem::Version.new(HTTPCLIENT_MIN_VERSION)
20
- current_version = Gem::Version.new(HTTPClient::VERSION)
21
-
22
- current_version >= minimum_supported_version
19
+ NewRelic::Helper.version_satisfied?(HTTPClient::VERSION, '>=', HTTPCLIENT_MIN_VERSION)
23
20
  end
24
21
 
25
22
  executes do
26
- NewRelic::Agent.logger.info('Installing HTTPClient instrumentation')
27
23
  require 'new_relic/agent/distributed_tracing/cross_app_tracing'
28
24
  require 'new_relic/agent/http_clients/httpclient_wrappers'
29
25
  end
@@ -14,7 +14,6 @@ DependencyDetection.defer do
14
14
  end
15
15
 
16
16
  executes do
17
- NewRelic::Agent.logger.info('Installing http.rb Wrappers')
18
17
  require 'new_relic/agent/distributed_tracing/cross_app_tracing'
19
18
  require 'new_relic/agent/http_clients/http_rb_wrappers'
20
19
  end
@@ -30,7 +30,7 @@ module NewRelic::Agent::Instrumentation::HTTPX
30
30
 
31
31
  def nr_finish_segment
32
32
  proc do |request, segment|
33
- response = @responses[request]
33
+ response = request.response if request
34
34
 
35
35
  unless response
36
36
  NewRelic::Agent.logger.debug('Processed an on-response callback for HTTPX but could not find the response!')
@@ -10,11 +10,7 @@ DependencyDetection.defer do
10
10
  named :httpx
11
11
 
12
12
  depends_on do
13
- defined?(HTTPX) && Gem::Version.new(HTTPX::VERSION) >= Gem::Version.new('1.0.0')
14
- end
15
-
16
- executes do
17
- NewRelic::Agent.logger.info('Installing httpx instrumentation')
13
+ defined?(HTTPX) && NewRelic::Helper.version_satisfied?(HTTPX::VERSION, '>=', '1.0.0')
18
14
  end
19
15
 
20
16
  executes do
@@ -15,12 +15,10 @@ DependencyDetection.defer do
15
15
  end
16
16
 
17
17
  executes do
18
- NewRelic::Agent.logger.info('Installing Logger instrumentation')
19
-
20
18
  if use_prepend?
21
19
  prepend_instrument Logger, NewRelic::Agent::Instrumentation::Logger::Prepend
22
20
  else
23
- chain_instrument NewRelic::Agent::Instrumentation::Logger
21
+ chain_instrument NewRelic::Agent::Instrumentation::Logger, NewRelic::Agent::Instrumentation::Logger::INSTRUMENTATION_NAME
24
22
  end
25
23
  end
26
24
  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 LogStasher::Chain
7
+ def self.instrument!
8
+ ::LogStasher.singleton_class.class_eval do
9
+ include NewRelic::Agent::Instrumentation::LogStasher
10
+
11
+ alias_method(:build_logstash_event_without_new_relic, :build_logstash_event)
12
+
13
+ def build_logstash_event(*args)
14
+ build_logstash_event_with_new_relic(*args) do
15
+ build_logstash_event_without_new_relic(*args)
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,24 @@
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 LogStasher
7
+ INSTRUMENTATION_NAME = NewRelic::Agent.base_name(name)
8
+
9
+ def self.enabled?
10
+ NewRelic::Agent.config[:'instrumentation.logstasher'] != 'disabled'
11
+ end
12
+
13
+ def build_logstash_event_with_new_relic(*args)
14
+ logstasher_event = yield
15
+ log = logstasher_event.instance_variable_get(:@data)
16
+
17
+ ::NewRelic::Agent.record_instrumentation_invocation(INSTRUMENTATION_NAME)
18
+ ::NewRelic::Agent.agent.log_event_aggregator.record_logstasher_event(log)
19
+ ::NewRelic::Agent::LocalLogDecorator.decorate(log)
20
+
21
+ logstasher_event
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,13 @@
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 LogStasher::Prepend
7
+ include NewRelic::Agent::Instrumentation::LogStasher
8
+
9
+ def build_logstash_event(*args)
10
+ build_logstash_event_with_new_relic(*args) { super }
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,25 @@
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 'logstasher/instrumentation'
6
+ require_relative 'logstasher/chain'
7
+ require_relative 'logstasher/prepend'
8
+
9
+ DependencyDetection.defer do
10
+ named :logstasher
11
+
12
+ depends_on do
13
+ defined?(LogStasher) &&
14
+ NewRelic::Helper.version_satisfied?(LogStasher::VERSION, '>=', '1.0.0') &&
15
+ NewRelic::Agent.config[:'application_logging.enabled']
16
+ end
17
+
18
+ executes do
19
+ if use_prepend?
20
+ prepend_instrument LogStasher.singleton_class, NewRelic::Agent::Instrumentation::LogStasher::Prepend
21
+ else
22
+ chain_instrument NewRelic::Agent::Instrumentation::LogStasher::Chain
23
+ end
24
+ end
25
+ end
@@ -61,7 +61,7 @@ module NewRelic
61
61
  # TODO: MAJOR VERSION
62
62
  # Dalli - 3.1.0 renamed send_multiget to pipelined_get, but the method is otherwise the same
63
63
  # Once we no longer support Dalli < 3.1.0, remove this conditional logic
64
- if Gem::Version.new(::Dalli::VERSION) >= Gem::Version.new('3.1.0')
64
+ if NewRelic::Helper.version_satisfied?(::Dalli::VERSION, '>=', '3.1.0')
65
65
  alias_method(:pipelined_get_without_newrelic_trace, :pipelined_get)
66
66
  def pipelined_get(keys)
67
67
  send_multiget_with_newrelic_tracing(keys) { pipelined_get_without_newrelic_trace(keys) }
@@ -9,11 +9,11 @@ module NewRelic::Agent::Instrumentation
9
9
  BINARY_PROTOCOL_SUPPORTED_VERSION = Gem::Version.new('3.0.2')
10
10
 
11
11
  def supports_datastore_instances?
12
- DATASTORE_INSTANCES_SUPPORTED_VERSION <= Gem::Version.new(::Dalli::VERSION)
12
+ NewRelic::Helper.version_satisfied?(DATASTORE_INSTANCES_SUPPORTED_VERSION, '<=', ::Dalli::VERSION)
13
13
  end
14
14
 
15
15
  def supports_binary_protocol?
16
- BINARY_PROTOCOL_SUPPORTED_VERSION <= Gem::Version.new(::Dalli::VERSION)
16
+ NewRelic::Helper.version_satisfied?(BINARY_PROTOCOL_SUPPORTED_VERSION, '<=', ::Dalli::VERSION)
17
17
  end
18
18
 
19
19
  def client_methods
@@ -6,7 +6,7 @@ module NewRelic::Agent::Instrumentation
6
6
  module Memcache
7
7
  module Tracer
8
8
  SLASH = '/'
9
- UNKNOWN = 'unknown'
9
+ UNKNOWN = NewRelic::UNKNOWN_LOWER
10
10
  LOCALHOST = 'localhost'
11
11
  MULTIGET_METRIC_NAME = 'get_multi_request'
12
12
  MEMCACHED = 'Memcached'
@@ -87,7 +87,7 @@ module NewRelic::Agent::Instrumentation
87
87
  # TODO: MAJOR VERSION
88
88
  # Dalli - 3.1.0 renamed send_multiget to pipelined_get, but the method is otherwise the same
89
89
  # Once we no longer support Dalli < 3.1.0, remove this conditional logic
90
- if Gem::Version.new(::Dalli::VERSION) >= Gem::Version.new('3.1.0')
90
+ if NewRelic::Helper.version_satisfied?(::Dalli::VERSION, '>=', '3.1.0')
91
91
  def pipelined_get(keys)
92
92
  send_multiget_with_newrelic_tracing(keys) { super }
93
93
  end
@@ -74,7 +74,6 @@ DependencyDetection.defer do
74
74
  depends_on { NewRelic::Agent::Instrumentation::Memcache::DalliCAS.should_instrument? }
75
75
 
76
76
  executes do
77
- NewRelic::Agent.logger.info('Installing Dalli CAS Client Memcache instrumentation')
78
77
  if use_prepend?
79
78
  prepend_module = NewRelic::Agent::Instrumentation::Memcache::Prepend
80
79
  prepend_module.dalli_cas_prependers do |client_class, instrumenting_module|
@@ -106,7 +106,7 @@ module NewRelic
106
106
  )
107
107
  end
108
108
 
109
- UNKNOWN = 'unknown'.freeze
109
+ UNKNOWN = NewRelic::UNKNOWN_LOWER
110
110
  LOCALHOST = 'localhost'.freeze
111
111
 
112
112
  def host_from_address(address)
@@ -21,7 +21,7 @@ module NewRelic
21
21
 
22
22
  begin
23
23
  response = nil
24
- segment.add_request_headers(wrapped_request)
24
+ segment&.add_request_headers(wrapped_request)
25
25
 
26
26
  # RUBY-1244 Disable further tracing in request to avoid double
27
27
  # counting if connection wasn't started (which calls request again).
@@ -34,10 +34,10 @@ module NewRelic
34
34
  wrapped_response = NewRelic::Agent::HTTPClients::NetHTTPResponse.new(response)
35
35
 
36
36
  if NewRelic::Agent::LLM.openai_parent?(segment)
37
- NewRelic::Agent::LLM.populate_openai_response_headers(wrapped_response, segment.parent)
37
+ NewRelic::Agent::LLM.populate_openai_response_headers(wrapped_response, segment&.parent)
38
38
  end
39
39
 
40
- segment.process_response_headers(wrapped_response)
40
+ segment&.process_response_headers(wrapped_response)
41
41
 
42
42
  response
43
43
  ensure
@@ -19,7 +19,8 @@ DependencyDetection.defer do
19
19
 
20
20
  # Airbrake uses method chaining on Net::HTTP in versions < 10.0.2 (10.0.2 updated to prepend for Net:HTTP)
21
21
  conflicts_with_prepend do
22
- defined?(Airbrake) && defined?(Airbrake::AIRBRAKE_VERSION) && Gem::Version.create(Airbrake::AIRBRAKE_VERSION) < Gem::Version.create('10.0.2')
22
+ defined?(Airbrake) && defined?(Airbrake::AIRBRAKE_VERSION) &&
23
+ NewRelic::Helper.version_satisfied?(Airbrake::AIRBRAKE_VERSION, '<', '10.0.2')
23
24
  end
24
25
 
25
26
  conflicts_with_prepend do
@@ -16,8 +16,6 @@ module NewRelic
16
16
  end
17
17
 
18
18
  def self.find_all_subscribers
19
- # TODO: need to talk to Rails core about an API for this,
20
- # rather than digging through Listener ivars
21
19
  instance_variable_names = [:@subscribers, :@string_subscribers, :@other_subscribers]
22
20
  all_subscribers = []
23
21
 
@@ -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 OpenSearch::Chain
7
+ def self.instrument!
8
+ ::OpenSearch::Transport::Client.class_eval do
9
+ include NewRelic::Agent::Instrumentation::OpenSearch
10
+
11
+ alias_method(:perform_request_without_tracing, :perform_request)
12
+
13
+ def perform_request(*args)
14
+ perform_request_with_tracing(*args) do
15
+ perform_request_without_tracing(*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 OpenSearch
7
+ PRODUCT_NAME = 'OpenSearch'
8
+ OPERATION = 'perform_request'
9
+ OPERATION_PATTERN = %r{/lib/opensearch/api/(?!.+#{OPERATION})}
10
+ INSTANCE_METHOD_PATTERN = /:in (?:`|')(?:.+#)?([^']+)'\z/
11
+ INSTRUMENTATION_NAME = NewRelic::Agent.base_name(name)
12
+
13
+ def perform_request_with_tracing(_method, _path, params = NewRelic::EMPTY_HASH, body = nil, _headers = nil, _opts = nil, &_block)
14
+ return yield unless NewRelic::Agent::Tracer.tracing_enabled?
15
+
16
+ segment = NewRelic::Agent::Tracer.start_datastore_segment(
17
+ product: PRODUCT_NAME,
18
+ operation: nr_operation || OPERATION,
19
+ host: nr_hosts[:host],
20
+ port_path_or_id: nr_hosts[:port],
21
+ database_name: nr_cluster_name
22
+ )
23
+ begin
24
+ NewRelic::Agent::Tracer.capture_segment_error(segment) { yield }
25
+ ensure
26
+ if segment
27
+ segment.notice_nosql_statement(nr_reported_query(body || params))
28
+ segment.finish
29
+ end
30
+ end
31
+ end
32
+
33
+ private
34
+
35
+ # See Elasticsearch instrumentation for explanation on Ruby 3.4 changes to match instance method
36
+ def nr_operation
37
+ location = caller_locations.detect { |loc| loc.to_s.match?(OPERATION_PATTERN) }
38
+ return unless location && location.to_s =~ INSTANCE_METHOD_PATTERN
39
+
40
+ Regexp.last_match(1)
41
+ end
42
+
43
+ def nr_reported_query(query)
44
+ return unless NewRelic::Agent.config[:'opensearch.capture_queries']
45
+ return query unless NewRelic::Agent.config[:'opensearch.obfuscate_queries']
46
+
47
+ NewRelic::Agent::Datastores::NosqlObfuscator.obfuscate_statement(query)
48
+ end
49
+
50
+ def nr_cluster_name
51
+ return @nr_cluster_name if defined?(@nr_cluster_name)
52
+ return if nr_hosts.empty?
53
+
54
+ NewRelic::Agent.disable_all_tracing do
55
+ @nr_cluster_name ||= perform_request('GET', '/').body['cluster_name']
56
+ end
57
+ rescue StandardError => e
58
+ NewRelic::Agent.logger.error('Failed to get cluster name for OpenSearch', e)
59
+ nil
60
+ end
61
+
62
+ def nr_hosts
63
+ @nr_hosts ||= (transport.hosts.first || NewRelic::EMPTY_HASH)
64
+ end
65
+ end
66
+ end
@@ -3,11 +3,11 @@
3
3
  # frozen_string_literal: true
4
4
 
5
5
  module NewRelic::Agent::Instrumentation
6
- module <%= @class_name %>
6
+ module OpenSearch::Prepend
7
+ include NewRelic::Agent::Instrumentation::OpenSearch
7
8
 
8
- def <%= @method.downcase %>_with_new_relic<%= "(#{@args})" unless @args.empty? %>
9
- # add instrumentation content here
10
- yield
9
+ def perform_request(*args)
10
+ perform_request_with_tracing(*args) { super }
11
11
  end
12
12
  end
13
13
  end
@@ -0,0 +1,23 @@
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 'opensearch/instrumentation'
6
+ require_relative 'opensearch/chain'
7
+ require_relative 'opensearch/prepend'
8
+
9
+ DependencyDetection.defer do
10
+ named :opensearch
11
+
12
+ depends_on do
13
+ defined?(OpenSearch)
14
+ end
15
+
16
+ executes do
17
+ if use_prepend?
18
+ prepend_instrument OpenSearch::Transport::Client, NewRelic::Agent::Instrumentation::OpenSearch::Prepend
19
+ else
20
+ chain_instrument NewRelic::Agent::Instrumentation::OpenSearch::Chain
21
+ end
22
+ end
23
+ end
@@ -22,11 +22,11 @@ DependencyDetection.defer do
22
22
  depends_on { defined?(Padrino) && defined?(Padrino::Routing::InstanceMethods) }
23
23
 
24
24
  executes do
25
- NewRelic::Agent.logger.info('Installing Padrino instrumentation')
25
+ supportability_name = NewRelic::Agent::Instrumentation::Padrino::INSTRUMENTATION_NAME
26
26
  if use_prepend?
27
- prepend_instrument Padrino::Application, NewRelic::Agent::Instrumentation::PadrinoTracer::Prepend
27
+ prepend_instrument Padrino::Application, NewRelic::Agent::Instrumentation::PadrinoTracer::Prepend, supportability_name
28
28
  else
29
- chain_instrument NewRelic::Agent::Instrumentation::PadrinoTracer::Chain
29
+ chain_instrument NewRelic::Agent::Instrumentation::PadrinoTracer::Chain, supportability_name
30
30
  end
31
31
  end
32
32
  end
@@ -13,6 +13,7 @@ module NewRelic
13
13
  attr_accessor :_nr_deferred_detection_ran
14
14
  end
15
15
  builder_class._nr_deferred_detection_ran = false
16
+ NewRelic::Control::SecurityInterface.instance.wait = true
16
17
  end
17
18
 
18
19
  def deferred_dependency_check
@@ -21,6 +22,8 @@ module NewRelic
21
22
  NewRelic::Agent.logger.info('Doing deferred dependency-detection before Rack startup')
22
23
  DependencyDetection.detect!
23
24
  self.class._nr_deferred_detection_ran = true
25
+ NewRelic::Control::SecurityInterface.instance.wait = false
26
+ NewRelic::Control::SecurityInterface.instance.init_agent
24
27
  end
25
28
 
26
29
  def check_for_late_instrumentation(app)
@@ -32,15 +32,19 @@ DependencyDetection.defer do
32
32
  NewRelic::Agent::Instrumentation::ActionControllerSubscriber \
33
33
  .subscribe(/^process_action.action_controller$/)
34
34
 
35
- subs = %w[send_file
35
+ subs = %w[exist_fragment?
36
+ expire_fragment
37
+ halted_callback
38
+ read_fragment
39
+ redirect_to
36
40
  send_data
41
+ send_file
37
42
  send_stream
38
- redirect_to
39
- halted_callback
40
- unpermitted_parameters]
43
+ write_fragment
44
+ unpermitted_parameters].map { |s| Regexp.escape(s) }
41
45
 
42
46
  # have to double escape period because its going from string -> regex
43
47
  NewRelic::Agent::Instrumentation::ActionControllerOtherSubscriber \
44
- .subscribe(Regexp.new("^(#{subs.join('|')})\\.action_controller$"))
48
+ .subscribe(Regexp.new("^(?:#{subs.join('|')})\\.action_controller$"))
45
49
  end
46
50
  end
@@ -12,12 +12,11 @@ DependencyDetection.defer do
12
12
  configure_with :rake
13
13
 
14
14
  depends_on { defined?(Rake) && defined?(Rake::VERSION) }
15
- depends_on { Gem::Version.new(Rake::VERSION) >= Gem::Version.new('10.0.0') }
15
+ depends_on { NewRelic::Helper.version_satisfied?(Rake::VERSION, '>=', '10.0.0') }
16
16
  depends_on { NewRelic::Agent.config[:'rake.tasks'].any? }
17
17
  depends_on { NewRelic::Agent::Instrumentation::Rake.safe_from_third_party_gem? }
18
18
 
19
19
  executes do
20
- NewRelic::Agent.logger.info('Installing Rake instrumentation')
21
20
  NewRelic::Agent.logger.debug("Instrumenting Rake tasks: #{NewRelic::Agent.config[:'rake.tasks']}")
22
21
  end
23
22
 
@@ -0,0 +1,72 @@
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 'instrumentation'
6
+
7
+ module NewRelic::Agent::Instrumentation
8
+ module Rdkafka::Chain
9
+ def self.instrument!
10
+ ::Rdkafka::Producer.class_eval do
11
+ include NewRelic::Agent::Instrumentation::Rdkafka
12
+
13
+ alias_method(:produce_without_new_relic, :produce)
14
+
15
+ def produce(**kwargs)
16
+ produce_with_new_relic(kwargs) do |headers|
17
+ kwargs[:headers] = headers
18
+ produce_without_new_relic(**kwargs)
19
+ end
20
+ end
21
+ end
22
+
23
+ ::Rdkafka::Consumer.class_eval do
24
+ include NewRelic::Agent::Instrumentation::Rdkafka
25
+
26
+ alias_method(:each_without_new_relic, :each)
27
+
28
+ def each(**kwargs)
29
+ each_without_new_relic(**kwargs) do |message|
30
+ each_with_new_relic(message) do
31
+ yield(message)
32
+ end
33
+ end
34
+ end
35
+ end
36
+
37
+ ::Rdkafka::Config.class_eval do
38
+ include NewRelic::Agent::Instrumentation::RdkafkaConfig
39
+
40
+ alias_method(:producer_without_new_relic, :producer)
41
+ alias_method(:consumer_without_new_relic, :consumer)
42
+
43
+ if NewRelic::Helper.version_satisfied?(::Rdkafka::VERSION, '>=', '0.16.0') ||
44
+ NewRelic::Helper.version_satisfied?(RUBY_VERSION, '>=', '2.7.0')
45
+ def producer(**kwargs)
46
+ producer_without_new_relic(**kwargs).tap do |producer|
47
+ set_nr_config(producer)
48
+ end
49
+ end
50
+
51
+ def consumer(**kwargs)
52
+ consumer_without_new_relic(**kwargs).tap do |consumer|
53
+ set_nr_config(consumer)
54
+ end
55
+ end
56
+ else
57
+ def producer
58
+ producer_without_new_relic.tap do |producer|
59
+ set_nr_config(producer)
60
+ end
61
+ end
62
+
63
+ def consumer
64
+ consumer_without_new_relic.tap do |consumer|
65
+ set_nr_config(consumer)
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,70 @@
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 'new_relic/agent/messaging'
6
+
7
+ module NewRelic::Agent::Instrumentation
8
+ module Rdkafka
9
+ MESSAGING_LIBRARY = 'Kafka'
10
+ PRODUCE = 'Produce'
11
+ CONSUME = 'Consume'
12
+
13
+ INSTRUMENTATION_NAME = 'Rdkafka'
14
+
15
+ def produce_with_new_relic(*args)
16
+ NewRelic::Agent.record_instrumentation_invocation(INSTRUMENTATION_NAME)
17
+
18
+ topic_name = args[0][:topic]
19
+ segment = NewRelic::Agent::Tracer.start_message_broker_segment(
20
+ action: :produce,
21
+ library: MESSAGING_LIBRARY,
22
+ destination_type: :topic,
23
+ destination_name: topic_name
24
+ )
25
+ create_kafka_metrics(action: PRODUCE, topic: topic_name)
26
+
27
+ headers = args[0][:headers] || {}
28
+ ::NewRelic::Agent::DistributedTracing.insert_distributed_trace_headers(headers)
29
+
30
+ NewRelic::Agent::Tracer.capture_segment_error(segment) { yield(headers) }
31
+ ensure
32
+ segment&.finish
33
+ end
34
+
35
+ def each_with_new_relic(message)
36
+ NewRelic::Agent.record_instrumentation_invocation(INSTRUMENTATION_NAME)
37
+
38
+ headers = message&.headers || {}
39
+ topic_name = message&.topic
40
+
41
+ NewRelic::Agent::Messaging.wrap_message_broker_consume_transaction(
42
+ library: MESSAGING_LIBRARY,
43
+ destination_type: :topic,
44
+ destination_name: topic_name,
45
+ headers: headers,
46
+ action: :consume
47
+ ) do
48
+ create_kafka_metrics(action: CONSUME, topic: topic_name)
49
+ yield
50
+ end
51
+ end
52
+
53
+ def create_kafka_metrics(action:, topic:)
54
+ hosts = []
55
+ # both 'bootstrap.servers' and 'metadata.broker.list' are valid ways to specify the Kafka server
56
+ hosts << @nr_config[:'bootstrap.servers'] if @nr_config[:'bootstrap.servers']
57
+ hosts << @nr_config[:'metadata.broker.list'] if @nr_config[:'metadata.broker.list']
58
+ hosts.each do |host|
59
+ NewRelic::Agent.record_metric("MessageBroker/Kafka/Nodes/#{host}/#{action}/#{topic}", 1)
60
+ NewRelic::Agent.record_metric("MessageBroker/Kafka/Nodes/#{host}", 1)
61
+ end
62
+ end
63
+ end
64
+
65
+ module RdkafkaConfig
66
+ def set_nr_config(producer_or_consumer)
67
+ producer_or_consumer.instance_variable_set(:@nr_config, self)
68
+ end
69
+ end
70
+ end