datadog 2.8.0 → 2.10.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 (128) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +62 -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 +66 -56
  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_stack.h +2 -2
  10. data/ext/datadog_profiling_native_extension/collectors_thread_context.c +221 -127
  11. data/ext/datadog_profiling_native_extension/heap_recorder.c +50 -92
  12. data/ext/datadog_profiling_native_extension/heap_recorder.h +2 -2
  13. data/ext/datadog_profiling_native_extension/http_transport.c +4 -4
  14. data/ext/datadog_profiling_native_extension/private_vm_api_access.c +3 -0
  15. data/ext/datadog_profiling_native_extension/private_vm_api_access.h +3 -1
  16. data/ext/datadog_profiling_native_extension/profiling.c +10 -8
  17. data/ext/datadog_profiling_native_extension/ruby_helpers.c +8 -8
  18. data/ext/datadog_profiling_native_extension/stack_recorder.c +63 -76
  19. data/ext/datadog_profiling_native_extension/stack_recorder.h +2 -2
  20. data/ext/datadog_profiling_native_extension/time_helpers.h +1 -1
  21. data/ext/datadog_profiling_native_extension/unsafe_api_calls_check.c +47 -0
  22. data/ext/datadog_profiling_native_extension/unsafe_api_calls_check.h +31 -0
  23. data/ext/libdatadog_api/crashtracker.c +3 -0
  24. data/lib/datadog/appsec/actions_handler.rb +27 -0
  25. data/lib/datadog/appsec/assets/waf_rules/recommended.json +355 -157
  26. data/lib/datadog/appsec/assets/waf_rules/strict.json +62 -32
  27. data/lib/datadog/appsec/component.rb +14 -8
  28. data/lib/datadog/appsec/configuration/settings.rb +9 -0
  29. data/lib/datadog/appsec/context.rb +74 -0
  30. data/lib/datadog/appsec/contrib/active_record/instrumentation.rb +12 -8
  31. data/lib/datadog/appsec/contrib/devise/patcher/authenticatable_patch.rb +6 -6
  32. data/lib/datadog/appsec/contrib/devise/patcher/registration_controller_patch.rb +4 -4
  33. data/lib/datadog/appsec/contrib/graphql/appsec_trace.rb +1 -7
  34. data/lib/datadog/appsec/contrib/graphql/gateway/watcher.rb +20 -30
  35. data/lib/datadog/appsec/contrib/graphql/reactive/multiplex.rb +6 -6
  36. data/lib/datadog/appsec/contrib/rack/gateway/response.rb +3 -3
  37. data/lib/datadog/appsec/contrib/rack/gateway/watcher.rb +67 -96
  38. data/lib/datadog/appsec/contrib/rack/reactive/request.rb +11 -11
  39. data/lib/datadog/appsec/contrib/rack/reactive/request_body.rb +6 -6
  40. data/lib/datadog/appsec/contrib/rack/reactive/response.rb +7 -7
  41. data/lib/datadog/appsec/contrib/rack/request_body_middleware.rb +10 -11
  42. data/lib/datadog/appsec/contrib/rack/request_middleware.rb +43 -60
  43. data/lib/datadog/appsec/contrib/rails/gateway/watcher.rb +23 -33
  44. data/lib/datadog/appsec/contrib/rails/patcher.rb +4 -14
  45. data/lib/datadog/appsec/contrib/rails/reactive/action.rb +7 -7
  46. data/lib/datadog/appsec/contrib/sinatra/gateway/watcher.rb +45 -65
  47. data/lib/datadog/appsec/contrib/sinatra/patcher.rb +5 -28
  48. data/lib/datadog/appsec/contrib/sinatra/reactive/routed.rb +6 -6
  49. data/lib/datadog/appsec/event.rb +6 -6
  50. data/lib/datadog/appsec/ext.rb +8 -1
  51. data/lib/datadog/appsec/metrics/collector.rb +38 -0
  52. data/lib/datadog/appsec/metrics/exporter.rb +35 -0
  53. data/lib/datadog/appsec/metrics/telemetry.rb +23 -0
  54. data/lib/datadog/appsec/metrics.rb +13 -0
  55. data/lib/datadog/appsec/monitor/gateway/watcher.rb +23 -32
  56. data/lib/datadog/appsec/monitor/reactive/set_user.rb +6 -6
  57. data/lib/datadog/appsec/processor/rule_loader.rb +0 -3
  58. data/lib/datadog/appsec/processor.rb +4 -3
  59. data/lib/datadog/appsec/response.rb +18 -80
  60. data/lib/datadog/appsec/security_engine/result.rb +67 -0
  61. data/lib/datadog/appsec/security_engine/runner.rb +88 -0
  62. data/lib/datadog/appsec/security_engine.rb +9 -0
  63. data/lib/datadog/appsec.rb +17 -8
  64. data/lib/datadog/auto_instrument.rb +3 -0
  65. data/lib/datadog/core/configuration/agent_settings_resolver.rb +39 -11
  66. data/lib/datadog/core/configuration/components.rb +4 -2
  67. data/lib/datadog/core/configuration.rb +1 -1
  68. data/lib/datadog/{tracing → core}/contrib/rails/utils.rb +1 -3
  69. data/lib/datadog/core/crashtracking/component.rb +1 -3
  70. data/lib/datadog/core/telemetry/event.rb +87 -3
  71. data/lib/datadog/core/telemetry/logging.rb +2 -2
  72. data/lib/datadog/core/telemetry/metric.rb +22 -0
  73. data/lib/datadog/core/telemetry/worker.rb +33 -0
  74. data/lib/datadog/di/base.rb +115 -0
  75. data/lib/datadog/di/code_tracker.rb +7 -4
  76. data/lib/datadog/di/component.rb +19 -11
  77. data/lib/datadog/di/configuration/settings.rb +11 -1
  78. data/lib/datadog/di/contrib/railtie.rb +15 -0
  79. data/lib/datadog/di/contrib.rb +26 -0
  80. data/lib/datadog/di/error.rb +5 -0
  81. data/lib/datadog/di/instrumenter.rb +39 -18
  82. data/lib/datadog/di/{init.rb → preload.rb} +2 -4
  83. data/lib/datadog/di/probe_manager.rb +4 -4
  84. data/lib/datadog/di/probe_notification_builder.rb +22 -2
  85. data/lib/datadog/di/probe_notifier_worker.rb +5 -6
  86. data/lib/datadog/di/redactor.rb +0 -1
  87. data/lib/datadog/di/remote.rb +30 -9
  88. data/lib/datadog/di/transport.rb +2 -4
  89. data/lib/datadog/di.rb +5 -108
  90. data/lib/datadog/kit/appsec/events.rb +3 -3
  91. data/lib/datadog/kit/identity.rb +4 -4
  92. data/lib/datadog/profiling/component.rb +55 -53
  93. data/lib/datadog/profiling/http_transport.rb +1 -26
  94. data/lib/datadog/tracing/contrib/action_cable/integration.rb +5 -2
  95. data/lib/datadog/tracing/contrib/action_mailer/integration.rb +6 -2
  96. data/lib/datadog/tracing/contrib/action_pack/integration.rb +5 -2
  97. data/lib/datadog/tracing/contrib/action_view/integration.rb +5 -2
  98. data/lib/datadog/tracing/contrib/active_job/integration.rb +5 -2
  99. data/lib/datadog/tracing/contrib/active_record/integration.rb +6 -2
  100. data/lib/datadog/tracing/contrib/active_support/cache/events/cache.rb +3 -1
  101. data/lib/datadog/tracing/contrib/active_support/cache/instrumentation.rb +3 -1
  102. data/lib/datadog/tracing/contrib/active_support/configuration/settings.rb +10 -0
  103. data/lib/datadog/tracing/contrib/active_support/integration.rb +5 -2
  104. data/lib/datadog/tracing/contrib/auto_instrument.rb +2 -2
  105. data/lib/datadog/tracing/contrib/aws/integration.rb +3 -0
  106. data/lib/datadog/tracing/contrib/concurrent_ruby/integration.rb +3 -0
  107. data/lib/datadog/tracing/contrib/extensions.rb +15 -3
  108. data/lib/datadog/tracing/contrib/http/integration.rb +3 -0
  109. data/lib/datadog/tracing/contrib/httprb/integration.rb +3 -0
  110. data/lib/datadog/tracing/contrib/kafka/integration.rb +3 -0
  111. data/lib/datadog/tracing/contrib/mongodb/integration.rb +3 -0
  112. data/lib/datadog/tracing/contrib/opensearch/integration.rb +3 -0
  113. data/lib/datadog/tracing/contrib/presto/integration.rb +3 -0
  114. data/lib/datadog/tracing/contrib/rack/integration.rb +2 -2
  115. data/lib/datadog/tracing/contrib/rails/framework.rb +2 -2
  116. data/lib/datadog/tracing/contrib/rails/patcher.rb +1 -1
  117. data/lib/datadog/tracing/contrib/rest_client/integration.rb +3 -0
  118. data/lib/datadog/tracing/span.rb +12 -4
  119. data/lib/datadog/tracing/span_event.rb +123 -3
  120. data/lib/datadog/tracing/span_operation.rb +6 -0
  121. data/lib/datadog/tracing/transport/serializable_trace.rb +24 -6
  122. data/lib/datadog/version.rb +1 -1
  123. metadata +40 -17
  124. data/lib/datadog/appsec/contrib/sinatra/ext.rb +0 -14
  125. data/lib/datadog/appsec/processor/context.rb +0 -107
  126. data/lib/datadog/appsec/reactive/operation.rb +0 -68
  127. data/lib/datadog/appsec/scope.rb +0 -58
  128. data/lib/datadog/core/crashtracking/agent_base_url.rb +0 -21
@@ -119,7 +119,6 @@ module Datadog
119
119
  "dburl",
120
120
  "encryptionkey",
121
121
  "encryptionkeyid",
122
- "env",
123
122
  "geolocation",
124
123
  "gpgkey",
125
124
  "ipaddress",
@@ -49,28 +49,48 @@ module Datadog
49
49
  begin
50
50
  probe_spec = parse_content(content)
51
51
  probe = ProbeBuilder.build_from_remote_config(probe_spec)
52
- payload = component.probe_notification_builder.build_received(probe)
53
- component.probe_notifier_worker.add_status(payload)
54
- component.logger.info("Received probe from RC: #{probe.type} #{probe.location}")
52
+ probe_notification_builder = component.probe_notification_builder
53
+ payload = probe_notification_builder.build_received(probe)
54
+ probe_notifier_worker = component.probe_notifier_worker
55
+ probe_notifier_worker.add_status(payload)
56
+ component.logger.debug { "di: received probe from RC: #{probe.type} #{probe.location}" }
55
57
 
56
58
  begin
57
59
  # TODO test exception capture
58
60
  probe_manager.add_probe(probe)
59
61
  content.applied
62
+ rescue DI::Error::DITargetNotInRegistry => exc
63
+ component.telemetry&.report(exc, description: "Line probe is targeting a loaded file that is not in code tracker")
64
+
65
+ payload = probe_notification_builder.build_errored(probe, exc)
66
+ probe_notifier_worker.add_status(payload)
67
+
68
+ # If a probe fails to install, we will mark the content
69
+ # as errored. On subsequent remote configuration application
70
+ # attemps, probe manager will raise the "previously errored"
71
+ # exception and we'll rescue it here, again marking the
72
+ # content as errored but with a somewhat different exception
73
+ # message.
74
+ # TODO assert content state (errored for this example)
75
+ content.errored("Error applying dynamic instrumentation configuration: #{exc.class.name} #{exc.message}")
60
76
  rescue => exc
61
77
  raise if component.settings.dynamic_instrumentation.internal.propagate_all_exceptions
62
78
 
63
- component.logger.warn("Unhandled exception adding probe in DI remote receiver: #{exc.class}: #{exc}")
79
+ component.logger.debug { "di: unhandled exception adding probe in DI remote receiver: #{exc.class}: #{exc}" }
64
80
  component.telemetry&.report(exc, description: "Unhandled exception adding probe in DI remote receiver")
65
81
 
82
+ # TODO test this path
83
+ payload = probe_notification_builder.build_errored(probe, exc)
84
+ probe_notifier_worker.add_status(payload)
85
+
66
86
  # If a probe fails to install, we will mark the content
67
87
  # as errored. On subsequent remote configuration application
68
88
  # attemps, probe manager will raise the "previously errored"
69
89
  # exception and we'll rescue it here, again marking the
70
90
  # content as errored but with a somewhat different exception
71
91
  # message.
72
- # TODO stack trace must be redacted or not sent at all
73
- content.errored("Error applying dynamic instrumentation configuration: #{exc.class.name} #{exc.message}: #{Array(exc.backtrace).join("\n")}")
92
+ # TODO assert content state (errored for this example)
93
+ content.errored("Error applying dynamic instrumentation configuration: #{exc.class.name} #{exc.message}")
74
94
  end
75
95
 
76
96
  # Important: even if processing fails for this probe config,
@@ -81,10 +101,11 @@ module Datadog
81
101
  rescue => exc
82
102
  raise if component.settings.dynamic_instrumentation.internal.propagate_all_exceptions
83
103
 
84
- component.logger.warn("Unhandled exception handling probe in DI remote receiver: #{exc.class}: #{exc}")
104
+ component.logger.debug { "di: unhandled exception handling probe in DI remote receiver: #{exc.class}: #{exc}" }
85
105
  component.telemetry&.report(exc, description: "Unhandled exception handling probe in DI remote receiver")
86
106
 
87
- content.errored("Error applying dynamic instrumentation configuration: #{exc.class.name} #{exc.message}: #{Array(exc.backtrace).join("\n")}")
107
+ # TODO assert content state (errored for this example)
108
+ content.errored("Error applying dynamic instrumentation configuration: #{exc.class.name} #{exc.message}")
88
109
  end
89
110
  end
90
111
  end
@@ -95,7 +116,7 @@ module Datadog
95
116
  rescue => exc
96
117
  raise if component.settings.dynamic_instrumentation.internal.propagate_all_exceptions
97
118
 
98
- component.logger.warn("Unhandled exception removing probes in DI remote receiver: #{exc.class}: #{exc}")
119
+ component.logger.debug { "di: unhandled exception removing probes in DI remote receiver: #{exc.class}: #{exc}" }
99
120
  component.telemetry&.report(exc, description: "Unhandled exception removing probes in DI remote receiver")
100
121
  end
101
122
  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