newrelic_rpm 9.1.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 (360) hide show
  1. checksums.yaml +4 -4
  2. data/.build_ignore +27 -0
  3. data/CHANGELOG.md +841 -7
  4. data/CONTRIBUTING.md +2 -9
  5. data/README.md +25 -22
  6. data/Rakefile +2 -2
  7. data/bin/newrelic +3 -9
  8. data/bin/newrelic_rpm +15 -0
  9. data/init.rb +2 -2
  10. data/lib/boot/strap.rb +102 -0
  11. data/lib/new_relic/agent/agent.rb +11 -2
  12. data/lib/new_relic/agent/agent_helpers/connect.rb +13 -8
  13. data/lib/new_relic/agent/agent_helpers/harvest.rb +3 -0
  14. data/lib/new_relic/agent/agent_helpers/shutdown.rb +4 -1
  15. data/lib/new_relic/agent/agent_helpers/special_startup.rb +1 -1
  16. data/lib/new_relic/agent/agent_helpers/start_worker_thread.rb +4 -3
  17. data/lib/new_relic/agent/agent_helpers/startup.rb +11 -3
  18. data/lib/new_relic/agent/agent_logger.rb +3 -1
  19. data/lib/new_relic/agent/attribute_filter.rb +3 -3
  20. data/lib/new_relic/agent/attribute_pre_filtering.rb +109 -0
  21. data/lib/new_relic/agent/aws.rb +68 -0
  22. data/lib/new_relic/agent/configuration/default_source.rb +918 -166
  23. data/lib/new_relic/agent/configuration/environment_source.rb +15 -3
  24. data/lib/new_relic/agent/configuration/high_security_source.rb +1 -0
  25. data/lib/new_relic/agent/configuration/manager.rb +72 -11
  26. data/lib/new_relic/agent/configuration/security_policy_source.rb +11 -0
  27. data/lib/new_relic/agent/configuration/yaml_source.rb +22 -2
  28. data/lib/new_relic/agent/connect/request_builder.rb +1 -1
  29. data/lib/new_relic/agent/custom_event_aggregator.rb +27 -1
  30. data/lib/new_relic/agent/database/obfuscation_helpers.rb +11 -11
  31. data/lib/new_relic/agent/database/obfuscator.rb +1 -0
  32. data/lib/new_relic/agent/database.rb +41 -1
  33. data/lib/new_relic/agent/database_adapter.rb +1 -1
  34. data/lib/new_relic/agent/datastores/mongo/metric_translator.rb +1 -1
  35. data/lib/new_relic/agent/datastores/redis.rb +1 -1
  36. data/lib/new_relic/agent/distributed_tracing/cross_app_tracing.rb +1 -1
  37. data/lib/new_relic/agent/distributed_tracing/distributed_trace_payload.rb +4 -8
  38. data/lib/new_relic/agent/distributed_tracing.rb +5 -3
  39. data/lib/new_relic/agent/error_collector.rb +40 -11
  40. data/lib/new_relic/agent/event_loop.rb +1 -1
  41. data/lib/new_relic/agent/external.rb +2 -0
  42. data/lib/new_relic/agent/harvester.rb +1 -1
  43. data/lib/new_relic/agent/health_check.rb +136 -0
  44. data/lib/new_relic/agent/http_clients/abstract.rb +4 -0
  45. data/lib/new_relic/agent/http_clients/async_http_wrappers.rb +80 -0
  46. data/lib/new_relic/agent/http_clients/curb_wrappers.rb +1 -3
  47. data/lib/new_relic/agent/http_clients/ethon_wrappers.rb +109 -0
  48. data/lib/new_relic/agent/http_clients/excon_wrappers.rb +0 -3
  49. data/lib/new_relic/agent/http_clients/http_rb_wrappers.rb +1 -3
  50. data/lib/new_relic/agent/http_clients/httpclient_wrappers.rb +0 -3
  51. data/lib/new_relic/agent/http_clients/httpx_wrappers.rb +91 -0
  52. data/lib/new_relic/agent/http_clients/net_http_wrappers.rb +1 -4
  53. data/lib/new_relic/agent/http_clients/typhoeus_wrappers.rb +0 -3
  54. data/lib/new_relic/agent/http_clients/uri_util.rb +1 -1
  55. data/lib/new_relic/agent/instrumentation/action_controller_other_subscriber.rb +1 -1
  56. data/lib/new_relic/agent/instrumentation/action_dispatch.rb +1 -1
  57. data/lib/new_relic/agent/instrumentation/action_dispatch_subscriber.rb +1 -1
  58. data/lib/new_relic/agent/instrumentation/action_mailbox.rb +1 -1
  59. data/lib/new_relic/agent/instrumentation/action_mailer.rb +1 -1
  60. data/lib/new_relic/agent/instrumentation/active_job.rb +1 -1
  61. data/lib/new_relic/agent/instrumentation/active_job_subscriber.rb +6 -2
  62. data/lib/new_relic/agent/instrumentation/active_merchant.rb +3 -16
  63. data/lib/new_relic/agent/instrumentation/active_record.rb +8 -13
  64. data/lib/new_relic/agent/instrumentation/active_record_helper.rb +8 -5
  65. data/lib/new_relic/agent/instrumentation/active_record_notifications.rb +13 -10
  66. data/lib/new_relic/agent/instrumentation/active_record_prepend.rb +2 -2
  67. data/lib/new_relic/agent/instrumentation/active_record_subscriber.rb +9 -16
  68. data/lib/new_relic/agent/instrumentation/active_support_broadcast_logger/chain.rb +69 -0
  69. data/lib/new_relic/agent/instrumentation/active_support_broadcast_logger/instrumentation.rb +17 -0
  70. data/lib/new_relic/agent/instrumentation/active_support_broadcast_logger/prepend.rb +37 -0
  71. data/lib/new_relic/agent/instrumentation/active_support_broadcast_logger.rb +21 -0
  72. data/lib/new_relic/agent/instrumentation/active_support_logger/instrumentation.rb +4 -0
  73. data/lib/new_relic/agent/instrumentation/active_support_logger.rb +3 -3
  74. data/lib/new_relic/agent/instrumentation/async_http/chain.rb +23 -0
  75. data/lib/new_relic/agent/instrumentation/async_http/instrumentation.rb +37 -0
  76. data/lib/new_relic/agent/instrumentation/async_http/prepend.rb +15 -0
  77. data/lib/new_relic/agent/instrumentation/async_http.rb +27 -0
  78. data/lib/new_relic/agent/instrumentation/aws_sdk_firehose/chain.rb +21 -0
  79. data/lib/new_relic/agent/instrumentation/aws_sdk_firehose/instrumentation.rb +66 -0
  80. data/lib/new_relic/agent/instrumentation/aws_sdk_firehose/prepend.rb +15 -0
  81. data/lib/new_relic/agent/instrumentation/aws_sdk_firehose.rb +22 -0
  82. data/lib/new_relic/agent/instrumentation/aws_sdk_kinesis/chain.rb +21 -0
  83. data/lib/new_relic/agent/instrumentation/aws_sdk_kinesis/instrumentation.rb +91 -0
  84. data/lib/new_relic/agent/instrumentation/aws_sdk_kinesis/prepend.rb +15 -0
  85. data/lib/new_relic/agent/instrumentation/aws_sdk_kinesis.rb +22 -0
  86. data/lib/new_relic/agent/instrumentation/aws_sdk_lambda/chain.rb +33 -0
  87. data/lib/new_relic/agent/instrumentation/aws_sdk_lambda/instrumentation.rb +93 -0
  88. data/lib/new_relic/agent/instrumentation/aws_sdk_lambda/prepend.rb +23 -0
  89. data/lib/new_relic/agent/instrumentation/aws_sdk_lambda.rb +23 -0
  90. data/lib/new_relic/agent/instrumentation/aws_sqs/chain.rb +37 -0
  91. data/lib/new_relic/agent/instrumentation/aws_sqs/instrumentation.rb +67 -0
  92. data/lib/new_relic/agent/instrumentation/aws_sqs/prepend.rb +21 -0
  93. data/lib/new_relic/agent/instrumentation/aws_sqs.rb +23 -0
  94. data/lib/new_relic/agent/instrumentation/bunny/chain.rb +1 -1
  95. data/lib/new_relic/agent/instrumentation/bunny/instrumentation.rb +23 -0
  96. data/lib/new_relic/agent/instrumentation/bunny.rb +4 -5
  97. data/lib/new_relic/agent/instrumentation/concurrent_ruby/chain.rb +1 -1
  98. data/lib/new_relic/agent/instrumentation/concurrent_ruby/instrumentation.rb +3 -4
  99. data/lib/new_relic/agent/instrumentation/concurrent_ruby/prepend.rb +1 -1
  100. data/lib/new_relic/agent/instrumentation/concurrent_ruby.rb +2 -3
  101. data/lib/new_relic/agent/instrumentation/controller_instrumentation.rb +5 -2
  102. data/lib/new_relic/agent/instrumentation/curb/instrumentation.rb +4 -0
  103. data/lib/new_relic/agent/instrumentation/curb.rb +4 -5
  104. data/lib/new_relic/agent/instrumentation/delayed_job/chain.rb +1 -0
  105. data/lib/new_relic/agent/instrumentation/delayed_job/instrumentation.rb +3 -0
  106. data/lib/new_relic/agent/instrumentation/delayed_job_instrumentation.rb +0 -23
  107. data/lib/new_relic/agent/instrumentation/dynamodb/chain.rb +27 -0
  108. data/lib/new_relic/agent/instrumentation/dynamodb/instrumentation.rb +64 -0
  109. data/lib/new_relic/agent/instrumentation/dynamodb/prepend.rb +19 -0
  110. data/lib/new_relic/agent/instrumentation/dynamodb.rb +23 -0
  111. data/lib/new_relic/agent/instrumentation/elasticsearch/chain.rb +2 -3
  112. data/lib/new_relic/agent/instrumentation/elasticsearch/instrumentation.rb +65 -10
  113. data/lib/new_relic/agent/instrumentation/elasticsearch.rb +2 -4
  114. data/lib/new_relic/agent/instrumentation/ethon/chain.rb +39 -0
  115. data/lib/new_relic/agent/instrumentation/ethon/instrumentation.rb +105 -0
  116. data/lib/new_relic/agent/instrumentation/ethon/prepend.rb +35 -0
  117. data/lib/new_relic/agent/instrumentation/ethon.rb +35 -0
  118. data/lib/new_relic/agent/instrumentation/excon/middleware.rb +3 -0
  119. data/lib/new_relic/agent/instrumentation/excon.rb +1 -17
  120. data/lib/new_relic/agent/instrumentation/fiber/chain.rb +11 -4
  121. data/lib/new_relic/agent/instrumentation/fiber/instrumentation.rb +2 -6
  122. data/lib/new_relic/agent/instrumentation/fiber/prepend.rb +10 -3
  123. data/lib/new_relic/agent/instrumentation/fiber.rb +1 -3
  124. data/lib/new_relic/agent/instrumentation/grape/instrumentation.rb +4 -3
  125. data/lib/new_relic/agent/instrumentation/grape.rb +1 -1
  126. data/lib/new_relic/agent/instrumentation/grpc/client/chain.rb +1 -1
  127. data/lib/new_relic/agent/instrumentation/grpc/client/instrumentation.rb +5 -2
  128. data/lib/new_relic/agent/instrumentation/grpc/client/prepend.rb +1 -1
  129. data/lib/new_relic/agent/instrumentation/grpc/client/request_wrapper.rb +1 -1
  130. data/lib/new_relic/agent/instrumentation/grpc/server/instrumentation.rb +5 -1
  131. data/lib/new_relic/agent/instrumentation/grpc_client.rb +2 -2
  132. data/lib/new_relic/agent/instrumentation/grpc_server.rb +2 -2
  133. data/lib/new_relic/agent/instrumentation/httpclient/instrumentation.rb +4 -0
  134. data/lib/new_relic/agent/instrumentation/httpclient.rb +1 -5
  135. data/lib/new_relic/agent/instrumentation/httprb/instrumentation.rb +4 -0
  136. data/lib/new_relic/agent/instrumentation/httprb.rb +0 -1
  137. data/lib/new_relic/agent/instrumentation/httpx/chain.rb +20 -0
  138. data/lib/new_relic/agent/instrumentation/httpx/instrumentation.rb +51 -0
  139. data/lib/new_relic/agent/instrumentation/httpx/prepend.rb +15 -0
  140. data/lib/new_relic/agent/instrumentation/httpx.rb +23 -0
  141. data/lib/new_relic/agent/instrumentation/logger/instrumentation.rb +3 -0
  142. data/lib/new_relic/agent/instrumentation/logger.rb +1 -3
  143. data/lib/new_relic/agent/instrumentation/logstasher/chain.rb +21 -0
  144. data/lib/new_relic/agent/instrumentation/logstasher/instrumentation.rb +24 -0
  145. data/lib/new_relic/agent/instrumentation/logstasher/prepend.rb +13 -0
  146. data/lib/new_relic/agent/instrumentation/logstasher.rb +25 -0
  147. data/lib/new_relic/agent/instrumentation/memcache/dalli.rb +4 -2
  148. data/lib/new_relic/agent/instrumentation/memcache/helper.rb +2 -2
  149. data/lib/new_relic/agent/instrumentation/memcache/instrumentation.rb +13 -4
  150. data/lib/new_relic/agent/instrumentation/memcache/prepend.rb +4 -2
  151. data/lib/new_relic/agent/instrumentation/memcache.rb +4 -5
  152. data/lib/new_relic/agent/instrumentation/mongodb_command_subscriber.rb +3 -5
  153. data/lib/new_relic/agent/instrumentation/net_http/instrumentation.rb +13 -3
  154. data/lib/new_relic/agent/instrumentation/net_http.rb +2 -1
  155. data/lib/new_relic/agent/instrumentation/notifications_subscriber.rb +4 -2
  156. data/lib/new_relic/agent/instrumentation/opensearch/chain.rb +21 -0
  157. data/lib/new_relic/agent/instrumentation/opensearch/instrumentation.rb +66 -0
  158. data/lib/new_relic/agent/instrumentation/opensearch/prepend.rb +13 -0
  159. data/lib/new_relic/agent/instrumentation/opensearch.rb +23 -0
  160. data/lib/new_relic/agent/instrumentation/padrino/instrumentation.rb +4 -0
  161. data/lib/new_relic/agent/instrumentation/padrino.rb +3 -3
  162. data/lib/new_relic/agent/instrumentation/queue_time.rb +1 -1
  163. data/lib/new_relic/agent/instrumentation/rack/instrumentation.rb +9 -0
  164. data/lib/new_relic/agent/instrumentation/rails3/action_controller.rb +4 -0
  165. data/lib/new_relic/agent/instrumentation/rails_notifications/action_cable.rb +1 -1
  166. data/lib/new_relic/agent/instrumentation/rails_notifications/action_controller.rb +10 -5
  167. data/lib/new_relic/agent/instrumentation/rake/instrumentation.rb +4 -0
  168. data/lib/new_relic/agent/instrumentation/rake.rb +1 -2
  169. data/lib/new_relic/agent/instrumentation/rdkafka/chain.rb +72 -0
  170. data/lib/new_relic/agent/instrumentation/rdkafka/instrumentation.rb +70 -0
  171. data/lib/new_relic/agent/instrumentation/rdkafka/prepend.rb +67 -0
  172. data/lib/new_relic/agent/instrumentation/rdkafka.rb +25 -0
  173. data/lib/new_relic/agent/instrumentation/redis/cluster_middleware.rb +26 -0
  174. data/lib/new_relic/agent/instrumentation/redis/constants.rb +2 -2
  175. data/lib/new_relic/agent/instrumentation/redis/instrumentation.rb +18 -11
  176. data/lib/new_relic/agent/instrumentation/redis/middleware.rb +3 -0
  177. data/lib/new_relic/agent/instrumentation/redis.rb +11 -5
  178. data/lib/new_relic/agent/instrumentation/resque/instrumentation.rb +4 -0
  179. data/lib/new_relic/agent/instrumentation/resque.rb +8 -6
  180. data/lib/new_relic/agent/instrumentation/roda/chain.rb +43 -0
  181. data/lib/new_relic/agent/instrumentation/roda/ignorer.rb +45 -0
  182. data/lib/new_relic/agent/instrumentation/roda/instrumentation.rb +68 -0
  183. data/lib/new_relic/agent/instrumentation/roda/prepend.rb +24 -0
  184. data/lib/new_relic/agent/instrumentation/roda/roda_transaction_namer.rb +29 -0
  185. data/lib/new_relic/agent/instrumentation/roda.rb +36 -0
  186. data/lib/new_relic/agent/instrumentation/ruby_kafka/chain.rb +55 -0
  187. data/lib/new_relic/agent/instrumentation/ruby_kafka/instrumentation.rb +67 -0
  188. data/lib/new_relic/agent/instrumentation/ruby_kafka/prepend.rb +60 -0
  189. data/lib/new_relic/agent/instrumentation/ruby_kafka.rb +25 -0
  190. data/lib/new_relic/agent/instrumentation/ruby_openai/chain.rb +36 -0
  191. data/lib/new_relic/agent/instrumentation/ruby_openai/instrumentation.rb +196 -0
  192. data/lib/new_relic/agent/instrumentation/ruby_openai/prepend.rb +20 -0
  193. data/lib/new_relic/agent/instrumentation/ruby_openai.rb +35 -0
  194. data/lib/new_relic/agent/instrumentation/sequel.rb +1 -1
  195. data/lib/new_relic/agent/instrumentation/sidekiq/client.rb +4 -0
  196. data/lib/new_relic/agent/instrumentation/sidekiq/extensions/delay_extensions.rb +24 -0
  197. data/lib/new_relic/agent/instrumentation/sidekiq/extensions/delayed_class.rb +2 -2
  198. data/lib/new_relic/agent/instrumentation/sidekiq/server.rb +26 -3
  199. data/lib/new_relic/agent/instrumentation/sidekiq.rb +13 -16
  200. data/lib/new_relic/agent/instrumentation/sinatra/ignorer.rb +1 -1
  201. data/lib/new_relic/agent/instrumentation/sinatra/instrumentation.rb +4 -0
  202. data/lib/new_relic/agent/instrumentation/sinatra/transaction_namer.rb +1 -3
  203. data/lib/new_relic/agent/instrumentation/sinatra.rb +3 -19
  204. data/lib/new_relic/agent/instrumentation/stripe.rb +28 -0
  205. data/lib/new_relic/agent/instrumentation/stripe_subscriber.rb +98 -0
  206. data/lib/new_relic/agent/instrumentation/thread/chain.rb +1 -1
  207. data/lib/new_relic/agent/instrumentation/thread/instrumentation.rb +1 -5
  208. data/lib/new_relic/agent/instrumentation/thread/prepend.rb +1 -1
  209. data/lib/new_relic/agent/instrumentation/thread.rb +0 -2
  210. data/lib/new_relic/agent/instrumentation/tilt/instrumentation.rb +4 -0
  211. data/lib/new_relic/agent/instrumentation/tilt.rb +0 -4
  212. data/lib/new_relic/agent/instrumentation/typhoeus/instrumentation.rb +7 -3
  213. data/lib/new_relic/agent/instrumentation/typhoeus.rb +0 -1
  214. data/lib/new_relic/agent/instrumentation/view_component/chain.rb +21 -0
  215. data/lib/new_relic/agent/instrumentation/view_component/instrumentation.rb +45 -0
  216. data/lib/{tasks/instrumentation_generator/templates/instrumentation.tt → new_relic/agent/instrumentation/view_component/prepend.rb} +4 -4
  217. data/lib/new_relic/agent/instrumentation/view_component.rb +24 -0
  218. data/lib/new_relic/agent/javascript_instrumentor.rb +2 -4
  219. data/lib/new_relic/agent/llm/chat_completion_message.rb +25 -0
  220. data/lib/new_relic/agent/llm/chat_completion_summary.rb +66 -0
  221. data/lib/new_relic/agent/llm/embedding.rb +60 -0
  222. data/lib/new_relic/agent/llm/llm_event.rb +95 -0
  223. data/lib/new_relic/agent/llm/response_headers.rb +80 -0
  224. data/lib/new_relic/agent/llm.rb +49 -0
  225. data/lib/new_relic/agent/local_log_decorator.rb +20 -3
  226. data/lib/new_relic/agent/log_event_aggregator.rb +149 -26
  227. data/lib/new_relic/agent/log_event_attributes.rb +115 -0
  228. data/lib/new_relic/agent/logging.rb +5 -5
  229. data/lib/new_relic/agent/messaging.rb +18 -7
  230. data/lib/new_relic/agent/method_tracer.rb +4 -1
  231. data/lib/new_relic/agent/method_tracer_helpers.rb +26 -5
  232. data/lib/new_relic/agent/monitors/inbound_request_monitor.rb +1 -1
  233. data/lib/new_relic/agent/monitors/synthetics_monitor.rb +12 -1
  234. data/lib/new_relic/agent/new_relic_service/encoders.rb +2 -2
  235. data/lib/new_relic/agent/new_relic_service/json_marshaller.rb +2 -2
  236. data/lib/new_relic/agent/new_relic_service.rb +61 -28
  237. data/lib/new_relic/agent/obfuscator.rb +0 -2
  238. data/lib/new_relic/agent/opentelemetry/context/propagation/trace_propagator.rb +66 -0
  239. data/lib/new_relic/agent/opentelemetry/context/propagation.rb +15 -0
  240. data/lib/{tasks/instrumentation_generator/templates/Envfile.tt → new_relic/agent/opentelemetry/context.rb} +9 -5
  241. data/lib/new_relic/agent/opentelemetry/trace/span.rb +31 -0
  242. data/lib/new_relic/agent/opentelemetry/trace/tracer.rb +129 -0
  243. data/lib/new_relic/agent/opentelemetry/trace/tracer_provider.rb +18 -0
  244. data/lib/new_relic/agent/opentelemetry/trace.rb +15 -0
  245. data/lib/new_relic/agent/opentelemetry/transaction_patch.rb +69 -0
  246. data/lib/new_relic/agent/opentelemetry_bridge.rb +32 -0
  247. data/lib/new_relic/agent/parameter_filtering.rb +1 -1
  248. data/lib/new_relic/agent/pipe_channel_manager.rb +2 -2
  249. data/lib/new_relic/agent/pipe_service.rb +1 -1
  250. data/lib/new_relic/agent/rules_engine/segment_terms_rule.rb +1 -2
  251. data/lib/new_relic/agent/rules_engine.rb +1 -1
  252. data/lib/new_relic/agent/sampler.rb +1 -0
  253. data/lib/new_relic/agent/samplers/cpu_sampler.rb +1 -1
  254. data/lib/new_relic/agent/samplers/memory_sampler.rb +1 -1
  255. data/lib/new_relic/agent/serverless_handler.rb +406 -0
  256. data/lib/new_relic/agent/serverless_handler_event_sources.json +155 -0
  257. data/lib/new_relic/agent/serverless_handler_event_sources.rb +49 -0
  258. data/lib/new_relic/agent/span_event_primitive.rb +32 -15
  259. data/lib/new_relic/agent/sql_sampler.rb +0 -1
  260. data/lib/new_relic/agent/system_info.rb +40 -0
  261. data/lib/new_relic/agent/threading/agent_thread.rb +1 -2
  262. data/lib/new_relic/agent/threading/backtrace_node.rb +10 -1
  263. data/lib/new_relic/agent/tracer.rb +16 -16
  264. data/lib/new_relic/agent/transaction/abstract_segment.rb +103 -41
  265. data/lib/new_relic/agent/transaction/datastore_segment.rb +1 -1
  266. data/lib/new_relic/agent/transaction/distributed_tracer.rb +3 -3
  267. data/lib/new_relic/agent/transaction/distributed_tracing.rb +7 -8
  268. data/lib/new_relic/agent/transaction/external_request_segment.rb +5 -12
  269. data/lib/new_relic/agent/transaction/message_broker_segment.rb +5 -3
  270. data/lib/new_relic/agent/transaction/request_attributes.rb +54 -11
  271. data/lib/new_relic/agent/transaction/trace_context.rb +34 -5
  272. data/lib/new_relic/agent/transaction/tracing.rb +20 -4
  273. data/lib/new_relic/agent/transaction.rb +38 -13
  274. data/lib/new_relic/agent/transaction_error_primitive.rb +39 -19
  275. data/lib/new_relic/agent/transaction_event_primitive.rb +19 -0
  276. data/lib/new_relic/agent/transaction_time_aggregator.rb +1 -1
  277. data/lib/new_relic/agent/utilization/ecs.rb +22 -0
  278. data/lib/new_relic/agent/utilization/ecs_v4.rb +22 -0
  279. data/lib/new_relic/agent/utilization/gcp.rb +1 -3
  280. data/lib/new_relic/agent/utilization/vendor.rb +5 -7
  281. data/lib/new_relic/agent/utilization_data.rb +40 -5
  282. data/lib/new_relic/agent/vm/{mri_vm.rb → c_ruby_vm.rb} +10 -18
  283. data/lib/new_relic/agent/vm.rb +2 -2
  284. data/lib/new_relic/agent/worker_loop.rb +1 -1
  285. data/lib/new_relic/agent.rb +286 -17
  286. data/lib/new_relic/base64.rb +25 -0
  287. data/lib/new_relic/cli/command.rb +6 -3
  288. data/lib/new_relic/constants.rb +8 -0
  289. data/lib/new_relic/control/class_methods.rb +1 -7
  290. data/lib/new_relic/control/frameworks/grape.rb +14 -0
  291. data/lib/new_relic/control/frameworks/padrino.rb +14 -0
  292. data/lib/new_relic/control/frameworks/rails.rb +17 -5
  293. data/lib/new_relic/control/frameworks/rails4.rb +1 -3
  294. data/lib/new_relic/control/frameworks/roda.rb +20 -0
  295. data/lib/new_relic/control/instance_methods.rb +13 -0
  296. data/lib/new_relic/control/instrumentation.rb +2 -16
  297. data/lib/new_relic/control/private_instance_methods.rb +4 -0
  298. data/lib/new_relic/control/security_interface.rb +57 -0
  299. data/lib/new_relic/control.rb +1 -1
  300. data/lib/new_relic/dependency_detection.rb +25 -13
  301. data/lib/new_relic/environment_report.rb +2 -2
  302. data/lib/new_relic/helper.rb +22 -0
  303. data/lib/new_relic/language_support.rb +12 -1
  304. data/lib/new_relic/latest_changes.rb +1 -1
  305. data/lib/new_relic/local_environment.rb +31 -18
  306. data/lib/new_relic/noticed_error.rb +5 -2
  307. data/lib/new_relic/rack/agent_hooks.rb +1 -1
  308. data/lib/new_relic/rack/agent_middleware.rb +0 -16
  309. data/lib/new_relic/rack/browser_monitoring.rb +29 -13
  310. data/lib/new_relic/supportability_helper.rb +5 -1
  311. data/lib/new_relic/thread_local_storage.rb +31 -0
  312. data/lib/new_relic/traced_thread.rb +2 -3
  313. data/lib/new_relic/version.rb +1 -1
  314. data/lib/sequel/extensions/new_relic_instrumentation.rb +4 -3
  315. data/lib/tasks/bump_version.rake +21 -0
  316. data/lib/tasks/config.rake +11 -5
  317. data/lib/tasks/coverage_report.rake +1 -1
  318. data/lib/tasks/gha.rake +31 -0
  319. data/lib/tasks/helpers/config.html.erb +94 -0
  320. data/lib/tasks/helpers/format.rb +11 -7
  321. data/lib/tasks/helpers/newrelicyml.rb +211 -0
  322. data/lib/tasks/helpers/version_bump.rb +62 -0
  323. data/lib/tasks/newrelic.rb +1 -0
  324. data/lib/tasks/newrelicyml.rake +13 -0
  325. data/lib/tasks/tests.rake +71 -0
  326. data/newrelic.yml +657 -251
  327. data/newrelic_rpm.gemspec +17 -10
  328. data/test/agent_helper.rb +38 -4
  329. metadata +230 -44
  330. data/.gitignore +0 -43
  331. data/.project +0 -23
  332. data/.rubocop.yml +0 -1909
  333. data/.rubocop_todo.yml +0 -61
  334. data/.simplecov +0 -15
  335. data/.snyk +0 -11
  336. data/.yardopts +0 -27
  337. data/Brewfile +0 -12
  338. data/DOCKER.md +0 -167
  339. data/Dockerfile +0 -10
  340. data/Guardfile +0 -26
  341. data/bin/newrelic_cmd +0 -6
  342. data/config/database.yml +0 -5
  343. data/config.dot +0 -278
  344. data/docker-compose.yml +0 -107
  345. data/lefthook.yml +0 -9
  346. data/lib/new_relic/agent/range_extensions.rb +0 -27
  347. data/lib/tasks/helpers/removers.rb +0 -33
  348. data/lib/tasks/instrumentation_generator/README.md +0 -63
  349. data/lib/tasks/instrumentation_generator/TODO.md +0 -33
  350. data/lib/tasks/instrumentation_generator/instrumentation.thor +0 -121
  351. data/lib/tasks/instrumentation_generator/templates/chain.tt +0 -22
  352. data/lib/tasks/instrumentation_generator/templates/chain_method.tt +0 -8
  353. data/lib/tasks/instrumentation_generator/templates/dependency_detection.tt +0 -29
  354. data/lib/tasks/instrumentation_generator/templates/instrumentation_method.tt +0 -3
  355. data/lib/tasks/instrumentation_generator/templates/newrelic.yml.tt +0 -19
  356. data/lib/tasks/instrumentation_generator/templates/prepend.tt +0 -13
  357. data/lib/tasks/instrumentation_generator/templates/prepend_method.tt +0 -3
  358. data/lib/tasks/instrumentation_generator/templates/test.tt +0 -15
  359. data/lib/tasks/multiverse.rake +0 -6
  360. data/lib/tasks/multiverse.rb +0 -83
@@ -92,16 +92,20 @@ module NewRelic
92
92
  elsif type == Symbol
93
93
  self[config_key] = value.to_sym
94
94
  elsif type == Array
95
- self[config_key] = value.split(/\s*,\s*/)
95
+ self[config_key] = if DEFAULTS[config_key].key?(:transform)
96
+ DEFAULTS[config_key][:transform].call(value)
97
+ else
98
+ value.split(/\s*,\s*/)
99
+ end
96
100
  elsif type == NewRelic::Agent::Configuration::Boolean
97
101
  if /false|off|no/i.match?(value)
98
102
  self[config_key] = false
99
103
  elsif !value.nil?
100
104
  self[config_key] = true
101
105
  end
102
- else
106
+ elsif !serverless?
103
107
  ::NewRelic::Agent.logger.info("#{environment_key} does not have a corresponding configuration setting (#{config_key} does not exist).")
104
- ::NewRelic::Agent.logger.info('Run `rake newrelic:config:docs` or visit https://newrelic.com/docs/ruby/ruby-agent-configuration to see a list of available configuration settings.')
108
+ ::NewRelic::Agent.logger.info('Run `rake newrelic:config:docs` or visit https://docs.newrelic.com/docs/apm/agents/ruby-agent/configuration/ruby-agent-configuration to see a list of available configuration settings.')
105
109
  self[config_key] = value
106
110
  end
107
111
  end
@@ -114,6 +118,14 @@ module NewRelic
114
118
  def collect_new_relic_environment_variable_keys
115
119
  ENV.keys.select { |key| key.match(SUPPORTED_PREFIXES) }
116
120
  end
121
+
122
+ # we can't rely on the :'serverless_mode.enabled' config parameter being
123
+ # set yet to signify serverless mode given that we're in the midst of
124
+ # building the config but we can always rely on the env var being set
125
+ # by the Lambda layer
126
+ def serverless?
127
+ NewRelic::Agent::ServerlessHandler.env_var_set?
128
+ end
117
129
  end
118
130
  end
119
131
  end
@@ -19,6 +19,7 @@ module NewRelic
19
19
  :'elasticsearch.obfuscate_queries' => true,
20
20
  :'transaction_tracer.record_redis_arguments' => false,
21
21
 
22
+ :'ai_monitoring.enabled' => false,
22
23
  :'custom_insights_events.enabled' => false,
23
24
  :'strip_exception_messages.enabled' => true
24
25
  })
@@ -15,6 +15,8 @@ module NewRelic
15
15
  module Agent
16
16
  module Configuration
17
17
  class Manager
18
+ DEPENDENCY_DETECTION_VALUES = %i[prepend chain unsatisfied].freeze
19
+
18
20
  # Defining these explicitly saves object allocations that we incur
19
21
  # if we use Forwardable and def_delegators.
20
22
  def [](key)
@@ -32,6 +34,7 @@ module NewRelic
32
34
  def initialize
33
35
  reset_to_defaults
34
36
  @callbacks = Hash.new { |hash, key| hash[key] = [] }
37
+ @lock = Mutex.new
35
38
  end
36
39
 
37
40
  def add_config_for_testing(source, level = 0)
@@ -135,7 +138,14 @@ module NewRelic
135
138
  end
136
139
 
137
140
  def evaluate_and_apply_transformations(key, value)
138
- apply_transformations(key, evaluate_procs(value))
141
+ evaluated = evaluate_procs(value)
142
+ default = enforce_allowlist(key, evaluated)
143
+ return default if default
144
+
145
+ boolean = enforce_boolean(key, value)
146
+ evaluated = boolean if [true, false].include?(boolean)
147
+
148
+ apply_transformations(key, evaluated)
139
149
  end
140
150
 
141
151
  def apply_transformations(key, value)
@@ -143,7 +153,7 @@ module NewRelic
143
153
  begin
144
154
  transform.call(value)
145
155
  rescue => e
146
- ::NewRelic::Agent.logger.error("Error applying transformation for #{key}, pre-transform value was: #{value}.", e)
156
+ NewRelic::Agent.logger.error("Error applying transformation for #{key}, pre-transform value was: #{value}.", e)
147
157
  raise e
148
158
  end
149
159
  else
@@ -151,8 +161,33 @@ module NewRelic
151
161
  end
152
162
  end
153
163
 
164
+ def enforce_allowlist(key, value)
165
+ return unless allowlist = default_source.allowlist_for(key)
166
+ return if allowlist.include?(value)
167
+
168
+ default = default_source.default_for(key)
169
+ NewRelic::Agent.logger.warn "Invalid value '#{value}' for #{key}, applying default value of '#{default}'"
170
+ default
171
+ end
172
+
173
+ def enforce_boolean(key, value)
174
+ type = default_source.value_from_defaults(key, :type)
175
+ return unless type == Boolean
176
+
177
+ bool_value = default_source.boolean_for(key, value)
178
+ return bool_value unless bool_value.nil?
179
+
180
+ default = default_source.default_for(key)
181
+ NewRelic::Agent.logger.warn "Invalid value '#{value}' for #{key}, applying default value of '#{default}'"
182
+ default
183
+ end
184
+
154
185
  def transform_from_default(key)
155
- ::NewRelic::Agent::Configuration::DefaultSource.transform_for(key)
186
+ default_source.transform_for(key)
187
+ end
188
+
189
+ def default_source
190
+ NewRelic::Agent::Configuration::DefaultSource
156
191
  end
157
192
 
158
193
  def register_callback(key, &proc)
@@ -211,7 +246,7 @@ module NewRelic
211
246
  begin
212
247
  thawed_layer[k] = instance_eval(&v) if v.respond_to?(:call)
213
248
  rescue => e
214
- ::NewRelic::Agent.logger.debug("#{e.class.name} : #{e.message} - when accessing config key #{k}")
249
+ NewRelic::Agent.logger.debug("#{e.class.name} : #{e.message} - when accessing config key #{k}")
215
250
  thawed_layer[k] = nil
216
251
  end
217
252
  thawed_layer.delete(:config)
@@ -228,7 +263,7 @@ module NewRelic
228
263
  end
229
264
 
230
265
  def to_collector_hash
231
- DottedHash.new(apply_mask(flattened)).to_hash.delete_if do |k, v|
266
+ DottedHash.new(apply_mask(flattened)).to_hash.delete_if do |k, _v|
232
267
  default = DEFAULTS[k]
233
268
  if default
234
269
  default[:exclude_from_reported_settings]
@@ -347,6 +382,7 @@ module NewRelic
347
382
  @security_policy_source = nil
348
383
  @high_security_source = nil
349
384
  @environment_source = EnvironmentSource.new
385
+ log_config(:add, @environment_source) # this is the only place the EnvironmentSource is ever created, so we should log it
350
386
  @server_source = nil
351
387
  @manual_source = nil
352
388
  @yaml_source = nil
@@ -357,17 +393,42 @@ module NewRelic
357
393
  reset_cache
358
394
  end
359
395
 
396
+ # reset the configuration hash, but do not replace previously auto
397
+ # determined dependency detection values with nil or 'auto'
360
398
  def reset_cache
399
+ return new_cache unless defined?(@cache) && @cache
400
+
401
+ # Modifying the @cache hash under JRuby - even with a `synchronize do`
402
+ # block and a `Hash#dup` operation - has been known to cause issues
403
+ # with JRuby for concurrent access of the hash while it is being
404
+ # modified. The hash really only needs to be modified for the benefit
405
+ # of the security agent, so if JRuby is in play and the security agent
406
+ # is not, don't attempt to modify the hash at all and return early.
407
+ return new_cache if NewRelic::LanguageSupport.jruby? && !Agent.config[:'security.agent.enabled']
408
+
409
+ @lock.synchronize do
410
+ preserved = @cache.dup.select { |_k, v| DEPENDENCY_DETECTION_VALUES.include?(v) }
411
+ new_cache
412
+ preserved.each { |k, v| @cache[k] = v }
413
+ end
414
+
415
+ @cache
416
+ end
417
+
418
+ def new_cache
361
419
  @cache = Hash.new { |hash, key| hash[key] = self.fetch(key) }
362
420
  end
363
421
 
364
422
  def log_config(direction, source)
365
- # Just generating this log message (specifically calling
366
- # flattened.inspect) is expensive enough that we don't want to do it
367
- # unless we're actually going to be logging the message based on our
368
- # current log level.
369
- ::NewRelic::Agent.logger.debug do
370
- "Updating config (#{direction}) from #{source.class}. Results: #{flattened.inspect}"
423
+ # Just generating this log message (specifically calling `flattened`)
424
+ # is expensive enough that we don't want to do it unless we're
425
+ # actually going to be logging the message based on our current log
426
+ # level, so use a `do` block.
427
+ NewRelic::Agent.logger.debug do
428
+ source_hash = source.dup.to_h.delete_if { |k, _v| DEFAULTS.fetch(k, {}).fetch(:exclude_from_reported_settings, false) }
429
+ final_hash = flattened.delete_if { |k, _h| DEFAULTS.fetch(k, {}).fetch(:exclude_from_reported_settings, false) }
430
+
431
+ "Updating config (#{direction}) from #{source.class} with values: #{source_hash}. \nConfig Stack Results: #{final_hash.inspect}"
371
432
  end
372
433
  end
373
434
 
@@ -7,6 +7,8 @@ require 'new_relic/agent/configuration/dotted_hash'
7
7
  module NewRelic
8
8
  module Agent
9
9
  module Configuration
10
+ # The Language Security Policy Source gives customers the ability to
11
+ # configure high security mode settings.
10
12
  class SecurityPolicySource < DottedHash
11
13
  class << self
12
14
  def enabled?(option)
@@ -147,6 +149,15 @@ module NewRelic
147
149
  permitted_fn: nil
148
150
  }
149
151
  ],
152
+ 'ai_monitoring' => [
153
+ {
154
+ option: :'ai_monitoring.enabled',
155
+ supported: true,
156
+ enabled_fn: method(:enabled?),
157
+ disabled_value: false,
158
+ permitted_fn: nil
159
+ }
160
+ ],
150
161
  'allow_raw_exception_messages' => [
151
162
  {
152
163
  option: :'strip_exception_messages.enabled',
@@ -36,11 +36,13 @@ module NewRelic
36
36
  erb_file = process_erb(raw_file)
37
37
  config = process_yaml(erb_file, env, config, @file_path)
38
38
  rescue ScriptError, StandardError => e
39
+ NewRelic::Agent.agent&.health_check&.update_status(NewRelic::Agent::HealthCheck::FAILED_TO_PARSE_CONFIG)
39
40
  log_failure("Failed to read or parse configuration file at #{path}", e)
40
41
  end
41
42
 
42
43
  substitute_transaction_threshold(config)
43
44
  booleanify_values(config, 'agent_enabled', 'enabled')
45
+ apply_aliases(config)
44
46
 
45
47
  super(config, true)
46
48
  end
@@ -52,6 +54,8 @@ module NewRelic
52
54
  protected
53
55
 
54
56
  def validate_config_file_path(path)
57
+ return if NewRelic::Agent.config[:'serverless_mode.enabled']
58
+
55
59
  expanded_path = File.expand_path(path)
56
60
 
57
61
  if path.empty? || !File.exist?(expanded_path)
@@ -63,7 +67,7 @@ module NewRelic
63
67
  end
64
68
 
65
69
  def warn_missing_config_file(path)
66
- based_on = 'unknown'
70
+ based_on = NewRelic::UNKNOWN_LOWER
67
71
  source = ::NewRelic::Agent.config.source(:config_path)
68
72
  candidate_paths = [path]
69
73
 
@@ -96,7 +100,11 @@ module NewRelic
96
100
  file.gsub!(/^\s*#.*$/, '#')
97
101
  ERB.new(file).result(binding)
98
102
  rescue ScriptError, StandardError => e
99
- log_failure('Failed ERB processing configuration file. This is typically caused by a Ruby error in <% %> templating blocks in your newrelic.yml file.', e)
103
+ NewRelic::Agent.agent&.health_check&.update_status(NewRelic::Agent::HealthCheck::FAILED_TO_PARSE_CONFIG)
104
+ message = 'Failed ERB processing configuration file. This is typically caused by a Ruby error in <% %> templating blocks in your newrelic.yml file.'
105
+ failure_array = [message, e]
106
+ failure_array << e.backtrace[0] if NewRelic::Helper.version_satisfied?(RUBY_VERSION, '>=', '3.4.0')
107
+ log_failure(*failure_array)
100
108
  nil
101
109
  end
102
110
  end
@@ -165,6 +173,18 @@ module NewRelic
165
173
  end
166
174
  result
167
175
  end
176
+
177
+ def apply_aliases(config)
178
+ DEFAULTS.each do |config_setting, value|
179
+ next unless value[:aliases]
180
+
181
+ value[:aliases].each do |config_alias|
182
+ next unless config[config_setting].nil? && !config[config_alias.to_s].nil?
183
+
184
+ config[config_setting] = config[config_alias.to_s]
185
+ end
186
+ end
187
+ end
168
188
  end
169
189
  end
170
190
  end
@@ -24,7 +24,7 @@ module NewRelic
24
24
  :host => local_host,
25
25
  :display_host => Agent.config[:'process_host.display_name'],
26
26
  :app_name => Agent.config[:app_name],
27
- :language => 'ruby',
27
+ :language => LANGUAGE,
28
28
  :labels => Agent.config.parsed_labels,
29
29
  :agent_version => NewRelic::VERSION::STRING,
30
30
  :environment => @environment_report,
@@ -14,6 +14,9 @@ module NewRelic
14
14
  TIMESTAMP = 'timestamp'.freeze
15
15
  PRIORITY = 'priority'.freeze
16
16
  EVENT_TYPE_REGEX = /^[a-zA-Z0-9:_ ]+$/.freeze
17
+ MAX_ATTRIBUTE_COUNT = 64
18
+ MAX_ATTRIBUTE_SIZE = 4095
19
+ MAX_NAME_SIZE = 255
17
20
 
18
21
  named :CustomEventAggregator
19
22
  capacity_key :'custom_insights_events.max_samples_stored'
@@ -49,10 +52,33 @@ module NewRelic
49
52
  {TYPE => type,
50
53
  TIMESTAMP => Process.clock_gettime(Process::CLOCK_REALTIME).to_i,
51
54
  PRIORITY => priority},
52
- AttributeProcessing.flatten_and_coerce(attributes)
55
+ create_custom_event_attributes(type, attributes)
53
56
  ]
54
57
  end
55
58
 
59
+ def create_custom_event_attributes(type, attributes)
60
+ result = AttributeProcessing.flatten_and_coerce(attributes)
61
+
62
+ if result.size > MAX_ATTRIBUTE_COUNT
63
+ NewRelic::Agent.logger.warn("Custom event attributes are limited to #{MAX_ATTRIBUTE_COUNT}. Discarding #{result.size - MAX_ATTRIBUTE_COUNT} attributes")
64
+ result = result.first(MAX_ATTRIBUTE_COUNT)
65
+ end
66
+
67
+ result.each_with_object({}) do |(key, val), new_result|
68
+ # name is limited to 255
69
+ if key.is_a?(String) && key.length > MAX_NAME_SIZE
70
+ key = key[0, MAX_NAME_SIZE]
71
+ end
72
+
73
+ # value is limited to 4095 except for LLM content-related events
74
+ if val.is_a?(String) && val.length > MAX_ATTRIBUTE_SIZE
75
+ val = val[0, MAX_ATTRIBUTE_SIZE] unless NewRelic::Agent::LLM.exempt_event_attribute?(type, key)
76
+ end
77
+
78
+ new_result[key] = val
79
+ end
80
+ end
81
+
56
82
  def after_initialize
57
83
  @type_strings = Hash.new { |hash, key| hash[key] = key.to_s.freeze }
58
84
  end
@@ -7,17 +7,17 @@ module NewRelic
7
7
  module Database
8
8
  module ObfuscationHelpers
9
9
  COMPONENTS_REGEX_MAP = {
10
- :single_quotes => /'(?:[^']|'')*?(?:\\'.*|'(?!'))/,
11
- :double_quotes => /"(?:[^"]|"")*?(?:\\".*|"(?!"))/,
12
- :dollar_quotes => /(\$(?!\d)[^$]*?\$).*?(?:\1|$)/,
13
- :uuids => /\{?(?:[0-9a-fA-F]\-*){32}\}?/,
14
- :numeric_literals => /-?\b(?:[0-9]+\.)?[0-9]+([eE][+-]?[0-9]+)?\b/,
15
- :boolean_literals => /\b(?:true|false|null)\b/i,
16
- :hexadecimal_literals => /0x[0-9a-fA-F]+/,
17
- :comments => /(?:#|--).*?(?=\r|\n|$)/i,
18
- :multi_line_comments => /\/\*(?:[^\/]|\/[^*])*?(?:\*\/|\/\*.*)/,
19
- :oracle_quoted_strings => /q'\[.*?(?:\]'|$)|q'\{.*?(?:\}'|$)|q'\<.*?(?:\>'|$)|q'\(.*?(?:\)'|$)/
20
- }
10
+ single_quotes: /'(?:[^']|'')*?(?:\\'.*|'(?!'))/,
11
+ double_quotes: /"(?:[^"]|"")*?(?:\\".*|"(?!"))/,
12
+ dollar_quotes: /(\$(?!\d)[^$]*?\$).*?(?:\1|$)/,
13
+ uuids: /\{?(?:[0-9a-fA-F]-*){32}\}?/,
14
+ numeric_literals: /-?\b(?:[0-9]+\.)?[0-9]+([eE][+-]?[0-9]+)?\b/,
15
+ boolean_literals: /\b(?:true|false|null)\b/i,
16
+ hexadecimal_literals: /0x[0-9a-fA-F]+/,
17
+ comments: /(?:#|--).*?(?=\r|\n|$)/i,
18
+ multi_line_comments: %r{/\*.*?\*/}m,
19
+ oracle_quoted_strings: /q'\[.*?(?:\]'|$)|q'\{.*?(?:\}'|$)|q'<.*?(?:>'|$)|q'\(.*?(?:\)'|$)/
20
+ }.freeze
21
21
 
22
22
  DIALECT_COMPONENTS = {
23
23
  :fallback => COMPONENTS_REGEX_MAP.keys,
@@ -2,6 +2,7 @@
2
2
  # See https://github.com/newrelic/newrelic-ruby-agent/blob/main/LICENSE for complete details.
3
3
  # frozen_string_literal: true
4
4
 
5
+ require 'singleton'
5
6
  require 'new_relic/agent/database/obfuscation_helpers'
6
7
 
7
8
  module NewRelic
@@ -90,6 +90,42 @@ module NewRelic
90
90
  ConnectionManager.instance.get_connection(config, &connector)
91
91
  end
92
92
 
93
+ def explain_this(statement, use_execute = false)
94
+ if supports_with_connection?
95
+ explain_this_using_with_connection(statement)
96
+ else
97
+ explain_this_using_adapter_connection(statement, use_execute)
98
+ end
99
+ rescue => e
100
+ NewRelic::Agent.logger.error("Couldn't fetch the explain plan for statement: #{e}")
101
+ end
102
+
103
+ def explain_this_using_with_connection(statement)
104
+ ::ActiveRecord::Base.with_connection do |conn|
105
+ conn.exec_query("EXPLAIN #{statement.sql}", "Explain #{statement.name}", statement.binds)
106
+ end
107
+ end
108
+
109
+ def explain_this_using_adapter_connection(statement, use_execute)
110
+ connection = get_connection(statement.config) do
111
+ ::ActiveRecord::Base.send(:"#{statement.config[:adapter]}_connection", statement.config)
112
+ end
113
+
114
+ if use_execute
115
+ connection.execute("EXPLAIN #{statement.sql}")
116
+ else
117
+ connection.exec_query("EXPLAIN #{statement.sql}", "Explain #{statement.name}", statement.binds)
118
+ end
119
+ end
120
+
121
+ # ActiveRecord v7.2.0 introduced with_connection
122
+ def supports_with_connection?
123
+ return @supports_with_connection if defined?(@supports_with_connection)
124
+
125
+ @supports_with_connection = defined?(::ActiveRecord::VERSION::STRING) &&
126
+ NewRelic::Helper.version_satisfied?(ActiveRecord::VERSION::STRING, '>=', '7.2.0')
127
+ end
128
+
93
129
  def close_connections
94
130
  ConnectionManager.instance.close_connections
95
131
  end
@@ -241,9 +277,11 @@ module NewRelic
241
277
  MYSQL_PREFIX = 'mysql'.freeze
242
278
  MYSQL2_PREFIX = 'mysql2'.freeze
243
279
  SQLITE_PREFIX = 'sqlite'.freeze
280
+ TRILOGY_PREFIX = 'trilogy'.freeze
281
+ REDSHIFT_PREFIX = 'redshift'.freeze
244
282
 
245
283
  def symbolized_adapter(adapter)
246
- if adapter.start_with?(POSTGRES_PREFIX) || adapter == POSTGIS_PREFIX
284
+ if adapter.start_with?(POSTGRES_PREFIX) || adapter == POSTGIS_PREFIX || adapter == REDSHIFT_PREFIX
247
285
  :postgres
248
286
  elsif adapter == MYSQL_PREFIX
249
287
  :mysql
@@ -253,6 +291,8 @@ module NewRelic
253
291
  :mysql2
254
292
  elsif adapter.start_with?(SQLITE_PREFIX)
255
293
  :sqlite
294
+ elsif adapter == TRILOGY_PREFIX
295
+ :trilogy
256
296
  else
257
297
  adapter.to_sym
258
298
  end
@@ -25,7 +25,7 @@ module NewRelic
25
25
  end
26
26
 
27
27
  def value
28
- match = VERSIONS.keys.find { |key| version >= Gem::Version.new(key) }
28
+ match = VERSIONS.keys.find { |key| NewRelic::Helper.version_satisfied?(version, '>=', key) }
29
29
  return unless match
30
30
 
31
31
  VERSIONS[match].call(env)
@@ -128,7 +128,7 @@ module NewRelic
128
128
  end
129
129
 
130
130
  def self.drop_indexes?(name, payload)
131
- name == :deleteIndexes && payload[:selector] && payload[:selector][:index] == '*'
131
+ name == :deleteIndexes && payload[:selector] && payload[:selector][:index] == ASTERISK
132
132
  end
133
133
 
134
134
  def self.drop_index?(name, payload)
@@ -83,7 +83,7 @@ module NewRelic
83
83
  end
84
84
 
85
85
  def self.is_supported_version?
86
- Gem::Version.new(::Redis::VERSION) >= Gem::Version.new('3.0.0')
86
+ NewRelic::Helper.version_satisfied?(::Redis::VERSION, '>=', '3.0.0')
87
87
  end
88
88
 
89
89
  def self.ellipsize(result, string)
@@ -207,7 +207,7 @@ module NewRelic
207
207
  decoded_appdata.set_encoding(::Encoding::UTF_8) if
208
208
  decoded_appdata.respond_to?(:set_encoding)
209
209
 
210
- ::JSON.load(decoded_appdata)
210
+ ::JSON.parse(decoded_appdata)
211
211
  end
212
212
 
213
213
  def valid_cross_app_id?(xp_id)
@@ -3,7 +3,7 @@
3
3
  # frozen_string_literal: true
4
4
 
5
5
  require 'json'
6
- require 'base64'
6
+ require 'new_relic/base64'
7
7
 
8
8
  module NewRelic
9
9
  module Agent
@@ -35,7 +35,7 @@ module NewRelic
35
35
 
36
36
  class << self
37
37
  def for_transaction(transaction)
38
- return nil unless connected?
38
+ return nil unless Agent.instance.connected?
39
39
 
40
40
  payload = new
41
41
  payload.version = VERSION
@@ -78,7 +78,7 @@ module NewRelic
78
78
  end
79
79
 
80
80
  def from_http_safe(http_safe_payload)
81
- decoded_payload = Base64.strict_decode64(http_safe_payload)
81
+ decoded_payload = NewRelic::Base64.strict_decode64(http_safe_payload)
82
82
  from_json(decoded_payload)
83
83
  end
84
84
 
@@ -101,10 +101,6 @@ module NewRelic
101
101
  transaction.current_segment.guid
102
102
  end
103
103
  end
104
-
105
- def connected?
106
- Agent.instance.connected?
107
- end
108
104
  end
109
105
 
110
106
  attr_accessor :version,
@@ -156,7 +152,7 @@ module NewRelic
156
152
  #
157
153
  # @api public
158
154
  def http_safe
159
- Base64.strict_encode64(text)
155
+ NewRelic::Base64.strict_encode64(text)
160
156
  end
161
157
  end
162
158
  end
@@ -39,13 +39,14 @@ module NewRelic
39
39
  # @return {Transaction} The transaction the headers were inserted from,
40
40
  # or +nil+ if headers were not inserted.
41
41
  #
42
+ # @!scope class
42
43
  # @api public
43
44
  #
44
45
  def insert_distributed_trace_headers(headers = {})
45
46
  record_api_supportability_metric(:insert_distributed_trace_headers)
46
47
 
47
48
  unless Agent.config[:'distributed_tracing.enabled']
48
- NewRelic::Agent.logger.warn('Not configured to insert distributed trace headers')
49
+ NewRelic::Agent.logger.debug('Not configured to insert distributed trace headers')
49
50
  return nil
50
51
  end
51
52
 
@@ -87,19 +88,20 @@ module NewRelic
87
88
  # header-friendly string returned from
88
89
  # {DistributedTracePayload#http_safe}
89
90
  #
90
- # @param transport_Type [String] May be one of: +HTTP+, +HTTPS+, +Kafka+, +JMS+,
91
+ # @param transport_type [String] May be one of: +HTTP+, +HTTPS+, +Kafka+, +JMS+,
91
92
  # +IronMQ+, +AMQP+, +Queue+, +Other+. Values are
92
93
  # case sensitive. All other values result in +Unknown+
93
94
  #
94
95
  # @return {Transaction} if successful, +nil+ otherwise
95
96
  #
97
+ # @!scope class
96
98
  # @api public
97
99
  #
98
100
  def accept_distributed_trace_headers(headers, transport_type = NewRelic::HTTP)
99
101
  record_api_supportability_metric(:accept_distributed_trace_headers)
100
102
 
101
103
  unless Agent.config[:'distributed_tracing.enabled']
102
- NewRelic::Agent.logger.warn('Not configured to accept distributed trace headers')
104
+ NewRelic::Agent.logger.debug('Not configured to accept distributed trace headers')
103
105
  return nil
104
106
  end
105
107
 
@@ -110,6 +110,29 @@ module NewRelic
110
110
  false
111
111
  end
112
112
 
113
+ # Neither ignored nor expected errors impact apdex.
114
+ #
115
+ # Ignored errors are checked via `#error_is_ignored?`
116
+ # Expected errors are checked in 2 separate ways:
117
+ # 1. The presence of an `expected: true` attribute key/value pair in the
118
+ # options hash, which will be set if that key/value pair was used in
119
+ # the `notice_error` public API.
120
+ # 2. By calling `#expected?` which in turn calls `ErrorFilter#expected?`
121
+ # which checks for 3 things:
122
+ # - A match for user-defined HTTP status codes to expect
123
+ # - A match for user-defined error classes to expect
124
+ # - A match for user-defined error messages to expect
125
+ def error_affects_apdex?(error, options)
126
+ return false if error_is_ignored?(error)
127
+ return false if options[:expected]
128
+
129
+ !expected?(error, ::NewRelic::Agent::Tracer.state.current_transaction&.http_response_code)
130
+ rescue => e
131
+ NewRelic::Agent.logger.error("Could not determine if error '#{error}' should impact Apdex - " \
132
+ "#{e.class}: #{e.message}. Defaulting to 'true' (it should impact Apdex).")
133
+ true
134
+ end
135
+
113
136
  # Calling instance_variable_set on a wrapped Java object in JRuby will
114
137
  # generate a warning unless that object's class has already been marked
115
138
  # as persistent, so we skip tagging of exception objects that are actually
@@ -214,7 +237,10 @@ module NewRelic
214
237
  end
215
238
 
216
239
  def notice_segment_error(segment, exception, options = {})
217
- return if skip_notice_error?(exception)
240
+ status_code = process_http_status_code(exception, options)
241
+ return if skip_notice_error?(exception, status_code)
242
+
243
+ options.merge!(segment.llm_event.error_attributes(exception)) if segment.llm_event
218
244
 
219
245
  segment.set_noticed_error(create_noticed_error(exception, options))
220
246
  exception
@@ -225,15 +251,13 @@ module NewRelic
225
251
 
226
252
  # See NewRelic::Agent.notice_error for options and commentary
227
253
  def notice_error(exception, options = {}, span_id = nil)
228
- state = ::NewRelic::Agent::Tracer.state
229
- transaction = state.current_transaction
230
- status_code = transaction&.http_response_code
231
-
254
+ status_code = process_http_status_code(exception, options)
232
255
  return if skip_notice_error?(exception, status_code)
233
256
 
234
257
  tag_exception(exception)
235
258
 
236
- if options[:expected] || @error_filter.expected?(exception, status_code)
259
+ state = ::NewRelic::Agent::Tracer.state
260
+ if options[:expected]
237
261
  increment_expected_error_count!(state, exception)
238
262
  else
239
263
  increment_error_count!(state, exception, options)
@@ -241,10 +265,8 @@ module NewRelic
241
265
 
242
266
  noticed_error = create_noticed_error(exception, options)
243
267
  error_trace_aggregator.add_to_error_queue(noticed_error)
244
- transaction = state.current_transaction
245
- payload = transaction&.payload
246
- span_id ||= transaction&.current_segment ? transaction.current_segment.guid : nil
247
- error_event_aggregator.record(noticed_error, payload, span_id)
268
+ span_id ||= state.current_transaction&.current_segment&.guid
269
+ error_event_aggregator.record(noticed_error, state.current_transaction&.payload, span_id)
248
270
  exception
249
271
  rescue => e
250
272
  ::NewRelic::Agent.logger.warn("Failure when capturing error '#{exception}':", e)
@@ -277,7 +299,7 @@ module NewRelic
277
299
  noticed_error.line_number = sense_method(exception, :line_number)
278
300
  noticed_error.stack_trace = truncate_trace(extract_stack_trace(exception))
279
301
 
280
- noticed_error.expected = !options.delete(:expected).nil? || expected?(exception)
302
+ noticed_error.expected = !!options.delete(:expected) || expected?(exception) # rubocop:disable Style/DoubleNegation
281
303
 
282
304
  noticed_error.attributes_from_notice_error = options.delete(:custom_params) || {}
283
305
 
@@ -334,6 +356,13 @@ module NewRelic
334
356
  def error_group_callback
335
357
  NewRelic::Agent.error_group_callback
336
358
  end
359
+
360
+ def process_http_status_code(exception, options)
361
+ status_code = ::NewRelic::Agent::Tracer.state.current_transaction&.http_response_code
362
+ options[:expected] = true if !options[:expected] && @error_filter.expected?(exception, status_code)
363
+
364
+ status_code
365
+ end
337
366
  end
338
367
  end
339
368
  end