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
@@ -0,0 +1,75 @@
1
+ # This file is distributed under New Relic's license terms.
2
+ # See https://github.com/newrelic/newrelic-ruby-agent/blob/main/LICENSE for complete details.
3
+ # frozen_string_literal: true
4
+
5
+ module NewRelic
6
+ module Agent
7
+ module DistributedTraceMetrics
8
+ extend self
9
+
10
+ ALL_SUFFIX = "all"
11
+ ALL_WEB_SUFFIX = "allWeb"
12
+ ALL_OTHER_SUFFIX = "allOther"
13
+
14
+ UNKNOWN_CALLER_PREFIX = "%s/Unknown/Unknown/Unknown/%s"
15
+
16
+ def transaction_type_suffix
17
+ if Transaction.recording_web_transaction?
18
+ ALL_WEB_SUFFIX
19
+ else
20
+ ALL_OTHER_SUFFIX
21
+ end
22
+ end
23
+
24
+ def record_metrics_for_transaction(transaction)
25
+ return unless Agent.config[:'distributed_tracing.enabled']
26
+
27
+ dt = transaction.distributed_tracer
28
+ payload = dt.distributed_trace_payload || dt.trace_state_payload
29
+
30
+ record_caller_by_duration_metrics(transaction, payload)
31
+ record_transport_duration_metrics(transaction, payload)
32
+ record_errors_by_caller_metrics(transaction, payload)
33
+ end
34
+
35
+ def prefix_for_metric(name, transaction, payload)
36
+ if payload
37
+ "#{name}/" \
38
+ "#{payload.parent_type}/" \
39
+ "#{payload.parent_account_id}/" \
40
+ "#{payload.parent_app_id}/" \
41
+ "#{transaction.distributed_tracer.caller_transport_type}"
42
+ else
43
+ UNKNOWN_CALLER_PREFIX % [name, transaction.distributed_tracer.caller_transport_type]
44
+ end
45
+ end
46
+
47
+ def record_caller_by_duration_metrics(transaction, payload)
48
+ prefix = prefix_for_metric("DurationByCaller", transaction, payload)
49
+ record_unscoped_metric(transaction, prefix, transaction.duration)
50
+ end
51
+
52
+ def record_transport_duration_metrics(transaction, payload)
53
+ return unless payload
54
+
55
+ prefix = prefix_for_metric("TransportDuration", transaction, payload)
56
+ duration = transaction.calculate_transport_duration(payload)
57
+ record_unscoped_metric(transaction, prefix, duration)
58
+ end
59
+
60
+ def record_errors_by_caller_metrics(transaction, payload)
61
+ return unless transaction.exceptions.size > 0
62
+
63
+ prefix = prefix_for_metric("ErrorsByCaller", transaction, payload)
64
+ record_unscoped_metric(transaction, prefix, 1)
65
+ end
66
+
67
+ private
68
+
69
+ def record_unscoped_metric(transaction, prefix, duration)
70
+ transaction.metrics.record_unscoped("#{prefix}/#{ALL_SUFFIX}", duration)
71
+ transaction.metrics.record_unscoped("#{prefix}/#{transaction_type_suffix}", duration)
72
+ end
73
+ end
74
+ end
75
+ end
@@ -0,0 +1,163 @@
1
+ # This file is distributed under New Relic's license terms.
2
+ # See https://github.com/newrelic/newrelic-ruby-agent/blob/main/LICENSE for complete details.
3
+ # frozen_string_literal: true
4
+
5
+ require 'json'
6
+ require 'base64'
7
+
8
+ module NewRelic
9
+ module Agent
10
+ #
11
+ # This class contains properties related to distributed traces.
12
+ # To obtain an instance, call
13
+ # {DistributedTracing#create_distributed_trace_payload}
14
+ #
15
+ # @api public
16
+ class DistributedTracePayload
17
+ extend Coerce
18
+
19
+ VERSION = [0, 1].freeze
20
+ PARENT_TYPE = "App"
21
+
22
+ # Key names for serialization
23
+ VERSION_KEY = 'v'
24
+ DATA_KEY = 'd'
25
+ PARENT_TYPE_KEY = 'ty'
26
+ PARENT_ACCOUNT_ID_KEY = 'ac'
27
+ PARENT_APP_KEY = 'ap'
28
+ TRUSTED_ACCOUNT_KEY = 'tk'
29
+ ID_KEY = 'id'
30
+ TX_KEY = 'tx'
31
+ TRACE_ID_KEY = 'tr'
32
+ SAMPLED_KEY = 'sa'
33
+ TIMESTAMP_KEY = 'ti'
34
+ PRIORITY_KEY = 'pr'
35
+
36
+ class << self
37
+ def for_transaction(transaction)
38
+ return nil unless connected?
39
+
40
+ payload = new
41
+ payload.version = VERSION
42
+ payload.parent_type = PARENT_TYPE
43
+ payload.parent_account_id = Agent.config[:account_id]
44
+ payload.parent_app_id = Agent.config[:primary_application_id]
45
+
46
+ assign_trusted_account_key(payload, payload.parent_account_id)
47
+
48
+ payload.id = current_segment_id(transaction)
49
+ payload.transaction_id = transaction.guid
50
+ payload.timestamp = Process.clock_gettime(Process::CLOCK_REALTIME, :millisecond)
51
+ payload.trace_id = transaction.trace_id
52
+ payload.sampled = transaction.sampled?
53
+ payload.priority = transaction.priority
54
+
55
+ payload
56
+ end
57
+
58
+ def from_json(serialized_payload)
59
+ raw_payload = JSON.parse(serialized_payload)
60
+ return raw_payload if raw_payload.nil?
61
+
62
+ payload_data = raw_payload[DATA_KEY]
63
+
64
+ payload = new
65
+ payload.version = raw_payload[VERSION_KEY]
66
+ payload.parent_type = payload_data[PARENT_TYPE_KEY]
67
+ payload.parent_account_id = payload_data[PARENT_ACCOUNT_ID_KEY]
68
+ payload.parent_app_id = payload_data[PARENT_APP_KEY]
69
+ payload.trusted_account_key = payload_data[TRUSTED_ACCOUNT_KEY]
70
+ payload.timestamp = payload_data[TIMESTAMP_KEY]
71
+ payload.id = payload_data[ID_KEY]
72
+ payload.transaction_id = payload_data[TX_KEY]
73
+ payload.trace_id = payload_data[TRACE_ID_KEY]
74
+ payload.sampled = payload_data[SAMPLED_KEY]
75
+ payload.priority = payload_data[PRIORITY_KEY]
76
+
77
+ payload
78
+ end
79
+
80
+ def from_http_safe(http_safe_payload)
81
+ decoded_payload = Base64.strict_decode64(http_safe_payload)
82
+ from_json(decoded_payload)
83
+ end
84
+
85
+ def major_version_matches?(payload)
86
+ payload.version[0] == VERSION[0]
87
+ end
88
+
89
+ private
90
+
91
+ def assign_trusted_account_key(payload, account_id)
92
+ trusted_account_key = Agent.config[:trusted_account_key]
93
+
94
+ if account_id != trusted_account_key
95
+ payload.trusted_account_key = trusted_account_key
96
+ end
97
+ end
98
+
99
+ def current_segment_id(transaction)
100
+ if Agent.config[:'span_events.enabled'] && transaction.current_segment
101
+ transaction.current_segment.guid
102
+ end
103
+ end
104
+
105
+ def connected?
106
+ Agent.instance.connected?
107
+ end
108
+ end
109
+
110
+ attr_accessor :version,
111
+ :parent_type,
112
+ :parent_account_id,
113
+ :parent_app_id,
114
+ :trusted_account_key,
115
+ :id,
116
+ :transaction_id,
117
+ :trace_id,
118
+ :sampled,
119
+ :priority,
120
+ :timestamp
121
+
122
+ alias_method :sampled?, :sampled
123
+
124
+ # Represent this payload as a raw JSON string.
125
+ #
126
+ # @return [String] Payload translated to JSON
127
+ #
128
+ # @api public
129
+ def text
130
+ result = {
131
+ VERSION_KEY => version
132
+ }
133
+
134
+ result[DATA_KEY] = {
135
+ PARENT_TYPE_KEY => parent_type,
136
+ PARENT_ACCOUNT_ID_KEY => parent_account_id,
137
+ PARENT_APP_KEY => parent_app_id,
138
+ TX_KEY => transaction_id,
139
+ TRACE_ID_KEY => trace_id,
140
+ SAMPLED_KEY => sampled,
141
+ PRIORITY_KEY => priority,
142
+ TIMESTAMP_KEY => timestamp
143
+ }
144
+
145
+ result[DATA_KEY][ID_KEY] = id if id
146
+ result[DATA_KEY][TRUSTED_ACCOUNT_KEY] = trusted_account_key if trusted_account_key
147
+
148
+ JSON.dump(result)
149
+ end
150
+
151
+ # Encode this payload as a string suitable for passing via an
152
+ # HTTP header.
153
+ #
154
+ # @return [String] Payload translated to JSON and encoded for
155
+ # inclusion in headers
156
+ #
157
+ # @api public
158
+ def http_safe
159
+ Base64.strict_encode64(text)
160
+ end
161
+ end
162
+ end
163
+ end
@@ -0,0 +1,38 @@
1
+ # This file is distributed under New Relic's license terms.
2
+ # See https://github.com/newrelic/newrelic-ruby-agent/blob/main/LICENSE for complete details.
3
+ # frozen_string_literal: true
4
+
5
+ module NewRelic
6
+ module Agent
7
+ module DistributedTraceTransportType
8
+ extend self
9
+
10
+ ALLOWABLE_TRANSPORT_TYPES = [
11
+ NewRelic::UNKNOWN,
12
+ NewRelic::HTTP,
13
+ NewRelic::HTTPS,
14
+ "Kafka",
15
+ "JMS",
16
+ "IronMQ",
17
+ "AMQP",
18
+ "Queue",
19
+ "Other"
20
+ ].freeze
21
+
22
+ URL_SCHEMES = {
23
+ 'http' => NewRelic::HTTP,
24
+ 'https' => NewRelic::HTTPS
25
+ }.freeze
26
+
27
+ RACK_URL_SCHEME = 'rack.url_scheme'
28
+
29
+ def from(value)
30
+ ALLOWABLE_TRANSPORT_TYPES.include?(value) ? value : NewRelic::UNKNOWN
31
+ end
32
+
33
+ def for_rack_request(request)
34
+ URL_SCHEMES[request[RACK_URL_SCHEME]]
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,245 @@
1
+ # This file is distributed under New Relic's license terms.
2
+ # See https://github.com/newrelic/newrelic-ruby-agent/blob/main/LICENSE for complete details.
3
+ # frozen_string_literal: true
4
+
5
+ require_relative 'trace_context_payload'
6
+
7
+ module NewRelic
8
+ module Agent
9
+ module DistributedTracing
10
+ class TraceContext
11
+ VERSION = 0x0
12
+
13
+ COMMA = ','
14
+ EQUALS = '='
15
+ INVALID_TRACE_ID = ('0' * 32)
16
+ INVALID_PARENT_ID = ('0' * 16)
17
+ INVALID_VERSION = 'ff'
18
+
19
+ TRACE_ID_KEY = 'trace_id'
20
+ TRACE_FLAGS_KEY = 'trace_flags'
21
+ PARENT_ID_KEY = 'parent_id'
22
+ VERSION_KEY = 'version'
23
+ UNDEFINED_FIELDS_KEY = 'undefined_fields'
24
+
25
+ TP_VERSION = "(?<#{VERSION_KEY}>[a-f\\d]{2})"
26
+ TP_TRACE_ID = "(?<#{TRACE_ID_KEY}>[a-f\\d]{32})"
27
+ TP_PARENT_ID = "(?<#{PARENT_ID_KEY}>[a-f\\d]{16})"
28
+ TP_TRACE_FLAGS = "(?<#{TRACE_FLAGS_KEY}>\\d{2})"
29
+ TP_UNDEFINED_FIELDS = "(?<#{UNDEFINED_FIELDS_KEY}>-[a-zA-Z\\d-]*)"
30
+ TRACE_PARENT_REGEX = /\A#{TP_VERSION}-#{TP_TRACE_ID}-#{TP_PARENT_ID}-#{TP_TRACE_FLAGS}#{TP_UNDEFINED_FIELDS}?\z/
31
+
32
+ TRACE_PARENT_FORMAT_STRING = "%02x-%s-%s-%02x"
33
+
34
+ MAX_TRACE_STATE_SIZE = 512 # bytes
35
+ MAX_TRACE_STATE_ENTRY_SIZE = 128 # bytes
36
+
37
+ SUPPORTABILITY_TRACE_PARENT_PARSE_EXCEPTION = "Supportability/TraceContext/TraceParent/Parse/Exception"
38
+ SUPPORTABILITY_TRACE_STATE_PARSE_EXCEPTION = "Supportability/TraceContext/TraceState/Parse/Exception"
39
+ SUPPORTABILITY_TRACE_STATE_INVALID_NR_ENTRY = "Supportability/TraceContext/TraceState/InvalidNrEntry"
40
+
41
+ class << self
42
+ def insert(format: NewRelic::FORMAT_NON_RACK,
43
+ carrier: nil,
44
+ parent_id: nil,
45
+ trace_id: nil,
46
+ trace_flags: nil,
47
+ trace_state: nil)
48
+
49
+ trace_parent_header = trace_parent_header_for_format(format)
50
+ carrier[trace_parent_header] = format_trace_parent( \
51
+ trace_id: trace_id,
52
+ parent_id: parent_id,
53
+ trace_flags: trace_flags
54
+ )
55
+
56
+ trace_state_header = trace_state_header_for_format(format)
57
+ carrier[trace_state_header] = trace_state if trace_state && !trace_state.empty?
58
+ end
59
+
60
+ def parse(format: NewRelic::FORMAT_NON_RACK,
61
+ carrier: nil,
62
+ trace_state_entry_key: nil)
63
+ trace_parent = extract_traceparent(format, carrier)
64
+ unless trace_parent_valid?(trace_parent)
65
+ NewRelic::Agent.increment_metric(SUPPORTABILITY_TRACE_PARENT_PARSE_EXCEPTION)
66
+ return nil
67
+ end
68
+
69
+ begin
70
+ if header_data = extract_tracestate(format, carrier, trace_state_entry_key)
71
+ header_data.trace_parent = trace_parent
72
+ header_data
73
+ end
74
+ rescue Exception
75
+ NewRelic::Agent.increment_metric(SUPPORTABILITY_TRACE_STATE_PARSE_EXCEPTION)
76
+ return nil
77
+ end
78
+ end
79
+
80
+ def create_trace_state_entry(entry_key, payload)
81
+ "#{entry_key}=#{payload}".dup
82
+ end
83
+
84
+ private
85
+
86
+ def format_trace_parent(trace_id: nil,
87
+ parent_id: nil,
88
+ trace_flags: nil)
89
+ sprintf(TRACE_PARENT_FORMAT_STRING,
90
+ VERSION,
91
+ trace_id,
92
+ parent_id,
93
+ trace_flags)
94
+ end
95
+
96
+ def extract_traceparent(format, carrier)
97
+ header_name = trace_parent_header_for_format(format)
98
+ return unless header = carrier[header_name]
99
+
100
+ if matchdata = header.match(TRACE_PARENT_REGEX)
101
+ TRACE_PARENT_REGEX.named_captures.inject({}) do |hash, (name, (index))|
102
+ hash[name] = matchdata[index]
103
+ hash
104
+ end
105
+ end
106
+ end
107
+
108
+ def trace_parent_valid?(trace_parent)
109
+ return false if trace_parent.nil?
110
+ return false if trace_parent[TRACE_ID_KEY] == INVALID_TRACE_ID
111
+ return false if trace_parent[PARENT_ID_KEY] == INVALID_PARENT_ID
112
+ return false if trace_parent[VERSION_KEY] == INVALID_VERSION
113
+ return false if trace_parent[VERSION_KEY].to_i(16) == VERSION && !trace_parent[UNDEFINED_FIELDS_KEY].nil?
114
+
115
+ true
116
+ end
117
+
118
+ def trace_parent_header_for_format(format)
119
+ if format == NewRelic::FORMAT_RACK
120
+ NewRelic::HTTP_TRACEPARENT_KEY
121
+ else
122
+ NewRelic::TRACEPARENT_KEY
123
+ end
124
+ end
125
+
126
+ def trace_state_header_for_format(format)
127
+ if format == NewRelic::FORMAT_RACK
128
+ NewRelic::HTTP_TRACESTATE_KEY
129
+ else
130
+ NewRelic::TRACESTATE_KEY
131
+ end
132
+ end
133
+
134
+ def extract_tracestate(format, carrier, trace_state_entry_key)
135
+ header_name = trace_state_header_for_format(format)
136
+ header = carrier[header_name]
137
+ return HeaderData.create if header.nil? || header.empty?
138
+
139
+ payload = nil
140
+ trace_state_size = 0
141
+ trace_state_vendors = String.new
142
+ trace_state = header.split(COMMA).map(&:strip)
143
+ trace_state.reject! do |entry|
144
+ if entry == NewRelic::EMPTY_STR
145
+ false
146
+ else
147
+ vendor_id = entry.slice(0, entry.index(EQUALS))
148
+ if vendor_id == trace_state_entry_key
149
+ payload = entry.slice!(trace_state_entry_key.size + 1, entry.size)
150
+ true
151
+ else
152
+ trace_state_size += entry.size
153
+ trace_state_vendors << vendor_id << COMMA
154
+ false
155
+ end
156
+ end
157
+ end
158
+
159
+ trace_state_vendors.chomp!(COMMA)
160
+
161
+ HeaderData.create(trace_state_payload: payload ? decode_payload(payload) : nil,
162
+ trace_state_entries: trace_state,
163
+ trace_state_size: trace_state_size,
164
+ trace_state_vendors: trace_state_vendors)
165
+ end
166
+
167
+ def decode_payload(payload)
168
+ TraceContextPayload.from_s(payload)
169
+ rescue
170
+ if payload
171
+ NewRelic::Agent.increment_metric(SUPPORTABILITY_TRACE_STATE_INVALID_NR_ENTRY)
172
+ end
173
+ return nil
174
+ end
175
+ end
176
+
177
+ class HeaderData
178
+ class << self
179
+ def create(trace_parent: nil,
180
+ trace_state_payload: nil,
181
+ trace_state_entries: nil,
182
+ trace_state_size: 0,
183
+ trace_state_vendors: nil)
184
+ new(trace_parent, \
185
+ trace_state_payload, \
186
+ trace_state_entries, \
187
+ trace_state_size, \
188
+ trace_state_vendors)
189
+ end
190
+ end
191
+
192
+ def initialize(trace_parent, trace_state_payload, trace_state_entries, trace_state_size, trace_state_vendors)
193
+ @trace_parent = trace_parent
194
+ @trace_state = nil
195
+ @trace_state_entries = trace_state_entries
196
+ @trace_state_payload = trace_state_payload
197
+ @trace_state_size = trace_state_size
198
+ @trace_state_vendors = trace_state_vendors
199
+ end
200
+
201
+ attr_accessor :trace_parent, :trace_state_payload, :trace_state_vendors
202
+
203
+ def trace_state(trace_state_entry)
204
+ @trace_state ||= join_trace_state(trace_state_entry.size)
205
+ @trace_state_entries = nil
206
+
207
+ trace_state_entry = "#{trace_state_entry}#{@trace_state}"
208
+ end
209
+
210
+ def trace_id
211
+ @trace_parent[TRACE_ID_KEY]
212
+ end
213
+
214
+ def parent_id
215
+ @trace_parent[PARENT_ID_KEY]
216
+ end
217
+
218
+ private
219
+
220
+ def join_trace_state(trace_state_entry_size)
221
+ return @trace_state || NewRelic::EMPTY_STR if @trace_state_entries.nil? || @trace_state_entries.empty?
222
+
223
+ max_size = MAX_TRACE_STATE_SIZE - trace_state_entry_size
224
+ return @trace_state_entries.join(COMMA).prepend(COMMA) if @trace_state_size < max_size
225
+
226
+ joined_trace_state = ''.dup
227
+
228
+ used_size = 0
229
+
230
+ @trace_state_entries.each do |entry|
231
+ entry_size = entry.size + 1
232
+ break if used_size + entry_size > max_size
233
+ next if entry_size > MAX_TRACE_STATE_ENTRY_SIZE
234
+
235
+ joined_trace_state << COMMA << entry
236
+ used_size += entry_size
237
+ end
238
+
239
+ joined_trace_state
240
+ end
241
+ end
242
+ end
243
+ end
244
+ end
245
+ end
@@ -0,0 +1,127 @@
1
+ # This file is distributed under New Relic's license terms.
2
+ # See https://github.com/newrelic/newrelic-ruby-agent/blob/main/LICENSE for complete details.
3
+ # frozen_string_literal: true
4
+
5
+ require 'new_relic/coerce'
6
+
7
+ module NewRelic
8
+ module Agent
9
+ class TraceContextPayload
10
+ VERSION = 0
11
+ PARENT_TYPE = 0
12
+ DELIMITER = "-".freeze
13
+ SUPPORTABILITY_PARSE_EXCEPTION = "Supportability/TraceContext/Parse/Exception".freeze
14
+
15
+ TRUE_CHAR = '1'.freeze
16
+ FALSE_CHAR = '0'.freeze
17
+
18
+ PARENT_TYPES = %w[App Browser Mobile].map(&:freeze).freeze
19
+
20
+ class << self
21
+ def create(version: VERSION,
22
+ parent_type: PARENT_TYPE,
23
+ parent_account_id: nil,
24
+ parent_app_id: nil,
25
+ id: nil,
26
+ transaction_id: nil,
27
+ sampled: nil,
28
+ priority: nil,
29
+ timestamp: now_ms)
30
+
31
+ new(version, parent_type, parent_account_id, parent_app_id, id,
32
+ transaction_id, sampled, priority, timestamp)
33
+ end
34
+
35
+ include NewRelic::Coerce
36
+
37
+ def from_s(payload_string)
38
+ attrs = payload_string.split(DELIMITER)
39
+
40
+ payload = create( \
41
+ version: int!(attrs[0]),
42
+ parent_type: int!(attrs[1]),
43
+ parent_account_id: attrs[2],
44
+ parent_app_id: attrs[3],
45
+ id: value_or_nil(attrs[4]),
46
+ transaction_id: value_or_nil(attrs[5]),
47
+ sampled: value_or_nil(attrs[6]) ? boolean_int!(attrs[6]) == 1 : nil,
48
+ priority: float!(attrs[7]),
49
+ timestamp: int!(attrs[8])
50
+ )
51
+ handle_invalid_payload(message: 'payload missing attributes') unless payload.valid?
52
+ payload
53
+ rescue => e
54
+ handle_invalid_payload(error: e)
55
+ raise
56
+ end
57
+
58
+ private
59
+
60
+ def now_ms
61
+ Process.clock_gettime(Process::CLOCK_REALTIME, :millisecond)
62
+ end
63
+
64
+ def handle_invalid_payload(error: nil, message: nil)
65
+ NewRelic::Agent.increment_metric(SUPPORTABILITY_PARSE_EXCEPTION)
66
+ if error
67
+ NewRelic::Agent.logger.warn("Error parsing trace context payload", error)
68
+ elsif message
69
+ NewRelic::Agent.logger.warn("Error parsing trace context payload: #{message}")
70
+ end
71
+ end
72
+ end
73
+
74
+ attr_accessor :version,
75
+ :parent_type_id,
76
+ :parent_account_id,
77
+ :parent_app_id,
78
+ :id,
79
+ :transaction_id,
80
+ :sampled,
81
+ :priority,
82
+ :timestamp
83
+
84
+ alias_method :sampled?, :sampled
85
+
86
+ def initialize(version, parent_type_id, parent_account_id, parent_app_id,
87
+ id, transaction_id, sampled, priority, timestamp)
88
+ @version = version
89
+ @parent_type_id = parent_type_id
90
+ @parent_account_id = parent_account_id
91
+ @parent_app_id = parent_app_id
92
+ @id = id
93
+ @transaction_id = transaction_id
94
+ @sampled = sampled
95
+ @priority = priority
96
+ @timestamp = timestamp
97
+ end
98
+
99
+ def parent_type
100
+ @parent_type_string ||= PARENT_TYPES[@parent_type_id]
101
+ end
102
+
103
+ def valid?
104
+ version \
105
+ && parent_type_id \
106
+ && !parent_account_id.empty? \
107
+ && !parent_app_id.empty? \
108
+ && timestamp
109
+ rescue
110
+ false
111
+ end
112
+
113
+ def to_s
114
+ result = version.to_s # required
115
+ result << DELIMITER << parent_type_id.to_s # required
116
+ result << DELIMITER << parent_account_id # required
117
+ result << DELIMITER << parent_app_id # required
118
+ result << DELIMITER << (id || NewRelic::EMPTY_STR)
119
+ result << DELIMITER << (transaction_id || NewRelic::EMPTY_STR)
120
+ result << DELIMITER << (sampled ? TRUE_CHAR : FALSE_CHAR)
121
+ result << DELIMITER << sprintf("%.6f", priority)
122
+ result << DELIMITER << timestamp.to_s # required
123
+ result
124
+ end
125
+ end
126
+ end
127
+ end