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
@@ -29,17 +29,23 @@ module NewRelic
29
29
  CATEGORY_KEY = 'category'
30
30
  HTTP_URL_KEY = 'http.url'
31
31
  HTTP_METHOD_KEY = 'http.method'
32
+ HTTP_REQUEST_METHOD_KEY = 'http.request.method'
32
33
  HTTP_STATUS_CODE_KEY = 'http.statusCode'
33
34
  COMPONENT_KEY = 'component'
34
35
  DB_INSTANCE_KEY = 'db.instance'
35
36
  DB_STATEMENT_KEY = 'db.statement'
37
+ DB_SYSTEM_KEY = 'db.system'
36
38
  PEER_ADDRESS_KEY = 'peer.address'
37
39
  PEER_HOSTNAME_KEY = 'peer.hostname'
40
+ SERVER_ADDRESS_KEY = 'server.address'
41
+ SERVER_PORT_KEY = 'server.port'
38
42
  SPAN_KIND_KEY = 'span.kind'
43
+ STACKTRACE_KEY = 'code.stacktrace'
39
44
  ENTRY_POINT_KEY = 'nr.entryPoint'
40
45
  TRUSTED_PARENT_KEY = 'trustedParentId'
41
46
  TRACING_VENDORS_KEY = 'tracingVendors'
42
47
  TRANSACTION_NAME_KEY = 'transaction.name'
48
+ THREAD_ID_KEY = 'thread.id'
43
49
 
44
50
  # Strings for static values of the event structure
45
51
  EVENT_TYPE = 'Span'
@@ -48,6 +54,8 @@ module NewRelic
48
54
  DATASTORE_CATEGORY = 'datastore'
49
55
  CLIENT = 'client'
50
56
 
57
+ DB_STATEMENT_MAX_BYTES = 4096
58
+
51
59
  # Builds a Hash of error attributes as well as the Span ID when
52
60
  # an error is present. Otherwise, returns nil when no error present.
53
61
  def error_attributes(segment)
@@ -69,31 +77,29 @@ module NewRelic
69
77
 
70
78
  intrinsics[COMPONENT_KEY] = segment.library
71
79
  intrinsics[HTTP_METHOD_KEY] = segment.procedure
80
+ intrinsics[HTTP_REQUEST_METHOD_KEY] = segment.procedure
72
81
  intrinsics[HTTP_STATUS_CODE_KEY] = segment.http_status_code if segment.http_status_code
73
82
  intrinsics[CATEGORY_KEY] = HTTP_CATEGORY
74
83
  intrinsics[SPAN_KIND_KEY] = CLIENT
75
-
76
- agent_attributes = error_attributes(segment) || {}
84
+ intrinsics[SERVER_ADDRESS_KEY] = segment.uri.host
85
+ intrinsics[SERVER_PORT_KEY] = segment.uri.port
86
+ agent_attributes = {}
77
87
 
78
88
  if allowed?(HTTP_URL_KEY)
79
89
  agent_attributes[HTTP_URL_KEY] = truncate(segment.uri)
80
90
  end
81
91
 
82
- if segment.respond_to?(:record_agent_attributes?) && segment.record_agent_attributes?
83
- agent_attributes.merge!(agent_attributes(segment))
84
- end
85
-
86
- [intrinsics, custom_attributes(segment), agent_attributes]
92
+ [intrinsics, custom_attributes(segment), agent_attributes.merge(agent_attributes(segment))]
87
93
  end
88
94
 
89
- def for_datastore_segment(segment)
95
+ def for_datastore_segment(segment) # rubocop:disable Metrics/AbcSize
90
96
  intrinsics = intrinsics_for(segment)
91
97
 
92
98
  intrinsics[COMPONENT_KEY] = segment.product
93
99
  intrinsics[SPAN_KIND_KEY] = CLIENT
94
100
  intrinsics[CATEGORY_KEY] = DATASTORE_CATEGORY
95
101
 
96
- agent_attributes = error_attributes(segment) || {}
102
+ agent_attributes = {}
97
103
 
98
104
  if segment.database_name && allowed?(DB_INSTANCE_KEY)
99
105
  agent_attributes[DB_INSTANCE_KEY] = truncate(segment.database_name)
@@ -101,17 +107,27 @@ module NewRelic
101
107
  if segment.host && segment.port_path_or_id && allowed?(PEER_ADDRESS_KEY)
102
108
  agent_attributes[PEER_ADDRESS_KEY] = truncate("#{segment.host}:#{segment.port_path_or_id}")
103
109
  end
104
- if segment.host && allowed?(PEER_HOSTNAME_KEY)
105
- agent_attributes[PEER_HOSTNAME_KEY] = truncate(segment.host)
110
+ if segment.host
111
+ [PEER_HOSTNAME_KEY, SERVER_ADDRESS_KEY].each do |key|
112
+ agent_attributes[key] = truncate(segment.host) if allowed?(key)
113
+ end
114
+ end
115
+ if segment.port_path_or_id&.match?(/^\d+$/) && allowed?(SERVER_PORT_KEY)
116
+ agent_attributes[SERVER_PORT_KEY] = segment.port_path_or_id
106
117
  end
118
+ agent_attributes[DB_SYSTEM_KEY] = segment.product if allowed?(DB_SYSTEM_KEY)
107
119
 
108
120
  if segment.sql_statement && allowed?(DB_STATEMENT_KEY)
109
- agent_attributes[DB_STATEMENT_KEY] = truncate(segment.sql_statement.safe_sql, 2000)
121
+ agent_attributes[DB_STATEMENT_KEY] = truncate(segment.sql_statement.safe_sql, DB_STATEMENT_MAX_BYTES)
110
122
  elsif segment.nosql_statement && allowed?(DB_STATEMENT_KEY)
111
- agent_attributes[DB_STATEMENT_KEY] = truncate(segment.nosql_statement, 2000)
123
+ agent_attributes[DB_STATEMENT_KEY] = truncate(segment.nosql_statement, DB_STATEMENT_MAX_BYTES)
124
+ end
125
+
126
+ if segment.params[:backtrace]
127
+ agent_attributes[STACKTRACE_KEY] = segment.params[:backtrace]
112
128
  end
113
129
 
114
- [intrinsics, custom_attributes(segment), agent_attributes]
130
+ [intrinsics, custom_attributes(segment), agent_attributes.merge(agent_attributes(segment))]
115
131
  end
116
132
 
117
133
  private
@@ -125,7 +141,8 @@ module NewRelic
125
141
  PRIORITY_KEY => segment.transaction.priority,
126
142
  TIMESTAMP_KEY => milliseconds_since_epoch(segment),
127
143
  DURATION_KEY => segment.duration,
128
- NAME_KEY => segment.name
144
+ NAME_KEY => segment.name,
145
+ THREAD_ID_KEY => segment.thread_id
129
146
  }
130
147
 
131
148
  # with infinite-tracing, transactions may or may not be sampled!
@@ -3,7 +3,6 @@
3
3
  # frozen_string_literal: true
4
4
 
5
5
  require 'zlib'
6
- require 'base64'
7
6
  require 'digest/md5'
8
7
 
9
8
  module NewRelic
@@ -13,10 +13,26 @@ require 'socket'
13
13
  module NewRelic
14
14
  module Agent
15
15
  module SystemInfo
16
+ DOCKER_CGROUPS_V2_PATTERN = %r{.*/docker/containers/([0-9a-f]{64})/.*}.freeze
17
+
16
18
  def self.ruby_os_identifier
17
19
  RbConfig::CONFIG['target_os']
18
20
  end
19
21
 
22
+ def self.os_distribution
23
+ case
24
+ when darwin? then :darwin
25
+ when linux? then :linux
26
+ when bsd? then :bsd
27
+ when windows? then :windows
28
+ else ruby_os_identifier
29
+ end
30
+ end
31
+
32
+ def self.windows?
33
+ !!(ruby_os_identifier[/mingw|mswin/i])
34
+ end
35
+
20
36
  def self.darwin?
21
37
  !!(ruby_os_identifier =~ /darwin/i)
22
38
  end
@@ -172,15 +188,39 @@ module NewRelic
172
188
  proc_try_read('/proc/version')
173
189
  end
174
190
 
191
+ # When operating within a Docker container, attempt to obtain the
192
+ # container id.
193
+ #
194
+ # First look for `/proc/self/mountinfo` to exist on disk to signify
195
+ # cgroups v2. If that file exists, read it and expect it to contain one
196
+ # or more "/docker/containers/<container_id>/" lines from which the
197
+ # container id can be gleaned.
198
+ #
199
+ # Next look for `/proc/self/cgroup` to exist on disk to signify cgroup v1.
200
+ # If that file exists, read it and parse the "cpu" group info in the hope
201
+ # of finding a 64 character container id value.
202
+ #
203
+ # For non-cgroups based containers, use a `nil` value for the container
204
+ # id without generating any warnings or errors.
175
205
  def self.docker_container_id
176
206
  return unless ruby_os_identifier.include?('linux')
177
207
 
208
+ cgroupsv2_based_id = docker_container_id_for_cgroupsv2
209
+ return cgroupsv2_based_id if cgroupsv2_based_id
210
+
178
211
  cgroup_info = proc_try_read('/proc/self/cgroup')
179
212
  return unless cgroup_info
180
213
 
181
214
  parse_docker_container_id(cgroup_info)
182
215
  end
183
216
 
217
+ def self.docker_container_id_for_cgroupsv2
218
+ mountinfo = proc_try_read('/proc/self/mountinfo')
219
+ return unless mountinfo
220
+
221
+ Regexp.last_match(1) if mountinfo =~ DOCKER_CGROUPS_V2_PATTERN
222
+ end
223
+
184
224
  def self.parse_docker_container_id(cgroup_info)
185
225
  cpu_cgroup = parse_cgroup_ids(cgroup_info)['cpu']
186
226
  return unless cpu_cgroup
@@ -9,8 +9,7 @@ module NewRelic
9
9
  def self.create(label, &blk)
10
10
  ::NewRelic::Agent.logger.debug("Creating AgentThread: #{label}")
11
11
  wrapped_blk = proc do
12
- if ::Thread.current[:newrelic_tracer_state] && Thread.current[:newrelic_tracer_state].current_transaction
13
- txn = ::Thread.current[:newrelic_tracer_state].current_transaction
12
+ if (txn = ::NewRelic::ThreadLocalStorage[:newrelic_tracer_state]&.current_transaction)
14
13
  ::NewRelic::Agent.logger.warn("AgentThread created with current transaction #{txn.best_name}")
15
14
  end
16
15
  begin
@@ -125,7 +125,16 @@ module NewRelic
125
125
 
126
126
  # Returns [filename, method, line number]
127
127
  def parse_backtrace_frame(frame)
128
- frame =~ /([^:]*)(\:(\d+))?\:in `(.*)'/
128
+ # TODO: OLD RUBIES - Ruby 3.3
129
+ # The (?:`|') non-capturing group can be removed when the agent
130
+ # drops support for Ruby 3.3
131
+ # This group is used to capture the pre-Ruby 3.4.0 backtrace syntax.
132
+ # Example frame:
133
+ # Ruby 3.3.0 and below
134
+ # "irb.rb:69:in `catch'"
135
+ # Ruby 3.4.0+
136
+ # "irb.rb:69:in 'Kernel#catch'"
137
+ frame =~ /([^:]*)(\:(\d+))?\:in (?:`|')(.*)'/
129
138
  [$1, $4, $3] # sic
130
139
  end
131
140
  end
@@ -66,9 +66,10 @@ module NewRelic
66
66
  #
67
67
  # @api public
68
68
  def transaction_sampled?
69
- if txn = current_transaction
70
- txn.sampled?
71
- end
69
+ txn = current_transaction
70
+ return false unless txn
71
+
72
+ txn.sampled?
72
73
  end
73
74
  alias_method :sampled?, :transaction_sampled?
74
75
 
@@ -246,7 +247,7 @@ module NewRelic
246
247
  log_error('start_segment', exception)
247
248
  end
248
249
 
249
- UNKNOWN = 'Unknown'.freeze
250
+ UNKNOWN = NewRelic::UNKNOWN
250
251
  OTHER = 'other'.freeze
251
252
 
252
253
  # Creates and starts a datastore segment used to time
@@ -356,9 +357,7 @@ module NewRelic
356
357
  yield
357
358
  rescue => exception
358
359
  # needs else branch coverage
359
- if segment && segment.is_a?(Transaction::AbstractSegment) # rubocop:disable Style/SafeNavigation
360
- segment.notice_error(exception)
361
- end
360
+ segment.notice_error(exception) if segment&.is_a?(Transaction::AbstractSegment)
362
361
  raise
363
362
  end
364
363
 
@@ -393,11 +392,11 @@ module NewRelic
393
392
  #
394
393
  # If ever exposed, this requires additional synchronization
395
394
  def state_for(thread)
396
- state = thread[:newrelic_tracer_state]
395
+ state = ThreadLocalStorage.get(thread, :newrelic_tracer_state)
397
396
 
398
397
  if state.nil?
399
398
  state = Tracer::State.new
400
- thread[:newrelic_tracer_state] = state
399
+ ThreadLocalStorage.set(thread, :newrelic_tracer_state, state)
401
400
  end
402
401
 
403
402
  state
@@ -406,7 +405,7 @@ module NewRelic
406
405
  alias_method :tl_state_for, :state_for
407
406
 
408
407
  def clear_state
409
- Thread.current[:newrelic_tracer_state] = nil
408
+ ThreadLocalStorage[:newrelic_tracer_state] = nil
410
409
  end
411
410
 
412
411
  alias_method :tl_clear, :clear_state
@@ -419,16 +418,17 @@ module NewRelic
419
418
  NewRelic::Agent.config[:'instrumentation.thread.tracing']
420
419
  end
421
420
 
422
- def thread_block_with_current_transaction(*args, segment_name:, parent: nil, &block)
421
+ def thread_block_with_current_transaction(segment_name: nil, parent: nil, &block)
423
422
  parent ||= current_segment
424
- current_txn = ::Thread.current[:newrelic_tracer_state]&.current_transaction if ::Thread.current[:newrelic_tracer_state]&.is_execution_traced?
425
- proc do
423
+ current_txn = ThreadLocalStorage[:newrelic_tracer_state]&.current_transaction if ThreadLocalStorage[:newrelic_tracer_state]&.is_execution_traced?
424
+ proc do |*args|
426
425
  begin
427
- if current_txn
426
+ if current_txn && !current_txn.finished?
428
427
  NewRelic::Agent::Tracer.state.current_transaction = current_txn
428
+ ThreadLocalStorage[:newrelic_thread_span_parent] = parent
429
429
  current_txn.async = true
430
- segment_name += "/Thread#{::Thread.current.object_id}/Fiber#{::Fiber.current.object_id}" if NewRelic::Agent.config[:'thread_ids_enabled']
431
- segment = NewRelic::Agent::Tracer.start_segment(name: segment_name, parent: parent)
430
+ segment_name = "#{segment_name}/Thread#{::Thread.current.object_id}/Fiber#{::Fiber.current.object_id}" if NewRelic::Agent.config[:'thread_ids_enabled']
431
+ segment = NewRelic::Agent::Tracer.start_segment(name: segment_name, parent: parent) if segment_name
432
432
  end
433
433
  NewRelic::Agent::Tracer.capture_segment_error(segment) do
434
434
  yield(*args)
@@ -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 'new_relic/agent/range_extensions'
6
5
  require 'new_relic/agent/guid_generator'
7
6
 
8
7
  module NewRelic
@@ -20,14 +19,18 @@ module NewRelic
20
19
  # after its parent. We will use the optimized exclusive duration
21
20
  # calculation in all other cases.
22
21
  #
23
- attr_reader :start_time, :end_time, :duration, :exclusive_duration, :guid, :starting_segment_key
24
- attr_accessor :name, :parent, :children_time, :transaction, :transaction_name
22
+ attr_reader :start_time, :end_time, :duration, :exclusive_duration, :guid, :starting_segment_key, :thread_id
23
+ attr_accessor :name, :parent, :children_time, :transaction, :transaction_name, :llm_event
25
24
  attr_writer :record_metrics, :record_scoped_metric, :record_on_finish
26
25
  attr_reader :noticed_error
27
26
 
27
+ CALLBACK = :@callback
28
+ SEGMENT = 'segment'
29
+
28
30
  def initialize(name = nil, start_time = nil)
29
31
  @name = name
30
32
  @starting_segment_key = NewRelic::Agent::Tracer.current_segment_key
33
+ @thread_id = Thread.current.object_id
31
34
  @transaction_name = nil
32
35
  @transaction = nil
33
36
  @guid = NewRelic::Agent::GuidGenerator.generate_guid
@@ -50,6 +53,7 @@ module NewRelic
50
53
  @code_function = nil
51
54
  @code_lineno = nil
52
55
  @code_namespace = nil
56
+ invoke_callback
53
57
  end
54
58
 
55
59
  def start
@@ -105,38 +109,6 @@ module NewRelic
105
109
  @start_time.to_f..@end_time.to_f
106
110
  end
107
111
 
108
- def timings_overlap?(timing1, timing2)
109
- (timing1.first >= timing2.first && timing1.first <= timing2.last) ||
110
- (timing2.first >= timing1.first && timing2.first <= timing1.last)
111
- end
112
-
113
- def merge_timings(timing1, timing2)
114
- [([timing1.first, timing2.first].min),
115
- ([timing1.last, timing2.last].max)]
116
- end
117
-
118
- # @children_timings is an array of array, with each inner array
119
- # holding exactly 2 values, a child segment's start time and finish
120
- # time (in that order). When it's time to record, these timings are
121
- # converted into an array of range objects (using the same start and
122
- # end values as the original array). Any two range objects that
123
- # intersect and merged into a larger range. This checking for a
124
- # intersections and merging of ranges is expensive, so the operation
125
- # is only done at recording time.
126
- def children_time_ranges
127
- @children_time_ranges ||= begin
128
- overlapped = @children_timings.each_with_object([]) do |timing, timings|
129
- i = timings.index { |t| timings_overlap?(t, timing) }
130
- if i
131
- timings[i] = merge_timings(timing, timings[i])
132
- else
133
- timings << timing
134
- end
135
- end
136
- overlapped.map { |t| Range.new(t.first, t.last) }
137
- end
138
- end
139
-
140
112
  def children_time_ranges?
141
113
  !@children_timings.empty?
142
114
  end
@@ -299,12 +271,6 @@ module NewRelic
299
271
  end
300
272
 
301
273
  def record_exclusive_duration
302
- overlapping_duration = if children_time_ranges?
303
- RangeExtensions.compute_overlap(time_range, children_time_ranges)
304
- else
305
- 0.0
306
- end
307
-
308
274
  @exclusive_duration = duration - children_time - overlapping_duration
309
275
  transaction.total_time += @exclusive_duration
310
276
  params[:exclusive_duration_millis] = @exclusive_duration * 1000 if transaction.async?
@@ -314,6 +280,51 @@ module NewRelic
314
280
  transaction.metrics
315
281
  end
316
282
 
283
+ def ranges_intersect?(r1, r2)
284
+ r1.begin > r2.begin ? r2.cover?(r1.begin) : r1.cover?(r2.begin)
285
+ end
286
+
287
+ def range_overlap(range)
288
+ return 0.0 unless ranges_intersect?(range, time_range)
289
+
290
+ [range.end, time_range.end].min - [range.begin, time_range.begin].max
291
+ end
292
+
293
+ # Child segments operating concurrently with this segment may have
294
+ # start and end times that overlap with this segment's own times. The
295
+ # amount of overlap needs to be removed from the `children_time` total
296
+ # when calculating an `@exclusive_duration` value to be added to the
297
+ # transaction's total time.
298
+ #
299
+ # If there aren't any child segments, return 0.0. Otherwise, take the
300
+ # `@children_timings` array of arrays (each array holds a child
301
+ # segment's start time and end time), sort it by the first elements
302
+ # (start times), and use the start and finish times to create Range
303
+ # objects. Combine all of the child segment ranges that overlap with
304
+ # one another into new bigger ranges. Then take those bigger ranges
305
+ # and calculate how much overlap there is between them and this
306
+ # segment's own time range. Keep a running sum of all of the overlap
307
+ # amounts and then return it.
308
+ def overlapping_duration
309
+ sum = 0.0
310
+ return sum unless children_time_ranges?
311
+
312
+ @children_timings.sort_by!(&:first)
313
+ range = Range.new(*@children_timings.first)
314
+ (1..(@children_timings.size - 1)).each do |i|
315
+ possible = Range.new(*@children_timings[i])
316
+
317
+ if ranges_intersect?(range, possible)
318
+ range = range.begin..possible.end
319
+ else
320
+ sum += range_overlap(range)
321
+ range = possible
322
+ end
323
+ end
324
+
325
+ sum += range_overlap(range)
326
+ end
327
+
317
328
  def transaction_state
318
329
  @transaction_state ||= if @transaction
319
330
  transaction.state
@@ -321,6 +332,57 @@ module NewRelic
321
332
  Tracer.state
322
333
  end
323
334
  end
335
+
336
+ # for segment callback usage info, see self.set_segment_callback
337
+ def invoke_callback
338
+ return unless self.class.instance_variable_defined?(CALLBACK)
339
+
340
+ NewRelic::Agent.logger.debug("Invoking callback for #{self.class.name}...")
341
+ self.class.instance_variable_get(CALLBACK).call
342
+ rescue Exception => e
343
+ NewRelic::Agent.logger.error("Error encountered while invoking callback for #{self.class.name}: " +
344
+ "#{e.class} - #{e.message}")
345
+ end
346
+
347
+ # Setting and invoking a segment callback
348
+ # =======================================
349
+ # Each individual segment class such as `ExternalRequestSegment` allows
350
+ # for exactly one instance of a `Proc` (meaning a proc or lambda) to be
351
+ # set as a callback. A callback can be set on a segment class by calling
352
+ # `.set_segment_callback` with a proc or lambda as the only argument.
353
+ # If set, the callback will be invoked with `#call` at segment class
354
+ # initialization time.
355
+ #
356
+ # Example usage:
357
+ # callback = -> { puts 'Hello, World! }
358
+ # ExternalRequestSegment.set_segment_callback(callback)
359
+ # ExternalRequestSegment.new(library, uri, procedure)
360
+ #
361
+ # A callback set on a segment class will only be called when that
362
+ # specific segment class is initialized. Other segment classes will not
363
+ # be impacted.
364
+ #
365
+ # Great caution should be taken in the defining of the callback block
366
+ # to not have the block perform anything too time consuming or resource
367
+ # intensive in order to keep the New Relic Ruby agent operating
368
+ # normally.
369
+ #
370
+ # Given that callbacks are user defined, they must be set entirely at
371
+ # the user's own risk. It is recommended that each callback use
372
+ # conditional logic that only performs work for certain qualified
373
+ # segments. It is recommended that each callback be thoroughly tested
374
+ # in non-production environments before being introduced to production
375
+ # environments.
376
+ def self.set_segment_callback(callback_proc)
377
+ unless callback_proc.is_a?(Proc)
378
+ NewRelic::Agent.logger.error("#{self}.#{__method__}: expected an argument of type Proc, " \
379
+ "got #{callback_proc.class}")
380
+ return
381
+ end
382
+
383
+ NewRelic::Agent.record_api_supportability_metric(:set_segment_callback)
384
+ instance_variable_set(CALLBACK, callback_proc)
385
+ end
324
386
  end
325
387
  end
326
388
  end
@@ -11,7 +11,7 @@ module NewRelic
11
11
  module Agent
12
12
  class Transaction
13
13
  class DatastoreSegment < Segment
14
- UNKNOWN = 'unknown'.freeze
14
+ UNKNOWN = NewRelic::UNKNOWN_LOWER
15
15
 
16
16
  attr_reader :product, :operation, :collection, :sql_statement, :nosql_statement, :host, :port_path_or_id
17
17
  attr_accessor :database_name, :record_sql
@@ -35,7 +35,7 @@ module NewRelic
35
35
  end
36
36
 
37
37
  def caller_transport_type
38
- @caller_transport_type ||= 'Unknown'
38
+ @caller_transport_type ||= NewRelic::UNKNOWN
39
39
  end
40
40
 
41
41
  def accept_transport_type_from_api(value)
@@ -127,7 +127,7 @@ module NewRelic
127
127
  def consume_message_synthetics_headers(headers)
128
128
  synthetics_header = headers[CrossAppTracing::NR_MESSAGE_BROKER_SYNTHETICS_HEADER]
129
129
  if synthetics_header and
130
- incoming_payload = ::JSON.load(deobfuscate(synthetics_header)) and
130
+ incoming_payload = ::JSON.parse(deobfuscate(synthetics_header)) and
131
131
  SyntheticsMonitor.is_valid_payload?(incoming_payload) and
132
132
  SyntheticsMonitor.is_supported_version?(incoming_payload) and
133
133
  SyntheticsMonitor.is_trusted?(incoming_payload)
@@ -167,7 +167,7 @@ module NewRelic
167
167
  return unless CrossAppTracing.trusted_valid_cross_app_id?(decoded_id)
168
168
 
169
169
  txn_header = headers[CrossAppTracing::NR_MESSAGE_BROKER_TXN_HEADER]
170
- txn_info = ::JSON.load(deobfuscate(txn_header))
170
+ txn_info = ::JSON.parse(deobfuscate(txn_header))
171
171
  payload = CrossAppPayload.new(decoded_id, transaction, txn_info)
172
172
 
173
173
  @cross_app_payload = payload
@@ -119,14 +119,13 @@ module NewRelic
119
119
  end
120
120
 
121
121
  def check_required_fields_present(payload)
122
- if \
123
- !payload.version.nil? &&
124
- !payload.parent_account_id.nil? &&
125
- !payload.parent_app_id.nil? &&
126
- !payload.parent_type.nil? &&
127
- (!payload.transaction_id.nil? || !payload.id.nil?) &&
128
- !payload.trace_id.nil? &&
129
- !payload.timestamp.nil?
122
+ if !payload.version.nil? &&
123
+ !payload.parent_account_id.nil? &&
124
+ !payload.parent_app_id.nil? &&
125
+ !payload.parent_type.nil? &&
126
+ (!payload.transaction_id.nil? || !payload.id.nil?) &&
127
+ !payload.trace_id.nil? &&
128
+ !payload.timestamp.nil?
130
129
 
131
130
  true
132
131
  else
@@ -14,6 +14,7 @@ module NewRelic
14
14
  # @api public
15
15
  class ExternalRequestSegment < Segment
16
16
  NR_SYNTHETICS_HEADER = 'X-NewRelic-Synthetics'
17
+ NR_SYNTHETICS_INFO_HEADER = 'X-NewRelic-Synthetics-Info'
17
18
  APP_DATA_KEY = 'NewRelicAppData'
18
19
 
19
20
  EXTERNAL_ALL = 'External/all'
@@ -22,7 +23,6 @@ module NewRelic
22
23
  MISSING_STATUS_CODE = 'MissingHTTPStatusCode'
23
24
 
24
25
  attr_reader :library, :uri, :procedure, :http_status_code
25
- attr_writer :record_agent_attributes
26
26
 
27
27
  def initialize(library, uri, procedure, start_time = nil) # :nodoc:
28
28
  @library = library
@@ -31,7 +31,6 @@ module NewRelic
31
31
  @host_header = nil
32
32
  @app_data = nil
33
33
  @http_status_code = nil
34
- @record_agent_attributes = false
35
34
  super(nil, nil, start_time)
36
35
  end
37
36
 
@@ -43,14 +42,6 @@ module NewRelic
43
42
  @host_header || uri.host
44
43
  end
45
44
 
46
- # By default external request segments only have errors and the http
47
- # url recorded as agent attributes. To have all the agent attributes
48
- # recorded, use the attr_writer like so `segment.record_agent_attributes = true`
49
- # See: SpanEventPrimitive#for_external_request_segment
50
- def record_agent_attributes?
51
- @record_agent_attributes
52
- end
53
-
54
45
  # This method adds New Relic request headers to a given request made to an
55
46
  # external API and checks to see if a host header is used for the request.
56
47
  # If a host header is used, it updates the segment name to match the host
@@ -63,7 +54,8 @@ module NewRelic
63
54
  def add_request_headers(request)
64
55
  process_host_header(request)
65
56
  synthetics_header = transaction&.raw_synthetics_header
66
- insert_synthetics_header(request, synthetics_header) if synthetics_header
57
+ synthetics_info_header = transaction&.raw_synthetics_info_header
58
+ insert_synthetics_header(request, synthetics_header, synthetics_info_header) if synthetics_header
67
59
 
68
60
  return unless record_metrics?
69
61
 
@@ -207,8 +199,9 @@ module NewRelic
207
199
  end
208
200
  end
209
201
 
210
- def insert_synthetics_header(request, header)
202
+ def insert_synthetics_header(request, header, info)
211
203
  request[NR_SYNTHETICS_HEADER] = header
204
+ request[NR_SYNTHETICS_INFO_HEADER] = info if info
212
205
  end
213
206
 
214
207
  def segment_complete
@@ -15,14 +15,15 @@ module NewRelic
15
15
  PRODUCE = 'Produce'.freeze
16
16
  QUEUE = 'Queue'.freeze
17
17
  PURGE = 'Purge'.freeze
18
- SLASH = '/'.freeze
18
+ STREAM = 'Stream'.freeze
19
19
  TEMP = 'Temp'.freeze
20
20
  TOPIC = 'Topic'.freeze
21
- UNKNOWN = 'Unknown'.freeze
21
+ UNKNOWN = NewRelic::UNKNOWN
22
22
 
23
23
  DESTINATION_TYPES = [
24
24
  :exchange,
25
25
  :queue,
26
+ :stream,
26
27
  :topic,
27
28
  :temporary_queue,
28
29
  :temporary_topic,
@@ -38,6 +39,7 @@ module NewRelic
38
39
  TYPES = {
39
40
  exchange: EXCHANGE,
40
41
  temporary_queue: QUEUE,
42
+ stream: STREAM,
41
43
  queue: QUEUE,
42
44
  temporary_topic: TOPIC,
43
45
  topic: TOPIC,
@@ -73,7 +75,7 @@ module NewRelic
73
75
  return @name if @name
74
76
 
75
77
  @name = METRIC_PREFIX + library
76
- @name << SLASH << TYPES[destination_type] << SLASH << ACTIONS[action] << SLASH
78
+ @name << NewRelic::SLASH << TYPES[destination_type] << NewRelic::SLASH << ACTIONS[action] << NewRelic::SLASH
77
79
 
78
80
  if destination_type == :temporary_queue || destination_type == :temporary_topic
79
81
  @name << TEMP