newrelic_rpm 5.7.0.350 → 9.0.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 (476) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +15 -1
  3. data/.rubocop.yml +1919 -0
  4. data/.rubocop_todo.yml +100 -0
  5. data/.simplecov +15 -0
  6. data/.snyk +11 -0
  7. data/.yardopts +2 -0
  8. data/Brewfile +12 -0
  9. data/CHANGELOG.md +4056 -2339
  10. data/CONTRIBUTING.md +132 -19
  11. data/DOCKER.md +167 -0
  12. data/Dockerfile +10 -0
  13. data/Gemfile +5 -2
  14. data/Guardfile +22 -4
  15. data/LICENSE +202 -38
  16. data/README.md +87 -87
  17. data/Rakefile +27 -27
  18. data/THIRD_PARTY_NOTICES.md +28 -0
  19. data/Thorfile +5 -0
  20. data/bin/newrelic +3 -2
  21. data/bin/newrelic_cmd +1 -0
  22. data/bin/nrdebug +77 -54
  23. data/config.dot +5 -5
  24. data/docker-compose.yml +107 -0
  25. data/init.rb +5 -7
  26. data/install.rb +3 -3
  27. data/lefthook.yml +9 -0
  28. data/lib/new_relic/agent/adaptive_sampler.rb +14 -10
  29. data/lib/new_relic/agent/agent.rb +125 -969
  30. data/lib/new_relic/agent/agent_helpers/connect.rb +227 -0
  31. data/lib/new_relic/agent/agent_helpers/harvest.rb +153 -0
  32. data/lib/new_relic/agent/agent_helpers/shutdown.rb +72 -0
  33. data/lib/new_relic/agent/agent_helpers/special_startup.rb +74 -0
  34. data/lib/new_relic/agent/agent_helpers/start_worker_thread.rb +167 -0
  35. data/lib/new_relic/agent/agent_helpers/startup.rb +202 -0
  36. data/lib/new_relic/agent/agent_helpers/transmit.rb +76 -0
  37. data/lib/new_relic/agent/agent_logger.rb +26 -18
  38. data/lib/new_relic/agent/attribute_filter.rb +69 -52
  39. data/lib/new_relic/agent/attribute_processing.rb +8 -8
  40. data/lib/new_relic/agent/attributes.rb +153 -0
  41. data/lib/new_relic/agent/audit_logger.rb +19 -4
  42. data/lib/new_relic/agent/autostart.rb +34 -28
  43. data/lib/new_relic/agent/chained_call.rb +2 -2
  44. data/lib/new_relic/agent/commands/agent_command.rb +4 -4
  45. data/lib/new_relic/agent/commands/agent_command_router.rb +15 -33
  46. data/lib/new_relic/agent/commands/thread_profiler_session.rb +13 -11
  47. data/lib/new_relic/agent/configuration/default_source.rb +1480 -1053
  48. data/lib/new_relic/agent/configuration/dotted_hash.rb +7 -6
  49. data/lib/new_relic/agent/configuration/environment_source.rb +15 -11
  50. data/lib/new_relic/agent/configuration/event_harvest_config.rb +68 -0
  51. data/lib/new_relic/agent/configuration/high_security_source.rb +9 -9
  52. data/lib/new_relic/agent/configuration/manager.rb +96 -79
  53. data/lib/new_relic/agent/configuration/manual_source.rb +2 -2
  54. data/lib/new_relic/agent/configuration/mask_defaults.rb +4 -4
  55. data/lib/new_relic/agent/configuration/security_policy_source.rb +83 -86
  56. data/lib/new_relic/agent/configuration/server_source.rb +49 -12
  57. data/lib/new_relic/agent/configuration/yaml_source.rb +42 -13
  58. data/lib/new_relic/agent/configuration.rb +2 -2
  59. data/lib/new_relic/agent/connect/request_builder.rb +61 -0
  60. data/lib/new_relic/agent/connect/response_handler.rb +58 -0
  61. data/lib/new_relic/agent/custom_event_aggregator.rb +15 -15
  62. data/lib/new_relic/agent/database/explain_plan_helpers.rb +5 -6
  63. data/lib/new_relic/agent/database/obfuscation_helpers.rb +16 -15
  64. data/lib/new_relic/agent/database/obfuscator.rb +3 -3
  65. data/lib/new_relic/agent/database/postgres_explain_obfuscator.rb +4 -4
  66. data/lib/new_relic/agent/database.rb +44 -53
  67. data/lib/new_relic/agent/database_adapter.rb +35 -0
  68. data/lib/new_relic/agent/datastores/metric_helper.rb +18 -20
  69. data/lib/new_relic/agent/datastores/mongo/event_formatter.rb +9 -8
  70. data/lib/new_relic/agent/datastores/mongo/metric_translator.rb +7 -11
  71. data/lib/new_relic/agent/datastores/mongo.rb +7 -12
  72. data/lib/new_relic/agent/datastores/nosql_obfuscator.rb +41 -0
  73. data/lib/new_relic/agent/datastores/redis.rb +6 -12
  74. data/lib/new_relic/agent/datastores.rb +19 -23
  75. data/lib/new_relic/agent/deprecator.rb +2 -2
  76. data/lib/new_relic/agent/{cross_app_payload.rb → distributed_tracing/cross_app_payload.rb} +13 -12
  77. data/lib/new_relic/agent/{cross_app_tracing.rb → distributed_tracing/cross_app_tracing.rb} +87 -66
  78. data/lib/new_relic/agent/distributed_tracing/distributed_trace_attributes.rb +84 -0
  79. data/lib/new_relic/agent/distributed_tracing/distributed_trace_metrics.rb +75 -0
  80. data/lib/new_relic/agent/distributed_tracing/distributed_trace_payload.rb +163 -0
  81. data/lib/new_relic/agent/distributed_tracing/distributed_trace_transport_type.rb +38 -0
  82. data/lib/new_relic/agent/distributed_tracing/trace_context.rb +245 -0
  83. data/lib/new_relic/agent/distributed_tracing/trace_context_payload.rb +127 -0
  84. data/lib/new_relic/agent/distributed_tracing.rb +113 -32
  85. data/lib/new_relic/agent/encoding_normalizer.rb +5 -3
  86. data/lib/new_relic/agent/error_collector.rb +99 -63
  87. data/lib/new_relic/agent/error_event_aggregator.rb +10 -8
  88. data/lib/new_relic/agent/error_filter.rb +174 -0
  89. data/lib/new_relic/agent/error_trace_aggregator.rb +6 -4
  90. data/lib/new_relic/agent/event_aggregator.rb +43 -48
  91. data/lib/new_relic/agent/event_buffer.rb +8 -9
  92. data/lib/new_relic/agent/event_listener.rb +2 -3
  93. data/lib/new_relic/agent/event_loop.rb +27 -25
  94. data/lib/new_relic/agent/external.rb +20 -51
  95. data/lib/new_relic/agent/guid_generator.rb +30 -0
  96. data/lib/new_relic/agent/harvester.rb +5 -6
  97. data/lib/new_relic/agent/heap.rb +8 -10
  98. data/lib/new_relic/agent/hostname.rb +26 -5
  99. data/lib/new_relic/agent/http_clients/abstract.rb +81 -0
  100. data/lib/new_relic/agent/http_clients/curb_wrappers.rb +26 -26
  101. data/lib/new_relic/agent/http_clients/excon_wrappers.rb +31 -17
  102. data/lib/new_relic/agent/http_clients/http_rb_wrappers.rb +18 -23
  103. data/lib/new_relic/agent/http_clients/httpclient_wrappers.rb +12 -15
  104. data/lib/new_relic/agent/http_clients/net_http_wrappers.rb +24 -8
  105. data/lib/new_relic/agent/http_clients/typhoeus_wrappers.rb +9 -12
  106. data/lib/new_relic/agent/http_clients/uri_util.rb +12 -13
  107. data/lib/new_relic/agent/instrumentation/action_cable_subscriber.rb +22 -52
  108. data/lib/new_relic/agent/instrumentation/action_controller_other_subscriber.rb +39 -0
  109. data/lib/new_relic/agent/instrumentation/action_controller_subscriber.rb +59 -72
  110. data/lib/new_relic/agent/instrumentation/action_dispatch.rb +31 -0
  111. data/lib/new_relic/agent/instrumentation/action_dispatch_subscriber.rb +64 -0
  112. data/lib/new_relic/agent/instrumentation/action_mailbox.rb +30 -0
  113. data/lib/new_relic/agent/instrumentation/action_mailbox_subscriber.rb +33 -0
  114. data/lib/new_relic/agent/instrumentation/action_mailer.rb +30 -0
  115. data/lib/new_relic/agent/instrumentation/action_mailer_subscriber.rb +85 -0
  116. data/lib/new_relic/agent/instrumentation/action_view_subscriber.rb +86 -62
  117. data/lib/new_relic/agent/instrumentation/active_job.rb +38 -19
  118. data/lib/new_relic/agent/instrumentation/active_job_subscriber.rb +41 -0
  119. data/lib/new_relic/agent/instrumentation/active_merchant.rb +21 -7
  120. data/lib/new_relic/agent/instrumentation/active_record.rb +95 -46
  121. data/lib/new_relic/agent/instrumentation/active_record_helper.rb +82 -61
  122. data/lib/new_relic/agent/instrumentation/active_record_notifications.rb +155 -0
  123. data/lib/new_relic/agent/instrumentation/active_record_prepend.rb +36 -12
  124. data/lib/new_relic/agent/instrumentation/active_record_subscriber.rb +69 -64
  125. data/lib/new_relic/agent/instrumentation/active_storage.rb +8 -4
  126. data/lib/new_relic/agent/instrumentation/active_storage_subscriber.rb +11 -32
  127. data/lib/new_relic/agent/instrumentation/active_support.rb +27 -0
  128. data/lib/new_relic/agent/instrumentation/active_support_logger/chain.rb +23 -0
  129. data/lib/new_relic/agent/instrumentation/active_support_logger/instrumentation.rb +20 -0
  130. data/lib/new_relic/agent/instrumentation/active_support_logger/prepend.rb +12 -0
  131. data/lib/new_relic/agent/instrumentation/active_support_logger.rb +24 -0
  132. data/lib/new_relic/agent/instrumentation/active_support_subscriber.rb +41 -0
  133. data/lib/new_relic/agent/instrumentation/bunny/chain.rb +45 -0
  134. data/lib/new_relic/agent/instrumentation/bunny/instrumentation.rb +150 -0
  135. data/lib/new_relic/agent/instrumentation/bunny/prepend.rb +35 -0
  136. data/lib/new_relic/agent/instrumentation/bunny.rb +14 -134
  137. data/lib/new_relic/agent/instrumentation/concurrent_ruby/chain.rb +36 -0
  138. data/lib/new_relic/agent/instrumentation/concurrent_ruby/instrumentation.rb +21 -0
  139. data/lib/new_relic/agent/instrumentation/concurrent_ruby/prepend.rb +27 -0
  140. data/lib/new_relic/agent/instrumentation/concurrent_ruby.rb +31 -0
  141. data/lib/new_relic/agent/instrumentation/controller_instrumentation.rb +77 -61
  142. data/lib/new_relic/agent/instrumentation/curb/chain.rb +91 -0
  143. data/lib/new_relic/agent/instrumentation/curb/instrumentation.rb +221 -0
  144. data/lib/new_relic/agent/instrumentation/curb/prepend.rb +61 -0
  145. data/lib/new_relic/agent/instrumentation/curb.rb +15 -187
  146. data/lib/new_relic/agent/instrumentation/custom_events.rb +12 -0
  147. data/lib/new_relic/agent/instrumentation/custom_events_subscriber.rb +37 -0
  148. data/lib/new_relic/agent/instrumentation/delayed_job/chain.rb +35 -0
  149. data/lib/new_relic/agent/instrumentation/delayed_job/instrumentation.rb +48 -0
  150. data/lib/new_relic/agent/instrumentation/delayed_job/prepend.rb +33 -0
  151. data/lib/new_relic/agent/instrumentation/delayed_job_instrumentation.rb +30 -52
  152. data/lib/new_relic/agent/instrumentation/elasticsearch/chain.rb +29 -0
  153. data/lib/new_relic/agent/instrumentation/elasticsearch/instrumentation.rb +66 -0
  154. data/lib/new_relic/agent/instrumentation/elasticsearch/prepend.rb +13 -0
  155. data/lib/new_relic/agent/instrumentation/elasticsearch.rb +31 -0
  156. data/lib/new_relic/agent/instrumentation/excon/middleware.rb +8 -7
  157. data/lib/new_relic/agent/instrumentation/excon.rb +29 -31
  158. data/lib/new_relic/agent/instrumentation/fiber/chain.rb +20 -0
  159. data/lib/new_relic/agent/instrumentation/fiber/instrumentation.rb +24 -0
  160. data/lib/new_relic/agent/instrumentation/fiber/prepend.rb +18 -0
  161. data/lib/new_relic/agent/instrumentation/fiber.rb +25 -0
  162. data/lib/new_relic/agent/instrumentation/grape/chain.rb +24 -0
  163. data/lib/new_relic/agent/instrumentation/grape/instrumentation.rb +100 -0
  164. data/lib/new_relic/agent/instrumentation/grape/prepend.rb +17 -0
  165. data/lib/new_relic/agent/instrumentation/grape.rb +16 -121
  166. data/lib/new_relic/agent/instrumentation/grpc/client/chain.rb +97 -0
  167. data/lib/new_relic/agent/instrumentation/grpc/client/instrumentation.rb +89 -0
  168. data/lib/new_relic/agent/instrumentation/grpc/client/prepend.rb +111 -0
  169. data/lib/new_relic/agent/instrumentation/grpc/client/request_wrapper.rb +30 -0
  170. data/lib/new_relic/agent/instrumentation/grpc/helper.rb +32 -0
  171. data/lib/new_relic/agent/instrumentation/grpc/server/chain.rb +69 -0
  172. data/lib/new_relic/agent/instrumentation/grpc/server/instrumentation.rb +134 -0
  173. data/lib/new_relic/agent/instrumentation/grpc/server/rpc_desc_prepend.rb +35 -0
  174. data/lib/new_relic/agent/instrumentation/grpc/server/rpc_server_prepend.rb +26 -0
  175. data/lib/new_relic/agent/instrumentation/grpc_client.rb +23 -0
  176. data/lib/new_relic/agent/instrumentation/grpc_server.rb +25 -0
  177. data/lib/new_relic/agent/instrumentation/httpclient/chain.rb +24 -0
  178. data/lib/new_relic/agent/instrumentation/httpclient/instrumentation.rb +37 -0
  179. data/lib/new_relic/agent/instrumentation/httpclient/prepend.rb +15 -0
  180. data/lib/new_relic/agent/instrumentation/httpclient.rb +12 -32
  181. data/lib/new_relic/agent/instrumentation/httprb/chain.rb +22 -0
  182. data/lib/new_relic/agent/instrumentation/httprb/instrumentation.rb +30 -0
  183. data/lib/new_relic/agent/instrumentation/httprb/prepend.rb +15 -0
  184. data/lib/new_relic/agent/instrumentation/httprb.rb +29 -0
  185. data/lib/new_relic/agent/instrumentation/ignore_actions.rb +5 -6
  186. data/lib/new_relic/agent/instrumentation/logger/chain.rb +21 -0
  187. data/lib/new_relic/agent/instrumentation/logger/instrumentation.rb +66 -0
  188. data/lib/new_relic/agent/instrumentation/logger/prepend.rb +13 -0
  189. data/lib/new_relic/agent/instrumentation/logger.rb +26 -0
  190. data/lib/new_relic/agent/instrumentation/memcache/chain.rb +15 -0
  191. data/lib/new_relic/agent/instrumentation/memcache/dalli.rb +58 -125
  192. data/lib/new_relic/agent/instrumentation/memcache/helper.rb +59 -0
  193. data/lib/new_relic/agent/instrumentation/memcache/instrumentation.rb +90 -0
  194. data/lib/new_relic/agent/instrumentation/memcache/prepend.rb +101 -0
  195. data/lib/new_relic/agent/instrumentation/memcache.rb +57 -71
  196. data/lib/new_relic/agent/instrumentation/middleware_proxy.rb +15 -14
  197. data/lib/new_relic/agent/instrumentation/middleware_tracing.rb +21 -14
  198. data/lib/new_relic/agent/instrumentation/mongo.rb +7 -132
  199. data/lib/new_relic/agent/instrumentation/mongodb_command_subscriber.rb +49 -13
  200. data/lib/new_relic/agent/instrumentation/net_http/chain.rb +24 -0
  201. data/lib/new_relic/agent/instrumentation/net_http/instrumentation.rb +40 -0
  202. data/lib/new_relic/agent/instrumentation/net_http/prepend.rb +21 -0
  203. data/lib/new_relic/agent/instrumentation/net_http.rb +44 -0
  204. data/lib/new_relic/agent/instrumentation/notifications_subscriber.rb +142 -0
  205. data/lib/new_relic/agent/instrumentation/padrino/chain.rb +38 -0
  206. data/lib/new_relic/agent/instrumentation/padrino/instrumentation.rb +28 -0
  207. data/lib/new_relic/agent/instrumentation/padrino/prepend.rb +20 -0
  208. data/lib/new_relic/agent/instrumentation/padrino.rb +22 -58
  209. data/lib/new_relic/agent/instrumentation/passenger_instrumentation.rb +7 -7
  210. data/lib/new_relic/agent/instrumentation/queue_time.rb +9 -10
  211. data/lib/new_relic/agent/instrumentation/rack/chain.rb +66 -0
  212. data/lib/new_relic/agent/instrumentation/rack/helpers.rb +33 -0
  213. data/lib/new_relic/agent/instrumentation/rack/instrumentation.rb +75 -0
  214. data/lib/new_relic/agent/instrumentation/rack/prepend.rb +43 -0
  215. data/lib/new_relic/agent/instrumentation/rack.rb +33 -141
  216. data/lib/new_relic/agent/instrumentation/rails3/action_controller.rb +19 -55
  217. data/lib/new_relic/agent/instrumentation/rails_middleware.rb +5 -5
  218. data/lib/new_relic/agent/instrumentation/rails_notifications/action_cable.rb +36 -0
  219. data/lib/new_relic/agent/instrumentation/rails_notifications/action_controller.rb +45 -0
  220. data/lib/new_relic/agent/instrumentation/rails_notifications/action_view.rb +30 -0
  221. data/lib/new_relic/agent/instrumentation/rails_notifications/custom_events.rb +30 -0
  222. data/lib/new_relic/agent/instrumentation/rake/chain.rb +20 -0
  223. data/lib/new_relic/agent/instrumentation/rake/instrumentation.rb +142 -0
  224. data/lib/new_relic/agent/instrumentation/rake/prepend.rb +14 -0
  225. data/lib/new_relic/agent/instrumentation/rake.rb +18 -159
  226. data/lib/new_relic/agent/instrumentation/redis/chain.rb +45 -0
  227. data/lib/new_relic/agent/instrumentation/redis/constants.rb +17 -0
  228. data/lib/new_relic/agent/instrumentation/redis/instrumentation.rb +93 -0
  229. data/lib/new_relic/agent/instrumentation/redis/middleware.rb +16 -0
  230. data/lib/new_relic/agent/instrumentation/redis/prepend.rb +29 -0
  231. data/lib/new_relic/agent/instrumentation/redis.rb +20 -103
  232. data/lib/new_relic/agent/instrumentation/resque/chain.rb +21 -0
  233. data/lib/new_relic/agent/instrumentation/resque/helper.rb +19 -0
  234. data/lib/new_relic/agent/instrumentation/resque/instrumentation.rb +34 -0
  235. data/lib/new_relic/agent/instrumentation/resque/prepend.rb +15 -0
  236. data/lib/new_relic/agent/instrumentation/resque.rb +33 -41
  237. data/lib/new_relic/agent/instrumentation/sequel.rb +17 -20
  238. data/lib/new_relic/agent/instrumentation/sequel_helper.rb +3 -3
  239. data/lib/new_relic/agent/instrumentation/sidekiq/client.rb +20 -0
  240. data/lib/new_relic/agent/instrumentation/sidekiq/extensions/delayed_class.rb +30 -0
  241. data/lib/new_relic/agent/instrumentation/sidekiq/server.rb +37 -0
  242. data/lib/new_relic/agent/instrumentation/sidekiq.rb +29 -46
  243. data/lib/new_relic/agent/instrumentation/sinatra/chain.rb +55 -0
  244. data/lib/new_relic/agent/instrumentation/sinatra/ignorer.rb +31 -37
  245. data/lib/new_relic/agent/instrumentation/sinatra/instrumentation.rb +125 -0
  246. data/lib/new_relic/agent/instrumentation/sinatra/prepend.rb +33 -0
  247. data/lib/new_relic/agent/instrumentation/sinatra/transaction_namer.rb +3 -3
  248. data/lib/new_relic/agent/instrumentation/sinatra.rb +35 -165
  249. data/lib/new_relic/agent/instrumentation/thread/chain.rb +24 -0
  250. data/lib/new_relic/agent/instrumentation/thread/instrumentation.rb +28 -0
  251. data/lib/new_relic/agent/instrumentation/thread/prepend.rb +22 -0
  252. data/lib/new_relic/agent/instrumentation/thread.rb +20 -0
  253. data/lib/new_relic/agent/instrumentation/tilt/chain.rb +24 -0
  254. data/lib/new_relic/agent/instrumentation/tilt/instrumentation.rb +41 -0
  255. data/lib/new_relic/agent/instrumentation/tilt/prepend.rb +13 -0
  256. data/lib/new_relic/agent/instrumentation/tilt.rb +25 -0
  257. data/lib/new_relic/agent/instrumentation/typhoeus/chain.rb +22 -0
  258. data/lib/new_relic/agent/instrumentation/typhoeus/instrumentation.rb +80 -0
  259. data/lib/new_relic/agent/instrumentation/typhoeus/prepend.rb +14 -0
  260. data/lib/new_relic/agent/instrumentation/typhoeus.rb +14 -76
  261. data/lib/new_relic/agent/instrumentation.rb +2 -2
  262. data/lib/new_relic/agent/internal_agent_error.rb +3 -3
  263. data/lib/new_relic/agent/javascript_instrumentor.rb +51 -45
  264. data/lib/new_relic/agent/linking_metadata.rb +44 -0
  265. data/lib/new_relic/agent/local_log_decorator.rb +37 -0
  266. data/lib/new_relic/agent/log_event_aggregator.rb +235 -0
  267. data/lib/new_relic/agent/log_once.rb +2 -2
  268. data/lib/new_relic/agent/log_priority.rb +20 -0
  269. data/lib/new_relic/agent/logging.rb +142 -0
  270. data/lib/new_relic/agent/memory_logger.rb +3 -3
  271. data/lib/new_relic/agent/messaging.rb +81 -164
  272. data/lib/new_relic/agent/method_tracer.rb +152 -145
  273. data/lib/new_relic/agent/method_tracer_helpers.rb +90 -13
  274. data/lib/new_relic/agent/monitors/cross_app_monitor.rb +117 -0
  275. data/lib/new_relic/agent/monitors/distributed_tracing_monitor.rb +28 -0
  276. data/lib/new_relic/agent/{inbound_request_monitor.rb → monitors/inbound_request_monitor.rb} +5 -6
  277. data/lib/new_relic/agent/{synthetics_monitor.rb → monitors/synthetics_monitor.rb} +9 -15
  278. data/lib/new_relic/agent/monitors.rb +26 -0
  279. data/lib/new_relic/agent/new_relic_service/encoders.rb +7 -7
  280. data/lib/new_relic/agent/new_relic_service/json_marshaller.rb +6 -7
  281. data/lib/new_relic/agent/new_relic_service/marshaller.rb +8 -29
  282. data/lib/new_relic/agent/new_relic_service/security_policy_settings.rb +5 -5
  283. data/lib/new_relic/agent/new_relic_service.rb +282 -166
  284. data/lib/new_relic/agent/noticeable_error.rb +19 -0
  285. data/lib/new_relic/agent/null_logger.rb +8 -4
  286. data/lib/new_relic/agent/obfuscator.rb +9 -11
  287. data/lib/new_relic/agent/parameter_filtering.rb +35 -8
  288. data/lib/new_relic/agent/payload_metric_mapping.rb +10 -11
  289. data/lib/new_relic/agent/pipe_channel_manager.rb +28 -18
  290. data/lib/new_relic/agent/pipe_service.rb +9 -6
  291. data/lib/new_relic/agent/prepend_supportability.rb +3 -3
  292. data/lib/new_relic/agent/priority_sampled_buffer.rb +16 -14
  293. data/lib/new_relic/agent/range_extensions.rb +9 -29
  294. data/lib/new_relic/agent/rules_engine/replacement_rule.rb +12 -12
  295. data/lib/new_relic/agent/rules_engine/segment_terms_rule.rb +13 -14
  296. data/lib/new_relic/agent/rules_engine.rb +6 -5
  297. data/lib/new_relic/agent/sampler.rb +4 -5
  298. data/lib/new_relic/agent/sampler_collection.rb +4 -5
  299. data/lib/new_relic/agent/samplers/cpu_sampler.rb +4 -3
  300. data/lib/new_relic/agent/samplers/delayed_job_sampler.rb +14 -11
  301. data/lib/new_relic/agent/samplers/memory_sampler.rb +26 -15
  302. data/lib/new_relic/agent/samplers/object_sampler.rb +2 -2
  303. data/lib/new_relic/agent/samplers/vm_sampler.rb +22 -20
  304. data/lib/new_relic/agent/span_event_aggregator.rb +14 -16
  305. data/lib/new_relic/agent/span_event_primitive.rb +118 -58
  306. data/lib/new_relic/agent/sql_sampler.rb +25 -25
  307. data/lib/new_relic/agent/stats.rb +79 -42
  308. data/lib/new_relic/agent/stats_engine/gc_profiler.rb +11 -13
  309. data/lib/new_relic/agent/stats_engine/stats_hash.rb +13 -14
  310. data/lib/new_relic/agent/stats_engine.rb +11 -11
  311. data/lib/new_relic/agent/synthetics_event_aggregator.rb +8 -9
  312. data/lib/new_relic/agent/system_info.rb +100 -66
  313. data/lib/new_relic/agent/threading/agent_thread.rb +20 -16
  314. data/lib/new_relic/agent/threading/backtrace_node.rb +13 -14
  315. data/lib/new_relic/agent/threading/backtrace_service.rb +18 -18
  316. data/lib/new_relic/agent/threading/thread_profile.rb +31 -45
  317. data/lib/new_relic/agent/timestamp_sampled_buffer.rb +2 -2
  318. data/lib/new_relic/agent/tracer.rb +513 -0
  319. data/lib/new_relic/agent/transaction/abstract_segment.rb +131 -41
  320. data/lib/new_relic/agent/transaction/datastore_segment.rb +22 -18
  321. data/lib/new_relic/agent/transaction/distributed_tracer.rb +184 -0
  322. data/lib/new_relic/agent/transaction/distributed_tracing.rb +72 -163
  323. data/lib/new_relic/agent/transaction/external_request_segment.rb +66 -63
  324. data/lib/new_relic/agent/transaction/message_broker_segment.rb +34 -46
  325. data/lib/new_relic/agent/transaction/request_attributes.rb +36 -36
  326. data/lib/new_relic/agent/transaction/segment.rb +46 -10
  327. data/lib/new_relic/agent/transaction/slowest_sample_buffer.rb +2 -4
  328. data/lib/new_relic/agent/transaction/synthetics_sample_buffer.rb +2 -2
  329. data/lib/new_relic/agent/transaction/trace.rb +21 -24
  330. data/lib/new_relic/agent/transaction/trace_builder.rb +11 -12
  331. data/lib/new_relic/agent/transaction/trace_context.rb +168 -0
  332. data/lib/new_relic/agent/transaction/trace_node.rb +31 -28
  333. data/lib/new_relic/agent/transaction/tracing.rb +15 -111
  334. data/lib/new_relic/agent/transaction/transaction_sample_buffer.rb +6 -6
  335. data/lib/new_relic/agent/transaction.rb +252 -259
  336. data/lib/new_relic/agent/transaction_error_primitive.rb +34 -37
  337. data/lib/new_relic/agent/transaction_event_aggregator.rb +13 -13
  338. data/lib/new_relic/agent/transaction_event_primitive.rb +44 -56
  339. data/lib/new_relic/agent/transaction_event_recorder.rb +17 -16
  340. data/lib/new_relic/agent/transaction_metrics.rb +11 -10
  341. data/lib/new_relic/agent/transaction_sampler.rb +7 -12
  342. data/lib/new_relic/agent/transaction_time_aggregator.rb +41 -26
  343. data/lib/new_relic/agent/utilization/aws.rb +34 -4
  344. data/lib/new_relic/agent/utilization/azure.rb +4 -4
  345. data/lib/new_relic/agent/utilization/gcp.rb +8 -8
  346. data/lib/new_relic/agent/utilization/pcf.rb +6 -5
  347. data/lib/new_relic/agent/utilization/vendor.rb +44 -29
  348. data/lib/new_relic/agent/utilization_data.rb +43 -6
  349. data/lib/new_relic/agent/vm/jruby_vm.rb +2 -2
  350. data/lib/new_relic/agent/vm/monotonic_gc_profiler.rb +3 -3
  351. data/lib/new_relic/agent/vm/mri_vm.rb +46 -19
  352. data/lib/new_relic/agent/vm/snapshot.rb +6 -6
  353. data/lib/new_relic/agent/vm.rb +2 -2
  354. data/lib/new_relic/agent/worker_loop.rb +11 -13
  355. data/lib/new_relic/agent.rb +151 -79
  356. data/lib/new_relic/cli/command.rb +21 -23
  357. data/lib/new_relic/cli/commands/deployments.rb +94 -45
  358. data/lib/new_relic/cli/commands/install.rb +24 -26
  359. data/lib/new_relic/coerce.rb +42 -15
  360. data/lib/new_relic/collection_helper.rb +51 -49
  361. data/lib/new_relic/constants.rb +39 -0
  362. data/lib/new_relic/control/class_methods.rb +11 -5
  363. data/lib/new_relic/control/frameworks/external.rb +3 -3
  364. data/lib/new_relic/control/frameworks/rails.rb +24 -18
  365. data/lib/new_relic/control/frameworks/rails3.rb +4 -5
  366. data/lib/new_relic/control/frameworks/rails4.rb +2 -2
  367. data/lib/new_relic/control/frameworks/rails_notifications.rb +14 -0
  368. data/lib/new_relic/control/frameworks/ruby.rb +4 -4
  369. data/lib/new_relic/control/frameworks/sinatra.rb +8 -2
  370. data/lib/new_relic/control/frameworks.rb +2 -2
  371. data/lib/new_relic/control/instance_methods.rb +33 -42
  372. data/lib/new_relic/control/instrumentation.rb +40 -12
  373. data/lib/new_relic/control/private_instance_methods.rb +48 -0
  374. data/lib/new_relic/control/server_methods.rb +4 -5
  375. data/lib/new_relic/control.rb +2 -3
  376. data/lib/new_relic/delayed_job_injection.rb +2 -2
  377. data/lib/new_relic/dependency_detection.rb +129 -18
  378. data/lib/new_relic/environment_report.rb +41 -35
  379. data/lib/new_relic/helper.rb +49 -8
  380. data/lib/new_relic/language_support.rb +30 -6
  381. data/lib/new_relic/latest_changes.rb +9 -8
  382. data/lib/new_relic/local_environment.rb +23 -27
  383. data/lib/new_relic/metric_data.rb +32 -27
  384. data/lib/new_relic/metric_spec.rb +9 -7
  385. data/lib/new_relic/noticed_error.rb +46 -33
  386. data/lib/new_relic/rack/agent_hooks.rb +2 -2
  387. data/lib/new_relic/rack/agent_middleware.rb +7 -5
  388. data/lib/new_relic/rack/browser_monitoring.rb +134 -117
  389. data/lib/new_relic/rack.rb +2 -2
  390. data/lib/new_relic/recipes/capistrano3.rb +4 -62
  391. data/lib/new_relic/recipes/capistrano_legacy.rb +24 -27
  392. data/lib/new_relic/recipes/helpers/send_deployment.rb +70 -0
  393. data/lib/new_relic/recipes.rb +2 -2
  394. data/lib/new_relic/supportability_helper.rb +21 -7
  395. data/lib/new_relic/traced_thread.rb +39 -0
  396. data/lib/new_relic/version.rb +7 -18
  397. data/lib/newrelic_rpm.rb +20 -33
  398. data/lib/sequel/extensions/{newrelic_instrumentation.rb → new_relic_instrumentation.rb} +16 -19
  399. data/lib/sequel/plugins/{newrelic_instrumentation.rb → new_relic_instrumentation.rb} +9 -15
  400. data/lib/tasks/all.rb +4 -4
  401. data/lib/tasks/config.rake +22 -118
  402. data/lib/tasks/coverage_report.rake +28 -0
  403. data/lib/tasks/helpers/config.html.erb +21 -0
  404. data/lib/tasks/helpers/format.rb +123 -0
  405. data/lib/tasks/helpers/matches.rb +12 -0
  406. data/lib/tasks/helpers/prompt.rb +24 -0
  407. data/lib/tasks/helpers/removers.rb +33 -0
  408. data/lib/tasks/install.rake +4 -0
  409. data/lib/tasks/instrumentation_generator/README.md +63 -0
  410. data/lib/tasks/instrumentation_generator/TODO.md +33 -0
  411. data/lib/tasks/instrumentation_generator/instrumentation.thor +121 -0
  412. data/lib/tasks/instrumentation_generator/templates/Envfile.tt +9 -0
  413. data/lib/tasks/instrumentation_generator/templates/chain.tt +22 -0
  414. data/lib/tasks/instrumentation_generator/templates/chain_method.tt +8 -0
  415. data/lib/tasks/instrumentation_generator/templates/dependency_detection.tt +29 -0
  416. data/lib/tasks/instrumentation_generator/templates/instrumentation.tt +13 -0
  417. data/lib/tasks/instrumentation_generator/templates/instrumentation_method.tt +3 -0
  418. data/lib/tasks/instrumentation_generator/templates/newrelic.yml.tt +19 -0
  419. data/lib/tasks/instrumentation_generator/templates/prepend.tt +13 -0
  420. data/lib/tasks/instrumentation_generator/templates/prepend_method.tt +3 -0
  421. data/lib/tasks/instrumentation_generator/templates/test.tt +15 -0
  422. data/lib/tasks/multiverse.rake +4 -0
  423. data/lib/tasks/multiverse.rb +12 -5
  424. data/lib/tasks/newrelic.rb +2 -2
  425. data/lib/tasks/tests.rake +14 -14
  426. data/newrelic.yml +672 -3
  427. data/newrelic_rpm.gemspec +40 -31
  428. data/recipes/newrelic.rb +3 -3
  429. data/test/agent_helper.rb +419 -98
  430. metadata +238 -127
  431. data/.travis.yml +0 -228
  432. data/bin/mongrel_rpm +0 -33
  433. data/cert/cacert.pem +0 -1177
  434. data/lib/new_relic/agent/commands/xray_session.rb +0 -55
  435. data/lib/new_relic/agent/commands/xray_session_collection.rb +0 -161
  436. data/lib/new_relic/agent/cross_app_monitor.rb +0 -110
  437. data/lib/new_relic/agent/datastores/mongo/obfuscator.rb +0 -44
  438. data/lib/new_relic/agent/datastores/mongo/statement_formatter.rb +0 -53
  439. data/lib/new_relic/agent/distributed_trace_monitor.rb +0 -41
  440. data/lib/new_relic/agent/distributed_trace_payload.rb +0 -246
  441. data/lib/new_relic/agent/http_clients/abstract_request.rb +0 -31
  442. data/lib/new_relic/agent/instrumentation/active_record_4.rb +0 -42
  443. data/lib/new_relic/agent/instrumentation/active_record_5.rb +0 -41
  444. data/lib/new_relic/agent/instrumentation/acts_as_solr.rb +0 -74
  445. data/lib/new_relic/agent/instrumentation/authlogic.rb +0 -25
  446. data/lib/new_relic/agent/instrumentation/data_mapper.rb +0 -202
  447. data/lib/new_relic/agent/instrumentation/evented_subscriber.rb +0 -104
  448. data/lib/new_relic/agent/instrumentation/excon/connection.rb +0 -46
  449. data/lib/new_relic/agent/instrumentation/http.rb +0 -46
  450. data/lib/new_relic/agent/instrumentation/merb/controller.rb +0 -44
  451. data/lib/new_relic/agent/instrumentation/merb/errors.rb +0 -33
  452. data/lib/new_relic/agent/instrumentation/net.rb +0 -50
  453. data/lib/new_relic/agent/instrumentation/rails/action_controller.rb +0 -125
  454. data/lib/new_relic/agent/instrumentation/rails/action_web_service.rb +0 -46
  455. data/lib/new_relic/agent/instrumentation/rails4/action_controller.rb +0 -32
  456. data/lib/new_relic/agent/instrumentation/rails4/action_view.rb +0 -27
  457. data/lib/new_relic/agent/instrumentation/rails5/action_cable.rb +0 -36
  458. data/lib/new_relic/agent/instrumentation/rails5/action_controller.rb +0 -33
  459. data/lib/new_relic/agent/instrumentation/rails5/action_view.rb +0 -27
  460. data/lib/new_relic/agent/instrumentation/rainbows_instrumentation.rb +0 -26
  461. data/lib/new_relic/agent/instrumentation/sunspot.rb +0 -33
  462. data/lib/new_relic/agent/supported_versions.rb +0 -275
  463. data/lib/new_relic/agent/transaction/attributes.rb +0 -154
  464. data/lib/new_relic/agent/transaction/xray_sample_buffer.rb +0 -64
  465. data/lib/new_relic/agent/transaction_state.rb +0 -186
  466. data/lib/new_relic/build.rb +0 -2
  467. data/lib/new_relic/control/frameworks/merb.rb +0 -29
  468. data/lib/new_relic/control/frameworks/rails5.rb +0 -14
  469. data/lib/new_relic/metrics.rb +0 -13
  470. data/lib/tasks/config.html.erb +0 -32
  471. data/lib/tasks/versions.html.erb +0 -28
  472. data/lib/tasks/versions.postface.html +0 -8
  473. data/lib/tasks/versions.preface.html +0 -9
  474. data/lib/tasks/versions.rake +0 -65
  475. data/lib/tasks/versions.txt.erb +0 -14
  476. /data/lib/tasks/{config.text.erb → helpers/config.text.erb} +0 -0
@@ -1,6 +1,6 @@
1
- # encoding: utf-8
2
1
  # This file is distributed under New Relic's license terms.
3
- # See https://github.com/newrelic/rpm/blob/master/LICENSE for complete details.
2
+ # See https://github.com/newrelic/newrelic-ruby-agent/blob/main/LICENSE for complete details.
3
+ # frozen_string_literal: true
4
4
 
5
5
  # This file may be independently required to set up method tracing prior to
6
6
  # the full agent loading. In those cases, we do need at least this require to
@@ -47,12 +47,12 @@ module NewRelic
47
47
  #
48
48
 
49
49
  module MethodTracer
50
- def self.included clazz
51
- clazz.extend ClassMethods
50
+ def self.included(klass)
51
+ klass.extend(ClassMethods)
52
52
  end
53
53
 
54
- def self.extended clazz
55
- clazz.extend ClassMethods
54
+ def self.extended(klass)
55
+ klass.extend(ClassMethods)
56
56
  end
57
57
 
58
58
  # Trace a given block with stats and keep track of the caller.
@@ -67,8 +67,8 @@ module NewRelic
67
67
  #
68
68
  # @api public
69
69
  #
70
- def trace_execution_scoped(metric_names, options={}) #THREAD_LOCAL_ACCESS
71
- NewRelic::Agent.record_api_supportability_metric :trace_execution_scoped
70
+ def trace_execution_scoped(metric_names, options = NewRelic::EMPTY_HASH) # THREAD_LOCAL_ACCESS
71
+ NewRelic::Agent.record_api_supportability_metric(:trace_execution_scoped) unless options[:internal]
72
72
  NewRelic::Agent::MethodTracerHelpers.trace_execution_scoped(metric_names, options) do
73
73
  # Using an implicit block avoids object allocation for a &block param
74
74
  yield
@@ -78,19 +78,20 @@ module NewRelic
78
78
  # Trace a given block with stats assigned to the given metric_name. It does not
79
79
  # provide scoped measurements, meaning whatever is being traced will not 'blame the
80
80
  # Controller'--that is to say appear in the breakdown chart.
81
- # This is code is inlined in #add_method_tracer.
81
+ #
82
82
  # * <tt>metric_names</tt> is a single name or an array of names of metrics
83
83
  #
84
84
  # @api public
85
85
  #
86
- def trace_execution_unscoped(metric_names, options={}) #THREAD_LOCAL_ACCESS
87
- NewRelic::Agent.record_api_supportability_metric :trace_execution_unscoped
86
+ def trace_execution_unscoped(metric_names, options = NewRelic::EMPTY_HASH) # THREAD_LOCAL_ACCESS
87
+ NewRelic::Agent.record_api_supportability_metric(:trace_execution_unscoped) unless options[:internal]
88
88
  return yield unless NewRelic::Agent.tl_is_execution_traced?
89
- t0 = Time.now
89
+
90
+ t0 = Process.clock_gettime(Process::CLOCK_MONOTONIC)
90
91
  begin
91
92
  yield
92
93
  ensure
93
- duration = (Time.now - t0).to_f # for some reason this is 3 usec faster than Time - Time
94
+ duration = Process.clock_gettime(Process::CLOCK_MONOTONIC) - t0
94
95
  NewRelic::Agent.instance.stats_engine.tl_record_unscoped_metrics(metric_names, duration)
95
96
  end
96
97
  end
@@ -100,52 +101,40 @@ module NewRelic
100
101
  module ClassMethods
101
102
  # contains methods refactored out of the #add_method_tracer method
102
103
  module AddMethodTracer
103
- ALLOWED_KEYS = [:metric, :push_scope, :code_header, :code_footer].freeze
104
-
105
- # raises an error when the
106
- # NewRelic::Agent::MethodTracer::ClassMethods#add_method_tracer
107
- # method is called with improper keys. This aids in
108
- # debugging new instrumentation by failing fast
109
- def check_for_illegal_keys!(method_name, options)
110
- unrecognized_keys = options.keys - ALLOWED_KEYS
104
+ ALLOWED_KEYS = [:metric, :push_scope, :code_header, :code_information, :code_footer].freeze
111
105
 
112
- if unrecognized_keys.any?
113
- raise "Unrecognized options when adding method tracer to #{method_name}: " +
114
- unrecognized_keys.join(', ')
115
- end
116
- end
117
-
118
- # validity checking - add_method_tracer must receive either
119
- # push scope or metric, or else it would record no
120
- # data. Raises an error if this is the case
121
- def check_for_push_scope_and_metric(options)
122
- unless options[:push_scope] || options[:metric]
123
- raise "Can't add a tracer where push_scope is false and metric is false"
124
- end
125
- end
126
-
127
- DEFAULT_SETTINGS = {:push_scope => true, :metric => true, :code_header => "", :code_footer => "" }.freeze
106
+ DEFAULT_SETTINGS = {:push_scope => true, :metric => true, :code_header => "", :code_footer => ""}.freeze
128
107
 
129
108
  # Checks the provided options to make sure that they make
130
109
  # sense. Raises an error if the options are incorrect to
131
110
  # assist with debugging, so that errors occur at class
132
111
  # construction time rather than instrumentation run time
133
- def validate_options(method_name, options)
112
+ def _nr_validate_method_tracer_options(method_name, options)
134
113
  unless options.is_a?(Hash)
135
114
  raise TypeError.new("Error adding method tracer to #{method_name}: provided options must be a Hash")
136
115
  end
137
- check_for_illegal_keys!(method_name, options)
116
+
117
+ unrecognized_keys = options.keys - ALLOWED_KEYS
118
+ if unrecognized_keys.any?
119
+ raise "Unrecognized options when adding method tracer to #{method_name}: " +
120
+ unrecognized_keys.join(', ')
121
+ end
122
+
138
123
  options = DEFAULT_SETTINGS.merge(options)
139
- check_for_push_scope_and_metric(options)
124
+ unless options[:push_scope] || options[:metric]
125
+ raise "Can't add a tracer where push_scope is false and metric is false"
126
+ end
127
+
140
128
  options
141
129
  end
142
130
 
143
131
  # Default to the class where the method is defined.
144
132
  #
145
133
  # Example:
146
- # Foo.default_metric_name_code('bar') #=> "Custom/#{Foo.name}/bar"
147
- def default_metric_name_code(method_name)
148
- "Custom/#{derived_class_name}/#{method_name}"
134
+ # Foo._nr_default_metric_name_code('bar') #=> "Custom/#{Foo.name}/bar"
135
+ def _nr_default_metric_name(method_name)
136
+ class_name = _nr_derived_class_name
137
+ -> (*) { "Custom/#{class_name}/#{method_name}" }
149
138
  end
150
139
 
151
140
  # Checks to see if the method we are attempting to trace
@@ -153,7 +142,7 @@ module NewRelic
153
142
  # anything if the method doesn't exist.
154
143
  def newrelic_method_exists?(method_name)
155
144
  exists = method_defined?(method_name) || private_method_defined?(method_name)
156
- ::NewRelic::Agent.logger.error("Did not trace #{derived_class_name}##{method_name} because that method does not exist") unless exists
145
+ ::NewRelic::Agent.logger.error("Did not trace #{_nr_derived_class_name}##{method_name} because that method does not exist") unless exists
157
146
  exists
158
147
  end
159
148
 
@@ -161,67 +150,25 @@ module NewRelic
161
150
  # given metric by checking to see if the traced method
162
151
  # exists. Warns the user if methods are being double-traced
163
152
  # to help with debugging custom instrumentation.
164
- def traced_method_exists?(method_name, metric_name_code)
165
- exists = method_defined?(_traced_method_name(method_name, metric_name_code))
166
- ::NewRelic::Agent.logger.error("Attempt to trace a method twice with the same metric: Method = #{method_name}, Metric Name = #{metric_name_code}") if exists
153
+ def method_traced?(method_name)
154
+ exists = method_name && _nr_traced_method_module.method_defined?(method_name)
155
+ ::NewRelic::Agent.logger.error("Attempt to trace a method twice: Method = #{method_name}") if exists
167
156
  exists
168
157
  end
169
158
 
170
- # Returns a code snippet to be eval'd that skips tracing
171
- # when the agent is not tracing execution. turns
172
- # instrumentation into effectively one method call overhead
173
- # when the agent is disabled
174
- def assemble_code_header(method_name, metric_name_code, options)
175
- header = "return #{_untraced_method_name(method_name, metric_name_code)}(*args, &block) unless NewRelic::Agent.tl_is_execution_traced?\n"
176
- header += options[:code_header].to_s
177
- header
178
- end
179
-
180
- # returns an eval-able string that contains the traced
181
- # method code used if the agent is not creating a scope for
182
- # use in scoped metrics.
183
- def method_without_push_scope(method_name, metric_name_code, options)
184
- "def #{_traced_method_name(method_name, metric_name_code)}(*args, &block)
185
- #{assemble_code_header(method_name, metric_name_code, options)}
186
- t0 = Time.now
187
- begin
188
- #{_untraced_method_name(method_name, metric_name_code)}(*args, &block)\n
189
- ensure
190
- duration = (Time.now - t0).to_f
191
- NewRelic::Agent.record_metric(\"#{metric_name_code}\", duration)
192
- #{options[:code_footer]}
193
- end
194
- end"
159
+ # Returns an anonymous module that stores prepended trace methods.
160
+ def _nr_traced_method_module
161
+ @_nr_traced_method_module ||= Module.new
195
162
  end
196
163
 
197
- # returns an eval-able string that contains the tracing code
198
- # for a fully traced metric including scoping
199
- def method_with_push_scope(method_name, metric_name_code, options)
200
- "def #{_traced_method_name(method_name, metric_name_code)}(*args, &block)
201
- #{options[:code_header]}
202
- result = ::NewRelic::Agent::MethodTracerHelpers.trace_execution_scoped(\"#{metric_name_code}\",
203
- :metric => #{options[:metric]}) do
204
- #{_untraced_method_name(method_name, metric_name_code)}(*args, &block)
205
- end
206
- #{options[:code_footer]}
207
- result
208
- end"
209
- end
210
-
211
- # Decides which code snippet we should be eval'ing in this
212
- # context, based on the options.
213
- def code_to_eval(method_name, metric_name_code, options)
214
- options = validate_options(method_name, options)
215
- if options[:push_scope]
216
- method_with_push_scope(method_name, metric_name_code, options)
217
- else
218
- method_without_push_scope(method_name, metric_name_code, options)
164
+ # for testing only
165
+ def _nr_clear_traced_methods!
166
+ _nr_traced_method_module.module_eval do
167
+ self.instance_methods.each { |m| remove_method(m) }
219
168
  end
220
169
  end
221
170
 
222
- private
223
-
224
- def derived_class_name
171
+ def _nr_derived_class_name
225
172
  return self.name if self.name && !self.name.empty?
226
173
  return "AnonymousModule" if self.to_s.start_with?("#<Module:")
227
174
 
@@ -247,22 +194,26 @@ module NewRelic
247
194
  #
248
195
  # === Overriding the metric name
249
196
  #
250
- # +metric_name_code+ is a string that is eval'd to get the name of the
251
- # metric associated with the call, so if you want to use interpolation
252
- # evaluated at call time, then single quote the value like this:
197
+ # +metric_name+ is a String or Proc. If a Proc is given, it is bound to
198
+ # the object that called the traced method. For example:
253
199
  #
254
- # add_method_tracer :foo, 'Custom/#{self.class.name}/foo'
200
+ # add_method_tracer :foo, -> { "Custom/#{self.class.name}/foo" }
255
201
  #
256
202
  # This would name the metric according to the class of the runtime
257
- # intance, as opposed to the class where +foo+ is defined.
203
+ # instance, as opposed to the class where +foo+ is defined.
258
204
  #
259
205
  # If not provided, the metric name will be <tt>Custom/ClassName/method_name</tt>.
260
206
  #
261
- # @param [Symbol] method_name the name of the method to trace
262
- # @param [String] metric_name_code the metric name to record calls to
263
- # the traced method under. This may be either a static string, or Ruby
264
- # code to be evaluated at call-time in order to determine the metric
207
+ # @param method_name [Symbol] the name of the method to trace
208
+ # @param metric_name [String,Proc,Array] the metric name to record calls to
209
+ # the traced method under. This may be either a String, or a Proc
210
+ # to be evaluated at call-time in order to determine the metric
265
211
  # name dynamically.
212
+ # This method also accepts an array of Strings/Procs, in which case the
213
+ # first metric given will be scoped, while the remaining metrics will be
214
+ # recorded as though passed with :push_scope => false. If an Array of
215
+ # metric names is given with :push_scope => false, all metrics will be
216
+ # unscoped.
266
217
  # @param [Hash] options additional options controlling how the method is
267
218
  # traced.
268
219
  # @option options [Boolean] :push_scope (true) If false, the traced method will
@@ -271,16 +222,17 @@ module NewRelic
271
222
  # @option options [Boolean] :metric (true) If false, the traced method will
272
223
  # only appear in transaction traces, but no metrics will be recorded
273
224
  # for it.
274
- # @option options [String] :code_header ('') Ruby code to be inserted and run
225
+ # @option options [Proc] :code_header ('') Ruby code to be inserted and run
275
226
  # before the tracer begins timing.
276
- # @option options [String] :code_footer ('') Ruby code to be inserted and run
227
+ # @option options [Proc] :code_footer ('') Ruby code to be inserted and run
277
228
  # after the tracer stops timing.
278
229
  #
279
230
  # @example
280
231
  # add_method_tracer :foo
281
232
  #
282
233
  # # With a custom metric name
283
- # add_method_tracer :foo, 'Custom/#{self.class.name}/foo'
234
+ # add_method_tracer :foo, "Custom/MyClass/foo"
235
+ # add_method_tracer :bar, -> { "Custom/#{self.class.name}/bar" }
284
236
  #
285
237
  # # Instrument foo only for custom dashboards (not in transaction
286
238
  # # traces or breakdown charts)
@@ -291,64 +243,119 @@ module NewRelic
291
243
  #
292
244
  # @api public
293
245
  #
294
- def add_method_tracer(method_name, metric_name_code = nil, options = {})
295
- ::NewRelic::Agent.add_or_defer_method_tracer(self, method_name, metric_name_code, options)
246
+ def add_method_tracer(method_name, metric_name = nil, options = {})
247
+ ::NewRelic::Agent.add_or_defer_method_tracer(self, method_name, metric_name, options)
296
248
  end
297
249
 
298
250
  # For tests only because tracers must be removed in reverse-order
299
251
  # from when they were added, or else other tracers that were added to the same method
300
252
  # may get removed as well.
301
- def remove_method_tracer(method_name, metric_name_code) # :nodoc:
253
+ def remove_method_tracer(method_name) # :nodoc:
302
254
  return unless Agent.config[:agent_enabled]
303
- if method_defined? "#{_traced_method_name(method_name, metric_name_code)}"
304
- alias_method method_name, "#{_untraced_method_name(method_name, metric_name_code)}"
305
- undef_method "#{_traced_method_name(method_name, metric_name_code)}"
306
- ::NewRelic::Agent.logger.debug("removed method tracer #{method_name} #{metric_name_code}\n")
255
+
256
+ if _nr_traced_method_module.method_defined?(method_name)
257
+ _nr_traced_method_module.send(:remove_method, method_name)
258
+ ::NewRelic::Agent.logger.debug("removed method tracer #{method_name}\n")
307
259
  else
308
- raise "No tracer for '#{metric_name_code}' on method '#{method_name}'"
260
+ raise "No tracer on method '#{method_name}'"
309
261
  end
310
262
  end
311
263
 
312
264
  private
313
265
 
314
- def _add_method_tracer_now(method_name, metric_name_code, options)
266
+ def _nr_add_method_tracer_now(method_name, metric_name, options)
315
267
  NewRelic::Agent.record_api_supportability_metric(:add_method_tracer)
316
-
317
268
  return unless newrelic_method_exists?(method_name)
318
- metric_name_code ||= default_metric_name_code(method_name)
319
- return if traced_method_exists?(method_name, metric_name_code)
320
269
 
321
- traced_method = code_to_eval(method_name, metric_name_code, options)
270
+ remove_method_tracer(method_name) if method_traced?(method_name)
322
271
 
323
- visibility = NewRelic::Helper.instance_method_visibility self, method_name
272
+ options = _nr_validate_method_tracer_options(method_name, options)
324
273
 
325
- class_eval traced_method, __FILE__, __LINE__
326
- alias_method _untraced_method_name(method_name, metric_name_code), method_name
327
- alias_method method_name, _traced_method_name(method_name, metric_name_code)
328
- send visibility, method_name
329
- send visibility, _traced_method_name(method_name, metric_name_code)
330
- ::NewRelic::Agent.logger.debug("Traced method: class = #{derived_class_name},"+
331
- "method = #{method_name}, "+
332
- "metric = '#{metric_name_code}'")
333
- end
274
+ visibility = NewRelic::Helper.instance_method_visibility(self, method_name)
275
+
276
+ scoped_metric, unscoped_metrics = _nr_scoped_unscoped_metrics(metric_name, method_name, push_scope: options[:push_scope])
277
+
278
+ _nr_define_traced_method(method_name, scoped_metric: scoped_metric, unscoped_metrics: unscoped_metrics,
279
+ code_header: options[:code_header], code_footer: options[:code_footer],
280
+ record_metrics: options[:metric], visibility: visibility,
281
+ code_information: options[:code_information])
282
+
283
+ prepend(_nr_traced_method_module)
334
284
 
335
- # given a method and a metric, this method returns the
336
- # untraced alias of the method name
337
- def _untraced_method_name(method_name, metric_name)
338
- "#{_sanitize_name(method_name)}_without_trace_#{_sanitize_name(metric_name)}"
285
+ ::NewRelic::Agent.logger.debug("Traced method: class = #{_nr_derived_class_name}," +
286
+ "method = #{method_name}, " +
287
+ "metric = '#{metric_name}'")
339
288
  end
340
289
 
341
- # given a method and a metric, this method returns the traced
342
- # alias of the method name
343
- def _traced_method_name(method_name, metric_name)
344
- "#{_sanitize_name(method_name)}_with_trace_#{_sanitize_name(metric_name)}"
290
+ # See #add_method_tracer; if multiple metric names are given, the first is
291
+ # treated as scoped, the rest unscoped. If options[:push_scope] is false,
292
+ # all given metrics are unscoped.
293
+ def _nr_scoped_unscoped_metrics(metric_name, method_name, push_scope: true)
294
+ if metric_name.is_a?(Array) && push_scope
295
+ [metric_name.shift, metric_name]
296
+ elsif push_scope
297
+ [metric_name || _nr_default_metric_name(method_name), []]
298
+ else
299
+ [nil, Array(metric_name)]
300
+ end
345
301
  end
346
302
 
347
- # makes sure that method names do not contain characters that
348
- # might break the interpreter, for example ! or ? characters
349
- # that are not allowed in the middle of method names
350
- def _sanitize_name(name)
351
- name.to_s.tr_s('^a-zA-Z0-9', '_')
303
+ def _nr_define_traced_method(method_name, scoped_metric: nil, unscoped_metrics: [],
304
+ code_header: nil, code_footer: nil, record_metrics: true,
305
+ visibility: :public, code_information: {})
306
+
307
+ _nr_traced_method_module.module_eval do
308
+ define_method(method_name) do |*args, &block|
309
+ return super(*args, &block) unless NewRelic::Agent.tl_is_execution_traced?
310
+
311
+ scoped_metric_eval, unscoped_metrics_eval = nil, []
312
+
313
+ scoped_metric_eval = case scoped_metric
314
+ when Proc
315
+ instance_exec(*args, &scoped_metric)
316
+ when String
317
+ scoped_metric
318
+ end
319
+
320
+ unscoped_metrics_eval = unscoped_metrics.map do |metric|
321
+ metric.kind_of?(Proc) ? instance_exec(*args, &metric) : metric.to_s
322
+ end
323
+
324
+ instance_exec(&code_header) if code_header.kind_of?(Proc)
325
+
326
+ # NOTE: Calling ::NewRelic::Agent::MethodTracer.trace_execution_scoped and
327
+ # .trace_execution_unscoped below relies on the fact that MethodTracer is included
328
+ # in Module on agent startup. If/when this changes, these methods should be
329
+ # explicitly namespaced and extended in MethodTracer.
330
+
331
+ # If tracing multiple metrics on this method, nest one unscoped trace inside the scoped trace.
332
+ begin
333
+ if scoped_metric_eval
334
+ ::NewRelic::Agent::MethodTracer.trace_execution_scoped(scoped_metric_eval,
335
+ metric: record_metrics,
336
+ internal: true,
337
+ code_information: code_information) do
338
+ if unscoped_metrics_eval.empty?
339
+ super(*args, &block)
340
+ else
341
+ ::NewRelic::Agent::MethodTracer.trace_execution_unscoped(unscoped_metrics_eval, internal: true) do
342
+ super(*args, &block)
343
+ end
344
+ end
345
+ end
346
+ elsif !unscoped_metrics_eval.empty?
347
+ ::NewRelic::Agent::MethodTracer.trace_execution_unscoped(unscoped_metrics_eval, internal: true) do
348
+ super(*args, &block)
349
+ end
350
+ end
351
+ ensure
352
+ instance_exec(&code_footer) if code_footer.kind_of?(Proc)
353
+ end
354
+ end
355
+
356
+ send(visibility, method_name)
357
+ ruby2_keywords(method_name) if respond_to?(:ruby2_keywords, true)
358
+ end
352
359
  end
353
360
  end
354
361
 
@@ -1,36 +1,113 @@
1
- # encoding: utf-8
2
1
  # This file is distributed under New Relic's license terms.
3
- # See https://github.com/newrelic/rpm/blob/master/LICENSE for complete details.
2
+ # See https://github.com/newrelic/newrelic-ruby-agent/blob/main/LICENSE for complete details.
3
+ # frozen_string_literal: true
4
4
 
5
5
  module NewRelic
6
6
  module Agent
7
7
  module MethodTracerHelpers
8
+ # These are code level metrics (CLM) attributes. For Ruby, they map like so:
9
+ # filepath: full path to an .rb file on disk
10
+ # lineno: the line number a Ruby method is defined on within a given .rb file
11
+ # function: the name of the Ruby method
12
+ # namespace: the Ruby class' namespace as a string, ex: 'MyModule::MyClass'
13
+ SOURCE_CODE_INFORMATION_PARAMETERS = %i[filepath lineno function namespace].freeze
14
+ SOURCE_CODE_INFORMATION_FAILURE_METRIC = "Supportability/CodeLevelMetrics/Ruby/Failure".freeze
8
15
  MAX_ALLOWED_METRIC_DURATION = 1_000_000_000 # roughly 31 years
9
16
 
10
17
  extend self
11
18
 
12
- def trace_execution_scoped(metric_names, options={}) #THREAD_LOCAL_ACCESS
13
- state = NewRelic::Agent::TransactionState.tl_get
14
- return yield unless state.is_execution_traced?
19
+ def trace_execution_scoped(metric_names, options = NewRelic::EMPTY_HASH) # THREAD_LOCAL_ACCESS
20
+ return yield unless NewRelic::Agent::Tracer.state.is_execution_traced?
15
21
 
16
22
  metric_names = Array(metric_names)
17
- first_name = metric_names.shift
23
+ first_name = metric_names.shift
18
24
  return yield unless first_name
19
25
 
20
- segment = NewRelic::Agent::Transaction.start_segment(
26
+ segment = NewRelic::Agent::Tracer.start_segment(
21
27
  name: first_name,
22
28
  unscoped_metrics: metric_names
23
29
  )
24
30
 
25
- if options[:metric] == false
26
- segment.record_metrics = false
31
+ segment.record_metrics = false if options[:metric] == false
32
+
33
+ unless !options.key?(:code_information) || options[:code_information].nil? || options[:code_information].empty?
34
+ segment.code_information = options[:code_information]
27
35
  end
28
36
 
29
- begin
30
- yield
31
- ensure
32
- segment.finish if segment
37
+ Tracer.capture_segment_error(segment) { yield }
38
+ ensure
39
+ ::NewRelic::Agent::Transaction::Segment.finish(segment)
40
+ end
41
+
42
+ def code_information(object, method_name)
43
+ return ::NewRelic::EMPTY_HASH unless clm_enabled? && object && method_name
44
+
45
+ @code_information ||= {}
46
+ cache_key = "#{object.object_id}#{method_name}".freeze
47
+ return @code_information[cache_key] if @code_information.key?(cache_key)
48
+
49
+ namespace, location, is_class_method = namespace_and_location(object, method_name.to_sym)
50
+
51
+ @code_information[cache_key] = {filepath: location.first,
52
+ lineno: location.last,
53
+ function: "#{'self.' if is_class_method}#{method_name}",
54
+ namespace: namespace}.freeze
55
+ rescue => e
56
+ ::NewRelic::Agent.logger.warn("Unable to determine source code info for '#{object}', " \
57
+ "method '#{method_name}' - #{e.class}: #{e.message}")
58
+ ::NewRelic::Agent.increment_metric(SOURCE_CODE_INFORMATION_FAILURE_METRIC, 1)
59
+ ::NewRelic::EMPTY_HASH
60
+ end
61
+
62
+ private
63
+
64
+ def clm_enabled?
65
+ ::NewRelic::Agent.config[:'code_level_metrics.enabled']
66
+ end
67
+
68
+ # The string representation of a singleton class looks like
69
+ # '#<Class:MyModule::MyClass>'. Return the 'MyModule::MyClass' part of
70
+ # that string
71
+ def klass_name(object)
72
+ name = Regexp.last_match(1) if object.to_s =~ /^#<Class:(.*)>$/
73
+ return name if name
74
+
75
+ raise "Unable to glean a class name from string '#{object}'"
76
+ end
77
+
78
+ # get at the underlying class from the singleton class
79
+ #
80
+ # note: even with the regex hit from klass_name(), `Object.const_get`
81
+ # is more performant than iterating through `ObjectSpace`
82
+ def klassify_singleton(object)
83
+ Object.const_get(klass_name(object))
84
+ end
85
+
86
+ # determine the namespace (class name including all module names in scope)
87
+ # and source code location (file path and line number) for the given
88
+ # object and method name
89
+ #
90
+ # traced class methods:
91
+ # * object is a singleton class, `#<Class::MyClass>`
92
+ # * get at the underlying non-singleton class
93
+ #
94
+ # traced instance methods and Rails controller methods:
95
+ # * object is a class, `MyClass`
96
+ #
97
+ # anonymous class based methods (`c = Class.new { def method; end; }`:
98
+ # * `#name` returns `nil`, so use '(Anonymous)' instead
99
+ #
100
+ def namespace_and_location(object, method_name)
101
+ klass = object.singleton_class? ? klassify_singleton(object) : object
102
+ name = klass.name || '(Anonymous)'
103
+ is_class_method = false
104
+ method = if (klass.instance_methods + klass.private_instance_methods).include?(method_name)
105
+ klass.instance_method(method_name)
106
+ else
107
+ is_class_method = true
108
+ klass.method(method_name)
33
109
  end
110
+ [name, method.source_location, is_class_method]
34
111
  end
35
112
  end
36
113
  end