datadog 2.8.0 → 2.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (108) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +36 -1
  3. data/ext/datadog_profiling_native_extension/clock_id.h +2 -2
  4. data/ext/datadog_profiling_native_extension/collectors_cpu_and_wall_time_worker.c +64 -54
  5. data/ext/datadog_profiling_native_extension/collectors_discrete_dynamic_sampler.c +1 -1
  6. data/ext/datadog_profiling_native_extension/collectors_discrete_dynamic_sampler.h +1 -1
  7. data/ext/datadog_profiling_native_extension/collectors_idle_sampling_helper.c +16 -16
  8. data/ext/datadog_profiling_native_extension/collectors_stack.c +7 -7
  9. data/ext/datadog_profiling_native_extension/collectors_thread_context.c +219 -122
  10. data/ext/datadog_profiling_native_extension/heap_recorder.h +1 -1
  11. data/ext/datadog_profiling_native_extension/http_transport.c +4 -4
  12. data/ext/datadog_profiling_native_extension/private_vm_api_access.c +3 -0
  13. data/ext/datadog_profiling_native_extension/private_vm_api_access.h +3 -1
  14. data/ext/datadog_profiling_native_extension/profiling.c +10 -8
  15. data/ext/datadog_profiling_native_extension/ruby_helpers.c +8 -8
  16. data/ext/datadog_profiling_native_extension/stack_recorder.c +54 -54
  17. data/ext/datadog_profiling_native_extension/stack_recorder.h +1 -1
  18. data/ext/datadog_profiling_native_extension/time_helpers.h +1 -1
  19. data/ext/datadog_profiling_native_extension/unsafe_api_calls_check.c +47 -0
  20. data/ext/datadog_profiling_native_extension/unsafe_api_calls_check.h +31 -0
  21. data/ext/libdatadog_api/crashtracker.c +3 -0
  22. data/lib/datadog/appsec/assets/waf_rules/recommended.json +355 -157
  23. data/lib/datadog/appsec/assets/waf_rules/strict.json +62 -32
  24. data/lib/datadog/appsec/context.rb +54 -0
  25. data/lib/datadog/appsec/contrib/active_record/instrumentation.rb +7 -7
  26. data/lib/datadog/appsec/contrib/devise/patcher/authenticatable_patch.rb +6 -6
  27. data/lib/datadog/appsec/contrib/devise/patcher/registration_controller_patch.rb +4 -4
  28. data/lib/datadog/appsec/contrib/graphql/gateway/watcher.rb +19 -28
  29. data/lib/datadog/appsec/contrib/graphql/reactive/multiplex.rb +5 -5
  30. data/lib/datadog/appsec/contrib/rack/gateway/response.rb +3 -3
  31. data/lib/datadog/appsec/contrib/rack/gateway/watcher.rb +64 -96
  32. data/lib/datadog/appsec/contrib/rack/reactive/request.rb +10 -10
  33. data/lib/datadog/appsec/contrib/rack/reactive/request_body.rb +5 -5
  34. data/lib/datadog/appsec/contrib/rack/reactive/response.rb +6 -6
  35. data/lib/datadog/appsec/contrib/rack/request_body_middleware.rb +10 -11
  36. data/lib/datadog/appsec/contrib/rack/request_middleware.rb +43 -49
  37. data/lib/datadog/appsec/contrib/rails/gateway/watcher.rb +21 -32
  38. data/lib/datadog/appsec/contrib/rails/patcher.rb +1 -1
  39. data/lib/datadog/appsec/contrib/rails/reactive/action.rb +6 -6
  40. data/lib/datadog/appsec/contrib/sinatra/gateway/watcher.rb +41 -63
  41. data/lib/datadog/appsec/contrib/sinatra/patcher.rb +2 -2
  42. data/lib/datadog/appsec/contrib/sinatra/reactive/routed.rb +5 -5
  43. data/lib/datadog/appsec/event.rb +6 -6
  44. data/lib/datadog/appsec/ext.rb +3 -1
  45. data/lib/datadog/appsec/monitor/gateway/watcher.rb +22 -32
  46. data/lib/datadog/appsec/monitor/reactive/set_user.rb +5 -5
  47. data/lib/datadog/appsec/processor/rule_loader.rb +0 -3
  48. data/lib/datadog/appsec.rb +3 -3
  49. data/lib/datadog/auto_instrument.rb +3 -0
  50. data/lib/datadog/core/configuration/agent_settings_resolver.rb +39 -11
  51. data/lib/datadog/core/configuration/components.rb +4 -2
  52. data/lib/datadog/core/configuration.rb +1 -1
  53. data/lib/datadog/{tracing → core}/contrib/rails/utils.rb +1 -3
  54. data/lib/datadog/core/crashtracking/component.rb +1 -3
  55. data/lib/datadog/core/telemetry/event.rb +87 -3
  56. data/lib/datadog/core/telemetry/logging.rb +2 -2
  57. data/lib/datadog/core/telemetry/metric.rb +22 -0
  58. data/lib/datadog/core/telemetry/worker.rb +33 -0
  59. data/lib/datadog/di/base.rb +115 -0
  60. data/lib/datadog/di/code_tracker.rb +7 -4
  61. data/lib/datadog/di/component.rb +17 -11
  62. data/lib/datadog/di/configuration/settings.rb +11 -1
  63. data/lib/datadog/di/contrib/railtie.rb +15 -0
  64. data/lib/datadog/di/contrib.rb +26 -0
  65. data/lib/datadog/di/error.rb +5 -0
  66. data/lib/datadog/di/instrumenter.rb +39 -18
  67. data/lib/datadog/di/{init.rb → preload.rb} +2 -4
  68. data/lib/datadog/di/probe_manager.rb +4 -4
  69. data/lib/datadog/di/probe_notification_builder.rb +16 -2
  70. data/lib/datadog/di/probe_notifier_worker.rb +5 -6
  71. data/lib/datadog/di/remote.rb +4 -4
  72. data/lib/datadog/di/transport.rb +2 -4
  73. data/lib/datadog/di.rb +5 -108
  74. data/lib/datadog/kit/appsec/events.rb +3 -3
  75. data/lib/datadog/kit/identity.rb +4 -4
  76. data/lib/datadog/profiling/component.rb +55 -53
  77. data/lib/datadog/profiling/http_transport.rb +1 -26
  78. data/lib/datadog/tracing/contrib/action_cable/integration.rb +5 -2
  79. data/lib/datadog/tracing/contrib/action_mailer/integration.rb +6 -2
  80. data/lib/datadog/tracing/contrib/action_pack/integration.rb +5 -2
  81. data/lib/datadog/tracing/contrib/action_view/integration.rb +5 -2
  82. data/lib/datadog/tracing/contrib/active_job/integration.rb +5 -2
  83. data/lib/datadog/tracing/contrib/active_record/integration.rb +6 -2
  84. data/lib/datadog/tracing/contrib/active_support/cache/events/cache.rb +3 -1
  85. data/lib/datadog/tracing/contrib/active_support/cache/instrumentation.rb +3 -1
  86. data/lib/datadog/tracing/contrib/active_support/configuration/settings.rb +10 -0
  87. data/lib/datadog/tracing/contrib/active_support/integration.rb +5 -2
  88. data/lib/datadog/tracing/contrib/auto_instrument.rb +2 -2
  89. data/lib/datadog/tracing/contrib/aws/integration.rb +3 -0
  90. data/lib/datadog/tracing/contrib/concurrent_ruby/integration.rb +3 -0
  91. data/lib/datadog/tracing/contrib/httprb/integration.rb +3 -0
  92. data/lib/datadog/tracing/contrib/kafka/integration.rb +3 -0
  93. data/lib/datadog/tracing/contrib/mongodb/integration.rb +3 -0
  94. data/lib/datadog/tracing/contrib/opensearch/integration.rb +3 -0
  95. data/lib/datadog/tracing/contrib/presto/integration.rb +3 -0
  96. data/lib/datadog/tracing/contrib/rack/integration.rb +2 -2
  97. data/lib/datadog/tracing/contrib/rails/framework.rb +2 -2
  98. data/lib/datadog/tracing/contrib/rails/patcher.rb +1 -1
  99. data/lib/datadog/tracing/contrib/rest_client/integration.rb +3 -0
  100. data/lib/datadog/tracing/span.rb +12 -4
  101. data/lib/datadog/tracing/span_event.rb +123 -3
  102. data/lib/datadog/tracing/span_operation.rb +6 -0
  103. data/lib/datadog/tracing/transport/serializable_trace.rb +24 -6
  104. data/lib/datadog/version.rb +1 -1
  105. metadata +19 -10
  106. data/lib/datadog/appsec/reactive/operation.rb +0 -68
  107. data/lib/datadog/appsec/scope.rb +0 -58
  108. data/lib/datadog/core/crashtracking/agent_base_url.rb +0 -21
@@ -51,7 +51,7 @@ module Datadog
51
51
  probe = ProbeBuilder.build_from_remote_config(probe_spec)
52
52
  payload = component.probe_notification_builder.build_received(probe)
53
53
  component.probe_notifier_worker.add_status(payload)
54
- component.logger.info("Received probe from RC: #{probe.type} #{probe.location}")
54
+ component.logger.debug { "di: received probe from RC: #{probe.type} #{probe.location}" }
55
55
 
56
56
  begin
57
57
  # TODO test exception capture
@@ -60,7 +60,7 @@ module Datadog
60
60
  rescue => exc
61
61
  raise if component.settings.dynamic_instrumentation.internal.propagate_all_exceptions
62
62
 
63
- component.logger.warn("Unhandled exception adding probe in DI remote receiver: #{exc.class}: #{exc}")
63
+ component.logger.debug { "di: unhandled exception adding probe in DI remote receiver: #{exc.class}: #{exc}" }
64
64
  component.telemetry&.report(exc, description: "Unhandled exception adding probe in DI remote receiver")
65
65
 
66
66
  # If a probe fails to install, we will mark the content
@@ -81,7 +81,7 @@ module Datadog
81
81
  rescue => exc
82
82
  raise if component.settings.dynamic_instrumentation.internal.propagate_all_exceptions
83
83
 
84
- component.logger.warn("Unhandled exception handling probe in DI remote receiver: #{exc.class}: #{exc}")
84
+ component.logger.debug { "di: unhandled exception handling probe in DI remote receiver: #{exc.class}: #{exc}" }
85
85
  component.telemetry&.report(exc, description: "Unhandled exception handling probe in DI remote receiver")
86
86
 
87
87
  content.errored("Error applying dynamic instrumentation configuration: #{exc.class.name} #{exc.message}: #{Array(exc.backtrace).join("\n")}")
@@ -95,7 +95,7 @@ module Datadog
95
95
  rescue => exc
96
96
  raise if component.settings.dynamic_instrumentation.internal.propagate_all_exceptions
97
97
 
98
- component.logger.warn("Unhandled exception removing probes in DI remote receiver: #{exc.class}: #{exc}")
98
+ component.logger.debug { "di: unhandled exception removing probes in DI remote receiver: #{exc.class}: #{exc}" }
99
99
  component.telemetry&.report(exc, description: "Unhandled exception removing probes in DI remote receiver")
100
100
  end
101
101
  end
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'ostruct'
4
3
  require_relative 'error'
4
+ require_relative '../core/transport/http/adapters/net'
5
5
 
6
6
  module Datadog
7
7
  module DI
@@ -60,9 +60,7 @@ module Datadog
60
60
  attr_reader :client
61
61
 
62
62
  def send_request(desc, **options)
63
- # steep:ignore:start
64
- env = OpenStruct.new(**options)
65
- # steep:ignore:end
63
+ env = Core::Transport::HTTP::Env.new(nil, options)
66
64
  response = client.post(env)
67
65
  unless response.ok?
68
66
  raise Error::AgentCommunicationError, "#{desc} failed: #{response.code}: #{response.payload}"
data/lib/datadog/di.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative 'di/base'
3
4
  require_relative 'di/error'
4
5
  require_relative 'di/code_tracker'
5
6
  require_relative 'di/component'
@@ -17,21 +18,6 @@ require_relative 'di/serializer'
17
18
  require_relative 'di/transport'
18
19
  require_relative 'di/utils'
19
20
 
20
- if defined?(ActiveRecord::Base)
21
- # The third-party library integrations need to be loaded after the
22
- # third-party libraries are loaded. Tracing and appsec use Railtie
23
- # to delay integrations until all of the application's dependencies
24
- # are loaded, when running under Rails. We should do the same here in
25
- # principle, however DI currently only has an ActiveRecord integration
26
- # and AR should be loaded before any application code is loaded, being
27
- # part of Rails, therefore for now we should be OK to just require the
28
- # AR integration from here.
29
- #
30
- # TODO this require might need to be delayed via Rails post-initialization
31
- # logic?
32
- require_relative 'di/contrib/active_record'
33
- end
34
-
35
21
  module Datadog
36
22
  # Namespace for Datadog dynamic instrumentation.
37
23
  #
@@ -46,67 +32,7 @@ module Datadog
46
32
  # Expose DI to global shared objects
47
33
  Extensions.activate!
48
34
 
49
- LOCK = Mutex.new
50
-
51
35
  class << self
52
- attr_reader :code_tracker
53
-
54
- # Activates code tracking. Normally this method should be called
55
- # when the application starts. If instrumenting third-party code,
56
- # code tracking needs to be enabled before the third-party libraries
57
- # are loaded. If you definitely will not be instrumenting
58
- # third-party libraries, activating tracking after third-party libraries
59
- # have been loaded may improve lookup performance.
60
- #
61
- # TODO test that activating tracker multiple times preserves
62
- # existing mappings in the registry
63
- def activate_tracking!
64
- (@code_tracker ||= CodeTracker.new).start
65
- end
66
-
67
- # Activates code tracking if possible.
68
- #
69
- # This method does nothing if invoked in an environment that does not
70
- # implement required trace points for code tracking (MRI Ruby < 2.6,
71
- # JRuby) and rescues any exceptions that may be raised by downstream
72
- # DI code.
73
- def activate_tracking
74
- # :script_compiled trace point was added in Ruby 2.6.
75
- return unless RUBY_VERSION >= '2.6'
76
-
77
- begin
78
- # Activate code tracking by default because line trace points will not work
79
- # without it.
80
- Datadog::DI.activate_tracking!
81
- rescue => exc
82
- if defined?(Datadog.logger)
83
- Datadog.logger.warn("Failed to activate code tracking for DI: #{exc.class}: #{exc}")
84
- else
85
- # We do not have Datadog logger potentially because DI code tracker is
86
- # being loaded early in application boot process and the rest of datadog
87
- # wasn't loaded yet. Output to standard error.
88
- warn("Failed to activate code tracking for DI: #{exc.class}: #{exc}")
89
- end
90
- end
91
- end
92
-
93
- # Deactivates code tracking. In normal usage of DI this method should
94
- # never be called, however it is used by DI's test suite to reset
95
- # state for individual tests.
96
- #
97
- # Note that deactivating tracking clears out the registry, losing
98
- # the ability to look up files that have been loaded into the process
99
- # already.
100
- def deactivate_tracking!
101
- code_tracker&.stop
102
- end
103
-
104
- # Returns whether code tracking is available.
105
- # This method should be used instead of querying #code_tracker
106
- # because the latter one may be nil.
107
- def code_tracking_active?
108
- code_tracker&.active? || false
109
- end
110
36
 
111
37
  # This method is called from DI Remote handler to issue DI operations
112
38
  # to the probe manager (add or remove probes).
@@ -120,39 +46,6 @@ module Datadog
120
46
  def component
121
47
  Datadog.send(:components).dynamic_instrumentation
122
48
  end
123
-
124
- # DI code tracker is instantiated globally before the regular set of
125
- # components is created, but the code tracker needs to call out to the
126
- # "current" DI component to perform instrumentation when application
127
- # code is loaded. Because this call may happen prior to Datadog
128
- # components having been initialized, we maintain the "current component"
129
- # which contains a reference to the most recently instantiated
130
- # DI::Component. This way, if a DI component hasn't been instantiated,
131
- # we do not try to reference Datadog.components.
132
- def current_component
133
- LOCK.synchronize do
134
- @current_components&.last
135
- end
136
- end
137
-
138
- # To avoid potential races with DI::Component being added and removed,
139
- # we maintain a list of the components. Normally the list should contain
140
- # either zero or one component depending on whether DI is enabled in
141
- # Datadog configuration. However, if a new instance of DI::Component
142
- # is created while the previous instance is still running, we are
143
- # guaranteed to not end up with no component when one is running.
144
- def add_current_component(component)
145
- LOCK.synchronize do
146
- @current_components ||= []
147
- @current_components << component
148
- end
149
- end
150
-
151
- def remove_current_component(component)
152
- LOCK.synchronize do
153
- @current_components&.delete(component)
154
- end
155
- end
156
49
  end
157
50
  end
158
51
  end
@@ -167,3 +60,7 @@ if %w(1 true).include?(ENV['DD_DYNAMIC_INSTRUMENTATION_ENABLED']) # steep:ignore
167
60
  # for line probes to work) activate tracking in an initializer.
168
61
  Datadog::DI.activate_tracking
169
62
  end
63
+
64
+ require_relative 'di/contrib'
65
+
66
+ Datadog::DI::Contrib.load_now_or_later
@@ -136,9 +136,9 @@ module Datadog
136
136
  private
137
137
 
138
138
  def set_trace_and_span_context(method, trace = nil, span = nil)
139
- if (appsec_scope = Datadog::AppSec.active_scope)
140
- trace = appsec_scope.trace
141
- span = appsec_scope.service_entry_span
139
+ if (appsec_context = Datadog::AppSec.active_context)
140
+ trace = appsec_context.trace
141
+ span = appsec_context.span
142
142
  end
143
143
 
144
144
  trace ||= Datadog::Tracing.active_trace
@@ -66,7 +66,7 @@ module Datadog
66
66
  active_span.set_tag("usr.#{k}", v) unless v.nil?
67
67
  end
68
68
 
69
- if Datadog::AppSec.active_scope
69
+ if Datadog::AppSec.active_context
70
70
  user = ::Datadog::AppSec::Instrumentation::Gateway::User.new(id)
71
71
  ::Datadog::AppSec::Instrumentation.gateway.push('identity.set_user', user)
72
72
  end
@@ -78,9 +78,9 @@ module Datadog
78
78
  private
79
79
 
80
80
  def set_trace_and_span_context(method, trace = nil, span = nil)
81
- if (appsec_scope = Datadog::AppSec.active_scope)
82
- trace = appsec_scope.trace
83
- span = appsec_scope.service_entry_span
81
+ if (appsec_context = Datadog::AppSec.active_context)
82
+ trace = appsec_context.trace
83
+ span = appsec_context.span
84
84
  end
85
85
 
86
86
  trace ||= Datadog::Tracing.active_trace
@@ -4,10 +4,13 @@ module Datadog
4
4
  module Profiling
5
5
  # Responsible for wiring up the Profiler for execution
6
6
  module Component
7
+ ALLOCATION_WITH_RACTORS_ONLY_ONCE = Datadog::Core::Utils::OnlyOnce.new
8
+ private_constant :ALLOCATION_WITH_RACTORS_ONLY_ONCE
9
+
7
10
  # Passing in a `nil` tracer is supported and will disable the following profiling features:
8
- # * Code Hotspots panel in the trace viewer, as well as scoping a profile down to a span
11
+ # * Profiling in the trace viewer, as well as scoping a profile down to a span
9
12
  # * Endpoint aggregation in the profiler UX, including normalization (resource per endpoint call)
10
- def self.build_profiler_component(settings:, agent_settings:, optional_tracer:) # rubocop:disable Metrics/MethodLength
13
+ def self.build_profiler_component(settings:, agent_settings:, optional_tracer:, logger:) # rubocop:disable Metrics/MethodLength
11
14
  return [nil, {profiling_enabled: false}] unless settings.profiling.enabled
12
15
 
13
16
  # Workaround for weird dependency direction: the Core::Configuration::Components class currently has a
@@ -36,14 +39,14 @@ module Datadog
36
39
 
37
40
  # NOTE: Please update the Initialization section of ProfilingDevelopment.md with any changes to this method
38
41
 
39
- no_signals_workaround_enabled = no_signals_workaround_enabled?(settings)
42
+ no_signals_workaround_enabled = no_signals_workaround_enabled?(settings, logger)
40
43
  timeline_enabled = settings.profiling.advanced.timeline_enabled
41
- allocation_profiling_enabled = enable_allocation_profiling?(settings)
44
+ allocation_profiling_enabled = enable_allocation_profiling?(settings, logger)
42
45
  heap_sample_every = get_heap_sample_every(settings)
43
- heap_profiling_enabled = enable_heap_profiling?(settings, allocation_profiling_enabled, heap_sample_every)
44
- heap_size_profiling_enabled = enable_heap_size_profiling?(settings, heap_profiling_enabled)
46
+ heap_profiling_enabled = enable_heap_profiling?(settings, allocation_profiling_enabled, heap_sample_every, logger)
47
+ heap_size_profiling_enabled = enable_heap_size_profiling?(settings, heap_profiling_enabled, logger)
45
48
 
46
- overhead_target_percentage = valid_overhead_target(settings.profiling.advanced.overhead_target_percentage)
49
+ overhead_target_percentage = valid_overhead_target(settings.profiling.advanced.overhead_target_percentage, logger)
47
50
  upload_period_seconds = [60, settings.profiling.advanced.upload_period_seconds].max
48
51
 
49
52
  recorder = Datadog::Profiling::StackRecorder.new(
@@ -57,13 +60,13 @@ module Datadog
57
60
  )
58
61
  thread_context_collector = build_thread_context_collector(settings, recorder, optional_tracer, timeline_enabled)
59
62
  worker = Datadog::Profiling::Collectors::CpuAndWallTimeWorker.new(
60
- gc_profiling_enabled: enable_gc_profiling?(settings),
63
+ gc_profiling_enabled: enable_gc_profiling?(settings, logger),
61
64
  no_signals_workaround_enabled: no_signals_workaround_enabled,
62
65
  thread_context_collector: thread_context_collector,
63
66
  dynamic_sampling_rate_overhead_target_percentage: overhead_target_percentage,
64
67
  allocation_profiling_enabled: allocation_profiling_enabled,
65
68
  allocation_counting_enabled: settings.profiling.advanced.allocation_counting_enabled,
66
- gvl_profiling_enabled: enable_gvl_profiling?(settings),
69
+ gvl_profiling_enabled: enable_gvl_profiling?(settings, logger),
67
70
  )
68
71
 
69
72
  internal_metadata = {
@@ -120,7 +123,7 @@ module Datadog
120
123
  )
121
124
  end
122
125
 
123
- private_class_method def self.enable_gc_profiling?(settings)
126
+ private_class_method def self.enable_gc_profiling?(settings, logger)
124
127
  return false unless settings.profiling.advanced.gc_enabled
125
128
 
126
129
  # SEVERE - Only with Ractors
@@ -131,14 +134,14 @@ module Datadog
131
134
  if RUBY_VERSION.start_with?("3.0.") ||
132
135
  (RUBY_VERSION.start_with?("3.1.") && RUBY_VERSION < "3.1.4") ||
133
136
  (RUBY_VERSION.start_with?("3.2.") && RUBY_VERSION < "3.2.3")
134
- Datadog.logger.warn(
137
+ logger.warn(
135
138
  "Current Ruby version (#{RUBY_VERSION}) has a VM bug where enabling GC profiling would cause " \
136
139
  "crashes (https://bugs.ruby-lang.org/issues/18464). GC profiling has been disabled."
137
140
  )
138
141
  return false
139
142
  elsif RUBY_VERSION.start_with?("3.")
140
- Datadog.logger.debug(
141
- "In all known versions of Ruby 3.x, using Ractors may result in GC profiling unexpectedly " \
143
+ logger.debug(
144
+ "Using Ractors may result in GC profiling unexpectedly " \
142
145
  "stopping (https://bugs.ruby-lang.org/issues/19112). Note that this stop has no impact in your " \
143
146
  "application stability or performance. This does not happen if Ractors are not used."
144
147
  )
@@ -155,7 +158,7 @@ module Datadog
155
158
  heap_sample_rate
156
159
  end
157
160
 
158
- private_class_method def self.enable_allocation_profiling?(settings)
161
+ private_class_method def self.enable_allocation_profiling?(settings, logger)
159
162
  return false unless settings.profiling.allocation_enabled
160
163
 
161
164
  # Allocation sampling is safe and supported on Ruby 2.x, but has a few caveats on Ruby 3.x.
@@ -165,7 +168,7 @@ module Datadog
165
168
  # https://github.com/ruby/ruby/pull/7464) that makes this crash in any configuration. This bug is
166
169
  # fixed on Ruby versions 3.2.3 and 3.3.0.
167
170
  if RUBY_VERSION.start_with?("3.2.") && RUBY_VERSION < "3.2.3"
168
- Datadog.logger.warn(
171
+ logger.warn(
169
172
  "Allocation profiling is not supported in Ruby versions 3.2.0, 3.2.1 and 3.2.2 and will be forcibly " \
170
173
  "disabled. This is due to a VM bug that can lead to crashes (https://bugs.ruby-lang.org/issues/19482). " \
171
174
  "Other Ruby versions do not suffer from this issue."
@@ -181,7 +184,7 @@ module Datadog
181
184
  if RUBY_VERSION.start_with?("3.0.") ||
182
185
  (RUBY_VERSION.start_with?("3.1.") && RUBY_VERSION < "3.1.4") ||
183
186
  (RUBY_VERSION.start_with?("3.2.") && RUBY_VERSION < "3.2.3")
184
- Datadog.logger.warn(
187
+ logger.warn(
185
188
  "Current Ruby version (#{RUBY_VERSION}) has a VM bug where enabling allocation profiling while using " \
186
189
  "Ractors may cause unexpected issues, including crashes (https://bugs.ruby-lang.org/issues/18464). " \
187
190
  "This does not happen if Ractors are not used."
@@ -190,25 +193,27 @@ module Datadog
190
193
  # On all known versions of Ruby 3.x, due to https://bugs.ruby-lang.org/issues/19112, when a ractor gets
191
194
  # garbage collected, Ruby will disable all active tracepoints, which this feature internally relies on.
192
195
  elsif RUBY_VERSION.start_with?("3.")
193
- Datadog.logger.warn(
194
- "In all known versions of Ruby 3.x, using Ractors may result in allocation profiling unexpectedly " \
195
- "stopping (https://bugs.ruby-lang.org/issues/19112). Note that this stop has no impact in your " \
196
- "application stability or performance. This does not happen if Ractors are not used."
197
- )
196
+ ALLOCATION_WITH_RACTORS_ONLY_ONCE.run do
197
+ logger.info(
198
+ "Using Ractors may result in allocation profiling " \
199
+ "stopping (https://bugs.ruby-lang.org/issues/19112). Note that this stop has no impact in your " \
200
+ "application stability or performance. This does not happen if Ractors are not used."
201
+ )
202
+ end
198
203
  end
199
204
 
200
- Datadog.logger.debug("Enabled allocation profiling")
205
+ logger.debug("Enabled allocation profiling")
201
206
 
202
207
  true
203
208
  end
204
209
 
205
- private_class_method def self.enable_heap_profiling?(settings, allocation_profiling_enabled, heap_sample_rate)
210
+ private_class_method def self.enable_heap_profiling?(settings, allocation_profiling_enabled, heap_sample_rate, logger)
206
211
  heap_profiling_enabled = settings.profiling.advanced.experimental_heap_enabled
207
212
 
208
213
  return false unless heap_profiling_enabled
209
214
 
210
215
  if RUBY_VERSION < "3.1"
211
- Datadog.logger.warn(
216
+ logger.warn(
212
217
  "Current Ruby version (#{RUBY_VERSION}) cannot support heap profiling due to VM limitations. " \
213
218
  "Please upgrade to Ruby >= 3.1 in order to use this feature. Heap profiling has been disabled."
214
219
  )
@@ -219,7 +224,7 @@ module Datadog
219
224
  raise ArgumentError, "Heap profiling requires allocation profiling to be enabled"
220
225
  end
221
226
 
222
- Datadog.logger.warn(
227
+ logger.warn(
223
228
  "Enabled experimental heap profiling: heap_sample_rate=#{heap_sample_rate}. This is experimental, not " \
224
229
  "recommended, and will increase overhead!"
225
230
  )
@@ -227,25 +232,23 @@ module Datadog
227
232
  true
228
233
  end
229
234
 
230
- private_class_method def self.enable_heap_size_profiling?(settings, heap_profiling_enabled)
235
+ private_class_method def self.enable_heap_size_profiling?(settings, heap_profiling_enabled, logger)
231
236
  heap_size_profiling_enabled = settings.profiling.advanced.experimental_heap_size_enabled
232
237
 
233
238
  return false unless heap_profiling_enabled && heap_size_profiling_enabled
234
239
 
235
- Datadog.logger.warn(
240
+ logger.warn(
236
241
  "Enabled experimental heap size profiling. This is experimental, not recommended, and will increase overhead!"
237
242
  )
238
243
 
239
244
  true
240
245
  end
241
246
 
242
- private_class_method def self.no_signals_workaround_enabled?(settings) # rubocop:disable Metrics/MethodLength
247
+ private_class_method def self.no_signals_workaround_enabled?(settings, logger) # rubocop:disable Metrics/MethodLength
243
248
  setting_value = settings.profiling.advanced.no_signals_workaround_enabled
244
- legacy_ruby_that_should_use_workaround = RUBY_VERSION.start_with?("2.5.")
245
249
 
246
250
  unless [true, false, :auto].include?(setting_value)
247
- # TODO: Replace with a warning instead.
248
- Datadog.logger.error(
251
+ logger.warn(
249
252
  "Ignoring invalid value for profiling no_signals_workaround_enabled setting: #{setting_value.inspect}. " \
250
253
  "Valid options are `true`, `false` or (default) `:auto`."
251
254
  )
@@ -254,23 +257,23 @@ module Datadog
254
257
  end
255
258
 
256
259
  if setting_value == false
257
- if legacy_ruby_that_should_use_workaround
258
- Datadog.logger.warn(
259
- 'The profiling "no signals" workaround has been disabled via configuration on a legacy Ruby version ' \
260
- "(< 2.6). This is not recommended " \
261
- "in production environments, as due to limitations in Ruby APIs, we suspect it may lead to crashes " \
262
- "in very rare situations. Please report any issues you run into to Datadog support or " \
260
+ if RUBY_VERSION.start_with?("2.5.")
261
+ logger.warn(
262
+ 'The profiling "no signals" workaround has been disabled via configuration on Ruby 2.5. ' \
263
+ "This is not recommended " \
264
+ "in production environments, as due to limitations in Ruby APIs, we suspect it may lead to rare crashes " \
265
+ "Please report any issues you run into to Datadog support or " \
263
266
  "via <https://github.com/datadog/dd-trace-rb/issues/new>!"
264
267
  )
265
268
  else
266
- Datadog.logger.warn('Profiling "no signals" workaround disabled via configuration')
269
+ logger.warn('Profiling "no signals" workaround disabled via configuration')
267
270
  end
268
271
 
269
272
  return false
270
273
  end
271
274
 
272
275
  if setting_value == true
273
- Datadog.logger.warn(
276
+ logger.warn(
274
277
  'Profiling "no signals" workaround enabled via configuration. Profiling data will have lower quality.'
275
278
  )
276
279
 
@@ -280,10 +283,10 @@ module Datadog
280
283
  # Setting is in auto mode. Let's probe to see if we should enable it:
281
284
 
282
285
  # We don't warn users in this situation because "upgrade your Ruby" is not a great warning
283
- return true if legacy_ruby_that_should_use_workaround
286
+ return true if RUBY_VERSION.start_with?("2.5.")
284
287
 
285
- if Gem.loaded_specs["mysql2"] && incompatible_libmysqlclient_version?(settings)
286
- Datadog.logger.warn(
288
+ if Gem.loaded_specs["mysql2"] && incompatible_libmysqlclient_version?(settings, logger)
289
+ logger.warn(
287
290
  'Enabling the profiling "no signals" workaround because an incompatible version of the mysql2 gem is ' \
288
291
  "installed. Profiling data will have lower quality. " \
289
292
  "To fix this, upgrade the libmysqlclient in your OS image to version 8.0.0 or above."
@@ -292,7 +295,7 @@ module Datadog
292
295
  end
293
296
 
294
297
  if Gem.loaded_specs["rugged"]
295
- Datadog.logger.warn(
298
+ logger.warn(
296
299
  'Enabling the profiling "no signals" workaround because the rugged gem is installed. ' \
297
300
  "This is needed because some operations on this gem are currently incompatible with the normal working mode " \
298
301
  "of the profiler, as detailed in <https://github.com/datadog/dd-trace-rb/issues/2721>. " \
@@ -302,7 +305,7 @@ module Datadog
302
305
  end
303
306
 
304
307
  if (defined?(::PhusionPassenger) || Gem.loaded_specs["passenger"]) && incompatible_passenger_version?
305
- Datadog.logger.warn(
308
+ logger.warn(
306
309
  'Enabling the profiling "no signals" workaround because an incompatible version of the passenger gem is ' \
307
310
  "installed. Profiling data will have lower quality." \
308
311
  "To fix this, upgrade the passenger gem to version 6.0.19 or above."
@@ -322,10 +325,10 @@ module Datadog
322
325
  #
323
326
  # The `mysql2` gem's `info` method can be used to determine which `libmysqlclient` version is in use, and thus to
324
327
  # detect if it's safe for the profiler to use signals or if we need to employ a fallback.
325
- private_class_method def self.incompatible_libmysqlclient_version?(settings)
328
+ private_class_method def self.incompatible_libmysqlclient_version?(settings, logger)
326
329
  return true if settings.profiling.advanced.skip_mysql2_check
327
330
 
328
- Datadog.logger.debug(
331
+ logger.debug(
329
332
  "Requiring `mysql2` to check if the `libmysqlclient` version it uses is compatible with profiling"
330
333
  )
331
334
 
@@ -354,14 +357,14 @@ module Datadog
354
357
  libmysqlclient_version >= Gem::Version.new("8.0.0") ||
355
358
  looks_like_mariadb?(info, libmysqlclient_version)
356
359
 
357
- Datadog.logger.debug(
360
+ logger.debug(
358
361
  "The `mysql2` gem is using #{compatible ? "a compatible" : "an incompatible"} version of " \
359
362
  "the `libmysqlclient` library (#{libmysqlclient_version})"
360
363
  )
361
364
 
362
365
  !compatible
363
366
  rescue StandardError, LoadError => e
364
- Datadog.logger.warn(
367
+ logger.warn(
365
368
  "Failed to probe `mysql2` gem information. " \
366
369
  "Cause: #{e.class.name} #{e.message} Location: #{Array(e.backtrace).first}"
367
370
  )
@@ -383,12 +386,11 @@ module Datadog
383
386
  end
384
387
  end
385
388
 
386
- private_class_method def self.valid_overhead_target(overhead_target_percentage)
389
+ private_class_method def self.valid_overhead_target(overhead_target_percentage, logger)
387
390
  if overhead_target_percentage > 0 && overhead_target_percentage <= 20
388
391
  overhead_target_percentage
389
392
  else
390
- # TODO: Replace with a warning instead.
391
- Datadog.logger.error(
393
+ logger.warn(
392
394
  "Ignoring invalid value for profiling overhead_target_percentage setting: " \
393
395
  "#{overhead_target_percentage.inspect}. Falling back to default value."
394
396
  )
@@ -432,10 +434,10 @@ module Datadog
432
434
  settings.profiling.advanced.dir_interruption_workaround_enabled
433
435
  end
434
436
 
435
- private_class_method def self.enable_gvl_profiling?(settings)
437
+ private_class_method def self.enable_gvl_profiling?(settings, logger)
436
438
  if RUBY_VERSION < "3.2"
437
439
  if settings.profiling.advanced.preview_gvl_enabled
438
- Datadog.logger.warn("GVL profiling is currently not supported in Ruby < 3.2 and will not be enabled.")
440
+ logger.warn("GVL profiling is currently not supported in Ruby < 3.2 and will not be enabled.")
439
441
  end
440
442
 
441
443
  return false
@@ -13,13 +13,11 @@ module Datadog
13
13
  def initialize(agent_settings:, site:, api_key:, upload_timeout_seconds:)
14
14
  @upload_timeout_milliseconds = (upload_timeout_seconds * 1_000).to_i
15
15
 
16
- validate_agent_settings(agent_settings)
17
-
18
16
  @exporter_configuration =
19
17
  if agentless?(site, api_key)
20
18
  [:agentless, site, api_key].freeze
21
19
  else
22
- [:agent, base_url_from(agent_settings)].freeze
20
+ [:agent, agent_settings.url].freeze
23
21
  end
24
22
 
25
23
  status, result = validate_exporter(exporter_configuration)
@@ -75,29 +73,6 @@ module Datadog
75
73
 
76
74
  private
77
75
 
78
- def base_url_from(agent_settings)
79
- case agent_settings.adapter
80
- when Datadog::Core::Configuration::Ext::Agent::HTTP::ADAPTER
81
- "#{agent_settings.ssl ? "https" : "http"}://#{agent_settings.hostname}:#{agent_settings.port}/"
82
- when Datadog::Core::Configuration::Ext::Agent::UnixSocket::ADAPTER
83
- "unix://#{agent_settings.uds_path}"
84
- else
85
- raise ArgumentError, "Unexpected adapter: #{agent_settings.adapter}"
86
- end
87
- end
88
-
89
- def validate_agent_settings(agent_settings)
90
- supported_adapters = [
91
- Datadog::Core::Configuration::Ext::Agent::UnixSocket::ADAPTER,
92
- Datadog::Core::Configuration::Ext::Agent::HTTP::ADAPTER
93
- ]
94
- unless supported_adapters.include?(agent_settings.adapter)
95
- raise ArgumentError,
96
- "Unsupported transport configuration for profiling: Adapter #{agent_settings.adapter} " \
97
- " is not supported"
98
- end
99
- end
100
-
101
76
  def agentless?(site, api_key)
102
77
  site && api_key && Core::Environment::VariableHelpers.env_to_bool(Profiling::Ext::ENV_AGENTLESS, false)
103
78
  end
@@ -3,7 +3,7 @@
3
3
  require_relative '../integration'
4
4
  require_relative 'configuration/settings'
5
5
  require_relative 'patcher'
6
- require_relative '../rails/utils'
6
+ require_relative '../../../core/contrib/rails/utils'
7
7
 
8
8
  module Datadog
9
9
  module Tracing
@@ -17,6 +17,9 @@ module Datadog
17
17
 
18
18
  # @public_api Changing the integration name or integration options can cause breaking changes
19
19
  register_as :action_cable, auto_patch: false
20
+ def self.gem_name
21
+ 'actioncable'
22
+ end
20
23
 
21
24
  def self.version
22
25
  Gem.loaded_specs['actioncable'] && Gem.loaded_specs['actioncable'].version
@@ -33,7 +36,7 @@ module Datadog
33
36
  # enabled by rails integration so should only auto instrument
34
37
  # if detected that it is being used without rails
35
38
  def auto_instrument?
36
- !Contrib::Rails::Utils.railtie_supported?
39
+ !Core::Contrib::Rails::Utils.railtie_supported?
37
40
  end
38
41
 
39
42
  def new_configuration
@@ -3,7 +3,7 @@
3
3
  require_relative 'configuration/settings'
4
4
  require_relative 'patcher'
5
5
  require_relative '../integration'
6
- require_relative '../rails/utils'
6
+ require_relative '../../../core/contrib/rails/utils'
7
7
 
8
8
  module Datadog
9
9
  module Tracing
@@ -18,6 +18,10 @@ module Datadog
18
18
  # @public_api Changing the integration name or integration options can cause breaking changes
19
19
  register_as :action_mailer, auto_patch: false
20
20
 
21
+ def self.gem_name
22
+ 'actionmailer'
23
+ end
24
+
21
25
  def self.version
22
26
  Gem.loaded_specs['actionmailer'] && Gem.loaded_specs['actionmailer'].version
23
27
  end
@@ -33,7 +37,7 @@ module Datadog
33
37
  # enabled by rails integration so should only auto instrument
34
38
  # if detected that it is being used without rails
35
39
  def auto_instrument?
36
- !Contrib::Rails::Utils.railtie_supported?
40
+ !Core::Contrib::Rails::Utils.railtie_supported?
37
41
  end
38
42
 
39
43
  def new_configuration
@@ -4,7 +4,7 @@ require_relative 'configuration/settings'
4
4
  require_relative 'patcher'
5
5
  require_relative '../integration'
6
6
  require_relative '../rails/ext'
7
- require_relative '../rails/utils'
7
+ require_relative '../../../core/contrib/rails/utils'
8
8
 
9
9
  module Datadog
10
10
  module Tracing
@@ -18,6 +18,9 @@ module Datadog
18
18
 
19
19
  # @public_api Changing the integration name or integration options can cause breaking changes
20
20
  register_as :action_pack, auto_patch: false
21
+ def self.gem_name
22
+ 'actionpack'
23
+ end
21
24
 
22
25
  def self.version
23
26
  Gem.loaded_specs['actionpack'] && Gem.loaded_specs['actionpack'].version
@@ -34,7 +37,7 @@ module Datadog
34
37
  # enabled by rails integration so should only auto instrument
35
38
  # if detected that it is being used without rails
36
39
  def auto_instrument?
37
- !Contrib::Rails::Utils.railtie_supported?
40
+ !Core::Contrib::Rails::Utils.railtie_supported?
38
41
  end
39
42
 
40
43
  def new_configuration