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
@@ -9,18 +9,12 @@ module NewRelic
9
9
  module Instrumentation
10
10
  module ActiveRecord
11
11
  EXPLAINER = lambda do |statement|
12
- connection = NewRelic::Agent::Database.get_connection(statement.config) do
13
- ::ActiveRecord::Base.send("#{statement.config[:adapter]}_connection",
14
- statement.config)
15
- end
16
- # the following line needs else branch coverage
17
- if connection && connection.respond_to?(:execute) # rubocop:disable Style/SafeNavigation
18
- return connection.execute("EXPLAIN #{statement.sql}")
19
- end
12
+ NewRelic::Agent::Database.explain_this(statement, true)
20
13
  end
21
14
 
22
15
  def self.insert_instrumentation
23
- if defined?(::ActiveRecord::VERSION::MAJOR) && ::ActiveRecord::VERSION::MAJOR.to_i >= 3
16
+ if defined?(::ActiveRecord::VERSION::MAJOR) &&
17
+ NewRelic::Helper.version_satisfied?(::ActiveRecord::VERSION::MAJOR, '>=', 3)
24
18
  if ::NewRelic::Agent.config[:prepend_active_record_instrumentation]
25
19
  ::ActiveRecord::Base.prepend(::NewRelic::Agent::Instrumentation::ActiveRecordPrepend::BaseExtensions)
26
20
  ::ActiveRecord::Relation.prepend(::NewRelic::Agent::Instrumentation::ActiveRecordPrepend::RelationExtensions)
@@ -44,7 +38,7 @@ module NewRelic
44
38
  end
45
39
  end
46
40
 
47
- if RUBY_VERSION < '2.7.0'
41
+ if NewRelic::Helper.version_satisfied?(RUBY_VERSION, '<', '2.7.0')
48
42
  def log_with_newrelic_instrumentation(*args, &block)
49
43
  state = NewRelic::Agent::Tracer.state
50
44
 
@@ -144,7 +138,7 @@ DependencyDetection.defer do
144
138
  depends_on do
145
139
  defined?(ActiveRecord) && defined?(ActiveRecord::Base) &&
146
140
  (!defined?(ActiveRecord::VERSION) ||
147
- ActiveRecord::VERSION::MAJOR.to_i <= 3)
141
+ NewRelic::Helper.version_satisfied?(ActiveRecord::VERSION::MAJOR, '<=', 3))
148
142
  end
149
143
 
150
144
  depends_on do
@@ -158,7 +152,8 @@ DependencyDetection.defer do
158
152
  executes do
159
153
  require 'new_relic/agent/instrumentation/active_record_helper'
160
154
 
161
- if defined?(Rails::VERSION::MAJOR) && Rails::VERSION::MAJOR.to_i == 3
155
+ if defined?(Rails::VERSION::MAJOR) &&
156
+ NewRelic::Helper.version_satisfied?(Rails::VERSION::MAJOR, '==', 3)
162
157
  ActiveSupport.on_load(:active_record) do
163
158
  NewRelic::Agent::Instrumentation::ActiveRecord.insert_instrumentation
164
159
  end
@@ -49,7 +49,7 @@ module NewRelic
49
49
 
50
50
  alias_method(:delete_all_without_newrelic, :delete_all)
51
51
 
52
- if RUBY_VERSION < '2.7.0'
52
+ if NewRelic::Helper.version_satisfied?(RUBY_VERSION, '<', '2.7.0')
53
53
  def delete_all(*args, &blk)
54
54
  ::NewRelic::Agent.with_database_metric_name(self.name, nil, ACTIVE_RECORD) do
55
55
  delete_all_without_newrelic(*args, &blk)
@@ -170,6 +170,9 @@ module NewRelic
170
170
 
171
171
  'sqlite3' => 'SQLite',
172
172
 
173
+ # https://rubygems.org/gems/trilogy
174
+ 'trilogy' => 'MySQL',
175
+
173
176
  # https://rubygems.org/gems/activerecord-jdbcpostgresql-adapter
174
177
  'jdbcmysql' => 'MySQL',
175
178
 
@@ -222,7 +225,8 @@ module NewRelic
222
225
 
223
226
  'postgresql' => :postgres,
224
227
  'jdbcpostgresql' => :postgres,
225
- 'postgis' => :postgres
228
+ 'postgis' => :postgres,
229
+ 'redshift' => :postgres
226
230
  }.freeze
227
231
 
228
232
  DATASTORE_DEFAULT_PORTS = {
@@ -231,7 +235,7 @@ module NewRelic
231
235
  }.freeze
232
236
 
233
237
  DEFAULT = 'default'.freeze
234
- UNKNOWN = 'unknown'.freeze
238
+ UNKNOWN = NewRelic::UNKNOWN_LOWER
235
239
  LOCALHOST = 'localhost'.freeze
236
240
 
237
241
  def adapter_from_config(config)
@@ -28,7 +28,7 @@ module NewRelic
28
28
  ) { yield }
29
29
  rescue => e
30
30
  # The translate_exception_class method got introduced in 4.1
31
- if ::ActiveRecord::VERSION::MINOR == 0
31
+ if NewRelic::Helper.version_satisfied?(::ActiveRecord::VERSION::MINOR, '==', 0)
32
32
  raise translate_exception(e, sql)
33
33
  else
34
34
  raise translate_exception_class(e, sql)
@@ -86,7 +86,7 @@ DependencyDetection.defer do
86
86
  depends_on do
87
87
  defined?(ActiveRecord) && defined?(ActiveRecord::Base) &&
88
88
  defined?(ActiveRecord::VERSION) &&
89
- ActiveRecord::VERSION::MAJOR.to_i >= 4
89
+ NewRelic::Helper.version_satisfied?(ActiveRecord::VERSION::MAJOR, '>=', 4)
90
90
  end
91
91
 
92
92
  depends_on do
@@ -113,7 +113,7 @@ DependencyDetection.defer do
113
113
 
114
114
  # Default to .prepending, unless the ActiveRecord version is <=4
115
115
  # **AND** the :prepend_active_record_instrumentation config is false
116
- if ActiveRecord::VERSION::MAJOR > 4 \
116
+ if NewRelic::Helper.version_satisfied?(ActiveRecord::VERSION::MAJOR, '>', 4) \
117
117
  || NewRelic::Agent.config[:prepend_active_record_instrumentation]
118
118
 
119
119
  ActiveRecord::Base.send(:prepend,
@@ -131,11 +131,13 @@ DependencyDetection.defer do
131
131
  major_version = ActiveRecord::VERSION::MAJOR.to_i
132
132
  minor_version = ActiveRecord::VERSION::MINOR.to_i
133
133
 
134
- activerecord_extension = if major_version == 4
134
+ activerecord_extension = if NewRelic::Helper.version_satisfied?(major_version, '==', 4)
135
135
  NewRelic::Agent::Instrumentation::ActiveRecordNotifications::BaseExtensions4x
136
- elsif major_version == 5 && minor_version == 0
136
+ elsif NewRelic::Helper.version_satisfied?(major_version, '==', 5) &&
137
+ NewRelic::Helper.version_satisfied?(minor_version, '==', 0)
137
138
  NewRelic::Agent::Instrumentation::ActiveRecordNotifications::BaseExtensions50
138
- elsif major_version == 5 && minor_version == 1
139
+ elsif NewRelic::Helper.version_satisfied?(major_version, '==', 5) &&
140
+ NewRelic::Helper.version_satisfied?(minor_version, '==', 1)
139
141
  NewRelic::Agent::Instrumentation::ActiveRecordNotifications::BaseExtensions51
140
142
  end
141
143
 
@@ -146,9 +148,9 @@ DependencyDetection.defer do
146
148
  end
147
149
 
148
150
  executes do
149
- if ActiveRecord::VERSION::MAJOR == 5 \
150
- && ActiveRecord::VERSION::MINOR.to_i == 1 \
151
- && ActiveRecord::VERSION::TINY.to_i >= 6
151
+ if NewRelic::Helper.version_satisfied?(ActiveRecord::VERSION::MAJOR, '==', 5) \
152
+ && NewRelic::Helper.version_satisfied?(ActiveRecord::VERSION::MINOR, '==', 1) \
153
+ && NewRelic::Helper.version_satisfied?(ActiveRecord::VERSION::TINY, '>=', 6)
152
154
 
153
155
  ActiveRecord::Base.prepend(NewRelic::Agent::Instrumentation::ActiveRecordPrepend::BaseExtensions516)
154
156
  end
@@ -11,7 +11,7 @@ module NewRelic
11
11
  ACTIVE_RECORD = 'ActiveRecord'.freeze
12
12
 
13
13
  module BaseExtensions
14
- if RUBY_VERSION < '2.7.0'
14
+ if NewRelic::Helper.version_satisfied?(RUBY_VERSION, '<', '2.7.0')
15
15
  def save(*args, &blk)
16
16
  ::NewRelic::Agent.with_database_metric_name(self.class.name, nil, ACTIVE_RECORD) do
17
17
  super
@@ -46,7 +46,7 @@ module NewRelic
46
46
  # Starting in v5.1.6, this call no longer happens. We'll
47
47
  # have to set the database metrics explicitly now.
48
48
  #
49
- if RUBY_VERSION < '2.7.0'
49
+ if NewRelic::Helper.version_satisfied?(RUBY_VERSION, '<', '2.7.0')
50
50
  def touch(*args, **kwargs, &blk)
51
51
  ::NewRelic::Agent.with_database_metric_name(self.class.name, nil, ACTIVE_RECORD) do
52
52
  super
@@ -70,18 +70,7 @@ module NewRelic
70
70
  end
71
71
 
72
72
  def get_explain_plan(statement)
73
- connection = NewRelic::Agent::Database.get_connection(statement.config) do
74
- ::ActiveRecord::Base.send("#{statement.config[:adapter]}_connection",
75
- statement.config)
76
- end
77
- # the following line needs else branch coverage
78
- if connection && connection.respond_to?(:exec_query) # rubocop:disable Style/SafeNavigation
79
- return connection.exec_query("EXPLAIN #{statement.sql}",
80
- "Explain #{statement.name}",
81
- statement.binds)
82
- end
83
- rescue => e
84
- NewRelic::Agent.logger.debug("Couldn't fetch the explain plan for #{statement} due to #{e}")
73
+ NewRelic::Agent::Database.explain_this(statement)
85
74
  end
86
75
 
87
76
  def active_record_config(payload)
@@ -127,10 +116,14 @@ module NewRelic
127
116
  port_path_or_id = nil
128
117
  database = nil
129
118
 
130
- if ActiveRecordHelper::InstanceIdentification.supported_adapter?(config)
131
- host = ActiveRecordHelper::InstanceIdentification.host(config)
132
- port_path_or_id = ActiveRecordHelper::InstanceIdentification.port_path_or_id(config)
133
- database = config && config[:database]
119
+ begin
120
+ if ActiveRecordHelper::InstanceIdentification.supported_adapter?(config)
121
+ host = ActiveRecordHelper::InstanceIdentification.host(config)
122
+ port_path_or_id = ActiveRecordHelper::InstanceIdentification.port_path_or_id(config)
123
+ database = config && config[:database]
124
+ end
125
+ rescue
126
+ NewRelic::Agent.logger.debug("Failed to retrieve ActiveRecord host, port, and database details for adapter: #{config && config[:adapter]}")
134
127
  end
135
128
 
136
129
  segment = Tracer.start_datastore_segment(product: product,
@@ -12,8 +12,6 @@ DependencyDetection.defer do
12
12
  depends_on { defined?(ActiveSupport::BroadcastLogger) }
13
13
 
14
14
  executes do
15
- NewRelic::Agent.logger.info('Installing ActiveSupport::BroadcastLogger instrumentation')
16
-
17
15
  if use_prepend?
18
16
  prepend_instrument ActiveSupport::BroadcastLogger, NewRelic::Agent::Instrumentation::ActiveSupportBroadcastLogger::Prepend
19
17
  else
@@ -14,8 +14,6 @@ DependencyDetection.defer do
14
14
  end
15
15
 
16
16
  executes do
17
- NewRelic::Agent.logger.info('Installing ActiveSupport::Logger instrumentation')
18
-
19
17
  if use_prepend?
20
18
  # the only method currently instrumented is a class method
21
19
  prepend_instrument ActiveSupport::Logger.singleton_class, NewRelic::Agent::Instrumentation::ActiveSupportLogger::Prepend
@@ -11,14 +11,13 @@ DependencyDetection.defer do
11
11
 
12
12
  depends_on do
13
13
  defined?(Async::HTTP) &&
14
- Gem::Version.new(Async::HTTP::VERSION) >= Gem::Version.new('0.59.0') &&
14
+ NewRelic::Helper.version_satisfied?(Async::HTTP::VERSION, '>=', '0.59.0') &&
15
15
  !defined?(Traces::Backend::NewRelic) # defined in the traces-backend-newrelic gem
16
16
  end
17
17
 
18
18
  executes do
19
- NewRelic::Agent.logger.info('Installing async_http instrumentation')
20
-
21
19
  require 'async/http/internet'
20
+
22
21
  if use_prepend?
23
22
  prepend_instrument Async::HTTP::Internet, NewRelic::Agent::Instrumentation::AsyncHttp::Prepend
24
23
  else
@@ -0,0 +1,21 @@
1
+ # This file is distributed under New Relic's license terms.
2
+ # See https://github.com/newrelic/newrelic-ruby-agent/blob/main/LICENSE for complete details.
3
+ # frozen_string_literal: true
4
+
5
+ module NewRelic::Agent::Instrumentation
6
+ module Firehose::Chain
7
+ def self.instrument!
8
+ ::Aws::Firehose::Client.class_eval do
9
+ include NewRelic::Agent::Instrumentation::Firehose
10
+
11
+ NewRelic::Agent::Instrumentation::Firehose::INSTRUMENTED_METHODS.each do |method_name|
12
+ alias_method("#{method_name}_without_new_relic".to_sym, method_name.to_sym)
13
+
14
+ define_method(method_name) do |*args|
15
+ instrument_method_with_new_relic(method_name, *args) { send("#{method_name}_without_new_relic".to_sym, *args) }
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,66 @@
1
+ # This file is distributed under New Relic's license terms.
2
+ # See https://github.com/newrelic/newrelic-ruby-agent/blob/main/LICENSE for complete details.
3
+ # frozen_string_literal: true
4
+
5
+ module NewRelic::Agent::Instrumentation
6
+ module Firehose
7
+ INSTRUMENTED_METHODS = %w[
8
+ create_delivery_stream
9
+ delete_delivery_stream
10
+ describe_delivery_stream
11
+ list_delivery_streams
12
+ list_tags_for_delivery_stream
13
+ put_record
14
+ put_record_batch
15
+ start_delivery_stream_encryption
16
+ stop_delivery_stream_encryption
17
+ tag_delivery_stream
18
+ untag_delivery_stream
19
+ update_destination
20
+ ].freeze
21
+
22
+ FIREHOSE = 'Firehose'
23
+ AWS_KINESIS_DELIVERY_STREAMS = 'aws_kinesis_delivery_streams'
24
+
25
+ def instrument_method_with_new_relic(method_name, *args)
26
+ return yield unless NewRelic::Agent::Tracer.tracing_enabled?
27
+
28
+ NewRelic::Agent.record_instrumentation_invocation(FIREHOSE)
29
+
30
+ params = args[0]
31
+ segment = NewRelic::Agent::Tracer.start_segment(name: get_segment_name(method_name, params))
32
+ arn = get_arn(params) if params
33
+ segment&.add_agent_attribute('cloud.resource_id', arn) if arn
34
+
35
+ begin
36
+ NewRelic::Agent::Tracer.capture_segment_error(segment) { yield }
37
+ ensure
38
+ segment&.add_agent_attribute('cloud.platform', AWS_KINESIS_DELIVERY_STREAMS)
39
+ segment&.finish
40
+ end
41
+ end
42
+
43
+ def get_segment_name(method_name, params)
44
+ stream_name = params&.dig(:delivery_stream_name)
45
+ return "#{FIREHOSE}/#{method_name}/#{stream_name}" if stream_name
46
+
47
+ "#{FIREHOSE}/#{method_name}"
48
+ rescue => e
49
+ NewRelic::Agent.logger.warn("Failed to create segment name: #{e}")
50
+ end
51
+
52
+ def nr_account_id
53
+ return @nr_account_id if defined?(@nr_account_id)
54
+
55
+ @nr_account_id = NewRelic::Agent::Aws.get_account_id(config)
56
+ end
57
+
58
+ def get_arn(params)
59
+ stream_arn = params&.dig(:delivery_stream_arn)
60
+ return stream_arn if stream_arn
61
+
62
+ stream_name = params&.dig(:delivery_stream_name)
63
+ NewRelic::Agent::Aws.create_arn(FIREHOSE.downcase, "deliverystream/#{stream_name}", config&.region, nr_account_id) if stream_name
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,15 @@
1
+ # This file is distributed under New Relic's license terms.
2
+ # See https://github.com/newrelic/newrelic-ruby-agent/blob/main/LICENSE for complete details.
3
+ # frozen_string_literal: true
4
+
5
+ module NewRelic::Agent::Instrumentation
6
+ module Firehose::Prepend
7
+ include NewRelic::Agent::Instrumentation::Firehose
8
+
9
+ INSTRUMENTED_METHODS.each do |method_name|
10
+ define_method(method_name) do |*args|
11
+ instrument_method_with_new_relic(method_name, *args) { super(*args) }
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,22 @@
1
+ # This file is distributed under New Relic's license terms.
2
+ # See https://github.com/newrelic/newrelic-ruby-agent/blob/main/LICENSE for complete details.
3
+ # frozen_string_literal: true
4
+
5
+ require_relative 'aws_sdk_firehose/instrumentation'
6
+ require_relative 'aws_sdk_firehose/chain'
7
+ require_relative 'aws_sdk_firehose/prepend'
8
+
9
+ DependencyDetection.defer do
10
+ named :aws_sdk_firehose
11
+
12
+ depends_on do
13
+ defined?(Aws::Firehose::Client)
14
+ end
15
+ executes do
16
+ if use_prepend?
17
+ prepend_instrument Aws::Firehose::Client, NewRelic::Agent::Instrumentation::Firehose::Prepend
18
+ else
19
+ chain_instrument NewRelic::Agent::Instrumentation::Firehose::Chain
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,21 @@
1
+ # This file is distributed under New Relic's license terms.
2
+ # See https://github.com/newrelic/newrelic-ruby-agent/blob/main/LICENSE for complete details.
3
+ # frozen_string_literal: true
4
+
5
+ module NewRelic::Agent::Instrumentation
6
+ module Kinesis::Chain
7
+ def self.instrument!
8
+ ::Aws::Kinesis::Client.class_eval do
9
+ include NewRelic::Agent::Instrumentation::Kinesis
10
+
11
+ NewRelic::Agent::Instrumentation::Kinesis::INSTRUMENTED_METHODS.each do |method_name|
12
+ alias_method("#{method_name}_without_new_relic".to_sym, method_name.to_sym)
13
+
14
+ define_method(method_name) do |*args|
15
+ instrument_method_with_new_relic(method_name, *args) { send("#{method_name}_without_new_relic".to_sym, *args) }
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,91 @@
1
+ # This file is distributed under New Relic's license terms.
2
+ # See https://github.com/newrelic/newrelic-ruby-agent/blob/main/LICENSE for complete details.
3
+ # frozen_string_literal: true
4
+
5
+ module NewRelic::Agent::Instrumentation
6
+ module Kinesis
7
+ INSTRUMENTED_METHODS = %w[
8
+ add_tags_to_stream
9
+ create_stream
10
+ decrease_stream_retention_period
11
+ delete_stream
12
+ describe_limits
13
+ describe_stream
14
+ disable_enhanced_monitoring
15
+ enable_enhanced_monitoring
16
+ get_records
17
+ get_shard_iterator
18
+ increase_stream_retention_period
19
+ list_streams
20
+ list_tags_for_stream
21
+ merge_shards
22
+ put_record
23
+ put_records
24
+ remove_tags_from_stream
25
+ split_shard
26
+ update_shard_count
27
+ ].freeze
28
+
29
+ KINESIS = 'Kinesis'
30
+ AWS_KINESIS_DATA_STREAMS = 'aws_kinesis_data_streams'
31
+ MESSAGE_BROKER_SEGMENT_METHODS = %w[put_record put_records get_records].freeze
32
+
33
+ def instrument_method_with_new_relic(method_name, *args)
34
+ return yield unless NewRelic::Agent::Tracer.tracing_enabled?
35
+
36
+ NewRelic::Agent.record_instrumentation_invocation(KINESIS)
37
+ params = args[0]
38
+ arn = get_arn(params) if params
39
+
40
+ if MESSAGE_BROKER_SEGMENT_METHODS.include?(method_name)
41
+ stream_name = get_stream_name(params, arn)
42
+ segment = NewRelic::Agent::Tracer.start_message_broker_segment(
43
+ action: method_name == 'get_records' ? :consume : :produce,
44
+ library: KINESIS,
45
+ destination_type: :stream,
46
+ destination_name: stream_name
47
+ )
48
+ else
49
+ segment = NewRelic::Agent::Tracer.start_segment(name: get_segment_name(method_name, params))
50
+ end
51
+
52
+ segment&.add_agent_attribute('cloud.resource_id', arn) if arn
53
+
54
+ begin
55
+ NewRelic::Agent::Tracer.capture_segment_error(segment) { yield }
56
+ ensure
57
+ segment&.add_agent_attribute('cloud.platform', AWS_KINESIS_DATA_STREAMS)
58
+ segment&.finish
59
+ end
60
+ end
61
+
62
+ def get_segment_name(method_name, params)
63
+ stream_name = params&.dig(:stream_name)
64
+ return "#{KINESIS}/#{method_name}/#{stream_name}" if stream_name
65
+
66
+ "#{KINESIS}/#{method_name}"
67
+ rescue => e
68
+ NewRelic::Agent.logger.warn("Failed to create segment name: #{e}")
69
+ end
70
+
71
+ def get_stream_name(params, arn)
72
+ params&.dig(:stream_name) || arn.split('/').last || NewRelic::UNKNOWN_LOWER
73
+ rescue => e
74
+ NewRelic::Agent.logger.warn("Failed to get stream name: #{e}")
75
+ end
76
+
77
+ def nr_account_id
78
+ return @nr_account_id if defined?(@nr_account_id)
79
+
80
+ @nr_account_id = NewRelic::Agent::Aws.get_account_id(config)
81
+ end
82
+
83
+ def get_arn(params)
84
+ stream_arn = params&.dig(:stream_arn)
85
+ return stream_arn if stream_arn
86
+
87
+ stream_name = params&.dig(:stream_name)
88
+ NewRelic::Agent::Aws.create_arn(KINESIS.downcase, "stream/#{stream_name}", config&.region, nr_account_id) if stream_name
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,15 @@
1
+ # This file is distributed under New Relic's license terms.
2
+ # See https://github.com/newrelic/newrelic-ruby-agent/blob/main/LICENSE for complete details.
3
+ # frozen_string_literal: true
4
+
5
+ module NewRelic::Agent::Instrumentation
6
+ module Kinesis::Prepend
7
+ include NewRelic::Agent::Instrumentation::Kinesis
8
+
9
+ INSTRUMENTED_METHODS.each do |method_name|
10
+ define_method(method_name) do |*args|
11
+ instrument_method_with_new_relic(method_name, *args) { super(*args) }
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,22 @@
1
+ # This file is distributed under New Relic's license terms.
2
+ # See https://github.com/newrelic/newrelic-ruby-agent/blob/main/LICENSE for complete details.
3
+ # frozen_string_literal: true
4
+
5
+ require_relative 'aws_sdk_kinesis/instrumentation'
6
+ require_relative 'aws_sdk_kinesis/chain'
7
+ require_relative 'aws_sdk_kinesis/prepend'
8
+
9
+ DependencyDetection.defer do
10
+ named :aws_sdk_kinesis
11
+
12
+ depends_on do
13
+ defined?(Aws::Kinesis::Client)
14
+ end
15
+ executes do
16
+ if use_prepend?
17
+ prepend_instrument Aws::Kinesis::Client, NewRelic::Agent::Instrumentation::Kinesis::Prepend
18
+ else
19
+ chain_instrument NewRelic::Agent::Instrumentation::Kinesis::Chain
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,33 @@
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 AwsSdkLambda::Chain
9
+ def self.instrument!
10
+ ::Aws::Lambda::Client.class_eval do
11
+ include NewRelic::Agent::Instrumentation::AwsSdkLambda
12
+
13
+ alias_method(:invoke_without_new_relic, :invoke)
14
+
15
+ def invoke(*args)
16
+ invoke_with_new_relic(*args) { invoke_without_new_relic(*args) }
17
+ end
18
+
19
+ alias_method(:invoke_async_without_new_relic, :invoke_async)
20
+
21
+ def invoke_async(*args)
22
+ invoke_async_with_new_relic(*args) { invoke_async_without_new_relic(*args) }
23
+ end
24
+
25
+ alias_method(:invoke_with_response_stream_without_new_relic, :invoke_with_response_stream)
26
+
27
+ def invoke_with_response_stream(*args)
28
+ invoke_with_response_stream_with_new_relic(*args) { invoke_with_response_stream_without_new_relic(*args) }
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,93 @@
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 'json'
6
+
7
+ module NewRelic::Agent::Instrumentation
8
+ module AwsSdkLambda
9
+ INSTRUMENTATION_NAME = 'aws_sdk_lambda'
10
+ AWS_SERVICE = 'lambda'
11
+ CLOUD_PLATFORM = 'aws_lambda'
12
+ WRAPPED_RESPONSE = Struct.new(:status_code, :has_status_code?)
13
+
14
+ def invoke_with_new_relic(*args)
15
+ with_tracing(:invoke, *args) { yield }
16
+ end
17
+
18
+ def invoke_async_with_new_relic(*args)
19
+ with_tracing(:invoke_async, *args) { yield }
20
+ end
21
+
22
+ def invoke_with_response_stream_with_new_relic(*args)
23
+ with_tracing(:invoke_with_response_stream, *args) { yield }
24
+ end
25
+
26
+ private
27
+
28
+ def with_tracing(action, *args)
29
+ segment = generate_segment(action, *args)
30
+
31
+ # prevent additional instrumentation for things like Net::HTTP from
32
+ # creating any segments that may appear as redundant / confusing
33
+ NewRelic::Agent.disable_all_tracing do
34
+ response = NewRelic::Agent::Tracer.capture_segment_error(segment) { yield }
35
+ process_response(response, segment)
36
+ response
37
+ end
38
+ ensure
39
+ segment&.finish
40
+ end
41
+
42
+ def process_response(response, segment)
43
+ process_function_error(response) if response.respond_to?(:function_error)
44
+ rescue => e
45
+ NewRelic::Agent.logger.error("Error processing aws-sdk-lambda invocation response: #{e}")
46
+ end
47
+
48
+ # notice error that was raised / unhandled by the function
49
+ def process_function_error(response)
50
+ function_error = response.function_error
51
+ return unless function_error
52
+
53
+ msg = "[#{function_error}]"
54
+ payload = response.payload&.string if response.respond_to?(:payload)
55
+ payload_hash = JSON.parse(payload) if payload
56
+ msg = "#{msg} #{payload_hash['errorType']} - #{payload_hash['errorMessage']}" if payload_hash
57
+ e = StandardError.new(msg)
58
+ e.set_backtrace(payload_hash['stackTrace']) if payload_hash
59
+
60
+ NewRelic::Agent.notice_error(e)
61
+ end
62
+
63
+ def generate_segment(action, options = {})
64
+ function = function_name(options)
65
+ region = aws_region
66
+ arn = aws_arn(function, region)
67
+ segment = NewRelic::Agent::Tracer.start_segment(name: "Lambda/#{action}/#{function}")
68
+ segment.add_agent_attribute('cloud.account.id', nr_account_id)
69
+ segment.add_agent_attribute('cloud.platform', CLOUD_PLATFORM)
70
+ segment.add_agent_attribute('cloud.region', region)
71
+ segment.add_agent_attribute('cloud.resource_id', arn) if arn
72
+ segment
73
+ end
74
+
75
+ def function_name(options = {})
76
+ (options.fetch(:function_name, nil) if options.respond_to?(:fetch)) || NewRelic::UNKNOWN
77
+ end
78
+
79
+ def aws_region
80
+ config&.region if self.respond_to?(:config)
81
+ end
82
+
83
+ def aws_arn(function, region)
84
+ NewRelic::Agent::Aws.create_arn(AWS_SERVICE, "function:#{function}", region, nr_account_id)
85
+ end
86
+
87
+ def nr_account_id
88
+ return @nr_account_id if defined?(@nr_account_id)
89
+
90
+ @nr_account_id = NewRelic::Agent::Aws.get_account_id(config)
91
+ end
92
+ end
93
+ end