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
@@ -0,0 +1,36 @@
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 OpenAI::Chain
7
+ def self.instrument!
8
+ ::OpenAI::Client.class_eval do
9
+ include NewRelic::Agent::Instrumentation::OpenAI
10
+
11
+ alias_method(:json_post_without_new_relic, :json_post)
12
+
13
+ # In versions 4.0.0+ json_post is an instance method
14
+ # defined in the OpenAI::HTTP module, included by the
15
+ # OpenAI::Client class
16
+ def json_post(**kwargs)
17
+ json_post_with_new_relic(**kwargs) do
18
+ json_post_without_new_relic(**kwargs)
19
+ end
20
+ end
21
+
22
+ # In versions below 4.0.0 json_post is a class method
23
+ # on OpenAI::Client
24
+ class << self
25
+ alias_method(:json_post_without_new_relic, :json_post)
26
+
27
+ def json_post(**kwargs)
28
+ json_post_with_new_relic(**kwargs) do
29
+ json_post_without_new_relic(**kwargs)
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,196 @@
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 OpenAI
7
+ VENDOR = 'openAI' # AIM expects this capitalization style for the UI
8
+ INSTRUMENTATION_NAME = NewRelic::Agent.base_name(name)
9
+ EMBEDDINGS_PATH = '/embeddings'
10
+ CHAT_COMPLETIONS_PATH = '/chat/completions'
11
+ EMBEDDINGS_SEGMENT_NAME = 'Llm/embedding/OpenAI/embeddings'
12
+ CHAT_COMPLETIONS_SEGMENT_NAME = 'Llm/completion/OpenAI/chat'
13
+
14
+ def json_post_with_new_relic(path:, parameters:)
15
+ return yield unless path == EMBEDDINGS_PATH || path == CHAT_COMPLETIONS_PATH
16
+
17
+ NewRelic::Agent.record_instrumentation_invocation(INSTRUMENTATION_NAME)
18
+ NewRelic::Agent::Llm::LlmEvent.set_llm_agent_attribute_on_transaction
19
+ record_openai_metric
20
+
21
+ if path == EMBEDDINGS_PATH
22
+ embeddings_instrumentation(parameters) { yield }
23
+ elsif path == CHAT_COMPLETIONS_PATH
24
+ chat_completions_instrumentation(parameters) { yield }
25
+ end
26
+ end
27
+
28
+ private
29
+
30
+ def embeddings_instrumentation(parameters)
31
+ segment = NewRelic::Agent::Tracer.start_segment(name: EMBEDDINGS_SEGMENT_NAME)
32
+ event = create_embeddings_event(parameters)
33
+ segment.llm_event = event
34
+ begin
35
+ response = NewRelic::Agent::Tracer.capture_segment_error(segment) { yield }
36
+ # TODO: Remove !response.include?('error') when we drop support for versions below 4.0.0
37
+ add_embeddings_response_params(response, event) if response && !response.include?('error')
38
+
39
+ response
40
+ ensure
41
+ finish(segment, event)
42
+ end
43
+ end
44
+
45
+ def chat_completions_instrumentation(parameters)
46
+ segment = NewRelic::Agent::Tracer.start_segment(name: CHAT_COMPLETIONS_SEGMENT_NAME)
47
+ event = create_chat_completion_summary(parameters)
48
+ segment.llm_event = event
49
+ messages = create_chat_completion_messages(parameters, event.id)
50
+
51
+ begin
52
+ response = NewRelic::Agent::Tracer.capture_segment_error(segment) { yield }
53
+ # TODO: Remove !response.include?('error') when we drop support for versions below 4.0.0
54
+ if response && !response.include?('error')
55
+ add_chat_completion_response_params(parameters, response, event)
56
+ messages = update_chat_completion_messages(messages, response, event)
57
+ end
58
+
59
+ response
60
+ ensure
61
+ finish(segment, event)
62
+ messages&.each { |m| m.record }
63
+ end
64
+ end
65
+
66
+ def create_chat_completion_summary(parameters)
67
+ NewRelic::Agent::Llm::ChatCompletionSummary.new(
68
+ vendor: VENDOR,
69
+ request_max_tokens: (parameters[:max_tokens] || parameters['max_tokens'])&.to_i,
70
+ request_model: parameters[:model] || parameters['model'],
71
+ request_temperature: (parameters[:temperature] || parameters['temperature'])&.to_f,
72
+ metadata: llm_custom_attributes
73
+ )
74
+ end
75
+
76
+ def create_embeddings_event(parameters)
77
+ event = NewRelic::Agent::Llm::Embedding.new(
78
+ vendor: VENDOR,
79
+ request_model: parameters[:model] || parameters['model'],
80
+ metadata: llm_custom_attributes
81
+ )
82
+ add_input(event, (parameters[:input] || parameters['input']))
83
+
84
+ event
85
+ end
86
+
87
+ def add_chat_completion_response_params(parameters, response, event)
88
+ event.response_number_of_messages = (parameters[:messages] || parameters['messages']).size + response['choices'].size
89
+ # The response hash always returns keys as strings, so we don't need to run an || check here
90
+ event.response_model = response['model']
91
+ event.response_choices_finish_reason = response['choices'][0]['finish_reason']
92
+ end
93
+
94
+ def add_embeddings_response_params(response, event)
95
+ event.response_model = response['model']
96
+ event.token_count = calculate_token_count(event.request_model, event.input)
97
+ end
98
+
99
+ def create_chat_completion_messages(parameters, summary_id)
100
+ (parameters[:messages] || parameters['messages']).map.with_index do |message, index|
101
+ msg = NewRelic::Agent::Llm::ChatCompletionMessage.new(
102
+ role: message[:role] || message['role'],
103
+ sequence: index,
104
+ completion_id: summary_id,
105
+ vendor: VENDOR
106
+ )
107
+ add_content(msg, (message[:content] || message['content']))
108
+
109
+ msg
110
+ end
111
+ end
112
+
113
+ def create_chat_completion_response_messages(response, sequence_origin, summary_id)
114
+ response['choices'].map.with_index(sequence_origin) do |choice, index|
115
+ msg = NewRelic::Agent::Llm::ChatCompletionMessage.new(
116
+ role: choice['message']['role'],
117
+ sequence: index,
118
+ completion_id: summary_id,
119
+ vendor: VENDOR,
120
+ is_response: true
121
+ )
122
+ add_content(msg, choice['message']['content'])
123
+
124
+ msg
125
+ end
126
+ end
127
+
128
+ def update_chat_completion_messages(messages, response, summary)
129
+ messages += create_chat_completion_response_messages(response, messages.size, summary.id)
130
+ response_id = response['id'] || NewRelic::Agent::GuidGenerator.generate_guid
131
+ messages.each do |message|
132
+ message.id = "#{response_id}-#{message.sequence}"
133
+ message.request_id = summary.request_id
134
+ message.response_model = response['model']
135
+ message.metadata = llm_custom_attributes
136
+
137
+ model = message.is_response ? message.response_model : summary.request_model
138
+
139
+ message.token_count = calculate_token_count(model, message.content)
140
+ end
141
+ end
142
+
143
+ def calculate_token_count(model, content)
144
+ return unless NewRelic::Agent.llm_token_count_callback
145
+
146
+ begin
147
+ count = NewRelic::Agent.llm_token_count_callback.call({model: model, content: content})
148
+ rescue => e
149
+ NewRelic::Agent.logger.warn("Error calculating token count using the provided proc. Error: #{e}'")
150
+ end
151
+
152
+ count if count.is_a?(Integer) && count > 0
153
+ end
154
+
155
+ def record_content_enabled?
156
+ NewRelic::Agent.config[:'ai_monitoring.record_content.enabled']
157
+ end
158
+
159
+ def add_content(message, content)
160
+ message.content = content if record_content_enabled?
161
+ end
162
+
163
+ def add_input(event, input)
164
+ event.input = input if record_content_enabled?
165
+ end
166
+
167
+ def llm_custom_attributes
168
+ NewRelic::Agent::Tracer.current_transaction&.attributes&.custom_attributes&.select { |k| k.to_s.match(/llm.*/) }
169
+ end
170
+
171
+ def record_openai_metric
172
+ NewRelic::Agent.record_metric(nr_supportability_metric, 0.0)
173
+ end
174
+
175
+ def segment_noticed_error?(segment)
176
+ segment&.noticed_error
177
+ end
178
+
179
+ def nr_supportability_metric
180
+ @nr_supportability_metric ||= "Supportability/Ruby/ML/OpenAI/#{::OpenAI::VERSION}"
181
+ end
182
+
183
+ def finish(segment, event)
184
+ segment&.finish
185
+
186
+ return unless event
187
+
188
+ if segment
189
+ event.error = true if segment_noticed_error?(segment)
190
+ event.duration = segment.duration
191
+ end
192
+
193
+ event.record
194
+ end
195
+ end
196
+ end
@@ -0,0 +1,20 @@
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 OpenAI::Prepend
7
+ include NewRelic::Agent::Instrumentation::OpenAI
8
+
9
+ # In versions 4.0.0+ json_post is an instance method defined in the
10
+ # OpenAI::HTTP module, included by the OpenAI::Client class.
11
+ #
12
+ # In versions below 4.0.0 json_post is a class method on OpenAI::Client.
13
+ #
14
+ # Dependency detection will apply the instrumentation to the correct scope,
15
+ # so we don't need to change the code here.
16
+ def json_post(**kwargs)
17
+ json_post_with_new_relic(**kwargs) { super }
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,35 @@
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 'ruby_openai/instrumentation'
6
+ require_relative 'ruby_openai/chain'
7
+ require_relative 'ruby_openai/prepend'
8
+
9
+ DependencyDetection.defer do
10
+ named :'ruby_openai'
11
+
12
+ depends_on do
13
+ NewRelic::Agent.config[:'ai_monitoring.enabled'] &&
14
+ defined?(OpenAI) && defined?(OpenAI::Client) &&
15
+ NewRelic::Helper.version_satisfied?(OpenAI::VERSION, '>=', '3.4.0')
16
+ end
17
+
18
+ executes do
19
+ if use_prepend?
20
+ # TODO: Remove condition when we drop support for versions below 5.0.0
21
+ if NewRelic::Helper.version_satisfied?(OpenAI::VERSION, '>=', '5.0.0')
22
+ prepend_instrument OpenAI::Client,
23
+ NewRelic::Agent::Instrumentation::OpenAI::Prepend,
24
+ NewRelic::Agent::Instrumentation::OpenAI::VENDOR
25
+ else
26
+ prepend_instrument OpenAI::Client.singleton_class,
27
+ NewRelic::Agent::Instrumentation::OpenAI::Prepend,
28
+ NewRelic::Agent::Instrumentation::OpenAI::VENDOR
29
+ end
30
+ else
31
+ chain_instrument NewRelic::Agent::Instrumentation::OpenAI::Chain,
32
+ NewRelic::Agent::Instrumentation::OpenAI::VENDOR
33
+ end
34
+ end
35
+ end
@@ -30,7 +30,7 @@ DependencyDetection.defer do
30
30
  else
31
31
  NewRelic::Agent.logger.info('Detected Sequel version %s.' % [Sequel::VERSION])
32
32
  NewRelic::Agent.logger.info('Please see additional documentation: ' +
33
- 'https://newrelic.com/docs/ruby/sequel-instrumentation')
33
+ 'https://docs.newrelic.com/docs/apm/agents/ruby-agent/frameworks/sequel-instrumentation/')
34
34
  end
35
35
 
36
36
  Sequel.synchronize { Sequel::DATABASES.dup }.each do |db|
@@ -6,7 +6,11 @@ module NewRelic::Agent::Instrumentation::Sidekiq
6
6
  class Client
7
7
  include Sidekiq::ClientMiddleware if defined?(Sidekiq::ClientMiddleware)
8
8
 
9
+ INSTRUMENTATION_NAME = 'SidekiqClient'
10
+
9
11
  def call(_worker_class, job, *_)
12
+ NewRelic::Agent.record_instrumentation_invocation(INSTRUMENTATION_NAME)
13
+
10
14
  job[NewRelic::NEWRELIC_KEY] ||= distributed_tracing_headers if ::NewRelic::Agent.config[:'distributed_tracing.enabled']
11
15
  yield
12
16
  end
@@ -0,0 +1,24 @@
1
+ # This file is distributed under New Relic's license terms.
2
+ # See https://github.com/newrelic/newrelic-ruby-agent/blob/main/LICENSE for complete details.
3
+ # frozen_string_literal: true
4
+
5
+ if defined?(Sidekiq::DelayExtensions)
6
+ class Sidekiq::DelayExtensions::GenericJob
7
+ def newrelic_trace_args(msg, queue)
8
+ (target, method_name, *) = ::Sidekiq::DelayExtensions::YAML.unsafe_load(msg['args'][0])
9
+
10
+ if target.is_a?(String)
11
+ target = target.constantize
12
+ end
13
+
14
+ {
15
+ :name => method_name,
16
+ :class_name => target.class.name,
17
+ :category => 'OtherTransaction/SidekiqJob'
18
+ }
19
+ rescue => e
20
+ NewRelic::Agent.logger.error('Failure during deserializing YAML for Sidekiq::DelayExtensions::GenericJob', e)
21
+ NewRelic::Agent::Instrumentation::Sidekiq::Server.default_trace_args(msg)
22
+ end
23
+ end
24
+ end
@@ -6,9 +6,9 @@
6
6
  # Delayed extensions are disabled by default in Sidekiq 5 and 6 and
7
7
  # were removed entirely in Sidekiq 7.
8
8
  #
9
- # see https://github.com/mperham/sidekiq/issues/5076 for the discussion
9
+ # see https://github.com/sidekiq/sidekiq/issues/5076 for the discussion
10
10
  # of the removal, which includes mentions of alternatives
11
- if defined?(Sidekiq::VERSION) && Sidekiq::VERSION < '7.0.0'
11
+ if defined?(Sidekiq::VERSION) && NewRelic::Helper.version_satisfied?(Sidekiq::VERSION, '<', '7.0.0')
12
12
  class Sidekiq::Extensions::DelayedClass
13
13
  def newrelic_trace_args(msg, queue)
14
14
  (target, method_name, _args) = if YAML.respond_to?(:unsafe_load)
@@ -7,9 +7,16 @@ module NewRelic::Agent::Instrumentation::Sidekiq
7
7
  include NewRelic::Agent::Instrumentation::ControllerInstrumentation
8
8
  include Sidekiq::ServerMiddleware if defined?(Sidekiq::ServerMiddleware)
9
9
 
10
+ ATTRIBUTE_BASE_NAMESPACE = 'sidekiq.args'
11
+ ATTRIBUTE_FILTER_TYPES = %i[include exclude].freeze
12
+ ATTRIBUTE_JOB_NAMESPACE = :"job.#{ATTRIBUTE_BASE_NAMESPACE}"
13
+ INSTRUMENTATION_NAME = 'SidekiqServer'
14
+
10
15
  # Client middleware has additional parameters, and our tests use the
11
16
  # middleware client-side to work inline.
12
17
  def call(worker, msg, queue, *_)
18
+ NewRelic::Agent.record_instrumentation_invocation(INSTRUMENTATION_NAME)
19
+
13
20
  trace_args = if worker.respond_to?(:newrelic_trace_args)
14
21
  worker.newrelic_trace_args(msg, queue)
15
22
  else
@@ -18,10 +25,16 @@ module NewRelic::Agent::Instrumentation::Sidekiq
18
25
  trace_headers = msg.delete(NewRelic::NEWRELIC_KEY)
19
26
 
20
27
  perform_action_with_newrelic_trace(trace_args) do
21
- NewRelic::Agent::Transaction.merge_untrusted_agent_attributes(msg['args'], :'job.sidekiq.args',
22
- NewRelic::Agent::AttributeFilter::DST_NONE)
28
+ NewRelic::Agent::Transaction.merge_untrusted_agent_attributes(
29
+ NewRelic::Agent::AttributePreFiltering.pre_filter(msg['args'], self.class.nr_attribute_options),
30
+ ATTRIBUTE_JOB_NAMESPACE,
31
+ NewRelic::Agent::AttributeFilter::DST_NONE
32
+ )
33
+
34
+ if ::NewRelic::Agent.config[:'distributed_tracing.enabled'] && trace_headers&.any?
35
+ ::NewRelic::Agent::DistributedTracing::accept_distributed_trace_headers(trace_headers, 'Other')
36
+ end
23
37
 
24
- ::NewRelic::Agent::DistributedTracing::accept_distributed_trace_headers(trace_headers, 'Other') if ::NewRelic::Agent.config[:'distributed_tracing.enabled'] && trace_headers&.any?
25
38
  yield
26
39
  end
27
40
  end
@@ -33,5 +46,15 @@ module NewRelic::Agent::Instrumentation::Sidekiq
33
46
  :category => 'OtherTransaction/SidekiqJob'
34
47
  }
35
48
  end
49
+
50
+ def self.nr_attribute_options
51
+ @nr_attribute_options ||= begin
52
+ ATTRIBUTE_FILTER_TYPES.each_with_object({}) do |type, opts|
53
+ pattern =
54
+ NewRelic::Agent::AttributePreFiltering.formulate_regexp_union(:"#{ATTRIBUTE_BASE_NAMESPACE}.#{type}")
55
+ opts[type] = pattern if pattern
56
+ end.merge(attribute_namespace: ATTRIBUTE_JOB_NAMESPACE)
57
+ end
58
+ end
36
59
  end
37
60
  end
@@ -1,9 +1,11 @@
1
1
  # This file is distributed under New Relic's license terms.
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_relative 'sidekiq/client'
5
6
  require_relative 'sidekiq/server'
6
7
  require_relative 'sidekiq/extensions/delayed_class'
8
+ require_relative 'sidekiq/extensions/delay_extensions'
7
9
 
8
10
  DependencyDetection.defer do
9
11
  @name = :sidekiq
@@ -28,28 +30,23 @@ DependencyDetection.defer do
28
30
  chain.add(NewRelic::Agent::Instrumentation::Sidekiq::Client)
29
31
  end
30
32
  config.server_middleware do |chain|
31
- chain.add(NewRelic::Agent::Instrumentation::Sidekiq::Server)
33
+ # We started prepending v chaining NR middleware in 9.18.0 in response to:
34
+ # https://github.com/newrelic/newrelic-ruby-agent/issues/3037
35
+ # This way, exceptions resolved by Sidekiq's own middleware are not reported in the agent
36
+ if chain.respond_to?(:prepend)
37
+ chain.prepend(NewRelic::Agent::Instrumentation::Sidekiq::Server)
38
+ else
39
+ chain.add(NewRelic::Agent::Instrumentation::Sidekiq::Server)
40
+ end
32
41
  end
33
42
 
34
43
  if config.respond_to?(:error_handlers)
35
- config.error_handlers << proc do |error, *_|
44
+ # Sidekiq 3.0.0 - 7.1.4 expect error_handlers to have 2 arguments
45
+ # Sidekiq 7.1.5+ expect error_handlers to have 3 arguments
46
+ config.error_handlers << proc do |error, _ctx, *_|
36
47
  NewRelic::Agent.notice_error(error)
37
48
  end
38
49
  end
39
50
  end
40
51
  end
41
-
42
- executes do
43
- next unless Gem::Version.new(Sidekiq::VERSION) < Gem::Version.new('5.0.0')
44
-
45
- deprecation_msg = 'Instrumentation for Sidekiq versions below 5.0.0 is deprecated.' \
46
- 'They will stop being monitored in version 9.0.0. ' \
47
- 'Please upgrade your Sidekiq version to continue receiving full support. '
48
-
49
- NewRelic::Agent.logger.log_once(
50
- :warn,
51
- :deprecated_sidekiq_version,
52
- deprecation_msg
53
- )
54
- end
55
52
  end
@@ -33,7 +33,7 @@ module NewRelic::Agent::Instrumentation
33
33
  set(:newrelic_ignores, Hash.new([])) if !respond_to?(:newrelic_ignores)
34
34
 
35
35
  # If we call an ignore without a route, it applies to the whole app
36
- routes = ['*'] if routes.empty?
36
+ routes = [::NewRelic::ASTERISK] if routes.empty?
37
37
 
38
38
  settings.newrelic_ignores[type] += routes.map do |r|
39
39
  # Ugly sending to private Base#compile, but we want to mimic
@@ -13,6 +13,8 @@ module NewRelic::Agent::Instrumentation
13
13
  module Tracer
14
14
  include ::NewRelic::Agent::Instrumentation::ControllerInstrumentation
15
15
 
16
+ INSTRUMENTATION_NAME = 'Sinatra'
17
+
16
18
  def self.included(clazz)
17
19
  clazz.extend(self)
18
20
  end
@@ -90,6 +92,8 @@ module NewRelic::Agent::Instrumentation
90
92
  end
91
93
 
92
94
  def dispatch_with_tracing
95
+ NewRelic::Agent.record_instrumentation_invocation(INSTRUMENTATION_NAME)
96
+
93
97
  request_params = get_request_params
94
98
  filtered_params = ::NewRelic::Agent::ParameterFiltering::apply_filters(request.env, request_params || {})
95
99
 
@@ -25,14 +25,12 @@ module NewRelic
25
25
  transaction_name(::NewRelic::Agent::UNKNOWN_METRIC, request)
26
26
  end
27
27
 
28
- ROOT = '/'.freeze
29
-
30
28
  def transaction_name(route_text, request)
31
29
  verb = http_verb(request)
32
30
 
33
31
  route_text = route_text.source if route_text.is_a?(Regexp)
34
32
  name = route_text.gsub(%r{^[/^\\A]*(.*?)[/\$\?\\z]*$}, '\1')
35
- name = ROOT if name.empty?
33
+ name = NewRelic::ROOT if name.empty?
36
34
  name = "#{verb} #{name}" unless verb.nil?
37
35
  name
38
36
  rescue => e
@@ -16,10 +16,6 @@ DependencyDetection.defer do
16
16
  depends_on { Sinatra::Base.private_method_defined?(:process_route) }
17
17
  depends_on { Sinatra::Base.private_method_defined?(:route_eval) }
18
18
 
19
- executes do
20
- NewRelic::Agent.logger.info('Installing Sinatra instrumentation')
21
- end
22
-
23
19
  executes do
24
20
  if use_prepend?
25
21
  prepend_instrument Sinatra::Base, NewRelic::Agent::Instrumentation::Sinatra::Prepend
@@ -32,27 +28,15 @@ DependencyDetection.defer do
32
28
  end
33
29
 
34
30
  executes do
31
+ supportability_name = NewRelic::Agent::Instrumentation::Sinatra::Tracer::INSTRUMENTATION_NAME
35
32
  # These requires are inside an executes block because they require rack, and
36
33
  # we can't be sure that rack is available when this file is first required.
37
34
  require 'new_relic/rack/agent_hooks'
38
35
  require 'new_relic/rack/browser_monitoring'
39
36
  if use_prepend?
40
- prepend_instrument Sinatra::Base.singleton_class, NewRelic::Agent::Instrumentation::Sinatra::Build::Prepend
37
+ prepend_instrument Sinatra::Base.singleton_class, NewRelic::Agent::Instrumentation::Sinatra::Build::Prepend, supportability_name
41
38
  else
42
- chain_instrument NewRelic::Agent::Instrumentation::Sinatra::Build::Chain
39
+ chain_instrument NewRelic::Agent::Instrumentation::Sinatra::Build::Chain, supportability_name
43
40
  end
44
41
  end
45
-
46
- executes do
47
- next unless Gem::Version.new(Sinatra::VERSION) < Gem::Version.new('2.0.0')
48
-
49
- deprecation_msg = 'The Ruby Agent is dropping support for Sinatra versions below 2.0.0 ' \
50
- 'in version 9.0.0. Please upgrade your Sinatra version to continue receiving full compatibility. ' \
51
-
52
- NewRelic::Agent.logger.log_once(
53
- :warn,
54
- :deprecated_sinatra_version,
55
- deprecation_msg
56
- )
57
- end
58
42
  end
@@ -0,0 +1,28 @@
1
+ # This file is distributed under New Relic's license terms.
2
+ # See https://github.com/newrelic/newrelic-ruby-agent/blob/main/LICENSE for complete details.
3
+ # frozen_string_literal: true
4
+
5
+ require 'new_relic/agent/instrumentation/stripe_subscriber'
6
+
7
+ DependencyDetection.defer do
8
+ named :stripe
9
+
10
+ depends_on do
11
+ NewRelic::Agent.config[:'instrumentation.stripe'] == 'enabled'
12
+ end
13
+
14
+ depends_on do
15
+ defined?(Stripe) &&
16
+ NewRelic::Helper.version_satisfied?(Stripe::VERSION, '>=', '5.38.0')
17
+ end
18
+
19
+ executes do
20
+ NewRelic::Agent.logger.info('Installing Stripe instrumentation')
21
+ end
22
+
23
+ executes do
24
+ newrelic_subscriber = NewRelic::Agent::Instrumentation::StripeSubscriber.new
25
+ Stripe::Instrumentation.subscribe(:request_begin) { |event| newrelic_subscriber.start_segment(event) }
26
+ Stripe::Instrumentation.subscribe(:request_end) { |event| newrelic_subscriber.finish_segment(event) }
27
+ end
28
+ end
@@ -0,0 +1,98 @@
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
6
+ module Agent
7
+ module Instrumentation
8
+ class StripeSubscriber
9
+ DEFAULT_DESTINATIONS = AttributeFilter::DST_SPAN_EVENTS
10
+ EVENT_ATTRIBUTES = %i[http_status method num_retries path request_id].freeze
11
+ ATTRIBUTE_NAMESPACE = 'stripe.user_data'
12
+ ATTRIBUTE_FILTER_TYPES = %i[include exclude].freeze
13
+ PATH_PORTION_PATTERN = %r{^/([^/]+/[^/]+)(?:/|\z)}.freeze
14
+
15
+ def start_segment(event)
16
+ return unless is_execution_traced?
17
+
18
+ segment = NewRelic::Agent::Tracer.start_segment(name: metric_name(event))
19
+ event.user_data[:newrelic_segment] = segment
20
+ rescue => e
21
+ NewRelic::Agent.logger.error("Error starting New Relic Stripe segment: #{e}")
22
+ end
23
+
24
+ def finish_segment(event)
25
+ return unless is_execution_traced?
26
+
27
+ segment = remove_and_return_nr_segment(event)
28
+ add_stripe_attributes(segment, event)
29
+ add_custom_attributes(segment, event)
30
+ rescue => e
31
+ NewRelic::Agent.logger.error("Error finishing New Relic Stripe segment: #{e}")
32
+ ensure
33
+ segment&.finish
34
+ end
35
+
36
+ private
37
+
38
+ def is_execution_traced?
39
+ NewRelic::Agent::Tracer.state.is_execution_traced?
40
+ end
41
+
42
+ def metric_name(event)
43
+ # Grab only the first 2 items from the slash (/) delimited event path.
44
+ # These items are the API version string and the category. Grabbing
45
+ # any more of the path will result in unique method names that will
46
+ # easily grow to be too numerous to sort through in the UI and
47
+ # possibly even violate default New Relic metric count thresholds.
48
+ # See newrelic/newrelic-ruby-agent#2654 and
49
+ # newrelic/newrelic-ruby-agent#2709 for more details.
50
+ #
51
+ # In Ruby v3.4 benchmarks, using regex to get at the first two path
52
+ # elements was seen as more performant than using String#split.
53
+ #
54
+ # Regex legend:
55
+ #
56
+ # ^ = starts with
57
+ # / = a literal '/'
58
+ # () = capture
59
+ # (?:) = don't capture
60
+ # [^/]+ = 1 or more characters that are not '/'
61
+ # /|\z = a literal '/' OR the end of the string
62
+ path_portion = event.path =~ PATH_PORTION_PATTERN ? Regexp.last_match(1) : NewRelic::UNKNOWN
63
+ "Stripe/#{path_portion}/#{event.method}"
64
+ end
65
+
66
+ def add_stripe_attributes(segment, event)
67
+ EVENT_ATTRIBUTES.each do |attribute|
68
+ segment.add_agent_attribute("stripe_#{attribute}", event.send(attribute), DEFAULT_DESTINATIONS)
69
+ end
70
+ end
71
+
72
+ def add_custom_attributes(segment, event)
73
+ return if NewRelic::Agent.config[:'stripe.user_data.include'].empty?
74
+
75
+ filtered_attributes = NewRelic::Agent::AttributePreFiltering.pre_filter_hash(event.user_data, nr_attribute_options)
76
+ filtered_attributes.each do |key, value|
77
+ segment.add_agent_attribute("stripe_user_data_#{key}", value, DEFAULT_DESTINATIONS)
78
+ end
79
+ end
80
+
81
+ def nr_attribute_options
82
+ ATTRIBUTE_FILTER_TYPES.each_with_object({}) do |type, opts|
83
+ pattern =
84
+ NewRelic::Agent::AttributePreFiltering.formulate_regexp_union(:"#{ATTRIBUTE_NAMESPACE}.#{type}")
85
+ opts[type] = pattern if pattern
86
+ end
87
+ end
88
+
89
+ def remove_and_return_nr_segment(event)
90
+ segment = event.user_data[:newrelic_segment]
91
+ event.user_data.delete(:newrelic_segment)
92
+
93
+ segment
94
+ end
95
+ end
96
+ end
97
+ end
98
+ end