newrelic_rpm 9.1.0 → 9.21.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (360) hide show
  1. checksums.yaml +4 -4
  2. data/.build_ignore +27 -0
  3. data/CHANGELOG.md +841 -7
  4. data/CONTRIBUTING.md +2 -9
  5. data/README.md +25 -22
  6. data/Rakefile +2 -2
  7. data/bin/newrelic +3 -9
  8. data/bin/newrelic_rpm +15 -0
  9. data/init.rb +2 -2
  10. data/lib/boot/strap.rb +102 -0
  11. data/lib/new_relic/agent/agent.rb +11 -2
  12. data/lib/new_relic/agent/agent_helpers/connect.rb +13 -8
  13. data/lib/new_relic/agent/agent_helpers/harvest.rb +3 -0
  14. data/lib/new_relic/agent/agent_helpers/shutdown.rb +4 -1
  15. data/lib/new_relic/agent/agent_helpers/special_startup.rb +1 -1
  16. data/lib/new_relic/agent/agent_helpers/start_worker_thread.rb +4 -3
  17. data/lib/new_relic/agent/agent_helpers/startup.rb +11 -3
  18. data/lib/new_relic/agent/agent_logger.rb +3 -1
  19. data/lib/new_relic/agent/attribute_filter.rb +3 -3
  20. data/lib/new_relic/agent/attribute_pre_filtering.rb +109 -0
  21. data/lib/new_relic/agent/aws.rb +68 -0
  22. data/lib/new_relic/agent/configuration/default_source.rb +918 -166
  23. data/lib/new_relic/agent/configuration/environment_source.rb +15 -3
  24. data/lib/new_relic/agent/configuration/high_security_source.rb +1 -0
  25. data/lib/new_relic/agent/configuration/manager.rb +72 -11
  26. data/lib/new_relic/agent/configuration/security_policy_source.rb +11 -0
  27. data/lib/new_relic/agent/configuration/yaml_source.rb +22 -2
  28. data/lib/new_relic/agent/connect/request_builder.rb +1 -1
  29. data/lib/new_relic/agent/custom_event_aggregator.rb +27 -1
  30. data/lib/new_relic/agent/database/obfuscation_helpers.rb +11 -11
  31. data/lib/new_relic/agent/database/obfuscator.rb +1 -0
  32. data/lib/new_relic/agent/database.rb +41 -1
  33. data/lib/new_relic/agent/database_adapter.rb +1 -1
  34. data/lib/new_relic/agent/datastores/mongo/metric_translator.rb +1 -1
  35. data/lib/new_relic/agent/datastores/redis.rb +1 -1
  36. data/lib/new_relic/agent/distributed_tracing/cross_app_tracing.rb +1 -1
  37. data/lib/new_relic/agent/distributed_tracing/distributed_trace_payload.rb +4 -8
  38. data/lib/new_relic/agent/distributed_tracing.rb +5 -3
  39. data/lib/new_relic/agent/error_collector.rb +40 -11
  40. data/lib/new_relic/agent/event_loop.rb +1 -1
  41. data/lib/new_relic/agent/external.rb +2 -0
  42. data/lib/new_relic/agent/harvester.rb +1 -1
  43. data/lib/new_relic/agent/health_check.rb +136 -0
  44. data/lib/new_relic/agent/http_clients/abstract.rb +4 -0
  45. data/lib/new_relic/agent/http_clients/async_http_wrappers.rb +80 -0
  46. data/lib/new_relic/agent/http_clients/curb_wrappers.rb +1 -3
  47. data/lib/new_relic/agent/http_clients/ethon_wrappers.rb +109 -0
  48. data/lib/new_relic/agent/http_clients/excon_wrappers.rb +0 -3
  49. data/lib/new_relic/agent/http_clients/http_rb_wrappers.rb +1 -3
  50. data/lib/new_relic/agent/http_clients/httpclient_wrappers.rb +0 -3
  51. data/lib/new_relic/agent/http_clients/httpx_wrappers.rb +91 -0
  52. data/lib/new_relic/agent/http_clients/net_http_wrappers.rb +1 -4
  53. data/lib/new_relic/agent/http_clients/typhoeus_wrappers.rb +0 -3
  54. data/lib/new_relic/agent/http_clients/uri_util.rb +1 -1
  55. data/lib/new_relic/agent/instrumentation/action_controller_other_subscriber.rb +1 -1
  56. data/lib/new_relic/agent/instrumentation/action_dispatch.rb +1 -1
  57. data/lib/new_relic/agent/instrumentation/action_dispatch_subscriber.rb +1 -1
  58. data/lib/new_relic/agent/instrumentation/action_mailbox.rb +1 -1
  59. data/lib/new_relic/agent/instrumentation/action_mailer.rb +1 -1
  60. data/lib/new_relic/agent/instrumentation/active_job.rb +1 -1
  61. data/lib/new_relic/agent/instrumentation/active_job_subscriber.rb +6 -2
  62. data/lib/new_relic/agent/instrumentation/active_merchant.rb +3 -16
  63. data/lib/new_relic/agent/instrumentation/active_record.rb +8 -13
  64. data/lib/new_relic/agent/instrumentation/active_record_helper.rb +8 -5
  65. data/lib/new_relic/agent/instrumentation/active_record_notifications.rb +13 -10
  66. data/lib/new_relic/agent/instrumentation/active_record_prepend.rb +2 -2
  67. data/lib/new_relic/agent/instrumentation/active_record_subscriber.rb +9 -16
  68. data/lib/new_relic/agent/instrumentation/active_support_broadcast_logger/chain.rb +69 -0
  69. data/lib/new_relic/agent/instrumentation/active_support_broadcast_logger/instrumentation.rb +17 -0
  70. data/lib/new_relic/agent/instrumentation/active_support_broadcast_logger/prepend.rb +37 -0
  71. data/lib/new_relic/agent/instrumentation/active_support_broadcast_logger.rb +21 -0
  72. data/lib/new_relic/agent/instrumentation/active_support_logger/instrumentation.rb +4 -0
  73. data/lib/new_relic/agent/instrumentation/active_support_logger.rb +3 -3
  74. data/lib/new_relic/agent/instrumentation/async_http/chain.rb +23 -0
  75. data/lib/new_relic/agent/instrumentation/async_http/instrumentation.rb +37 -0
  76. data/lib/new_relic/agent/instrumentation/async_http/prepend.rb +15 -0
  77. data/lib/new_relic/agent/instrumentation/async_http.rb +27 -0
  78. data/lib/new_relic/agent/instrumentation/aws_sdk_firehose/chain.rb +21 -0
  79. data/lib/new_relic/agent/instrumentation/aws_sdk_firehose/instrumentation.rb +66 -0
  80. data/lib/new_relic/agent/instrumentation/aws_sdk_firehose/prepend.rb +15 -0
  81. data/lib/new_relic/agent/instrumentation/aws_sdk_firehose.rb +22 -0
  82. data/lib/new_relic/agent/instrumentation/aws_sdk_kinesis/chain.rb +21 -0
  83. data/lib/new_relic/agent/instrumentation/aws_sdk_kinesis/instrumentation.rb +91 -0
  84. data/lib/new_relic/agent/instrumentation/aws_sdk_kinesis/prepend.rb +15 -0
  85. data/lib/new_relic/agent/instrumentation/aws_sdk_kinesis.rb +22 -0
  86. data/lib/new_relic/agent/instrumentation/aws_sdk_lambda/chain.rb +33 -0
  87. data/lib/new_relic/agent/instrumentation/aws_sdk_lambda/instrumentation.rb +93 -0
  88. data/lib/new_relic/agent/instrumentation/aws_sdk_lambda/prepend.rb +23 -0
  89. data/lib/new_relic/agent/instrumentation/aws_sdk_lambda.rb +23 -0
  90. data/lib/new_relic/agent/instrumentation/aws_sqs/chain.rb +37 -0
  91. data/lib/new_relic/agent/instrumentation/aws_sqs/instrumentation.rb +67 -0
  92. data/lib/new_relic/agent/instrumentation/aws_sqs/prepend.rb +21 -0
  93. data/lib/new_relic/agent/instrumentation/aws_sqs.rb +23 -0
  94. data/lib/new_relic/agent/instrumentation/bunny/chain.rb +1 -1
  95. data/lib/new_relic/agent/instrumentation/bunny/instrumentation.rb +23 -0
  96. data/lib/new_relic/agent/instrumentation/bunny.rb +4 -5
  97. data/lib/new_relic/agent/instrumentation/concurrent_ruby/chain.rb +1 -1
  98. data/lib/new_relic/agent/instrumentation/concurrent_ruby/instrumentation.rb +3 -4
  99. data/lib/new_relic/agent/instrumentation/concurrent_ruby/prepend.rb +1 -1
  100. data/lib/new_relic/agent/instrumentation/concurrent_ruby.rb +2 -3
  101. data/lib/new_relic/agent/instrumentation/controller_instrumentation.rb +5 -2
  102. data/lib/new_relic/agent/instrumentation/curb/instrumentation.rb +4 -0
  103. data/lib/new_relic/agent/instrumentation/curb.rb +4 -5
  104. data/lib/new_relic/agent/instrumentation/delayed_job/chain.rb +1 -0
  105. data/lib/new_relic/agent/instrumentation/delayed_job/instrumentation.rb +3 -0
  106. data/lib/new_relic/agent/instrumentation/delayed_job_instrumentation.rb +0 -23
  107. data/lib/new_relic/agent/instrumentation/dynamodb/chain.rb +27 -0
  108. data/lib/new_relic/agent/instrumentation/dynamodb/instrumentation.rb +64 -0
  109. data/lib/new_relic/agent/instrumentation/dynamodb/prepend.rb +19 -0
  110. data/lib/new_relic/agent/instrumentation/dynamodb.rb +23 -0
  111. data/lib/new_relic/agent/instrumentation/elasticsearch/chain.rb +2 -3
  112. data/lib/new_relic/agent/instrumentation/elasticsearch/instrumentation.rb +65 -10
  113. data/lib/new_relic/agent/instrumentation/elasticsearch.rb +2 -4
  114. data/lib/new_relic/agent/instrumentation/ethon/chain.rb +39 -0
  115. data/lib/new_relic/agent/instrumentation/ethon/instrumentation.rb +105 -0
  116. data/lib/new_relic/agent/instrumentation/ethon/prepend.rb +35 -0
  117. data/lib/new_relic/agent/instrumentation/ethon.rb +35 -0
  118. data/lib/new_relic/agent/instrumentation/excon/middleware.rb +3 -0
  119. data/lib/new_relic/agent/instrumentation/excon.rb +1 -17
  120. data/lib/new_relic/agent/instrumentation/fiber/chain.rb +11 -4
  121. data/lib/new_relic/agent/instrumentation/fiber/instrumentation.rb +2 -6
  122. data/lib/new_relic/agent/instrumentation/fiber/prepend.rb +10 -3
  123. data/lib/new_relic/agent/instrumentation/fiber.rb +1 -3
  124. data/lib/new_relic/agent/instrumentation/grape/instrumentation.rb +4 -3
  125. data/lib/new_relic/agent/instrumentation/grape.rb +1 -1
  126. data/lib/new_relic/agent/instrumentation/grpc/client/chain.rb +1 -1
  127. data/lib/new_relic/agent/instrumentation/grpc/client/instrumentation.rb +5 -2
  128. data/lib/new_relic/agent/instrumentation/grpc/client/prepend.rb +1 -1
  129. data/lib/new_relic/agent/instrumentation/grpc/client/request_wrapper.rb +1 -1
  130. data/lib/new_relic/agent/instrumentation/grpc/server/instrumentation.rb +5 -1
  131. data/lib/new_relic/agent/instrumentation/grpc_client.rb +2 -2
  132. data/lib/new_relic/agent/instrumentation/grpc_server.rb +2 -2
  133. data/lib/new_relic/agent/instrumentation/httpclient/instrumentation.rb +4 -0
  134. data/lib/new_relic/agent/instrumentation/httpclient.rb +1 -5
  135. data/lib/new_relic/agent/instrumentation/httprb/instrumentation.rb +4 -0
  136. data/lib/new_relic/agent/instrumentation/httprb.rb +0 -1
  137. data/lib/new_relic/agent/instrumentation/httpx/chain.rb +20 -0
  138. data/lib/new_relic/agent/instrumentation/httpx/instrumentation.rb +51 -0
  139. data/lib/new_relic/agent/instrumentation/httpx/prepend.rb +15 -0
  140. data/lib/new_relic/agent/instrumentation/httpx.rb +23 -0
  141. data/lib/new_relic/agent/instrumentation/logger/instrumentation.rb +3 -0
  142. data/lib/new_relic/agent/instrumentation/logger.rb +1 -3
  143. data/lib/new_relic/agent/instrumentation/logstasher/chain.rb +21 -0
  144. data/lib/new_relic/agent/instrumentation/logstasher/instrumentation.rb +24 -0
  145. data/lib/new_relic/agent/instrumentation/logstasher/prepend.rb +13 -0
  146. data/lib/new_relic/agent/instrumentation/logstasher.rb +25 -0
  147. data/lib/new_relic/agent/instrumentation/memcache/dalli.rb +4 -2
  148. data/lib/new_relic/agent/instrumentation/memcache/helper.rb +2 -2
  149. data/lib/new_relic/agent/instrumentation/memcache/instrumentation.rb +13 -4
  150. data/lib/new_relic/agent/instrumentation/memcache/prepend.rb +4 -2
  151. data/lib/new_relic/agent/instrumentation/memcache.rb +4 -5
  152. data/lib/new_relic/agent/instrumentation/mongodb_command_subscriber.rb +3 -5
  153. data/lib/new_relic/agent/instrumentation/net_http/instrumentation.rb +13 -3
  154. data/lib/new_relic/agent/instrumentation/net_http.rb +2 -1
  155. data/lib/new_relic/agent/instrumentation/notifications_subscriber.rb +4 -2
  156. data/lib/new_relic/agent/instrumentation/opensearch/chain.rb +21 -0
  157. data/lib/new_relic/agent/instrumentation/opensearch/instrumentation.rb +66 -0
  158. data/lib/new_relic/agent/instrumentation/opensearch/prepend.rb +13 -0
  159. data/lib/new_relic/agent/instrumentation/opensearch.rb +23 -0
  160. data/lib/new_relic/agent/instrumentation/padrino/instrumentation.rb +4 -0
  161. data/lib/new_relic/agent/instrumentation/padrino.rb +3 -3
  162. data/lib/new_relic/agent/instrumentation/queue_time.rb +1 -1
  163. data/lib/new_relic/agent/instrumentation/rack/instrumentation.rb +9 -0
  164. data/lib/new_relic/agent/instrumentation/rails3/action_controller.rb +4 -0
  165. data/lib/new_relic/agent/instrumentation/rails_notifications/action_cable.rb +1 -1
  166. data/lib/new_relic/agent/instrumentation/rails_notifications/action_controller.rb +10 -5
  167. data/lib/new_relic/agent/instrumentation/rake/instrumentation.rb +4 -0
  168. data/lib/new_relic/agent/instrumentation/rake.rb +1 -2
  169. data/lib/new_relic/agent/instrumentation/rdkafka/chain.rb +72 -0
  170. data/lib/new_relic/agent/instrumentation/rdkafka/instrumentation.rb +70 -0
  171. data/lib/new_relic/agent/instrumentation/rdkafka/prepend.rb +67 -0
  172. data/lib/new_relic/agent/instrumentation/rdkafka.rb +25 -0
  173. data/lib/new_relic/agent/instrumentation/redis/cluster_middleware.rb +26 -0
  174. data/lib/new_relic/agent/instrumentation/redis/constants.rb +2 -2
  175. data/lib/new_relic/agent/instrumentation/redis/instrumentation.rb +18 -11
  176. data/lib/new_relic/agent/instrumentation/redis/middleware.rb +3 -0
  177. data/lib/new_relic/agent/instrumentation/redis.rb +11 -5
  178. data/lib/new_relic/agent/instrumentation/resque/instrumentation.rb +4 -0
  179. data/lib/new_relic/agent/instrumentation/resque.rb +8 -6
  180. data/lib/new_relic/agent/instrumentation/roda/chain.rb +43 -0
  181. data/lib/new_relic/agent/instrumentation/roda/ignorer.rb +45 -0
  182. data/lib/new_relic/agent/instrumentation/roda/instrumentation.rb +68 -0
  183. data/lib/new_relic/agent/instrumentation/roda/prepend.rb +24 -0
  184. data/lib/new_relic/agent/instrumentation/roda/roda_transaction_namer.rb +29 -0
  185. data/lib/new_relic/agent/instrumentation/roda.rb +36 -0
  186. data/lib/new_relic/agent/instrumentation/ruby_kafka/chain.rb +55 -0
  187. data/lib/new_relic/agent/instrumentation/ruby_kafka/instrumentation.rb +67 -0
  188. data/lib/new_relic/agent/instrumentation/ruby_kafka/prepend.rb +60 -0
  189. data/lib/new_relic/agent/instrumentation/ruby_kafka.rb +25 -0
  190. data/lib/new_relic/agent/instrumentation/ruby_openai/chain.rb +36 -0
  191. data/lib/new_relic/agent/instrumentation/ruby_openai/instrumentation.rb +196 -0
  192. data/lib/new_relic/agent/instrumentation/ruby_openai/prepend.rb +20 -0
  193. data/lib/new_relic/agent/instrumentation/ruby_openai.rb +35 -0
  194. data/lib/new_relic/agent/instrumentation/sequel.rb +1 -1
  195. data/lib/new_relic/agent/instrumentation/sidekiq/client.rb +4 -0
  196. data/lib/new_relic/agent/instrumentation/sidekiq/extensions/delay_extensions.rb +24 -0
  197. data/lib/new_relic/agent/instrumentation/sidekiq/extensions/delayed_class.rb +2 -2
  198. data/lib/new_relic/agent/instrumentation/sidekiq/server.rb +26 -3
  199. data/lib/new_relic/agent/instrumentation/sidekiq.rb +13 -16
  200. data/lib/new_relic/agent/instrumentation/sinatra/ignorer.rb +1 -1
  201. data/lib/new_relic/agent/instrumentation/sinatra/instrumentation.rb +4 -0
  202. data/lib/new_relic/agent/instrumentation/sinatra/transaction_namer.rb +1 -3
  203. data/lib/new_relic/agent/instrumentation/sinatra.rb +3 -19
  204. data/lib/new_relic/agent/instrumentation/stripe.rb +28 -0
  205. data/lib/new_relic/agent/instrumentation/stripe_subscriber.rb +98 -0
  206. data/lib/new_relic/agent/instrumentation/thread/chain.rb +1 -1
  207. data/lib/new_relic/agent/instrumentation/thread/instrumentation.rb +1 -5
  208. data/lib/new_relic/agent/instrumentation/thread/prepend.rb +1 -1
  209. data/lib/new_relic/agent/instrumentation/thread.rb +0 -2
  210. data/lib/new_relic/agent/instrumentation/tilt/instrumentation.rb +4 -0
  211. data/lib/new_relic/agent/instrumentation/tilt.rb +0 -4
  212. data/lib/new_relic/agent/instrumentation/typhoeus/instrumentation.rb +7 -3
  213. data/lib/new_relic/agent/instrumentation/typhoeus.rb +0 -1
  214. data/lib/new_relic/agent/instrumentation/view_component/chain.rb +21 -0
  215. data/lib/new_relic/agent/instrumentation/view_component/instrumentation.rb +45 -0
  216. data/lib/{tasks/instrumentation_generator/templates/instrumentation.tt → new_relic/agent/instrumentation/view_component/prepend.rb} +4 -4
  217. data/lib/new_relic/agent/instrumentation/view_component.rb +24 -0
  218. data/lib/new_relic/agent/javascript_instrumentor.rb +2 -4
  219. data/lib/new_relic/agent/llm/chat_completion_message.rb +25 -0
  220. data/lib/new_relic/agent/llm/chat_completion_summary.rb +66 -0
  221. data/lib/new_relic/agent/llm/embedding.rb +60 -0
  222. data/lib/new_relic/agent/llm/llm_event.rb +95 -0
  223. data/lib/new_relic/agent/llm/response_headers.rb +80 -0
  224. data/lib/new_relic/agent/llm.rb +49 -0
  225. data/lib/new_relic/agent/local_log_decorator.rb +20 -3
  226. data/lib/new_relic/agent/log_event_aggregator.rb +149 -26
  227. data/lib/new_relic/agent/log_event_attributes.rb +115 -0
  228. data/lib/new_relic/agent/logging.rb +5 -5
  229. data/lib/new_relic/agent/messaging.rb +18 -7
  230. data/lib/new_relic/agent/method_tracer.rb +4 -1
  231. data/lib/new_relic/agent/method_tracer_helpers.rb +26 -5
  232. data/lib/new_relic/agent/monitors/inbound_request_monitor.rb +1 -1
  233. data/lib/new_relic/agent/monitors/synthetics_monitor.rb +12 -1
  234. data/lib/new_relic/agent/new_relic_service/encoders.rb +2 -2
  235. data/lib/new_relic/agent/new_relic_service/json_marshaller.rb +2 -2
  236. data/lib/new_relic/agent/new_relic_service.rb +61 -28
  237. data/lib/new_relic/agent/obfuscator.rb +0 -2
  238. data/lib/new_relic/agent/opentelemetry/context/propagation/trace_propagator.rb +66 -0
  239. data/lib/new_relic/agent/opentelemetry/context/propagation.rb +15 -0
  240. data/lib/{tasks/instrumentation_generator/templates/Envfile.tt → new_relic/agent/opentelemetry/context.rb} +9 -5
  241. data/lib/new_relic/agent/opentelemetry/trace/span.rb +31 -0
  242. data/lib/new_relic/agent/opentelemetry/trace/tracer.rb +129 -0
  243. data/lib/new_relic/agent/opentelemetry/trace/tracer_provider.rb +18 -0
  244. data/lib/new_relic/agent/opentelemetry/trace.rb +15 -0
  245. data/lib/new_relic/agent/opentelemetry/transaction_patch.rb +69 -0
  246. data/lib/new_relic/agent/opentelemetry_bridge.rb +32 -0
  247. data/lib/new_relic/agent/parameter_filtering.rb +1 -1
  248. data/lib/new_relic/agent/pipe_channel_manager.rb +2 -2
  249. data/lib/new_relic/agent/pipe_service.rb +1 -1
  250. data/lib/new_relic/agent/rules_engine/segment_terms_rule.rb +1 -2
  251. data/lib/new_relic/agent/rules_engine.rb +1 -1
  252. data/lib/new_relic/agent/sampler.rb +1 -0
  253. data/lib/new_relic/agent/samplers/cpu_sampler.rb +1 -1
  254. data/lib/new_relic/agent/samplers/memory_sampler.rb +1 -1
  255. data/lib/new_relic/agent/serverless_handler.rb +406 -0
  256. data/lib/new_relic/agent/serverless_handler_event_sources.json +155 -0
  257. data/lib/new_relic/agent/serverless_handler_event_sources.rb +49 -0
  258. data/lib/new_relic/agent/span_event_primitive.rb +32 -15
  259. data/lib/new_relic/agent/sql_sampler.rb +0 -1
  260. data/lib/new_relic/agent/system_info.rb +40 -0
  261. data/lib/new_relic/agent/threading/agent_thread.rb +1 -2
  262. data/lib/new_relic/agent/threading/backtrace_node.rb +10 -1
  263. data/lib/new_relic/agent/tracer.rb +16 -16
  264. data/lib/new_relic/agent/transaction/abstract_segment.rb +103 -41
  265. data/lib/new_relic/agent/transaction/datastore_segment.rb +1 -1
  266. data/lib/new_relic/agent/transaction/distributed_tracer.rb +3 -3
  267. data/lib/new_relic/agent/transaction/distributed_tracing.rb +7 -8
  268. data/lib/new_relic/agent/transaction/external_request_segment.rb +5 -12
  269. data/lib/new_relic/agent/transaction/message_broker_segment.rb +5 -3
  270. data/lib/new_relic/agent/transaction/request_attributes.rb +54 -11
  271. data/lib/new_relic/agent/transaction/trace_context.rb +34 -5
  272. data/lib/new_relic/agent/transaction/tracing.rb +20 -4
  273. data/lib/new_relic/agent/transaction.rb +38 -13
  274. data/lib/new_relic/agent/transaction_error_primitive.rb +39 -19
  275. data/lib/new_relic/agent/transaction_event_primitive.rb +19 -0
  276. data/lib/new_relic/agent/transaction_time_aggregator.rb +1 -1
  277. data/lib/new_relic/agent/utilization/ecs.rb +22 -0
  278. data/lib/new_relic/agent/utilization/ecs_v4.rb +22 -0
  279. data/lib/new_relic/agent/utilization/gcp.rb +1 -3
  280. data/lib/new_relic/agent/utilization/vendor.rb +5 -7
  281. data/lib/new_relic/agent/utilization_data.rb +40 -5
  282. data/lib/new_relic/agent/vm/{mri_vm.rb → c_ruby_vm.rb} +10 -18
  283. data/lib/new_relic/agent/vm.rb +2 -2
  284. data/lib/new_relic/agent/worker_loop.rb +1 -1
  285. data/lib/new_relic/agent.rb +286 -17
  286. data/lib/new_relic/base64.rb +25 -0
  287. data/lib/new_relic/cli/command.rb +6 -3
  288. data/lib/new_relic/constants.rb +8 -0
  289. data/lib/new_relic/control/class_methods.rb +1 -7
  290. data/lib/new_relic/control/frameworks/grape.rb +14 -0
  291. data/lib/new_relic/control/frameworks/padrino.rb +14 -0
  292. data/lib/new_relic/control/frameworks/rails.rb +17 -5
  293. data/lib/new_relic/control/frameworks/rails4.rb +1 -3
  294. data/lib/new_relic/control/frameworks/roda.rb +20 -0
  295. data/lib/new_relic/control/instance_methods.rb +13 -0
  296. data/lib/new_relic/control/instrumentation.rb +2 -16
  297. data/lib/new_relic/control/private_instance_methods.rb +4 -0
  298. data/lib/new_relic/control/security_interface.rb +57 -0
  299. data/lib/new_relic/control.rb +1 -1
  300. data/lib/new_relic/dependency_detection.rb +25 -13
  301. data/lib/new_relic/environment_report.rb +2 -2
  302. data/lib/new_relic/helper.rb +22 -0
  303. data/lib/new_relic/language_support.rb +12 -1
  304. data/lib/new_relic/latest_changes.rb +1 -1
  305. data/lib/new_relic/local_environment.rb +31 -18
  306. data/lib/new_relic/noticed_error.rb +5 -2
  307. data/lib/new_relic/rack/agent_hooks.rb +1 -1
  308. data/lib/new_relic/rack/agent_middleware.rb +0 -16
  309. data/lib/new_relic/rack/browser_monitoring.rb +29 -13
  310. data/lib/new_relic/supportability_helper.rb +5 -1
  311. data/lib/new_relic/thread_local_storage.rb +31 -0
  312. data/lib/new_relic/traced_thread.rb +2 -3
  313. data/lib/new_relic/version.rb +1 -1
  314. data/lib/sequel/extensions/new_relic_instrumentation.rb +4 -3
  315. data/lib/tasks/bump_version.rake +21 -0
  316. data/lib/tasks/config.rake +11 -5
  317. data/lib/tasks/coverage_report.rake +1 -1
  318. data/lib/tasks/gha.rake +31 -0
  319. data/lib/tasks/helpers/config.html.erb +94 -0
  320. data/lib/tasks/helpers/format.rb +11 -7
  321. data/lib/tasks/helpers/newrelicyml.rb +211 -0
  322. data/lib/tasks/helpers/version_bump.rb +62 -0
  323. data/lib/tasks/newrelic.rb +1 -0
  324. data/lib/tasks/newrelicyml.rake +13 -0
  325. data/lib/tasks/tests.rake +71 -0
  326. data/newrelic.yml +657 -251
  327. data/newrelic_rpm.gemspec +17 -10
  328. data/test/agent_helper.rb +38 -4
  329. metadata +230 -44
  330. data/.gitignore +0 -43
  331. data/.project +0 -23
  332. data/.rubocop.yml +0 -1909
  333. data/.rubocop_todo.yml +0 -61
  334. data/.simplecov +0 -15
  335. data/.snyk +0 -11
  336. data/.yardopts +0 -27
  337. data/Brewfile +0 -12
  338. data/DOCKER.md +0 -167
  339. data/Dockerfile +0 -10
  340. data/Guardfile +0 -26
  341. data/bin/newrelic_cmd +0 -6
  342. data/config/database.yml +0 -5
  343. data/config.dot +0 -278
  344. data/docker-compose.yml +0 -107
  345. data/lefthook.yml +0 -9
  346. data/lib/new_relic/agent/range_extensions.rb +0 -27
  347. data/lib/tasks/helpers/removers.rb +0 -33
  348. data/lib/tasks/instrumentation_generator/README.md +0 -63
  349. data/lib/tasks/instrumentation_generator/TODO.md +0 -33
  350. data/lib/tasks/instrumentation_generator/instrumentation.thor +0 -121
  351. data/lib/tasks/instrumentation_generator/templates/chain.tt +0 -22
  352. data/lib/tasks/instrumentation_generator/templates/chain_method.tt +0 -8
  353. data/lib/tasks/instrumentation_generator/templates/dependency_detection.tt +0 -29
  354. data/lib/tasks/instrumentation_generator/templates/instrumentation_method.tt +0 -3
  355. data/lib/tasks/instrumentation_generator/templates/newrelic.yml.tt +0 -19
  356. data/lib/tasks/instrumentation_generator/templates/prepend.tt +0 -13
  357. data/lib/tasks/instrumentation_generator/templates/prepend_method.tt +0 -3
  358. data/lib/tasks/instrumentation_generator/templates/test.tt +0 -15
  359. data/lib/tasks/multiverse.rake +0 -6
  360. data/lib/tasks/multiverse.rb +0 -83
@@ -15,7 +15,7 @@ module NewRelic
15
15
  if @pipe && @pipe.parent_pid != $$
16
16
  @pipe.after_fork_in_child
17
17
  else
18
- NewRelic::Agent.logger.error('No communication channel to parent process, please see https://newrelic.com/docs/ruby/resque-instrumentation for more information.')
18
+ NewRelic::Agent.logger.error('No communication channel to parent process, please see https://docs.newrelic.com/docs/apm/agents/ruby-agent/background-jobs/resque-instrumentation/ for more information.')
19
19
  end
20
20
  end
21
21
 
@@ -8,7 +8,6 @@ module NewRelic
8
8
  class SegmentTermsRule
9
9
  PREFIX_KEY = 'prefix'.freeze
10
10
  TERMS_KEY = 'terms'.freeze
11
- SEGMENT_PLACEHOLDER = '*'.freeze
12
11
  ADJACENT_PLACEHOLDERS_REGEX = %r{((?:^|/)\*)(?:/\*)*}.freeze
13
12
  ADJACENT_PLACEHOLDERS_REPLACEMENT = '\1'.freeze
14
13
 
@@ -52,7 +51,7 @@ module NewRelic
52
51
  rest = string[@trim_range]
53
52
  leading_slash = rest.slice!(LEADING_SLASH_REGEX)
54
53
  segments = rest.split(SEGMENT_SEPARATOR, -1)
55
- segments.map! { |s| @terms.include?(s) ? s : SEGMENT_PLACEHOLDER }
54
+ segments.map! { |s| @terms.include?(s) ? s : ASTERISK }
56
55
  transformed_suffix = collapse_adjacent_placeholder_segments(segments)
57
56
 
58
57
  "#{@prefix}#{leading_slash}#{transformed_suffix}"
@@ -9,7 +9,7 @@ require 'new_relic/language_support'
9
9
  module NewRelic
10
10
  module Agent
11
11
  class RulesEngine
12
- SEGMENT_SEPARATOR = '/'.freeze
12
+ SEGMENT_SEPARATOR = NewRelic::SLASH
13
13
  LEADING_SLASH_REGEX = %r{^/}.freeze
14
14
 
15
15
  include Enumerable
@@ -1,6 +1,7 @@
1
1
  # This file is distributed under New Relic's license terms.
2
2
  # See https://github.com/newrelic/newrelic-ruby-agent/blob/main/LICENSE for complete details.
3
3
  # frozen_string_literal: true
4
+
4
5
  #
5
6
  # A Sampler is used to capture meaningful metrics in a background thread
6
7
  # periodically. They will be invoked about once a minute, each time the agent
@@ -42,7 +42,7 @@ module NewRelic
42
42
  # Process.times on JRuby < 1.7.0 reports wall clock elapsed time,
43
43
  # not actual cpu time used, so this sampler can only be used on JRuby >= 1.7.0.
44
44
  if defined?(JRuby)
45
- return JRUBY_VERSION >= '1.7.0'
45
+ return NewRelic::Helper.version_satisfied?(JRUBY_VERSION, '>=', '1.7.0')
46
46
  end
47
47
 
48
48
  true
@@ -50,7 +50,7 @@ module NewRelic
50
50
  begin
51
51
  NewRelic::Helper.run_command('uname -s').downcase
52
52
  rescue NewRelic::CommandRunFailedError, NewRelic::CommandExecutableNotFoundError
53
- 'unknown'
53
+ NewRelic::UNKNOWN_LOWER
54
54
  end
55
55
  else
56
56
  RUBY_PLATFORM.downcase
@@ -0,0 +1,406 @@
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 'new_relic/base64'
7
+ require 'uri'
8
+
9
+ require_relative 'serverless_handler_event_sources'
10
+
11
+ module NewRelic
12
+ module Agent
13
+ class ServerlessHandler
14
+ AGENT_ATTRIBUTE_DESTINATIONS = NewRelic::Agent::AttributeFilter::DST_TRANSACTION_TRACER |
15
+ NewRelic::Agent::AttributeFilter::DST_TRANSACTION_EVENTS
16
+ EXECUTION_ENVIRONMENT = "AWS_Lambda_ruby#{RUBY_VERSION.rpartition('.').first}".freeze
17
+ LAMBDA_MARKER = 'NR_LAMBDA_MONITORING'
18
+ LAMBDA_ENVIRONMENT_VARIABLE = 'AWS_LAMBDA_FUNCTION_NAME'
19
+ METHOD_BLOCKLIST = %i[agent_command_results connect get_agent_commands preconnect profile_data
20
+ shutdown].freeze
21
+ NAMED_PIPE = '/tmp/newrelic-telemetry'
22
+ SUPPORTABILITY_METRIC = 'Supportability/AWSLambda/HandlerInvocation'
23
+ FUNCTION_NAME = 'lambda_function'
24
+ PAYLOAD_VERSION = ENV.fetch('NEW_RELIC_SERVERLESS_PAYLOAD_VERSION', 2)
25
+ DIGIT = /\d/
26
+ EVENT_SOURCES = NewRelic::Agent::ServerlessHandlerEventSources.to_hash
27
+
28
+ def self.env_var_set?
29
+ ENV.key?(LAMBDA_ENVIRONMENT_VARIABLE)
30
+ end
31
+
32
+ def initialize
33
+ @event = nil
34
+ @context = nil
35
+ @payloads = {}
36
+ end
37
+
38
+ def invoke_lambda_function_with_new_relic(event:, context:, method_name:, namespace: nil)
39
+ NewRelic::Agent.increment_metric(SUPPORTABILITY_METRIC)
40
+
41
+ @event, @context = event, context
42
+
43
+ txn_name = function_name
44
+ if ENV['NEW_RELIC_APM_LAMBDA_MODE'] == 'true'
45
+ source = event_source_event_info['name'] if event_source_event_info
46
+ txn_name = "#{source.upcase} #{txn_name}" if source
47
+ end
48
+
49
+ NewRelic::Agent::Tracer.in_transaction(category: category, name: txn_name) do
50
+ prep_transaction
51
+
52
+ process_response(NewRelic::LanguageSupport.constantize(namespace)
53
+ .send(method_name, event: event, context: context))
54
+ end
55
+ ensure
56
+ harvest!
57
+ write_output
58
+ reset!
59
+ end
60
+
61
+ def store_payload(method, payload)
62
+ return if METHOD_BLOCKLIST.include?(method)
63
+
64
+ @payloads[method] = payload
65
+ end
66
+
67
+ def metric_data(stats_hash)
68
+ payload = [nil,
69
+ stats_hash.started_at,
70
+ (stats_hash.harvested_at || Process.clock_gettime(Process::CLOCK_REALTIME)),
71
+ []]
72
+ stats_hash.each do |metric_spec, stats|
73
+ next if stats.is_reset?
74
+
75
+ hash = {name: metric_spec.name}
76
+ hash[:scope] = metric_spec.scope unless metric_spec.scope.empty?
77
+
78
+ payload.last.push([hash, [
79
+ stats.call_count,
80
+ stats.total_call_time,
81
+ stats.total_exclusive_time,
82
+ stats.min_call_time,
83
+ stats.max_call_time,
84
+ stats.sum_of_squares
85
+ ]])
86
+ end
87
+
88
+ return if payload.last.empty?
89
+
90
+ store_payload(:metric_data, payload)
91
+ end
92
+
93
+ def error_data(errors)
94
+ store_payload(:error_data, [nil, errors.map(&:to_collector_array)])
95
+ end
96
+
97
+ private
98
+
99
+ def prep_transaction
100
+ process_api_gateway_info
101
+ process_headers
102
+ add_agent_attributes
103
+ end
104
+
105
+ def harvest!
106
+ NewRelic::Agent.instance.harvest_and_send_analytic_event_data
107
+ NewRelic::Agent.instance.harvest_and_send_custom_event_data
108
+ NewRelic::Agent.instance.harvest_and_send_data_types
109
+ end
110
+
111
+ def metadata
112
+ m = {arn: @context.invoked_function_arn,
113
+ protocol_version: NewRelic::Agent::NewRelicService::PROTOCOL_VERSION,
114
+ function_version: @context.function_version,
115
+ execution_environment: EXECUTION_ENVIRONMENT,
116
+ agent_version: NewRelic::VERSION::STRING}
117
+ if PAYLOAD_VERSION >= 2
118
+ m[:metadata_version] = PAYLOAD_VERSION
119
+ m[:agent_language] = NewRelic::LANGUAGE
120
+ end
121
+ m
122
+ end
123
+
124
+ def function_name
125
+ ENV.fetch(LAMBDA_ENVIRONMENT_VARIABLE, FUNCTION_NAME)
126
+ end
127
+
128
+ def category
129
+ @category ||=
130
+ @event&.dig('requestContext', 'http', 'method') || @event&.fetch('httpMethod', nil) ? :web : :other
131
+ end
132
+
133
+ def write_output
134
+ string = PAYLOAD_VERSION == 1 ? payload_v1 : payload_v2
135
+
136
+ return puts string unless use_named_pipe?
137
+
138
+ File.write(NAMED_PIPE, string)
139
+
140
+ NewRelic::Agent.logger.debug "Wrote serverless payload to #{NAMED_PIPE}\n" \
141
+ "BEGIN PAYLOAD>>>\n#{string}\n<<<END PAYLOAD"
142
+ end
143
+
144
+ def payload_v1 # New Relic serverless payload v1
145
+ payload_hash = {'metadata' => metadata, 'data' => @payloads}
146
+ json = NewRelic::Agent.agent.service.marshaller.dump(payload_hash)
147
+ gzipped = NewRelic::Agent::NewRelicService::Encoders::Compressed::Gzip.encode(json)
148
+ base64_encoded = NewRelic::Base64.strict_encode64(gzipped)
149
+ array = [PAYLOAD_VERSION, LAMBDA_MARKER, base64_encoded]
150
+ ::JSON.dump(array)
151
+ end
152
+
153
+ def payload_v2 # New Relic serverless payload v2
154
+ json = NewRelic::Agent.agent.service.marshaller.dump(@payloads)
155
+ gzipped = NewRelic::Agent::NewRelicService::Encoders::Compressed::Gzip.encode(json)
156
+ base64_encoded = NewRelic::Base64.strict_encode64(gzipped)
157
+ array = [PAYLOAD_VERSION, LAMBDA_MARKER, metadata, base64_encoded]
158
+ ::JSON.dump(array)
159
+ end
160
+
161
+ def determine_api_gateway_version
162
+ return unless @event
163
+
164
+ version = @event.fetch('version', '')
165
+ if version.start_with?('2.')
166
+ return 2
167
+ elsif version.start_with?('1.')
168
+ return 1
169
+ end
170
+
171
+ headers = headers_from_event
172
+ return unless headers
173
+
174
+ if @event.dig('requestContext', 'http', 'path') && @event.dig('requestContext', 'http', 'method')
175
+ 2
176
+ elsif @event.fetch('path', nil) && @event.fetch('httpMethod', nil)
177
+ 1
178
+ end
179
+ end
180
+
181
+ def process_api_gateway_info
182
+ api_v = determine_api_gateway_version
183
+ return unless api_v
184
+
185
+ info = api_v == 2 ? info_for_api_gateway_v2 : info_for_api_gateway_v1
186
+ info[:query_parameters] = @event.fetch('queryStringParameters', nil)
187
+
188
+ @http_method = info[:method]
189
+ @http_uri = http_uri(info)
190
+ end
191
+
192
+ def http_uri(info)
193
+ return unless info[:host] && info[:path]
194
+
195
+ url_str = "https://#{info[:host]}"
196
+ url_str += ":#{info[:port]}" unless info[:host].match?(':')
197
+ url_str += "#{info[:path]}"
198
+
199
+ if info[:query_parameters]
200
+ qp = info[:query_parameters].map { |k, v| "#{k}=#{v}" }.join('&')
201
+ url_str += "?#{qp}"
202
+ end
203
+
204
+ URI.parse(url_str)
205
+ rescue StandardError => e
206
+ NewRelic::Agent.logger.error "ServerlessHandler failed to parse the source HTTP URI: #{e}"
207
+ end
208
+
209
+ def info_for_api_gateway_v2
210
+ ctx = @event.fetch('requestContext', nil)
211
+ return {} unless ctx
212
+
213
+ {method: ctx.dig('http', 'method'),
214
+ path: ctx.dig('http', 'path'),
215
+ host: ctx.fetch('domainName', @event.dig('headers', 'Host')),
216
+ port: @event.dig('headers', 'X-Forwarded-Port') || 443}
217
+ end
218
+
219
+ def info_for_api_gateway_v1
220
+ headers = headers_from_event
221
+ {method: @event.fetch('httpMethod', nil),
222
+ path: @event.fetch('path', nil),
223
+ host: headers.fetch('Host', nil),
224
+ port: headers.fetch('X-Forwarded-Port', 443)}
225
+ end
226
+
227
+ def process_headers
228
+ return unless ::NewRelic::Agent.config[:'distributed_tracing.enabled']
229
+
230
+ headers = headers_from_event
231
+ return unless headers && !headers.empty?
232
+
233
+ dt_headers = headers.fetch(NewRelic::NEWRELIC_KEY, nil)
234
+ return unless dt_headers
235
+
236
+ ::NewRelic::Agent::DistributedTracing::accept_distributed_trace_headers(dt_headers, 'Other')
237
+ end
238
+
239
+ def headers_from_event
240
+ @headers ||= @event&.dig('requestContext', 'http') || @event&.dig('headers')
241
+ end
242
+
243
+ def use_named_pipe?
244
+ return @use_named_pipe if defined?(@use_named_pipe)
245
+
246
+ @use_named_pipe = File.exist?(NAMED_PIPE) && File.writable?(NAMED_PIPE)
247
+ end
248
+
249
+ def add_agent_attributes
250
+ return unless NewRelic::Agent::Tracer.current_transaction
251
+
252
+ add_agent_attribute('aws.lambda.coldStart', true) if cold?
253
+ add_agent_attribute('aws.lambda.arn', @context.invoked_function_arn)
254
+ add_agent_attribute('aws.requestId', @context.aws_request_id)
255
+
256
+ add_event_source_attributes
257
+ add_http_attributes if api_gateway_event?
258
+ end
259
+
260
+ def add_http_attributes
261
+ return unless category == :web
262
+
263
+ if @http_uri
264
+ add_agent_attribute('uri.host', @http_uri.host)
265
+ add_agent_attribute('uri.port', @http_uri.port)
266
+ if NewRelic::Agent.instance.attribute_filter.allows_key?('http.url', AttributeFilter::DST_SPAN_EVENTS)
267
+ add_agent_attribute('http.url', @http_uri.to_s)
268
+ end
269
+ end
270
+
271
+ if @http_method
272
+ add_agent_attribute('http.method', @http_method)
273
+ add_agent_attribute('http.request.method', @http_method)
274
+ end
275
+ end
276
+
277
+ def api_gateway_event?
278
+ return false unless @event
279
+
280
+ # '1.0' for API Gateway V1, '2.0' for API Gateway V2
281
+ return true if @event.fetch('version', '').start_with?(DIGIT)
282
+
283
+ return false unless headers_from_event
284
+
285
+ # API Gateway V1 - look for toplevel 'path' and 'httpMethod' keys if a version is unset
286
+ return true if @event.fetch('path', nil) && @event.fetch('httpMethod', nil)
287
+
288
+ # API Gateway V2 - look for 'requestContext/http' inner nested 'path' and 'method' keys if a version is unset
289
+ return true if @event.dig('requestContext', 'http', 'path') && @event.dig('requestContext', 'http', 'method')
290
+
291
+ false
292
+ end
293
+
294
+ def add_event_source_attributes
295
+ arn = event_source_arn
296
+ add_agent_attribute('aws.lambda.eventSource.arn', arn) if arn
297
+
298
+ info = event_source_event_info
299
+ return unless info
300
+
301
+ add_agent_attribute('aws.lambda.eventSource.eventType', info['name'])
302
+
303
+ info['attributes'].each do |name, elements|
304
+ next if elements.empty?
305
+
306
+ size = false
307
+ if elements.last.eql?('#size')
308
+ elements = elements.dup
309
+ elements.pop
310
+ size = true
311
+ end
312
+ value = @event.dig(*elements)
313
+ value = value.size if size
314
+ next unless value
315
+
316
+ add_agent_attribute(name, value)
317
+ end
318
+ end
319
+
320
+ def event_source_arn
321
+ return unless @event
322
+
323
+ # SQS/Kinesis Stream/DynamoDB/CodeCommit/S3/SNS
324
+ return event_source_arn_for_records if @event.fetch('Records', nil)
325
+
326
+ # Kinesis Firehose
327
+ ds_arn = @event.fetch('deliveryStreamArn', nil) if @event.fetch('records', nil)
328
+ return ds_arn if ds_arn
329
+
330
+ # ELB
331
+ elb_arn = @event.dig('requestContext', 'elb', 'targetGroupArn')
332
+ return elb_arn if elb_arn
333
+
334
+ # (other)
335
+ es_arn = @event.dig('resources', 0)
336
+ return es_arn if es_arn
337
+
338
+ NewRelic::Agent.logger.debug 'Unable to determine an event source arn'
339
+
340
+ nil
341
+ end
342
+
343
+ def event_source_event_info
344
+ return unless @event
345
+
346
+ # if every required key for a source is found, consider that source
347
+ # to be a match
348
+ EVENT_SOURCES.each_value do |info|
349
+ return info unless info['required_keys'].detect { |r| @event.dig(*r).nil? }
350
+ end
351
+
352
+ nil
353
+ end
354
+
355
+ def event_source_arn_for_records
356
+ record = @event['Records'].first
357
+ unless record
358
+ NewRelic::Agent.logger.debug "Unable to find any records in the event's 'Records' array"
359
+ return
360
+ end
361
+
362
+ arn = record.fetch('eventSourceARN', nil) || # SQS/Kinesis Stream/DynamoDB/CodeCommit
363
+ record.dig('s3', 'bucket', 'arn') || # S3
364
+ record.fetch('EventSubscriptionArn', nil) # SNS
365
+
366
+ unless arn
367
+ NewRelic::Agent.logger.debug "Unable to determine an event source arn from the event's 'Records' array"
368
+ end
369
+
370
+ arn
371
+ end
372
+
373
+ def add_agent_attribute(attribute, value)
374
+ NewRelic::Agent::Tracer.current_transaction.add_agent_attribute(attribute, value, AGENT_ATTRIBUTE_DESTINATIONS)
375
+ end
376
+
377
+ def process_response(response)
378
+ return response unless category == :web && response.respond_to?(:fetch)
379
+
380
+ http_status = response.fetch(:statusCode, response.fetch('statusCode', nil))
381
+ return unless http_status
382
+
383
+ add_agent_attribute('http.statusCode', http_status)
384
+
385
+ response
386
+ end
387
+
388
+ def cold?
389
+ return @cold if defined?(@cold)
390
+
391
+ @cold = false
392
+ true
393
+ end
394
+
395
+ def reset!
396
+ @event = nil
397
+ @category = nil
398
+ @context = nil
399
+ @headers = nil
400
+ @http_method = nil
401
+ @http_uri = nil
402
+ @payloads.replace({})
403
+ end
404
+ end
405
+ end
406
+ end
@@ -0,0 +1,155 @@
1
+ {
2
+ "alb": {
3
+ "attributes": {},
4
+ "name": "alb",
5
+ "required_keys": [
6
+ "httpMethod",
7
+ "requestContext.elb"
8
+ ]
9
+ },
10
+
11
+ "apiGateway": {
12
+ "attributes": {
13
+ "aws.lambda.eventSource.accountId": "requestContext.accountId",
14
+ "aws.lambda.eventSource.apiId": "requestContext.apiId",
15
+ "aws.lambda.eventSource.resourceId": "requestContext.resourceId",
16
+ "aws.lambda.eventSource.resourcePath": "requestContext.resourcePath",
17
+ "aws.lambda.eventSource.stage": "requestContext.stage"
18
+ },
19
+ "name": "apiGateway",
20
+ "required_keys": [
21
+ "headers",
22
+ "httpMethod",
23
+ "path",
24
+ "requestContext",
25
+ "requestContext.stage"
26
+ ]
27
+ },
28
+
29
+ "apiGatewayV2": {
30
+ "attributes": {
31
+ "aws.lambda.eventSource.accountId": "requestContext.accountId",
32
+ "aws.lambda.eventSource.apiId": "requestContext.apiId",
33
+ "aws.lambda.eventSource.stage": "requestContext.stage"
34
+ },
35
+ "name": "apiGatewayV2",
36
+ "required_keys": [
37
+ "version",
38
+ "headers",
39
+ "requestContext.http",
40
+ "requestContext.http.path",
41
+ "requestContext.http.method",
42
+ "requestContext.stage"
43
+ ]
44
+ },
45
+
46
+ "cloudFront": {
47
+ "attributes": {},
48
+ "name": "cloudFront",
49
+ "required_keys": [
50
+ "Records[0].cf"
51
+ ]
52
+ },
53
+
54
+ "cloudWatchScheduled": {
55
+ "attributes": {
56
+ "aws.lambda.eventSource.account": "account",
57
+ "aws.lambda.eventSource.id": "id",
58
+ "aws.lambda.eventSource.region": "region",
59
+ "aws.lambda.eventSource.resource": "resources[0]",
60
+ "aws.lambda.eventSource.time": "time"
61
+ },
62
+ "name": "cloudWatch_scheduled",
63
+ "required_keys": [
64
+ "detail-type",
65
+ "source"
66
+ ]
67
+ },
68
+
69
+ "dynamoStreams": {
70
+ "attributes": {
71
+ "aws.lambda.eventSource.length": "Records.length"
72
+ },
73
+ "name": "dynamo_streams",
74
+ "required_keys": [
75
+ "Records[0].dynamodb"
76
+ ]
77
+ },
78
+
79
+ "firehose": {
80
+ "attributes": {
81
+ "aws.lambda.eventSource.length": "records.length",
82
+ "aws.lambda.eventSource.region": "region"
83
+ },
84
+ "name": "firehose",
85
+ "required_keys": [
86
+ "deliveryStreamArn",
87
+ "records[0].kinesisRecordMetadata"
88
+ ]
89
+ },
90
+
91
+ "kinesis": {
92
+ "attributes": {
93
+ "aws.lambda.eventSource.length": "Records.length",
94
+ "aws.lambda.eventSource.region": "Records[0].awsRegion"
95
+ },
96
+ "name": "kinesis",
97
+ "required_keys": [
98
+ "Records[0].kinesis"
99
+ ]
100
+ },
101
+
102
+ "s3": {
103
+ "attributes": {
104
+ "aws.lambda.eventSource.bucketName": "Records[0].s3.bucket.name",
105
+ "aws.lambda.eventSource.eventName": "Records[0].eventName",
106
+ "aws.lambda.eventSource.eventTime": "Records[0].eventTime",
107
+ "aws.lambda.eventSource.length": "Records.length",
108
+ "aws.lambda.eventSource.objectKey": "Records[0].s3.object.key",
109
+ "aws.lambda.eventSource.objectSequencer": "Records[0].s3.object.sequencer",
110
+ "aws.lambda.eventSource.objectSize": "Records[0].s3.object.size",
111
+ "aws.lambda.eventSource.region": "Records[0].awsRegion"
112
+ },
113
+ "name": "s3",
114
+ "required_keys": [
115
+ "Records[0].s3"
116
+ ]
117
+ },
118
+
119
+ "ses": {
120
+ "attributes": {
121
+ "aws.lambda.eventSource.date": "Records[0].ses.mail.commonHeaders.date",
122
+ "aws.lambda.eventSource.length": "Records.length",
123
+ "aws.lambda.eventSource.messageId": "Records[0].ses.mail.commonHeaders.messageId",
124
+ "aws.lambda.eventSource.returnPath": "Records[0].ses.mail.commonHeaders.returnPath"
125
+ },
126
+ "name": "ses",
127
+ "required_keys": [
128
+ "Records[0].ses"
129
+ ]
130
+ },
131
+
132
+ "sns": {
133
+ "attributes": {
134
+ "aws.lambda.eventSource.length": "Records.length",
135
+ "aws.lambda.eventSource.messageId": "Records[0].Sns.MessageId",
136
+ "aws.lambda.eventSource.timestamp": "Records[0].Sns.Timestamp",
137
+ "aws.lambda.eventSource.topicArn": "Records[0].Sns.TopicArn",
138
+ "aws.lambda.eventSource.type": "Records[0].Sns.Type"
139
+ },
140
+ "name": "sns",
141
+ "required_keys": [
142
+ "Records[0].Sns"
143
+ ]
144
+ },
145
+
146
+ "sqs": {
147
+ "attributes": {
148
+ "aws.lambda.eventSource.length": "Records.length"
149
+ },
150
+ "name": "sqs",
151
+ "required_keys": [
152
+ "Records[0].receiptHandle"
153
+ ]
154
+ }
155
+ }
@@ -0,0 +1,49 @@
1
+ # This file is distributed under New Relic's license terms.
2
+ # See https://github.com/newrelic/newrelic-ruby-agent/blob/main/LICENSE for complete details.
3
+ # frozen_string_literal: true
4
+
5
+ require 'json'
6
+
7
+ module NewRelic
8
+ module Agent
9
+ # ServerlessHandlerEventSources - New Relic's language agent devs maintain
10
+ # a cross-agent JSON map of all AWS resources with the potential to invoke
11
+ # an AWS Lambda function by issuing it an event. This map is used to glean
12
+ # source specific attributes while instrumenting the function's invocation.
13
+ #
14
+ # Given that the event arrives as a Ruby hash argument to the AWS Lambda
15
+ # function, the JSON map's values need to be converted into arrays that can
16
+ # be passed to `Hash#dig`. So a value such as `'records[0].name'` needs to
17
+ # be converted to `['records', 0, 'name']`. This class's `.to_hash` method
18
+ # yields the converted data.
19
+ #
20
+ # Furthermore, `.length` calls are converted to Ruby `#size` notation to
21
+ # denote that a method call must be performed on the dug value.
22
+ class ServerlessHandlerEventSources
23
+ JSON_SOURCE = File.join(File.dirname(__FILE__), 'serverless_handler_event_sources.json').freeze
24
+ JSON_RAW = JSON.parse(File.read(JSON_SOURCE)).freeze
25
+
26
+ def self.to_hash
27
+ JSON_RAW.each_with_object({}) do |(type, info), hash|
28
+ hash[type] = {'attributes' => {},
29
+ 'name' => info['name'],
30
+ 'required_keys' => []}
31
+ info['attributes'].each { |attr, value| hash[type]['attributes'][attr] = transform(value) }
32
+ info['required_keys'].each { |key| hash[type]['required_keys'].push(transform(key)) }
33
+ end.freeze
34
+ end
35
+
36
+ def self.transform(value)
37
+ value.gsub(/\[(\d+)\]/, '.\1').split('.').map do |e|
38
+ if e.match?(/^\d+$/)
39
+ e.to_i
40
+ elsif e == 'length'
41
+ '#size'
42
+ else
43
+ e
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end