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
@@ -14,7 +14,7 @@ module NewRelic::Agent::Instrumentation
14
14
  alias_method(:initialize_without_new_relic, :initialize)
15
15
 
16
16
  def initialize(*args, &block)
17
- traced_block = add_thread_tracing(*args, &block)
17
+ traced_block = add_thread_tracing(&block)
18
18
  initialize_with_newrelic_tracing { initialize_without_new_relic(*args, &traced_block) }
19
19
  end
20
20
  end
@@ -16,11 +16,7 @@ module NewRelic
16
16
  def add_thread_tracing(*args, &block)
17
17
  return block if !NewRelic::Agent::Tracer.thread_tracing_enabled?
18
18
 
19
- NewRelic::Agent::Tracer.thread_block_with_current_transaction(
20
- *args,
21
- segment_name: 'Ruby/Thread',
22
- &block
23
- )
19
+ NewRelic::Agent::Tracer.thread_block_with_current_transaction(&block)
24
20
  end
25
21
  end
26
22
  end
@@ -12,7 +12,7 @@ module NewRelic
12
12
  include NewRelic::Agent::Instrumentation::MonitoredThread
13
13
 
14
14
  def initialize(*args, &block)
15
- traced_block = add_thread_tracing(*args, &block)
15
+ traced_block = add_thread_tracing(&block)
16
16
  initialize_with_newrelic_tracing { super(*args, &traced_block) }
17
17
  end
18
18
  end
@@ -9,8 +9,6 @@ DependencyDetection.defer do
9
9
  named :thread
10
10
 
11
11
  executes do
12
- NewRelic::Agent.logger.info('Installing Thread Instrumentation')
13
-
14
12
  if use_prepend?
15
13
  prepend_instrument Thread, NewRelic::Agent::Instrumentation::MonitoredThread::Prepend
16
14
  else
@@ -6,6 +6,8 @@ module NewRelic
6
6
  module Agent
7
7
  module Instrumentation
8
8
  module Tilt
9
+ INSTRUMENTATION_NAME = NewRelic::Agent.base_name(name)
10
+
9
11
  def metric_name(klass, file)
10
12
  "View/#{klass}/#{file}/Rendering"
11
13
  end
@@ -21,6 +23,8 @@ module NewRelic
21
23
  end
22
24
 
23
25
  def render_with_tracing(*args, &block)
26
+ NewRelic::Agent.record_instrumentation_invocation(INSTRUMENTATION_NAME)
27
+
24
28
  begin
25
29
  finishable = Tracer.start_segment(
26
30
  name: metric_name(self.class, create_filename_for_metric(self.file))
@@ -11,10 +11,6 @@ DependencyDetection.defer do
11
11
 
12
12
  depends_on { defined?(Tilt) }
13
13
 
14
- executes do
15
- NewRelic::Agent.logger.info('Installing Tilt instrumentation')
16
- end
17
-
18
14
  executes do
19
15
  if use_prepend?
20
16
  prepend_instrument Tilt::Template, NewRelic::Agent::Instrumentation::Tilt::Prepend
@@ -8,11 +8,11 @@ module NewRelic
8
8
  module Typhoeus
9
9
  HYDRA_SEGMENT_NAME = 'External/Multiple/Typhoeus::Hydra/run'
10
10
  NOTICEABLE_ERROR_CLASS = 'Typhoeus::Errors::TyphoeusError'
11
-
12
- EARLIEST_VERSION = Gem::Version.new('0.5.3')
11
+ EARLIEST_VERSION = '0.5.3'
12
+ INSTRUMENTATION_NAME = NewRelic::Agent.base_name(name)
13
13
 
14
14
  def self.is_supported_version?
15
- Gem::Version.new(::Typhoeus::VERSION) >= EARLIEST_VERSION
15
+ NewRelic::Helper.version_satisfied?(::Typhoeus::VERSION, '>=', EARLIEST_VERSION)
16
16
  end
17
17
 
18
18
  def self.request_is_hydra_enabled?(request)
@@ -31,6 +31,8 @@ module NewRelic
31
31
  end
32
32
 
33
33
  def with_tracing
34
+ NewRelic::Agent.record_instrumentation_invocation(INSTRUMENTATION_NAME)
35
+
34
36
  segment = NewRelic::Agent::Tracer.start_segment(name: HYDRA_SEGMENT_NAME)
35
37
  instance_variable_set(:@__newrelic_hydra_segment, segment)
36
38
  begin
@@ -41,6 +43,8 @@ module NewRelic
41
43
  end
42
44
 
43
45
  def self.trace(request)
46
+ NewRelic::Agent.record_instrumentation_invocation(INSTRUMENTATION_NAME)
47
+
44
48
  state = NewRelic::Agent::Tracer.state
45
49
  return unless state.is_execution_traced?
46
50
 
@@ -18,7 +18,6 @@ DependencyDetection.defer do
18
18
  end
19
19
 
20
20
  executes do
21
- NewRelic::Agent.logger.info('Installing Typhoeus instrumentation')
22
21
  require 'new_relic/agent/distributed_tracing/cross_app_tracing'
23
22
  require 'new_relic/agent/http_clients/typhoeus_wrappers'
24
23
  end
@@ -0,0 +1,21 @@
1
+ # This file is distributed under New Relic's license terms.
2
+ # See https://github.com/newrelic/newrelic-ruby-agent/blob/main/LICENSE for complete details.
3
+ # frozen_string_literal: true
4
+
5
+ module NewRelic::Agent::Instrumentation
6
+ module ViewComponent::Chain
7
+ def self.instrument!
8
+ ::ViewComponent::Base.class_eval do
9
+ include NewRelic::Agent::Instrumentation::ViewComponent
10
+
11
+ alias_method(:render_in_without_tracing, :render_in)
12
+
13
+ def render_in(*args)
14
+ render_in_with_tracing(*args) do
15
+ render_in_without_tracing(*args)
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,45 @@
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 ViewComponent
7
+ INSTRUMENTATION_NAME = NewRelic::Agent.base_name(name)
8
+
9
+ def render_in_with_tracing(*args)
10
+ NewRelic::Agent.record_instrumentation_invocation(INSTRUMENTATION_NAME)
11
+
12
+ begin
13
+ segment = NewRelic::Agent::Tracer.start_segment(name: metric_name)
14
+ yield
15
+ rescue => e
16
+ NewRelic::Agent.notice_error(e)
17
+ raise
18
+ ensure
19
+ segment&.finish
20
+ end
21
+ end
22
+
23
+ def metric_name
24
+ # ViewComponent determines a component's identifier differently depending on the version
25
+ # https://github.com/ViewComponent/view_component/pull/2153
26
+ component_identifier = defined?(self.class.source_location) ? self.class.source_location : self.class.identifier
27
+
28
+ "View/#{metric_path(component_identifier)}/#{self.class.name}"
29
+ rescue => e
30
+ NewRelic::Agent.logger.error('Error identifying View Component metric name', e)
31
+
32
+ 'View/component'
33
+ end
34
+
35
+ def metric_path(identifier)
36
+ return 'component' unless identifier
37
+
38
+ if (parts = identifier.split('/')).size > 1
39
+ parts[-2..-1].join('/') # Get filepath by assuming the Rails' structure: app/components/home/example_component.rb
40
+ else
41
+ NewRelic::Agent::UNKNOWN_METRIC
42
+ end
43
+ end
44
+ end
45
+ end
@@ -3,11 +3,11 @@
3
3
  # frozen_string_literal: true
4
4
 
5
5
  module NewRelic::Agent::Instrumentation
6
- module <%= @class_name %>
6
+ module ViewComponent::Prepend
7
+ include NewRelic::Agent::Instrumentation::ViewComponent
7
8
 
8
- def <%= @method.downcase %>_with_new_relic<%= "(#{@args})" unless @args.empty? %>
9
- # add instrumentation content here
10
- yield
9
+ def render_in(*args)
10
+ render_in_with_tracing(*args) { super }
11
11
  end
12
12
  end
13
13
  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
+ require_relative 'view_component/instrumentation'
6
+ require_relative 'view_component/chain'
7
+ require_relative 'view_component/prepend'
8
+
9
+ DependencyDetection.defer do
10
+ named :view_component
11
+
12
+ depends_on do
13
+ defined?(ViewComponent) &&
14
+ ViewComponent::Base.method_defined?(:render_in)
15
+ end
16
+
17
+ executes do
18
+ if use_prepend?
19
+ prepend_instrument ViewComponent::Base, NewRelic::Agent::Instrumentation::ViewComponent::Prepend
20
+ else
21
+ chain_instrument NewRelic::Agent::Instrumentation::ViewComponent::Chain
22
+ end
23
+ end
24
+ end
@@ -2,7 +2,6 @@
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 'base64'
6
5
  require 'json'
7
6
  require 'new_relic/agent/obfuscator'
8
7
 
@@ -165,9 +164,8 @@ module NewRelic
165
164
 
166
165
  def add_ssl_for_http(data)
167
166
  ssl_for_http = NewRelic::Agent.config[:'browser_monitoring.ssl_for_http']
168
- unless ssl_for_http.nil?
169
- data[SSL_FOR_HTTP_KEY] = ssl_for_http
170
- end
167
+
168
+ data[SSL_FOR_HTTP_KEY] = ssl_for_http if ssl_for_http
171
169
  end
172
170
 
173
171
  def add_attributes(data, txn)
@@ -0,0 +1,25 @@
1
+ # This file is distributed under New Relic's license terms.
2
+ # See https://github.com/newrelic/newrelic-ruby-agent/blob/main/LICENSE for complete details.
3
+ # frozen_string_literal: true
4
+
5
+ module NewRelic
6
+ module Agent
7
+ module Llm
8
+ class ChatCompletionMessage < LlmEvent
9
+ ATTRIBUTES = %i[content role sequence completion_id token_count
10
+ is_response]
11
+ EVENT_NAME = 'LlmChatCompletionMessage'
12
+
13
+ attr_accessor(*ATTRIBUTES)
14
+
15
+ def attributes
16
+ LlmEvent::ATTRIBUTES + ATTRIBUTES
17
+ end
18
+
19
+ def event_name
20
+ EVENT_NAME
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,66 @@
1
+ # This file is distributed under New Relic's license terms.
2
+ # See https://github.com/newrelic/newrelic-ruby-agent/blob/main/LICENSE for complete details.
3
+ # frozen_string_literal: true
4
+
5
+ require_relative 'response_headers'
6
+
7
+ module NewRelic
8
+ module Agent
9
+ module Llm
10
+ class ChatCompletionSummary < LlmEvent
11
+ include ResponseHeaders
12
+
13
+ ATTRIBUTES = %i[request_max_tokens response_number_of_messages
14
+ request_model response_choices_finish_reason request_temperature
15
+ duration error]
16
+ ATTRIBUTE_NAME_EXCEPTIONS = {
17
+ response_number_of_messages: 'response.number_of_messages',
18
+ request_model: 'request.model',
19
+ response_choices_finish_reason: 'response.choices.finish_reason',
20
+ request_temperature: 'request.temperature'
21
+ }
22
+ ERROR_COMPLETION_ID = 'completion_id'
23
+ EVENT_NAME = 'LlmChatCompletionSummary'
24
+
25
+ attr_accessor(*ATTRIBUTES)
26
+
27
+ def attributes
28
+ LlmEvent::ATTRIBUTES + ResponseHeaders::ATTRIBUTES + ATTRIBUTES
29
+ end
30
+
31
+ def attribute_name_exceptions
32
+ # TODO: OLD RUBIES < 2.6
33
+ # Hash#merge accepts multiple arguments in 2.6
34
+ # Remove condition once support for Ruby <2.6 is dropped
35
+ if NewRelic::Helper.version_satisfied?(RUBY_VERSION, '>=', '2.6.0')
36
+ LlmEvent::ATTRIBUTE_NAME_EXCEPTIONS.merge(ResponseHeaders::ATTRIBUTE_NAME_EXCEPTIONS, ATTRIBUTE_NAME_EXCEPTIONS)
37
+ else
38
+ LlmEvent::ATTRIBUTE_NAME_EXCEPTIONS.merge(ResponseHeaders::ATTRIBUTE_NAME_EXCEPTIONS).merge(ATTRIBUTE_NAME_EXCEPTIONS)
39
+ end
40
+ end
41
+
42
+ def event_name
43
+ EVENT_NAME
44
+ end
45
+
46
+ def error_attributes(exception)
47
+ attrs = {ERROR_COMPLETION_ID => id}
48
+
49
+ error_attributes_from_response(exception, attrs)
50
+ end
51
+
52
+ private
53
+
54
+ def error_attributes_from_response(exception, attrs)
55
+ return attrs unless exception.respond_to?(:response)
56
+
57
+ attrs[ERROR_ATTRIBUTE_STATUS_CODE] = exception.response.dig(:status)
58
+ attrs[ERROR_ATTRIBUTE_CODE] = exception.response.dig(:body, ERROR_STRING, CODE_STRING)
59
+ attrs[ERROR_ATTRIBUTE_PARAM] = exception.response.dig(:body, ERROR_STRING, PARAM_STRING)
60
+
61
+ attrs
62
+ end
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,60 @@
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 Llm
8
+ class Embedding < LlmEvent
9
+ include ResponseHeaders
10
+
11
+ ATTRIBUTES = %i[input request_model token_count duration error].freeze
12
+ ATTRIBUTE_NAME_EXCEPTIONS = {
13
+ request_model: 'request.model'
14
+ }.freeze
15
+ ERROR_EMBEDDING_ID = 'embedding_id'
16
+ EVENT_NAME = 'LlmEmbedding'
17
+
18
+ attr_accessor(*ATTRIBUTES)
19
+
20
+ def attributes
21
+ LlmEvent::ATTRIBUTES + ResponseHeaders::ATTRIBUTES + ATTRIBUTES
22
+ end
23
+
24
+ def attribute_name_exceptions
25
+ # TODO: OLD RUBIES < 2.6
26
+ # Hash#merge accepts multiple arguments in 2.6
27
+ # Remove condition once support for Ruby <2.6 is dropped
28
+ if NewRelic::Helper.version_satisfied?(RUBY_VERSION, '>=', '2.6.0')
29
+ LlmEvent::ATTRIBUTE_NAME_EXCEPTIONS.merge(ResponseHeaders::ATTRIBUTE_NAME_EXCEPTIONS, ATTRIBUTE_NAME_EXCEPTIONS)
30
+ else
31
+ LlmEvent::ATTRIBUTE_NAME_EXCEPTIONS.merge(ResponseHeaders::ATTRIBUTE_NAME_EXCEPTIONS).merge(ATTRIBUTE_NAME_EXCEPTIONS)
32
+ end
33
+ end
34
+
35
+ def event_name
36
+ EVENT_NAME
37
+ end
38
+
39
+ def error_attributes(exception)
40
+ attrs = {}
41
+ attrs[ERROR_EMBEDDING_ID] = id
42
+
43
+ error_attributes_from_response(exception, attrs)
44
+ end
45
+
46
+ private
47
+
48
+ def error_attributes_from_response(exception, attrs)
49
+ return attrs unless exception.respond_to?(:response)
50
+
51
+ attrs[ERROR_ATTRIBUTE_STATUS_CODE] = exception.response.dig(:status)
52
+ attrs[ERROR_ATTRIBUTE_CODE] = exception.response.dig(:body, ERROR_STRING, CODE_STRING)
53
+ attrs[ERROR_ATTRIBUTE_PARAM] = exception.response.dig(:body, ERROR_STRING, PARAM_STRING)
54
+
55
+ attrs
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,95 @@
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 Llm
8
+ class LlmEvent
9
+ # Every subclass must define its own ATTRIBUTES constant, an array of symbols representing
10
+ # that class's unique attributes
11
+ ATTRIBUTES = %i[id request_id span_id trace_id response_model vendor
12
+ ingest_source metadata]
13
+ # These attributes should not be passed as arguments to initialize and will be set by the agent
14
+ AGENT_DEFINED_ATTRIBUTES = %i[span_id trace_id ingest_source]
15
+ # Some attributes have names that can't be written as symbols used for metaprogramming.
16
+ # The ATTRIBUTE_NAME_EXCEPTIONS hash should use the symbolized version of the name as the key
17
+ # and the string version expected by the UI as the value.
18
+ ATTRIBUTE_NAME_EXCEPTIONS = {response_model: 'response.model'}
19
+ INGEST_SOURCE = 'Ruby'
20
+ ERROR_ATTRIBUTE_STATUS_CODE = 'http.statusCode'
21
+ ERROR_ATTRIBUTE_CODE = 'error.code'
22
+ ERROR_ATTRIBUTE_PARAM = 'error.param'
23
+ ERROR_STRING = 'error'
24
+ CODE_STRING = 'code'
25
+ PARAM_STRING = 'param'
26
+
27
+ attr_accessor(*ATTRIBUTES)
28
+
29
+ def self.set_llm_agent_attribute_on_transaction
30
+ NewRelic::Agent::Transaction.add_agent_attribute(:llm, true, NewRelic::Agent::AttributeFilter::DST_TRANSACTION_EVENTS)
31
+ end
32
+
33
+ # This initialize method is used for all subclasses.
34
+ # It leverages the subclass's `attributes` method to iterate through
35
+ # all the attributes for that subclass.
36
+ # It assigns instance variables for all arguments passed to the method.
37
+ # It also assigns agent-defined attributes.
38
+ def initialize(opts = {})
39
+ (attributes - AGENT_DEFINED_ATTRIBUTES).each do |attr|
40
+ instance_variable_set(:"@#{attr}", opts[attr]) if opts.key?(attr)
41
+ end
42
+
43
+ @id = id || NewRelic::Agent::GuidGenerator.generate_guid
44
+ @span_id = NewRelic::Agent::Tracer.current_span_id
45
+ @trace_id = NewRelic::Agent::Tracer.current_trace_id
46
+ @ingest_source = INGEST_SOURCE
47
+ end
48
+
49
+ # All subclasses use event_attributes to get a full hash of all
50
+ # attributes and their values
51
+ def event_attributes
52
+ attributes_hash = attributes.each_with_object({}) do |attr, hash|
53
+ hash[replace_attr_with_string(attr)] = instance_variable_get(:"@#{attr}")
54
+ end
55
+ attributes_hash.merge!(metadata) && attributes_hash.delete(:metadata) if !metadata.nil?
56
+
57
+ attributes_hash
58
+ end
59
+
60
+ # Subclasses define an attributes method to concatenate attributes
61
+ # defined across their ancestors and other modules
62
+ def attributes
63
+ ATTRIBUTES
64
+ end
65
+
66
+ # Subclasses that record events will override this method
67
+ def event_name
68
+ end
69
+
70
+ # Some attribute names include periods, which aren't valid values for
71
+ # Ruby method names. This method returns a Hash with the key as the
72
+ # Ruby symbolized version of the attribute and the value as the
73
+ # period-delimited string expected upstream.
74
+ def attribute_name_exceptions
75
+ ATTRIBUTE_NAME_EXCEPTIONS
76
+ end
77
+
78
+ def record
79
+ NewRelic::Agent.record_custom_event(event_name, event_attributes)
80
+ end
81
+
82
+ # Subclasses that add attributes to noticed errors will override this method
83
+ def error_attributes(exception)
84
+ NewRelic::EMPTY_HASH
85
+ end
86
+
87
+ private
88
+
89
+ def replace_attr_with_string(attr)
90
+ attribute_name_exceptions.fetch(attr, attr)
91
+ end
92
+ end
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,80 @@
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 Llm
8
+ module ResponseHeaders
9
+ ATTRIBUTES = %i[response_organization llm_version ratelimit_limit_requests
10
+ ratelimit_limit_tokens ratelimit_remaining_requests
11
+ ratelimit_remaining_tokens ratelimit_reset_requests
12
+ ratelimit_reset_tokens ratelimit_limit_tokens_usage_based
13
+ ratelimit_reset_tokens_usage_based
14
+ ratelimit_remaining_tokens_usage_based].freeze
15
+
16
+ ATTRIBUTE_NAME_EXCEPTIONS = {
17
+ response_organization: 'response.organization',
18
+ llm_version: 'response.headers.llmVersion',
19
+ ratelimit_limit_requests: 'response.headers.ratelimitLimitRequests',
20
+ ratelimit_limit_tokens: 'response.headers.ratelimitLimitTokens',
21
+ ratelimit_remaining_requests: 'response.headers.ratelimitRemainingRequests',
22
+ ratelimit_remaining_tokens: 'response.headers.ratelimitRemainingTokens',
23
+ ratelimit_reset_requests: 'response.headers.ratelimitResetRequests',
24
+ ratelimit_reset_tokens: 'response.headers.ratelimitResetTokens',
25
+ ratelimit_limit_tokens_usage_based: 'response.headers.ratelimitLimitTokensUsageBased',
26
+ ratelimit_reset_tokens_usage_based: 'response.headers.ratelimitResetTokensUsageBased',
27
+ ratelimit_remaining_tokens_usage_based: 'response.headers.ratelimitRemainingTokensUsageBased'
28
+ }.freeze
29
+
30
+ OPENAI_ORGANIZATION = 'openai-organization'
31
+ OPENAI_VERSION = 'openai-version'
32
+ X_RATELIMIT_LIMIT_REQUESTS = 'x-ratelimit-limit-requests'
33
+ X_RATELIMIT_LIMIT_TOKENS = 'x-ratelimit-limit-tokens'
34
+ X_RATELIMIT_REMAINING_REQUESTS = 'x-ratelimit-remaining-requests'
35
+ X_RATELIMIT_REMAINING_TOKENS = 'x-ratelimit-remaining-tokens'
36
+ X_RATELIMIT_RESET_REQUESTS = 'x-ratelimit-reset-requests'
37
+ X_RATELIMIT_RESET_TOKENS = 'x-ratelimit-reset-tokens'
38
+ X_RATELIMIT_LIMIT_TOKENS_USAGE_BASED = 'x-ratelimit-limit-tokens-usage-based'
39
+ X_RATELIMIT_RESET_TOKENS_USAGE_BASED = 'x-ratelimit-reset-tokens-usage-based'
40
+ X_RATELIMIT_REMAINING_TOKENS_USAGE_BASED = 'x-ratelimit-remaining-tokens-usage-based'
41
+ X_REQUEST_ID = 'x-request-id'
42
+
43
+ attr_accessor(*ATTRIBUTES)
44
+
45
+ # Headers is a hash of Net::HTTP response headers
46
+ def populate_openai_response_headers(headers)
47
+ # Embedding, ChatCompletionSummary, and ChatCompletionMessage all need
48
+ # request_id, so it's defined in LlmEvent. ChatCompletionMessage
49
+ # adds the attribute via ChatCompletionSummary.
50
+ self.request_id = headers[X_REQUEST_ID]&.first
51
+ self.response_organization = headers[OPENAI_ORGANIZATION]&.first
52
+ self.llm_version = headers[OPENAI_VERSION]&.first
53
+ self.ratelimit_limit_requests = headers[X_RATELIMIT_LIMIT_REQUESTS]&.first.to_i
54
+ self.ratelimit_limit_tokens = headers[X_RATELIMIT_LIMIT_TOKENS]&.first.to_i
55
+ remaining_headers(headers)
56
+ reset_headers(headers)
57
+ tokens_usage_based_headers(headers)
58
+ end
59
+
60
+ private
61
+
62
+ def remaining_headers(headers)
63
+ self.ratelimit_remaining_requests = headers[X_RATELIMIT_REMAINING_REQUESTS]&.first.to_i
64
+ self.ratelimit_remaining_tokens = headers[X_RATELIMIT_REMAINING_TOKENS]&.first.to_i
65
+ end
66
+
67
+ def reset_headers(headers)
68
+ self.ratelimit_reset_requests = headers[X_RATELIMIT_RESET_REQUESTS]&.first
69
+ self.ratelimit_reset_tokens = headers[X_RATELIMIT_RESET_TOKENS]&.first
70
+ end
71
+
72
+ def tokens_usage_based_headers(headers)
73
+ self.ratelimit_limit_tokens_usage_based = headers[X_RATELIMIT_LIMIT_TOKENS_USAGE_BASED]&.first.to_i
74
+ self.ratelimit_reset_tokens_usage_based = headers[X_RATELIMIT_RESET_TOKENS_USAGE_BASED]&.first
75
+ self.ratelimit_remaining_tokens_usage_based = headers[X_RATELIMIT_REMAINING_TOKENS_USAGE_BASED]&.first.to_i
76
+ end
77
+ end
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,49 @@
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 'llm/llm_event'
6
+ require_relative 'llm/chat_completion_message'
7
+ require_relative 'llm/chat_completion_summary'
8
+ require_relative 'llm/embedding'
9
+ require_relative 'llm/response_headers'
10
+
11
+ module NewRelic
12
+ module Agent
13
+ class LLM
14
+ INPUT = 'input'
15
+ CONTENT = 'content'
16
+ SEGMENT_PATTERN = %r{Llm/.+/OpenAI/.+}.freeze
17
+
18
+ def self.instrumentation_enabled?
19
+ NewRelic::Agent.config[:'ai_monitoring.enabled']
20
+ end
21
+
22
+ # LLM content-related attributes are exempt from the 4095 byte limit
23
+ def self.exempt_event_attribute?(type, key)
24
+ return false unless instrumentation_enabled?
25
+
26
+ (type == NewRelic::Agent::Llm::Embedding::EVENT_NAME && key == INPUT) ||
27
+ (type == NewRelic::Agent::Llm::ChatCompletionMessage::EVENT_NAME && key == CONTENT)
28
+ end
29
+
30
+ def self.openai?
31
+ @openai ||= %i[prepend chain].include?(NewRelic::Agent.config[:'instrumentation.ruby_openai']) &&
32
+ NewRelic::Agent.config[:'ai_monitoring.enabled']
33
+ end
34
+
35
+ # Used in NetHTTP instrumentation
36
+ def self.openai_parent?(segment)
37
+ return false unless openai?
38
+
39
+ segment&.parent&.name&.match?(SEGMENT_PATTERN)
40
+ end
41
+
42
+ def self.populate_openai_response_headers(response, parent)
43
+ return unless parent.instance_variable_defined?(:@llm_event)
44
+
45
+ parent.llm_event.populate_openai_response_headers(response.to_hash)
46
+ end
47
+ end
48
+ end
49
+ end
@@ -9,9 +9,15 @@ module NewRelic
9
9
  extend self
10
10
 
11
11
  def decorate(message)
12
- return message unless decorating_enabled?
12
+ return message if !decorating_enabled? || message.nil?
13
13
 
14
14
  metadata = NewRelic::Agent.linking_metadata
15
+
16
+ if message.is_a?(Hash)
17
+ message.merge!(metadata) unless message.frozen?
18
+ return
19
+ end
20
+
15
21
  formatted_metadata = " NR-LINKING|#{metadata[ENTITY_GUID_KEY]}|#{metadata[HOSTNAME_KEY]}|" \
16
22
  "#{metadata[TRACE_ID_KEY]}|#{metadata[SPAN_ID_KEY]}|" \
17
23
  "#{escape_entity_name(metadata[ENTITY_NAME_KEY])}|"
@@ -23,14 +29,25 @@ module NewRelic
23
29
 
24
30
  def decorating_enabled?
25
31
  NewRelic::Agent.config[:'application_logging.enabled'] &&
26
- NewRelic::Agent::Instrumentation::Logger.enabled? &&
32
+ (NewRelic::Agent::Instrumentation::Logger.enabled? ||
33
+ NewRelic::Agent::Instrumentation::LogStasher.enabled?) &&
27
34
  NewRelic::Agent.config[:'application_logging.local_decorating.enabled']
28
35
  end
29
36
 
30
37
  def escape_entity_name(entity_name)
31
38
  return unless entity_name
32
39
 
33
- URI::DEFAULT_PARSER.escape(entity_name)
40
+ # TODO: OLD RUBIES 3.3
41
+ # URI version 1.0 marked URI::RFC3986_PARSER.escape as obsolete,
42
+ # which URI::DEFAULT_PARSER is an alias for.
43
+ # URI version 1.0+ will ship with Ruby 3.4
44
+ # Once we drop support for Rubies below 3.4, we can use the
45
+ # URI::RFC2396 parser exclusively.
46
+ if NewRelic::Helper.version_satisfied?(URI::VERSION, '>=', '1.0')
47
+ URI::RFC2396_PARSER.escape(entity_name)
48
+ else
49
+ URI::DEFAULT_PARSER.escape(entity_name)
50
+ end
34
51
  end
35
52
  end
36
53
  end