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
@@ -64,6 +64,7 @@ module NewRelic
64
64
  require 'new_relic/agent/linking_metadata'
65
65
  require 'new_relic/agent/local_log_decorator'
66
66
  require 'new_relic/agent/llm'
67
+ require 'new_relic/agent/aws'
67
68
 
68
69
  require 'new_relic/agent/instrumentation/controller_instrumentation'
69
70
 
@@ -84,6 +85,10 @@ module NewRelic
84
85
  # An exception that forces an agent to stop reporting until its mongrel is restarted.
85
86
  class ForceDisconnectException < StandardError; end
86
87
 
88
+ # Error handling for the automated custom instrumentation tracer logic
89
+ class AutomaticTracerParseException < StandardError; end
90
+ class AutomaticTracerTraceException < StandardError; end
91
+
87
92
  # An exception that forces an agent to restart.
88
93
  class ForceRestartException < StandardError
89
94
  def message
@@ -108,6 +113,9 @@ module NewRelic
108
113
  # placeholder name used when we cannot determine a transaction's name
109
114
  UNKNOWN_METRIC = '(unknown)'.freeze
110
115
  LLM_FEEDBACK_MESSAGE = 'LlmFeedbackMessage'
116
+ # give the observed app time to load the code that automatic tracers have
117
+ # been configured for
118
+ AUTOMATIC_TRACER_MAX_ATTEMPTS = 60 # 60 = try about twice a second for 30 seconds
111
119
 
112
120
  attr_reader :error_group_callback
113
121
  attr_reader :llm_token_count_callback
@@ -124,8 +132,8 @@ module NewRelic
124
132
  def agent # :nodoc:
125
133
  return @agent if @agent
126
134
 
127
- NewRelic::Agent.logger.warn("Agent unavailable as it hasn't been started.")
128
- NewRelic::Agent.logger.warn(caller.join("\n"))
135
+ NewRelic::Agent.logger.debug("Agent unavailable as it hasn't been started.")
136
+ NewRelic::Agent.logger.debug(caller.join("\n"))
129
137
  nil
130
138
  end
131
139
 
@@ -162,6 +170,92 @@ module NewRelic
162
170
  end
163
171
  end
164
172
 
173
+ # @api private
174
+ def self.add_automatic_method_tracers(arr)
175
+ return unless arr
176
+ return arr if arr.respond_to?(:empty?) && arr.empty?
177
+
178
+ arr = arr.split(/\s*,\s*/) if arr.is_a?(String)
179
+
180
+ add_tracers_once_methods_are_defined(arr.dup)
181
+
182
+ arr
183
+ end
184
+
185
+ # spawn a thread that will attempt to establish a tracer for each of the
186
+ # configured methods. the thread will continue to keep trying with each
187
+ # tracer until one of the following happens:
188
+ # - the tracer is successfully established
189
+ # - the configured method string couldn't be parsed
190
+ # - establishing a tracer for a successfully parsed string failed
191
+ # - the maximum number of attempts has been reached
192
+ # the thread will only be spawned once per agent initialization, to account
193
+ # for configuration reloading scenarios.
194
+ #
195
+ # @api private
196
+ def self.add_tracers_once_methods_are_defined(notations)
197
+ # this class method can be invoked multiple times at agent startup, so
198
+ # we return asap here instead of using a traditional memoization of
199
+ # waiting for the method's body to finish being executed
200
+ if defined?(@add_tracers_once_methods_are_defined)
201
+ return
202
+ else
203
+ @add_tracers_once_methods_are_defined = true
204
+ end
205
+
206
+ Thread.new do
207
+ AUTOMATIC_TRACER_MAX_ATTEMPTS.times do
208
+ notations.delete_if { |notation| prep_tracer_for(notation) }
209
+
210
+ break if notations.empty?
211
+
212
+ sleep 0.5
213
+ end
214
+ end
215
+ end
216
+
217
+ # returns `true` if the notation string has either been successfully
218
+ # processed or raised an error during processing. returns `false` if the
219
+ # string seems good but the (customer) code to be traced has not yet been
220
+ # loaded into the Ruby VM
221
+ #
222
+ # @api private
223
+ def self.prep_tracer_for(fully_qualified_method_notation)
224
+ delimiters = fully_qualified_method_notation.scan(/\.|#/)
225
+ raise AutomaticTracerParseException.new("Expected exactly one '.' or '#' delimiter.") unless delimiters.size == 1
226
+
227
+ delimiter = delimiters.first
228
+ namespace, method_name = fully_qualified_method_notation.split(delimiter)
229
+ unless namespace && !namespace.empty?
230
+ raise AutomaticTracerParseException.new("Nothing found to the left of the #{delimiter} delimiter.")
231
+ end
232
+ unless method_name && !method_name.empty?
233
+ raise AutomaticTracerParseException.new("Nothing found to the right of the #{delimiter} delimiter.")
234
+ end
235
+
236
+ begin
237
+ klass = ::NewRelic::LanguageSupport.constantize(namespace)
238
+ return false unless klass
239
+
240
+ klass_to_trace = delimiter.eql?('.') ? klass.singleton_class : klass
241
+ add_or_defer_method_tracer(klass_to_trace, method_name, nil, {})
242
+ rescue StandardError => e
243
+ raise AutomaticTracerTraceException.new("#{e.class} - #{e.message}")
244
+ end
245
+
246
+ true
247
+ rescue AutomaticTracerParseException => e
248
+ NewRelic::Agent.logger.error('Unable to parse out a usable method name to trace. Expected a valid, fully ' \
249
+ "qualified method notation. Got: '#{fully_qualified_method_notation}'. " \
250
+ "Error: #{e.message}")
251
+ true
252
+ rescue AutomaticTracerTraceException => e
253
+ NewRelic::Agent.logger.error('Unable to automatically apply a tracer to method ' \
254
+ "'#{fully_qualified_method_notation}'. Error: #{e.message}")
255
+ true
256
+ end
257
+
258
+ # @api private
165
259
  def add_deferred_method_tracers_now
166
260
  @tracer_lock.synchronize do
167
261
  @tracer_queue.each do |receiver, method_name, metric_name, options|
@@ -199,6 +293,7 @@ module NewRelic
199
293
  #
200
294
  # This method is safe to use from any thread.
201
295
  #
296
+ # @!scope class
202
297
  # @api public
203
298
  def record_metric(metric_name, value) # THREAD_LOCAL_ACCESS
204
299
  record_api_supportability_metric(:record_metric)
@@ -239,6 +334,7 @@ module NewRelic
239
334
  #
240
335
  # This method is safe to use from any thread.
241
336
  #
337
+ # @!scope class
242
338
  # @api public
243
339
  #
244
340
  def increment_metric(metric_name, amount = 1) # THREAD_LOCAL_ACCESS
@@ -266,6 +362,7 @@ module NewRelic
266
362
  #
267
363
  # Return the new block or the existing filter Proc if no block is passed.
268
364
  #
365
+ # @!scope class
269
366
  # @api public
270
367
  #
271
368
  def ignore_error_filter(&block)
@@ -304,6 +401,7 @@ module NewRelic
304
401
  # them if you are calling <code>notice_error</code> outside a
305
402
  # transaction.
306
403
  #
404
+ # @!scope class
307
405
  # @api public
308
406
  #
309
407
  def notice_error(exception, options = {})
@@ -341,6 +439,7 @@ module NewRelic
341
439
  # :'error.expected' => Whether (true) or not (false) the error was expected
342
440
  # :options => The options hash passed to `NewRelic::Agent.notice_error`
343
441
  #
442
+ # @!scope class
344
443
  # @api public
345
444
  #
346
445
  def set_error_group_callback(callback_proc)
@@ -380,6 +479,7 @@ module NewRelic
380
479
  # may be strings, symbols, numeric values or
381
480
  # booleans.
382
481
  #
482
+ # @!scope class
383
483
  # @api public
384
484
  #
385
485
  def record_custom_event(event_type, event_attrs)
@@ -412,6 +512,7 @@ module NewRelic
412
512
  # @param [optional, Hash] Set of key-value pairs to store any other
413
513
  # desired data to submit with the feedback event.
414
514
  #
515
+ # @!scope class
415
516
  # @api public
416
517
  #
417
518
  def record_llm_feedback_event(trace_id:,
@@ -465,6 +566,7 @@ module NewRelic
465
566
  # :model => [String] The name of the LLM model
466
567
  # :content => [String] The message content or prompt
467
568
  #
569
+ # @!scope class
468
570
  # @api public
469
571
  #
470
572
  def set_llm_token_count_callback(callback_proc)
@@ -497,6 +599,7 @@ module NewRelic
497
599
  # file logger. The setting for the newrelic.yml section to use
498
600
  # (ie, RAILS_ENV) can be overridden with an :env argument.
499
601
  #
602
+ # @!scope class
500
603
  # @api public
501
604
  #
502
605
  def manual_start(options = {})
@@ -529,6 +632,7 @@ module NewRelic
529
632
  # connection, this tells me to only try it once so this method returns
530
633
  # quickly if there is some kind of latency with the server.
531
634
  #
635
+ # @!scope class
532
636
  # @api public
533
637
  #
534
638
  def after_fork(options = {})
@@ -542,6 +646,7 @@ module NewRelic
542
646
  #
543
647
  # @param options [Hash] Unused options Hash, for back compatibility only
544
648
  #
649
+ # @!scope class
545
650
  # @api public
546
651
  #
547
652
  def shutdown(options = {})
@@ -552,6 +657,7 @@ module NewRelic
552
657
  # Clear out any data the agent has buffered but has not yet transmitted
553
658
  # to the collector.
554
659
  #
660
+ # @!scope class
555
661
  # @api public
556
662
  def drop_buffered_data
557
663
  # the following line needs else branch coverage
@@ -566,6 +672,7 @@ module NewRelic
566
672
  # register instrumentation than just loading the files directly,
567
673
  # although that probably also works.
568
674
  #
675
+ # @!scope class
569
676
  # @api public
570
677
  #
571
678
  def add_instrumentation(file_pattern)
@@ -575,6 +682,7 @@ module NewRelic
575
682
 
576
683
  # Require agent testing helper methods
577
684
  #
685
+ # @!scope class
578
686
  # @api public
579
687
  def require_test_helper
580
688
  record_api_supportability_metric(:require_test_helper)
@@ -595,6 +703,7 @@ module NewRelic
595
703
  # my_obfuscator(sql)
596
704
  # end
597
705
  #
706
+ # @!scope class
598
707
  # @api public
599
708
  #
600
709
  def set_sql_obfuscator(type = :replace, &block)
@@ -610,6 +719,7 @@ module NewRelic
610
719
  # traced errors, transaction traces, Insights events, slow SQL traces,
611
720
  # or RUM injection will happen for this transaction.
612
721
  #
722
+ # @!scope class
613
723
  # @api public
614
724
  #
615
725
  def ignore_transaction
@@ -620,6 +730,7 @@ module NewRelic
620
730
  # This method disables the recording of Apdex metrics in the current
621
731
  # transaction.
622
732
  #
733
+ # @!scope class
623
734
  # @api public
624
735
  #
625
736
  def ignore_apdex
@@ -630,6 +741,7 @@ module NewRelic
630
741
  # This method disables browser monitoring javascript injection in the
631
742
  # current transaction.
632
743
  #
744
+ # @!scope class
633
745
  # @api public
634
746
  #
635
747
  def ignore_enduser
@@ -642,6 +754,7 @@ module NewRelic
642
754
  # track of the first entry point and turn on tracing again after
643
755
  # leaving that block. This uses the thread local Tracer::State.
644
756
  #
757
+ # @!scope class
645
758
  # @api public
646
759
  #
647
760
  def disable_all_tracing
@@ -666,6 +779,7 @@ module NewRelic
666
779
  # ...
667
780
  # end
668
781
  #
782
+ # @!scope class
669
783
  # @api public
670
784
  #
671
785
  def disable_sql_recording
@@ -704,6 +818,7 @@ module NewRelic
704
818
  # may be strings, symbols, numeric values or
705
819
  # booleans.
706
820
  #
821
+ # @!scope class
707
822
  # @api public
708
823
  #
709
824
  def add_custom_attributes(params) # THREAD_LOCAL_ACCESS
@@ -744,6 +859,7 @@ module NewRelic
744
859
  # booleans.
745
860
  #
746
861
  # @see https://docs.newrelic.com/docs/using-new-relic/welcome-new-relic/get-started/glossary#span
862
+ # @!scope class
747
863
  # @api public
748
864
  def add_custom_span_attributes(params)
749
865
  record_api_supportability_metric(:add_custom_span_attributes)
@@ -785,6 +901,7 @@ module NewRelic
785
901
  #
786
902
  # Attribute pairs with empty or nil contents
787
903
  # will be dropped.
904
+ # @!scope class
788
905
  # @api public
789
906
  def add_custom_log_attributes(params)
790
907
  record_api_supportability_metric(:add_custom_log_attributes)
@@ -800,6 +917,7 @@ module NewRelic
800
917
  #
801
918
  # @param [String] user_id The user id to add to the current transaction attributes
802
919
  #
920
+ # @!scope class
803
921
  # @api public
804
922
  def set_user_id(user_id)
805
923
  record_api_supportability_metric(:set_user_id)
@@ -843,6 +961,7 @@ module NewRelic
843
961
  #
844
962
  # The default category is the same as the running transaction.
845
963
  #
964
+ # @!scope class
846
965
  # @api public
847
966
  #
848
967
  def set_transaction_name(name, options = {})
@@ -853,6 +972,7 @@ module NewRelic
853
972
  # Get the name of the current running transaction. This is useful if you
854
973
  # want to modify the default name.
855
974
  #
975
+ # @!scope class
856
976
  # @api public
857
977
  #
858
978
  def get_transaction_name # THREAD_LOCAL_ACCESS
@@ -924,6 +1044,7 @@ module NewRelic
924
1044
  # * entity.guid - The guid of the current entity.
925
1045
  # * hostname - The fully qualified hostname.
926
1046
  #
1047
+ # @!scope class
927
1048
  # @api public
928
1049
  def linking_metadata
929
1050
  metadata = Hash.new
@@ -950,6 +1071,7 @@ module NewRelic
950
1071
  #
951
1072
  # @param [String] nonce The nonce to use in the javascript tag for browser instrumentation
952
1073
  #
1074
+ # @!scope class
953
1075
  # @api public
954
1076
  #
955
1077
  def browser_timing_header(nonce = nil)
@@ -16,6 +16,7 @@ module NewRelic
16
16
  HTTP = 'HTTP'
17
17
  HTTPS = 'HTTPS'
18
18
  UNKNOWN = 'Unknown'
19
+ UNKNOWN_LOWER = 'unknown'
19
20
 
20
21
  FORMAT_NON_RACK = 0
21
22
  FORMAT_RACK = 1
@@ -0,0 +1,14 @@
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/control/frameworks/ruby'
6
+ module NewRelic
7
+ class Control
8
+ module Frameworks
9
+ # Contains basic control logic for Grape
10
+ class Grape < NewRelic::Control::Frameworks::Ruby
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,14 @@
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/control/frameworks/sinatra'
6
+ module NewRelic
7
+ class Control
8
+ module Frameworks
9
+ # Contains basic control logic for Padrino
10
+ class Padrino < NewRelic::Control::Frameworks::Sinatra
11
+ end
12
+ end
13
+ end
14
+ end
@@ -9,9 +9,7 @@ module NewRelic
9
9
  module Frameworks
10
10
  class Rails4 < NewRelic::Control::Frameworks::Rails3
11
11
  def rails_gem_list
12
- Bundler.rubygems.all_specs.map do |gem|
13
- "#{gem.name} (#{gem.version})"
14
- end
12
+ NewRelic::Helper.rubygems_specs.map { |gem| "#{gem.name} (#{gem.version})" }
15
13
  end
16
14
 
17
15
  def append_plugin_list
@@ -73,6 +73,8 @@ module NewRelic
73
73
  init_config(options)
74
74
  NewRelic::Agent.agent = NewRelic::Agent::Agent.instance
75
75
  init_instrumentation
76
+ init_security_agent
77
+ report_agent_version_metric
76
78
  end
77
79
 
78
80
  def determine_env(options)
@@ -170,6 +172,10 @@ module NewRelic
170
172
  def stdout
171
173
  STDOUT
172
174
  end
175
+
176
+ def report_agent_version_metric
177
+ NewRelic::Agent.record_metric_once("Supportability/AgentVersion/newrelic_rpm/#{NewRelic::VERSION::STRING}")
178
+ end
173
179
  end
174
180
  include InstanceMethods
175
181
  end
@@ -68,7 +68,7 @@ module NewRelic
68
68
  end
69
69
 
70
70
  def rails_32_deprecation
71
- return unless defined?(Rails::VERSION) && Gem::Version.new(Rails::VERSION::STRING) <= Gem::Version.new('3.2')
71
+ return unless defined?(Rails::VERSION) && NewRelic::Helper.version_satisfied?(Rails::VERSION::STRING, '<=', '3.2')
72
72
 
73
73
  deprecation_msg = 'The Ruby agent is dropping support for Rails 3.2 ' \
74
74
  'in a future major release. Please upgrade your Rails version to continue receiving support. ' \
@@ -43,6 +43,10 @@ module NewRelic
43
43
  DependencyDetection.detect!
44
44
  end
45
45
  end
46
+
47
+ def init_security_agent
48
+ SecurityInterface.instance.init_agent
49
+ end
46
50
  end
47
51
  end
48
52
  end
@@ -0,0 +1,57 @@
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 'singleton'
6
+
7
+ module NewRelic
8
+ class Control
9
+ class SecurityInterface
10
+ include Singleton
11
+
12
+ attr_accessor :wait
13
+
14
+ SUPPORTABILITY_PREFIX_SECURITY = 'Supportability/Ruby/SecurityAgent/Enabled/'
15
+ SUPPORTABILITY_PREFIX_SECURITY_AGENT = 'Supportability/Ruby/SecurityAgent/Agent/Enabled/'
16
+ ENABLED = 'enabled'
17
+ DISABLED = 'disabled'
18
+
19
+ def agent_started?
20
+ (@agent_started ||= false) == true
21
+ end
22
+
23
+ def waiting?
24
+ (@wait ||= false) == true
25
+ end
26
+
27
+ def init_agent
28
+ return if agent_started? || waiting?
29
+
30
+ record_supportability_metrics
31
+
32
+ if Agent.config[:'security.agent.enabled'] && !Agent.config[:high_security]
33
+ Agent.logger.info('Invoking New Relic security module')
34
+ require 'newrelic_security'
35
+
36
+ @agent_started = true
37
+ else
38
+ Agent.logger.info('New Relic Security is completely disabled by one of the user-provided configurations: `security.agent.enabled` or `high_security`. Not loading security capabilities.')
39
+ Agent.logger.info("high_security = #{Agent.config[:high_security]}")
40
+ Agent.logger.info("security.agent.enabled = #{Agent.config[:'security.agent.enabled']}")
41
+ end
42
+ rescue LoadError
43
+ Agent.logger.info('New Relic security agent not found - skipping')
44
+ rescue StandardError => exception
45
+ Agent.logger.error("Exception in New Relic security module loading: #{exception} #{exception.backtrace}")
46
+ end
47
+
48
+ def record_supportability_metrics
49
+ Agent.config[:'security.agent.enabled'] ? security_agent_metric(ENABLED) : security_agent_metric(DISABLED)
50
+ end
51
+
52
+ def security_agent_metric(setting)
53
+ NewRelic::Agent.record_metric_once(SUPPORTABILITY_PREFIX_SECURITY_AGENT + setting)
54
+ end
55
+ end
56
+ end
57
+ end
@@ -8,7 +8,6 @@ require 'new_relic/local_environment'
8
8
  require 'new_relic/language_support'
9
9
  require 'new_relic/helper'
10
10
 
11
- require 'singleton'
12
11
  require 'erb'
13
12
  require 'socket'
14
13
  require 'net/https'
@@ -18,6 +17,7 @@ require 'new_relic/control/server_methods'
18
17
  require 'new_relic/control/instrumentation'
19
18
  require 'new_relic/control/class_methods'
20
19
  require 'new_relic/control/instance_methods'
20
+ require 'new_relic/control/security_interface'
21
21
 
22
22
  require 'new_relic/agent'
23
23
  require 'new_relic/delayed_job_injection'
@@ -25,11 +25,9 @@ module DependencyDetection
25
25
 
26
26
  def detect!
27
27
  @items.each do |item|
28
- if item.dependencies_satisfied?
29
- item.execute
30
- else
31
- item.configure_as_unsatisfied unless item.disabled_configured?
32
- end
28
+ next if item.executed || item.disabled_configured?
29
+
30
+ item.dependencies_satisfied? ? item.execute : item.configure_as_unsatisfied
33
31
  end
34
32
  end
35
33
 
@@ -65,6 +63,13 @@ module DependencyDetection
65
63
  end
66
64
 
67
65
  def configure_as_unsatisfied
66
+ # TODO: currently using :unsatisfied for Padrino will clobber the value
67
+ # already set for Sinatra, so skip Padrino and circle back with a
68
+ # new Padrino specific solution in the future.
69
+ #
70
+ # https://github.com/newrelic/newrelic-ruby-agent/issues/2912
71
+ return if name == :padrino
72
+
68
73
  NewRelic::Agent.config.instance_variable_get(:@cache)[config_key] = :unsatisfied
69
74
  end
70
75
 
@@ -139,8 +144,6 @@ module DependencyDetection
139
144
  !(disabled_configured? || deprecated_disabled_configured?)
140
145
  end
141
146
 
142
- # TODO: MAJOR VERSION
143
- # will only return true if a disabled key is found and is truthy
144
147
  def deprecated_disabled_configured?
145
148
  return false if self.name.nil?
146
149
 
@@ -148,12 +151,7 @@ module DependencyDetection
148
151
  return false unless ::NewRelic::Agent.config[key] == true
149
152
 
150
153
  ::NewRelic::Agent.logger.debug("Not installing #{self.name} instrumentation because of configuration #{key}")
151
- ::NewRelic::Agent.logger.debug( \
152
- "[DEPRECATED] configuration #{key} for #{self.name} will be removed in the next major release. " \
153
- "Use `#{config_key}` with one of `#{VALID_CONFIG_VALUES.map(&:to_s).inspect}`"
154
- )
155
-
156
- return true
154
+ true
157
155
  end
158
156
 
159
157
  def config_key
@@ -181,7 +179,6 @@ module DependencyDetection
181
179
  # logs the resolved value during debug mode.
182
180
  def fetch_config_value(key)
183
181
  valid_value = valid_config_value(::NewRelic::Agent.config[key].to_s.to_sym)
184
- ::NewRelic::Agent.logger.debug("Using #{valid_value} configuration value for #{self.name} to configure instrumentation")
185
182
  return valid_value
186
183
  end
187
184
 
@@ -44,7 +44,7 @@ module NewRelic
44
44
  ####################################
45
45
  report_on('Gems') do
46
46
  begin
47
- Bundler.rubygems.all_specs.map { |gem| "#{gem.name}(#{gem.version})" }
47
+ NewRelic::Helper.rubygems_specs.map { |gem| "#{gem.name}(#{gem.version})" }
48
48
  rescue
49
49
  # There are certain rubygem, bundler, rails combinations (e.g. gem
50
50
  # 1.6.2, rails 2.3, bundler 1.2.3) where the code above throws an error
@@ -67,7 +67,7 @@ module NewRelic
67
67
  report_on('Physical Cores') { ::NewRelic::Agent::SystemInfo.num_physical_cores }
68
68
  report_on('Arch') { ::NewRelic::Agent::SystemInfo.processor_arch }
69
69
  report_on('OS version') { ::NewRelic::Agent::SystemInfo.os_version }
70
- report_on('OS') { ::NewRelic::Agent::SystemInfo.ruby_os_identifier }
70
+ report_on('OS') { ::NewRelic::Agent::SystemInfo.os_distribution }
71
71
  report_on('Database adapter') { ::NewRelic::Agent::DatabaseAdapter.value }
72
72
  report_on('Framework') { Agent.config[:framework].to_s }
73
73
  report_on('Dispatcher') { Agent.config[:dispatcher].to_s }
@@ -82,5 +82,27 @@ module NewRelic
82
82
  File.exist?(executable_path) && File.file?(executable_path) && File.executable?(executable_path)
83
83
  end
84
84
  end
85
+
86
+ def version_satisfied?(left, operator, right)
87
+ left = Gem::Version.new(left) unless left.is_a?(Gem::Version)
88
+ right = Gem::Version.new(right) unless right.is_a?(Gem::Version)
89
+
90
+ left.public_send(operator, right)
91
+ end
92
+
93
+ # Bundler version 2.5.12 deprecated all_specs and added installed_specs.
94
+ # To support newer Bundler versions, try to use installed_specs first,
95
+ # then fall back to all_specs.
96
+ # All callers expect this to be an array, so return an array if Bundler isn't defined
97
+ # @api private
98
+ def rubygems_specs
99
+ return [] unless defined?(Bundler)
100
+
101
+ if Bundler.rubygems.respond_to?(:installed_specs)
102
+ Bundler.rubygems.installed_specs
103
+ else
104
+ Bundler.rubygems.all_specs
105
+ end
106
+ end
85
107
  end
86
108
  end
@@ -88,7 +88,9 @@ module NewRelic
88
88
  end
89
89
 
90
90
  def bundled_gem?(gem_name)
91
- defined?(Bundler) && Bundler.rubygems.all_specs.map(&:name).include?(gem_name)
91
+ return false unless defined?(Bundler)
92
+
93
+ NewRelic::Helper.rubygems_specs.map(&:name).include?(gem_name)
92
94
  rescue => e
93
95
  ::NewRelic::Agent.logger.info("Could not determine if third party #{gem_name} gem is installed", e)
94
96
  false
@@ -142,10 +142,7 @@ module NewRelic
142
142
  end
143
143
 
144
144
  def check_for_falcon
145
- return unless defined?(::Falcon::Server) &&
146
- NewRelic::LanguageSupport.object_space_usable?
147
-
148
- @discovered_dispatcher = :falcon if find_class_in_object_space(::Falcon::Server)
145
+ @discovered_dispatcher = :falcon if defined?(::Falcon::Server) && File.basename($PROGRAM_NAME) == 'falcon'
149
146
  end
150
147
 
151
148
  def check_for_delayed_job