newrelic_rpm 9.9.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 (219) hide show
  1. checksums.yaml +4 -4
  2. data/.build_ignore +1 -0
  3. data/CHANGELOG.md +463 -1
  4. data/CONTRIBUTING.md +2 -2
  5. data/README.md +16 -17
  6. data/Rakefile +1 -1
  7. data/lib/boot/strap.rb +102 -0
  8. data/lib/new_relic/agent/agent.rb +6 -0
  9. data/lib/new_relic/agent/agent_helpers/connect.rb +3 -0
  10. data/lib/new_relic/agent/agent_helpers/harvest.rb +3 -0
  11. data/lib/new_relic/agent/agent_helpers/shutdown.rb +3 -0
  12. data/lib/new_relic/agent/agent_helpers/start_worker_thread.rb +1 -0
  13. data/lib/new_relic/agent/agent_helpers/startup.rb +7 -0
  14. data/lib/new_relic/agent/agent_logger.rb +1 -0
  15. data/lib/new_relic/agent/aws.rb +68 -0
  16. data/lib/new_relic/agent/configuration/default_source.rb +603 -105
  17. data/lib/new_relic/agent/configuration/environment_source.rb +5 -1
  18. data/lib/new_relic/agent/configuration/manager.rb +28 -2
  19. data/lib/new_relic/agent/configuration/yaml_source.rb +7 -2
  20. data/lib/new_relic/agent/database/obfuscation_helpers.rb +11 -11
  21. data/lib/new_relic/agent/database/obfuscator.rb +1 -0
  22. data/lib/new_relic/agent/database.rb +41 -1
  23. data/lib/new_relic/agent/database_adapter.rb +1 -1
  24. data/lib/new_relic/agent/datastores/redis.rb +1 -1
  25. data/lib/new_relic/agent/distributed_tracing/cross_app_tracing.rb +1 -1
  26. data/lib/new_relic/agent/distributed_tracing.rb +4 -2
  27. data/lib/new_relic/agent/error_collector.rb +37 -10
  28. data/lib/new_relic/agent/external.rb +2 -0
  29. data/lib/new_relic/agent/health_check.rb +136 -0
  30. data/lib/new_relic/agent/http_clients/uri_util.rb +1 -1
  31. data/lib/new_relic/agent/instrumentation/action_dispatch.rb +1 -1
  32. data/lib/new_relic/agent/instrumentation/action_dispatch_subscriber.rb +1 -1
  33. data/lib/new_relic/agent/instrumentation/action_mailbox.rb +1 -1
  34. data/lib/new_relic/agent/instrumentation/action_mailer.rb +1 -1
  35. data/lib/new_relic/agent/instrumentation/active_job.rb +1 -1
  36. data/lib/new_relic/agent/instrumentation/active_job_subscriber.rb +6 -2
  37. data/lib/new_relic/agent/instrumentation/active_merchant.rb +0 -13
  38. data/lib/new_relic/agent/instrumentation/active_record.rb +7 -12
  39. data/lib/new_relic/agent/instrumentation/active_record_helper.rb +7 -3
  40. data/lib/new_relic/agent/instrumentation/active_record_notifications.rb +11 -9
  41. data/lib/new_relic/agent/instrumentation/active_record_prepend.rb +2 -2
  42. data/lib/new_relic/agent/instrumentation/active_record_subscriber.rb +9 -16
  43. data/lib/new_relic/agent/instrumentation/active_support_broadcast_logger.rb +0 -2
  44. data/lib/new_relic/agent/instrumentation/active_support_logger.rb +0 -2
  45. data/lib/new_relic/agent/instrumentation/async_http.rb +2 -3
  46. data/lib/new_relic/agent/instrumentation/aws_sdk_firehose/chain.rb +21 -0
  47. data/lib/new_relic/agent/instrumentation/aws_sdk_firehose/instrumentation.rb +66 -0
  48. data/lib/new_relic/agent/instrumentation/aws_sdk_firehose/prepend.rb +15 -0
  49. data/lib/new_relic/agent/instrumentation/aws_sdk_firehose.rb +22 -0
  50. data/lib/new_relic/agent/instrumentation/aws_sdk_kinesis/chain.rb +21 -0
  51. data/lib/new_relic/agent/instrumentation/aws_sdk_kinesis/instrumentation.rb +91 -0
  52. data/lib/new_relic/agent/instrumentation/aws_sdk_kinesis/prepend.rb +15 -0
  53. data/lib/new_relic/agent/instrumentation/aws_sdk_kinesis.rb +22 -0
  54. data/lib/new_relic/agent/instrumentation/aws_sdk_lambda/chain.rb +33 -0
  55. data/lib/new_relic/agent/instrumentation/aws_sdk_lambda/instrumentation.rb +93 -0
  56. data/lib/new_relic/agent/instrumentation/aws_sdk_lambda/prepend.rb +23 -0
  57. data/lib/new_relic/agent/instrumentation/aws_sdk_lambda.rb +23 -0
  58. data/lib/new_relic/agent/instrumentation/aws_sqs/chain.rb +37 -0
  59. data/lib/new_relic/agent/instrumentation/aws_sqs/instrumentation.rb +67 -0
  60. data/lib/new_relic/agent/instrumentation/aws_sqs/prepend.rb +21 -0
  61. data/lib/new_relic/agent/instrumentation/aws_sqs.rb +23 -0
  62. data/lib/new_relic/agent/instrumentation/bunny/instrumentation.rb +14 -0
  63. data/lib/new_relic/agent/instrumentation/bunny.rb +3 -4
  64. data/lib/new_relic/agent/instrumentation/concurrent_ruby.rb +1 -3
  65. data/lib/new_relic/agent/instrumentation/controller_instrumentation.rb +4 -0
  66. data/lib/new_relic/agent/instrumentation/curb.rb +4 -5
  67. data/lib/new_relic/agent/instrumentation/delayed_job_instrumentation.rb +0 -23
  68. data/lib/new_relic/agent/instrumentation/dynamodb/chain.rb +27 -0
  69. data/lib/new_relic/agent/instrumentation/dynamodb/instrumentation.rb +64 -0
  70. data/lib/new_relic/agent/instrumentation/dynamodb/prepend.rb +19 -0
  71. data/lib/new_relic/agent/instrumentation/dynamodb.rb +23 -0
  72. data/lib/new_relic/agent/instrumentation/elasticsearch/chain.rb +1 -2
  73. data/lib/new_relic/agent/instrumentation/elasticsearch/instrumentation.rb +53 -7
  74. data/lib/new_relic/agent/instrumentation/elasticsearch.rb +1 -3
  75. data/lib/new_relic/agent/instrumentation/ethon.rb +1 -5
  76. data/lib/new_relic/agent/instrumentation/excon.rb +1 -17
  77. data/lib/new_relic/agent/instrumentation/fiber/chain.rb +1 -1
  78. data/lib/new_relic/agent/instrumentation/fiber/prepend.rb +1 -1
  79. data/lib/new_relic/agent/instrumentation/fiber.rb +0 -2
  80. data/lib/new_relic/agent/instrumentation/grape/instrumentation.rb +0 -3
  81. data/lib/new_relic/agent/instrumentation/grape.rb +1 -1
  82. data/lib/new_relic/agent/instrumentation/grpc/client/instrumentation.rb +0 -1
  83. data/lib/new_relic/agent/instrumentation/httpclient.rb +1 -5
  84. data/lib/new_relic/agent/instrumentation/httprb.rb +0 -1
  85. data/lib/new_relic/agent/instrumentation/httpx/instrumentation.rb +1 -1
  86. data/lib/new_relic/agent/instrumentation/httpx.rb +1 -5
  87. data/lib/new_relic/agent/instrumentation/logger.rb +1 -3
  88. data/lib/new_relic/agent/instrumentation/logstasher/chain.rb +21 -0
  89. data/lib/new_relic/agent/instrumentation/logstasher/instrumentation.rb +24 -0
  90. data/lib/new_relic/agent/instrumentation/logstasher/prepend.rb +13 -0
  91. data/lib/new_relic/agent/instrumentation/logstasher.rb +25 -0
  92. data/lib/new_relic/agent/instrumentation/memcache/dalli.rb +1 -1
  93. data/lib/new_relic/agent/instrumentation/memcache/helper.rb +2 -2
  94. data/lib/new_relic/agent/instrumentation/memcache/instrumentation.rb +1 -1
  95. data/lib/new_relic/agent/instrumentation/memcache/prepend.rb +1 -1
  96. data/lib/new_relic/agent/instrumentation/memcache.rb +0 -1
  97. data/lib/new_relic/agent/instrumentation/mongodb_command_subscriber.rb +1 -1
  98. data/lib/new_relic/agent/instrumentation/net_http/instrumentation.rb +3 -3
  99. data/lib/new_relic/agent/instrumentation/net_http.rb +2 -1
  100. data/lib/new_relic/agent/instrumentation/notifications_subscriber.rb +0 -2
  101. data/lib/new_relic/agent/instrumentation/opensearch/chain.rb +21 -0
  102. data/lib/new_relic/agent/instrumentation/opensearch/instrumentation.rb +66 -0
  103. data/lib/{tasks/instrumentation_generator/templates/instrumentation.tt → new_relic/agent/instrumentation/opensearch/prepend.rb} +4 -4
  104. data/lib/new_relic/agent/instrumentation/opensearch.rb +23 -0
  105. data/lib/new_relic/agent/instrumentation/padrino.rb +3 -3
  106. data/lib/new_relic/agent/instrumentation/rack/instrumentation.rb +3 -0
  107. data/lib/new_relic/agent/instrumentation/rails_notifications/action_controller.rb +9 -5
  108. data/lib/new_relic/agent/instrumentation/rake.rb +1 -2
  109. data/lib/new_relic/agent/instrumentation/rdkafka/chain.rb +72 -0
  110. data/lib/new_relic/agent/instrumentation/rdkafka/instrumentation.rb +70 -0
  111. data/lib/new_relic/agent/instrumentation/rdkafka/prepend.rb +67 -0
  112. data/lib/new_relic/agent/instrumentation/rdkafka.rb +25 -0
  113. data/lib/new_relic/agent/instrumentation/redis/cluster_middleware.rb +26 -0
  114. data/lib/new_relic/agent/instrumentation/redis/constants.rb +2 -2
  115. data/lib/new_relic/agent/instrumentation/redis/instrumentation.rb +14 -11
  116. data/lib/new_relic/agent/instrumentation/redis/middleware.rb +3 -0
  117. data/lib/new_relic/agent/instrumentation/redis.rb +11 -5
  118. data/lib/new_relic/agent/instrumentation/resque.rb +8 -6
  119. data/lib/new_relic/agent/instrumentation/roda.rb +5 -5
  120. data/lib/new_relic/agent/instrumentation/ruby_kafka/chain.rb +55 -0
  121. data/lib/new_relic/agent/instrumentation/ruby_kafka/instrumentation.rb +67 -0
  122. data/lib/new_relic/agent/instrumentation/ruby_kafka/prepend.rb +60 -0
  123. data/lib/new_relic/agent/instrumentation/ruby_kafka.rb +25 -0
  124. data/lib/new_relic/agent/instrumentation/ruby_openai.rb +2 -2
  125. data/lib/new_relic/agent/instrumentation/sidekiq/extensions/delay_extensions.rb +24 -0
  126. data/lib/new_relic/agent/instrumentation/sidekiq/extensions/delayed_class.rb +2 -2
  127. data/lib/new_relic/agent/instrumentation/sidekiq.rb +9 -15
  128. data/lib/new_relic/agent/instrumentation/sinatra.rb +3 -19
  129. data/lib/new_relic/agent/instrumentation/stripe.rb +1 -1
  130. data/lib/new_relic/agent/instrumentation/stripe_subscriber.rb +22 -1
  131. data/lib/new_relic/agent/instrumentation/thread.rb +0 -2
  132. data/lib/new_relic/agent/instrumentation/tilt.rb +0 -4
  133. data/lib/new_relic/agent/instrumentation/typhoeus/instrumentation.rb +2 -2
  134. data/lib/new_relic/agent/instrumentation/typhoeus.rb +0 -1
  135. data/lib/new_relic/agent/instrumentation/view_component/instrumentation.rb +11 -5
  136. data/lib/new_relic/agent/instrumentation/view_component.rb +0 -2
  137. data/lib/new_relic/agent/javascript_instrumentor.rb +2 -3
  138. data/lib/new_relic/agent/llm/chat_completion_summary.rb +1 -1
  139. data/lib/new_relic/agent/llm/embedding.rb +1 -1
  140. data/lib/new_relic/agent/local_log_decorator.rb +20 -3
  141. data/lib/new_relic/agent/log_event_aggregator.rb +119 -28
  142. data/lib/new_relic/agent/logging.rb +1 -1
  143. data/lib/new_relic/agent/messaging.rb +16 -5
  144. data/lib/new_relic/agent/method_tracer.rb +3 -0
  145. data/lib/new_relic/agent/monitors/inbound_request_monitor.rb +1 -1
  146. data/lib/new_relic/agent/monitors/synthetics_monitor.rb +1 -1
  147. data/lib/new_relic/agent/new_relic_service/json_marshaller.rb +2 -2
  148. data/lib/new_relic/agent/new_relic_service.rb +8 -2
  149. data/lib/new_relic/agent/opentelemetry/context/propagation/trace_propagator.rb +66 -0
  150. data/lib/new_relic/agent/opentelemetry/context/propagation.rb +15 -0
  151. data/lib/{tasks/instrumentation_generator/templates/Envfile.tt → new_relic/agent/opentelemetry/context.rb} +9 -5
  152. data/lib/new_relic/agent/opentelemetry/trace/span.rb +31 -0
  153. data/lib/new_relic/agent/opentelemetry/trace/tracer.rb +129 -0
  154. data/lib/new_relic/agent/opentelemetry/trace/tracer_provider.rb +18 -0
  155. data/lib/new_relic/agent/opentelemetry/trace.rb +15 -0
  156. data/lib/new_relic/agent/opentelemetry/transaction_patch.rb +69 -0
  157. data/lib/new_relic/agent/opentelemetry_bridge.rb +32 -0
  158. data/lib/new_relic/agent/parameter_filtering.rb +1 -1
  159. data/lib/new_relic/agent/samplers/cpu_sampler.rb +1 -1
  160. data/lib/new_relic/agent/samplers/memory_sampler.rb +1 -1
  161. data/lib/new_relic/agent/serverless_handler.rb +247 -12
  162. data/lib/new_relic/agent/serverless_handler_event_sources.json +155 -0
  163. data/lib/new_relic/agent/serverless_handler_event_sources.rb +49 -0
  164. data/lib/new_relic/agent/span_event_primitive.rb +16 -11
  165. data/lib/new_relic/agent/system_info.rb +14 -0
  166. data/lib/new_relic/agent/threading/backtrace_node.rb +10 -1
  167. data/lib/new_relic/agent/tracer.rb +1 -1
  168. data/lib/new_relic/agent/transaction/abstract_segment.rb +2 -1
  169. data/lib/new_relic/agent/transaction/datastore_segment.rb +1 -1
  170. data/lib/new_relic/agent/transaction/distributed_tracer.rb +3 -3
  171. data/lib/new_relic/agent/transaction/external_request_segment.rb +0 -10
  172. data/lib/new_relic/agent/transaction/message_broker_segment.rb +4 -1
  173. data/lib/new_relic/agent/transaction/request_attributes.rb +14 -7
  174. data/lib/new_relic/agent/transaction/trace_context.rb +34 -5
  175. data/lib/new_relic/agent/transaction/tracing.rb +3 -3
  176. data/lib/new_relic/agent/transaction.rb +4 -7
  177. data/lib/new_relic/agent/transaction_time_aggregator.rb +1 -1
  178. data/lib/new_relic/agent/utilization/ecs.rb +22 -0
  179. data/lib/new_relic/agent/utilization/ecs_v4.rb +22 -0
  180. data/lib/new_relic/agent/utilization_data.rb +40 -5
  181. data/lib/new_relic/agent/vm/c_ruby_vm.rb +3 -3
  182. data/lib/new_relic/agent.rb +124 -2
  183. data/lib/new_relic/constants.rb +1 -0
  184. data/lib/new_relic/control/frameworks/grape.rb +14 -0
  185. data/lib/new_relic/control/frameworks/padrino.rb +14 -0
  186. data/lib/new_relic/control/frameworks/rails4.rb +1 -3
  187. data/lib/new_relic/control/instance_methods.rb +6 -0
  188. data/lib/new_relic/control/instrumentation.rb +1 -1
  189. data/lib/new_relic/control/private_instance_methods.rb +4 -0
  190. data/lib/new_relic/control/security_interface.rb +57 -0
  191. data/lib/new_relic/control.rb +1 -1
  192. data/lib/new_relic/dependency_detection.rb +11 -14
  193. data/lib/new_relic/environment_report.rb +2 -2
  194. data/lib/new_relic/helper.rb +22 -0
  195. data/lib/new_relic/language_support.rb +3 -1
  196. data/lib/new_relic/local_environment.rb +1 -4
  197. data/lib/new_relic/rack/browser_monitoring.rb +20 -8
  198. data/lib/new_relic/version.rb +1 -1
  199. data/lib/sequel/extensions/new_relic_instrumentation.rb +3 -2
  200. data/lib/tasks/config.rake +7 -3
  201. data/lib/tasks/gha.rake +31 -0
  202. data/lib/tasks/helpers/config.html.erb +3 -2
  203. data/lib/tasks/helpers/format.rb +1 -1
  204. data/lib/tasks/helpers/newrelicyml.rb +80 -13
  205. data/newrelic.yml +425 -162
  206. data/newrelic_rpm.gemspec +3 -1
  207. data/test/agent_helper.rb +24 -2
  208. metadata +91 -22
  209. data/lib/tasks/instrumentation_generator/README.md +0 -63
  210. data/lib/tasks/instrumentation_generator/TODO.md +0 -33
  211. data/lib/tasks/instrumentation_generator/instrumentation.thor +0 -121
  212. data/lib/tasks/instrumentation_generator/templates/chain.tt +0 -21
  213. data/lib/tasks/instrumentation_generator/templates/chain_method.tt +0 -7
  214. data/lib/tasks/instrumentation_generator/templates/dependency_detection.tt +0 -29
  215. data/lib/tasks/instrumentation_generator/templates/instrumentation_method.tt +0 -3
  216. data/lib/tasks/instrumentation_generator/templates/newrelic.yml.tt +0 -19
  217. data/lib/tasks/instrumentation_generator/templates/prepend.tt +0 -13
  218. data/lib/tasks/instrumentation_generator/templates/prepend_method.tt +0 -3
  219. data/lib/tasks/instrumentation_generator/templates/test.tt +0 -15
@@ -0,0 +1,66 @@
1
+ # This file is distributed under New Relic's license terms.
2
+ # See https://github.com/newrelic/newrelic-ruby-agent/blob/main/LICENSE for complete details.
3
+ # frozen_string_literal: true
4
+
5
+ module NewRelic
6
+ module Agent
7
+ module OpenTelemetry
8
+ module Context
9
+ module Propagation
10
+ class TracePropagator
11
+ # The carrier is the object carrying the headers
12
+ # The context argument is a no-op, as the OpenTelemetry context is not used
13
+ # The setter argument is a no-op, added for consistency with the OpenTelemetry API
14
+ def inject(carrier, context: ::OpenTelemetry::Context.current, setter: nil)
15
+ # TODO: determine if we need to update this method to take Context into account
16
+ NewRelic::Agent::DistributedTracing.insert_distributed_trace_headers(carrier)
17
+ end
18
+
19
+ # The return value for this method should be an instance of the
20
+ # OpenTelemetry Context class. The return value of
21
+ # #accept_distributed_trace_headers is a transaction, so we cannot
22
+ # use it to extract the context.
23
+ def extract(carrier, context: ::OpenTelemetry::Context.current, getter: ::OpenTelemetry::Context::Propagation.text_map_getter)
24
+ carrier_format = determine_format(getter)
25
+ trace_context = NewRelic::Agent::DistributedTracing::TraceContext.parse(
26
+ carrier: carrier,
27
+ format: carrier_format,
28
+ trace_state_entry_key: Transaction::TraceContext::AccountHelpers.trace_state_entry_key
29
+ )
30
+ tp = trace_context.trace_parent
31
+ span_context = ::OpenTelemetry::Trace::SpanContext.new(
32
+ trace_id: tp['trace_id'],
33
+ span_id: tp['parent_id'],
34
+ trace_flags: tp['trace_flags'],
35
+ tracestate: trace_context.trace_state_payload,
36
+ remote: true
37
+ )
38
+ span = ::OpenTelemetry::Trace.non_recording_span(span_context)
39
+
40
+ ::OpenTelemetry::Trace.context_with_span(span, parent_context: context)
41
+ rescue StandardError => e
42
+ NewRelic::Agent.logger.error("Unable to extract context: #{e.message}")
43
+ context
44
+ end
45
+
46
+ private
47
+
48
+ # The getter is the way OpenTelemetry handles Rack vs. non-Rack
49
+ # formats. Rather than using their parser, get the class info we
50
+ # need to do things the New Relic way
51
+ def determine_format(getter)
52
+ case getter
53
+ when ::OpenTelemetry::Context::Propagation::RackEnvGetter
54
+ FORMAT_RACK
55
+ when defined?(::OpenTelemetry::Common) && ::OpenTelemetry::Common::Propagation::RackEnvGetter
56
+ FORMAT_RACK
57
+ else
58
+ FORMAT_NON_RACK
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,15 @@
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 OpenTelemetry
8
+ module Context
9
+ module Propagation
10
+ require_relative 'propagation/trace_propagator'
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -2,8 +2,12 @@
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
- instrumentation_methods :chain, :prepend
6
-
7
- gemfile <<~RB
8
- gem '<%= @name.downcase %>'
9
- RB
5
+ module NewRelic
6
+ module Agent
7
+ module OpenTelemetry
8
+ module Context
9
+ require_relative 'context/propagation'
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,31 @@
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 OpenTelemetry
8
+ module Trace
9
+ class Span < ::OpenTelemetry::Trace::Span
10
+ attr_accessor :finishable
11
+
12
+ def finish(end_timestamp: nil)
13
+ finishable&.finish
14
+ end
15
+
16
+ def set_attribute(key, value)
17
+ NewRelic::Agent.add_custom_span_attributes(key => value)
18
+ end
19
+
20
+ def add_attributes(attributes)
21
+ NewRelic::Agent.add_custom_span_attributes(attributes)
22
+ end
23
+
24
+ def record_exception(exception, attributes: nil)
25
+ NewRelic::Agent.notice_error(exception, attributes: attributes)
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,129 @@
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 OpenTelemetry
8
+ module Trace
9
+ class Tracer < ::OpenTelemetry::Trace::Tracer
10
+ def initialize(name = nil, version = nil)
11
+ @name = name || ''
12
+ @version = version || ''
13
+ end
14
+
15
+ def start_span(name, with_parent: nil, attributes: nil, links: nil, start_timestamp: nil, kind: nil)
16
+ parent_otel_context = ::OpenTelemetry::Trace.current_span(with_parent).context
17
+
18
+ finishable = if can_start_transaction?(parent_otel_context)
19
+ return if internal_span_kind_with_invalid_parent?(kind, parent_otel_context)
20
+
21
+ nr_item = NewRelic::Agent::Tracer.start_transaction_or_segment(name: name, category: :otel)
22
+ add_remote_context_to_txn(nr_item, parent_otel_context)
23
+ nr_item
24
+ else
25
+ NewRelic::Agent::Tracer.start_segment(name: name)
26
+ end
27
+
28
+ otel_span = get_otel_span_from_finishable(finishable)
29
+ otel_span.finishable = finishable
30
+ add_remote_context_to_otel_span(otel_span, parent_otel_context)
31
+ otel_span.add_attributes(attributes) if attributes
32
+ otel_span
33
+ end
34
+
35
+ def in_span(name, attributes: nil, links: nil, start_timestamp: nil, kind: nil)
36
+ span = start_span(name, attributes: attributes, links: links, start_timestamp: start_timestamp, kind: kind)
37
+ begin
38
+ yield
39
+ rescue => e
40
+ # TODO: Update for segment errors if finishable is a segment
41
+ NewRelic::Agent.notice_error(e)
42
+ raise
43
+ end
44
+ ensure
45
+ span&.finish
46
+ end
47
+
48
+ private
49
+
50
+ def get_otel_span_from_finishable(finishable)
51
+ case finishable
52
+ when NewRelic::Agent::Transaction
53
+ finishable.segments.first.instance_variable_get(:@otel_span)
54
+ when NewRelic::Agent::Transaction::Segment
55
+ finishable.instance_variable_get(:@otel_span)
56
+ else
57
+ NewRelic::Agent.logger.warn('Tracer#get_otel_span_from_finishable failed to get span from finishable - finishable is not a transaction or segment')
58
+ nil
59
+ end
60
+ end
61
+
62
+ def can_start_transaction?(parent_otel_context)
63
+ parent_otel_context.remote? || !parent_otel_context.valid?
64
+ end
65
+
66
+ def internal_span_kind_with_invalid_parent?(kind, parent_otel_context)
67
+ !parent_otel_context.valid? && kind == :internal
68
+ end
69
+
70
+ def transaction_and_remote_parent?(txn, parent_otel_context)
71
+ txn.is_a?(NewRelic::Agent::Transaction) && parent_otel_context.remote?
72
+ end
73
+
74
+ def add_remote_context_to_txn(txn, parent_otel_context)
75
+ return unless transaction_and_remote_parent?(txn, parent_otel_context)
76
+
77
+ txn.trace_id = parent_otel_context.trace_id
78
+ txn.parent_span_id = parent_otel_context.span_id
79
+
80
+ set_tracestate(txn.distributed_tracer, parent_otel_context)
81
+ end
82
+
83
+ def set_tracestate(distributed_tracer, otel_context)
84
+ case otel_context.tracestate
85
+ when ::OpenTelemetry::Trace::Tracestate
86
+ set_otel_trace_state(distributed_tracer, otel_context)
87
+ when NewRelic::Agent::TraceContextPayload
88
+ set_nr_trace_state(distributed_tracer, otel_context)
89
+ end
90
+ end
91
+
92
+ def set_nr_trace_state(distributed_tracer, otel_context)
93
+ distributed_tracer.instance_variable_set(:@trace_state_payload, otel_context.tracestate)
94
+ distributed_tracer.parent_transaction_id = distributed_tracer.trace_state_payload.transaction_id
95
+ distributed_tracer.determine_sampling_decision(otel_context.tracestate, otel_context.trace_flags)
96
+ end
97
+
98
+ def set_otel_trace_state(distributed_tracer, otel_context)
99
+ nr_entry = otel_context.tracestate.value(Transaction::TraceContext::AccountHelpers.trace_state_entry_key)
100
+ return unless nr_entry
101
+
102
+ nr_payload = NewRelic::Agent::TraceContextPayload.from_s(nr_entry)
103
+ distributed_tracer.instance_variable_set(:@trace_state_payload, nr_payload)
104
+ distributed_tracer.parent_transaction_id = distributed_tracer.trace_state_payload.transaction_id
105
+ trace_flags = parse_trace_flags(otel_context.trace_flags)
106
+ distributed_tracer.determine_sampling_decision(nr_payload, trace_flags)
107
+ end
108
+
109
+ def parse_trace_flags(trace_flags)
110
+ case trace_flags
111
+ when String
112
+ trace_flags
113
+ when Integer
114
+ trace_flags.to_s
115
+ when ::OpenTelemetry::Trace::TraceFlags
116
+ trace_flags.sampled? ? '01' : '00'
117
+ end
118
+ end
119
+
120
+ def add_remote_context_to_otel_span(otel_span, parent_otel_context)
121
+ return unless transaction_and_remote_parent?(otel_span.finishable, parent_otel_context)
122
+
123
+ otel_span.context.instance_variable_set(:@trace_id, otel_span.finishable.trace_id)
124
+ end
125
+ end
126
+ end
127
+ end
128
+ end
129
+ end
@@ -0,0 +1,18 @@
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 OpenTelemetry
8
+ module Trace
9
+ class TracerProvider < ::OpenTelemetry::Trace::TracerProvider
10
+ # TODO: Add a registration mechanism for tracers like exists in the SDK
11
+ def tracer(name = nil, version = nil)
12
+ @tracer ||= Tracer.new(name, version)
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,15 @@
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 OpenTelemetry
8
+ module Trace
9
+ require_relative 'trace/tracer_provider'
10
+ require_relative 'trace/tracer'
11
+ require_relative 'trace/span'
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,69 @@
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 OpenTelemetry
8
+ module TransactionPatch
9
+ attr_accessor :opentelemetry_context
10
+
11
+ def initialize(_category, _options)
12
+ @opentelemetry_context = {}
13
+ super
14
+ end
15
+
16
+ def set_current_segment(new_segment)
17
+ @current_segment_lock.synchronize do
18
+ unless opentelemetry_context.empty?
19
+ ::OpenTelemetry::Context.detach(opentelemetry_context[otel_current_span_key])
20
+ end
21
+
22
+ span = find_or_create_span(new_segment)
23
+ ctx = ::OpenTelemetry::Context.current.set_value(otel_current_span_key, span)
24
+ token = ::OpenTelemetry::Context.attach(ctx)
25
+
26
+ opentelemetry_context[otel_current_span_key] = token
27
+ end
28
+
29
+ super
30
+ end
31
+
32
+ def remove_current_segment_by_thread_id(id)
33
+ # make sure the context is fully detached when the transaction ends
34
+ @current_segment_lock.synchronize do
35
+ ::OpenTelemetry::Context.detach(opentelemetry_context[otel_current_span_key])
36
+ opentelemetry_context.delete(id)
37
+ end
38
+
39
+ super
40
+ end
41
+
42
+ private
43
+
44
+ def find_or_create_span(segment)
45
+ if segment.instance_variable_defined?(:@otel_span)
46
+ segment.instance_variable_get(:@otel_span)
47
+ else
48
+ span = Trace::Span.new(span_context: span_context_from_segment(segment))
49
+ segment.instance_variable_set(:@otel_span, span)
50
+ span
51
+ end
52
+ end
53
+
54
+ def span_context_from_segment(segment)
55
+ ::OpenTelemetry::Trace::SpanContext.new(
56
+ trace_id: segment.transaction.trace_id,
57
+ span_id: segment.guid,
58
+ remote: false
59
+ )
60
+ end
61
+
62
+ def otel_current_span_key
63
+ # CURRENT_SPAN_KEY is a private constant
64
+ ::OpenTelemetry::Trace.const_get(:CURRENT_SPAN_KEY)
65
+ end
66
+ end
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,32 @@
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
+ class OpenTelemetryBridge
8
+ def initialize
9
+ # no-op without OpenTelemetry API & config
10
+ return unless defined?(OpenTelemetry) &&
11
+ NewRelic::Agent.config[:'opentelemetry_bridge.enabled']
12
+
13
+ OpenTelemetryBridge.install
14
+ end
15
+
16
+ private
17
+
18
+ def self.install
19
+ require 'opentelemetry' # requires the opentelemetry-api gem
20
+ require_relative 'opentelemetry/trace'
21
+ require_relative 'opentelemetry/transaction_patch'
22
+ require_relative 'opentelemetry/context'
23
+
24
+ # TODO: Add a warning if SDK gem is installed
25
+
26
+ ::OpenTelemetry.tracer_provider = OpenTelemetry::Trace::TracerProvider.new
27
+ Transaction.prepend(OpenTelemetry::TransactionPatch)
28
+ ::OpenTelemetry.propagation = OpenTelemetry::Context::Propagation::TracePropagator.new
29
+ end
30
+ end
31
+ end
32
+ end
@@ -9,7 +9,7 @@ module NewRelic
9
9
 
10
10
  ACTION_DISPATCH_PARAMETER_FILTER ||= 'action_dispatch.parameter_filter'.freeze
11
11
 
12
- if defined?(Rails) && Gem::Version.new(::Rails::VERSION::STRING) >= Gem::Version.new('5.0.0')
12
+ if defined?(Rails) && NewRelic::Helper.version_satisfied?(::Rails::VERSION::STRING, '>=', '5.0.0')
13
13
  Rails.application.config.to_prepare do
14
14
  RAILS_FILTER_CLASS ||= if defined?(ActiveSupport::ParameterFilter)
15
15
  ActiveSupport::ParameterFilter
@@ -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