datadog 2.3.0 → 2.5.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 (173) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +64 -2
  3. data/ext/datadog_profiling_loader/datadog_profiling_loader.c +9 -1
  4. data/ext/datadog_profiling_loader/extconf.rb +10 -22
  5. data/ext/datadog_profiling_native_extension/NativeExtensionDesign.md +3 -3
  6. data/ext/datadog_profiling_native_extension/collectors_cpu_and_wall_time_worker.c +198 -41
  7. data/ext/datadog_profiling_native_extension/collectors_discrete_dynamic_sampler.c +4 -2
  8. data/ext/datadog_profiling_native_extension/collectors_stack.c +89 -46
  9. data/ext/datadog_profiling_native_extension/collectors_thread_context.c +645 -107
  10. data/ext/datadog_profiling_native_extension/collectors_thread_context.h +15 -1
  11. data/ext/datadog_profiling_native_extension/datadog_ruby_common.c +0 -27
  12. data/ext/datadog_profiling_native_extension/datadog_ruby_common.h +0 -4
  13. data/ext/datadog_profiling_native_extension/extconf.rb +42 -25
  14. data/ext/datadog_profiling_native_extension/gvl_profiling_helper.c +50 -0
  15. data/ext/datadog_profiling_native_extension/gvl_profiling_helper.h +75 -0
  16. data/ext/datadog_profiling_native_extension/heap_recorder.c +194 -34
  17. data/ext/datadog_profiling_native_extension/heap_recorder.h +11 -0
  18. data/ext/datadog_profiling_native_extension/http_transport.c +38 -6
  19. data/ext/datadog_profiling_native_extension/native_extension_helpers.rb +1 -1
  20. data/ext/datadog_profiling_native_extension/private_vm_api_access.c +53 -2
  21. data/ext/datadog_profiling_native_extension/private_vm_api_access.h +3 -0
  22. data/ext/datadog_profiling_native_extension/profiling.c +1 -1
  23. data/ext/datadog_profiling_native_extension/ruby_helpers.c +14 -11
  24. data/ext/datadog_profiling_native_extension/stack_recorder.c +58 -22
  25. data/ext/datadog_profiling_native_extension/stack_recorder.h +2 -0
  26. data/ext/libdatadog_api/crashtracker.c +20 -18
  27. data/ext/libdatadog_api/datadog_ruby_common.c +0 -27
  28. data/ext/libdatadog_api/datadog_ruby_common.h +0 -4
  29. data/ext/libdatadog_extconf_helpers.rb +1 -1
  30. data/lib/datadog/appsec/assets/waf_rules/recommended.json +2184 -108
  31. data/lib/datadog/appsec/assets/waf_rules/strict.json +1430 -2
  32. data/lib/datadog/appsec/component.rb +29 -8
  33. data/lib/datadog/appsec/configuration/settings.rb +10 -2
  34. data/lib/datadog/appsec/contrib/devise/patcher/authenticatable_patch.rb +1 -0
  35. data/lib/datadog/appsec/contrib/devise/patcher/rememberable_patch.rb +21 -0
  36. data/lib/datadog/appsec/contrib/devise/patcher.rb +12 -2
  37. data/lib/datadog/appsec/contrib/graphql/appsec_trace.rb +0 -14
  38. data/lib/datadog/appsec/contrib/graphql/gateway/multiplex.rb +67 -31
  39. data/lib/datadog/appsec/contrib/graphql/gateway/watcher.rb +14 -15
  40. data/lib/datadog/appsec/contrib/graphql/integration.rb +14 -1
  41. data/lib/datadog/appsec/contrib/graphql/reactive/multiplex.rb +7 -20
  42. data/lib/datadog/appsec/contrib/rack/gateway/request.rb +2 -5
  43. data/lib/datadog/appsec/contrib/rack/gateway/watcher.rb +9 -15
  44. data/lib/datadog/appsec/contrib/rack/reactive/request.rb +6 -18
  45. data/lib/datadog/appsec/contrib/rack/reactive/request_body.rb +7 -20
  46. data/lib/datadog/appsec/contrib/rack/reactive/response.rb +5 -18
  47. data/lib/datadog/appsec/contrib/rack/request_middleware.rb +3 -1
  48. data/lib/datadog/appsec/contrib/rails/gateway/watcher.rb +3 -5
  49. data/lib/datadog/appsec/contrib/rails/reactive/action.rb +5 -18
  50. data/lib/datadog/appsec/contrib/sinatra/gateway/watcher.rb +6 -10
  51. data/lib/datadog/appsec/contrib/sinatra/reactive/routed.rb +7 -20
  52. data/lib/datadog/appsec/event.rb +25 -1
  53. data/lib/datadog/appsec/ext.rb +4 -0
  54. data/lib/datadog/appsec/monitor/gateway/watcher.rb +3 -5
  55. data/lib/datadog/appsec/monitor/reactive/set_user.rb +7 -20
  56. data/lib/datadog/appsec/processor/context.rb +109 -0
  57. data/lib/datadog/appsec/processor/rule_loader.rb +3 -1
  58. data/lib/datadog/appsec/processor/rule_merger.rb +33 -15
  59. data/lib/datadog/appsec/processor.rb +42 -107
  60. data/lib/datadog/appsec/rate_limiter.rb +25 -40
  61. data/lib/datadog/appsec/remote.rb +7 -3
  62. data/lib/datadog/appsec/scope.rb +1 -4
  63. data/lib/datadog/appsec/utils/trace_operation.rb +15 -0
  64. data/lib/datadog/appsec/utils.rb +2 -0
  65. data/lib/datadog/appsec.rb +3 -2
  66. data/lib/datadog/core/configuration/agent_settings_resolver.rb +26 -25
  67. data/lib/datadog/core/configuration/components.rb +4 -3
  68. data/lib/datadog/core/configuration/settings.rb +96 -5
  69. data/lib/datadog/core/configuration.rb +1 -3
  70. data/lib/datadog/core/crashtracking/component.rb +9 -6
  71. data/lib/datadog/core/environment/execution.rb +5 -5
  72. data/lib/datadog/core/environment/yjit.rb +5 -0
  73. data/lib/datadog/core/metrics/client.rb +7 -0
  74. data/lib/datadog/core/rate_limiter.rb +183 -0
  75. data/lib/datadog/core/remote/client/capabilities.rb +4 -3
  76. data/lib/datadog/core/remote/component.rb +4 -2
  77. data/lib/datadog/core/remote/negotiation.rb +4 -4
  78. data/lib/datadog/core/remote/tie.rb +2 -0
  79. data/lib/datadog/core/remote/transport/http.rb +5 -0
  80. data/lib/datadog/core/remote/worker.rb +1 -1
  81. data/lib/datadog/core/runtime/ext.rb +1 -0
  82. data/lib/datadog/core/runtime/metrics.rb +5 -1
  83. data/lib/datadog/core/semaphore.rb +35 -0
  84. data/lib/datadog/core/telemetry/component.rb +2 -0
  85. data/lib/datadog/core/telemetry/event.rb +12 -7
  86. data/lib/datadog/core/telemetry/logger.rb +51 -0
  87. data/lib/datadog/core/telemetry/logging.rb +50 -14
  88. data/lib/datadog/core/telemetry/request.rb +13 -1
  89. data/lib/datadog/core/transport/ext.rb +1 -0
  90. data/lib/datadog/core/utils/time.rb +12 -0
  91. data/lib/datadog/core/workers/async.rb +1 -1
  92. data/lib/datadog/di/code_tracker.rb +166 -0
  93. data/lib/datadog/di/configuration/settings.rb +163 -0
  94. data/lib/datadog/di/configuration.rb +11 -0
  95. data/lib/datadog/di/error.rb +31 -0
  96. data/lib/datadog/di/extensions.rb +16 -0
  97. data/lib/datadog/di/instrumenter.rb +301 -0
  98. data/lib/datadog/di/probe.rb +162 -0
  99. data/lib/datadog/di/probe_builder.rb +47 -0
  100. data/lib/datadog/di/probe_notification_builder.rb +207 -0
  101. data/lib/datadog/di/probe_notifier_worker.rb +244 -0
  102. data/lib/datadog/di/redactor.rb +188 -0
  103. data/lib/datadog/di/serializer.rb +215 -0
  104. data/lib/datadog/di/transport.rb +67 -0
  105. data/lib/datadog/di/utils.rb +39 -0
  106. data/lib/datadog/di.rb +57 -0
  107. data/lib/datadog/opentelemetry/sdk/propagator.rb +2 -0
  108. data/lib/datadog/profiling/collectors/cpu_and_wall_time_worker.rb +12 -10
  109. data/lib/datadog/profiling/collectors/info.rb +12 -3
  110. data/lib/datadog/profiling/collectors/thread_context.rb +32 -8
  111. data/lib/datadog/profiling/component.rb +21 -4
  112. data/lib/datadog/profiling/http_transport.rb +6 -1
  113. data/lib/datadog/profiling/scheduler.rb +2 -0
  114. data/lib/datadog/profiling/stack_recorder.rb +40 -9
  115. data/lib/datadog/single_step_instrument.rb +12 -0
  116. data/lib/datadog/tracing/component.rb +13 -0
  117. data/lib/datadog/tracing/contrib/action_cable/instrumentation.rb +8 -12
  118. data/lib/datadog/tracing/contrib/action_pack/action_controller/instrumentation.rb +5 -0
  119. data/lib/datadog/tracing/contrib/action_pack/action_dispatch/instrumentation.rb +78 -0
  120. data/lib/datadog/tracing/contrib/action_pack/action_dispatch/patcher.rb +33 -0
  121. data/lib/datadog/tracing/contrib/action_pack/patcher.rb +2 -0
  122. data/lib/datadog/tracing/contrib/active_record/configuration/resolver.rb +4 -0
  123. data/lib/datadog/tracing/contrib/active_record/events/instantiation.rb +3 -1
  124. data/lib/datadog/tracing/contrib/active_record/events/sql.rb +3 -1
  125. data/lib/datadog/tracing/contrib/active_support/cache/events/cache.rb +5 -1
  126. data/lib/datadog/tracing/contrib/aws/instrumentation.rb +5 -0
  127. data/lib/datadog/tracing/contrib/elasticsearch/patcher.rb +6 -1
  128. data/lib/datadog/tracing/contrib/ethon/easy_patch.rb +4 -0
  129. data/lib/datadog/tracing/contrib/excon/middleware.rb +3 -0
  130. data/lib/datadog/tracing/contrib/faraday/middleware.rb +12 -0
  131. data/lib/datadog/tracing/contrib/grape/endpoint.rb +24 -2
  132. data/lib/datadog/tracing/contrib/graphql/patcher.rb +9 -12
  133. data/lib/datadog/tracing/contrib/graphql/trace_patcher.rb +3 -3
  134. data/lib/datadog/tracing/contrib/graphql/tracing_patcher.rb +3 -3
  135. data/lib/datadog/tracing/contrib/graphql/unified_trace.rb +13 -9
  136. data/lib/datadog/tracing/contrib/graphql/unified_trace_patcher.rb +6 -3
  137. data/lib/datadog/tracing/contrib/http/circuit_breaker.rb +9 -0
  138. data/lib/datadog/tracing/contrib/http/instrumentation.rb +22 -15
  139. data/lib/datadog/tracing/contrib/httpclient/instrumentation.rb +10 -5
  140. data/lib/datadog/tracing/contrib/httpclient/patcher.rb +1 -14
  141. data/lib/datadog/tracing/contrib/httprb/instrumentation.rb +9 -0
  142. data/lib/datadog/tracing/contrib/httprb/patcher.rb +1 -14
  143. data/lib/datadog/tracing/contrib/lograge/patcher.rb +1 -2
  144. data/lib/datadog/tracing/contrib/mongodb/subscribers.rb +2 -0
  145. data/lib/datadog/tracing/contrib/opensearch/patcher.rb +13 -6
  146. data/lib/datadog/tracing/contrib/patcher.rb +2 -1
  147. data/lib/datadog/tracing/contrib/presto/patcher.rb +1 -13
  148. data/lib/datadog/tracing/contrib/rack/middlewares.rb +27 -0
  149. data/lib/datadog/tracing/contrib/rails/runner.rb +1 -1
  150. data/lib/datadog/tracing/contrib/redis/tags.rb +4 -0
  151. data/lib/datadog/tracing/contrib/rest_client/request_patch.rb +3 -0
  152. data/lib/datadog/tracing/contrib/sinatra/tracer.rb +4 -0
  153. data/lib/datadog/tracing/contrib/stripe/request.rb +3 -2
  154. data/lib/datadog/tracing/distributed/propagation.rb +7 -0
  155. data/lib/datadog/tracing/metadata/ext.rb +2 -0
  156. data/lib/datadog/tracing/remote.rb +5 -2
  157. data/lib/datadog/tracing/sampling/matcher.rb +6 -1
  158. data/lib/datadog/tracing/sampling/rate_sampler.rb +1 -1
  159. data/lib/datadog/tracing/sampling/rule.rb +2 -0
  160. data/lib/datadog/tracing/sampling/rule_sampler.rb +15 -9
  161. data/lib/datadog/tracing/sampling/span/ext.rb +1 -1
  162. data/lib/datadog/tracing/sampling/span/rule.rb +2 -2
  163. data/lib/datadog/tracing/trace_operation.rb +26 -2
  164. data/lib/datadog/tracing/tracer.rb +29 -22
  165. data/lib/datadog/tracing/transport/http/client.rb +1 -0
  166. data/lib/datadog/tracing/transport/http.rb +4 -0
  167. data/lib/datadog/tracing/transport/io/client.rb +1 -0
  168. data/lib/datadog/tracing/workers/trace_writer.rb +1 -1
  169. data/lib/datadog/tracing/workers.rb +2 -2
  170. data/lib/datadog/tracing/writer.rb +26 -28
  171. data/lib/datadog/version.rb +1 -1
  172. metadata +40 -15
  173. data/lib/datadog/tracing/sampling/rate_limiter.rb +0 -185
@@ -1,60 +1,45 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative '../core/rate_limiter'
4
+
3
5
  module Datadog
4
6
  module AppSec
5
- # Simple per-thread rate limiter
6
- # Since AppSec marks sampling to keep on a security event, this limits the flood of egress traces involving AppSec
7
+ # Per-thread rate limiter based on token bucket rate limiter.
8
+ #
9
+ # Since AppSec marks sampling to keep on a security event, this limits
10
+ # the flood of egress traces involving AppSec
7
11
  class RateLimiter
8
- def initialize(rate)
9
- @rate = rate
10
- @timestamps = []
11
- end
12
-
13
- def limit
14
- now = Time.now.to_f
15
-
16
- loop do
17
- oldest = @timestamps.first
18
-
19
- break if oldest.nil? || now - oldest < 1
20
-
21
- @timestamps.shift
22
- end
23
-
24
- @timestamps << now
25
-
26
- if (count = @timestamps.count) <= @rate
27
- yield
28
- else
29
- Datadog.logger.debug { "Rate limit hit: #{count}/#{@rate} AppSec traces/second" }
30
- end
31
- end
12
+ THREAD_KEY = :datadog_security_appsec_rate_limiter
32
13
 
33
14
  class << self
34
- def limit(name, &block)
35
- rate_limiter(name).limit(&block)
15
+ def thread_local
16
+ rate_limiter = Thread.current.thread_variable_get(THREAD_KEY)
17
+ return rate_limiter unless rate_limiter.nil?
18
+
19
+ Thread.current.thread_variable_set(THREAD_KEY, new(trace_rate_limit))
36
20
  end
37
21
 
38
22
  # reset a rate limiter: used for testing
39
- def reset!(name)
40
- Thread.current[:datadog_security_trace_rate_limiter] = nil
23
+ def reset!
24
+ Thread.current.thread_variable_set(THREAD_KEY, nil)
41
25
  end
42
26
 
43
- protected
44
-
45
- def rate_limiter(name)
46
- case name
47
- when :traces
48
- Thread.current[:datadog_security_trace_rate_limiter] ||= RateLimiter.new(trace_rate_limit)
49
- else
50
- raise "unsupported rate limiter: #{name.inspect}"
51
- end
52
- end
27
+ private
53
28
 
54
29
  def trace_rate_limit
55
30
  Datadog.configuration.appsec.trace_rate_limit
56
31
  end
57
32
  end
33
+
34
+ def initialize(rate)
35
+ @rate_limiter = Core::TokenBucket.new(rate)
36
+ end
37
+
38
+ def limit
39
+ return yield if @rate_limiter.allow?
40
+
41
+ Datadog.logger.debug { "Rate limit hit: #{@rate_limiter.current_window_rate} AppSec traces/second" }
42
+ end
58
43
  end
59
44
  end
60
45
  end
@@ -53,7 +53,7 @@ module Datadog
53
53
  end
54
54
 
55
55
  # rubocop:disable Metrics/MethodLength
56
- def receivers
56
+ def receivers(telemetry)
57
57
  return [] unless remote_features_enabled?
58
58
 
59
59
  matcher = Core::Remote::Dispatcher::Matcher::Product.new(ASM_PRODUCTS)
@@ -86,7 +86,10 @@ module Datadog
86
86
  end
87
87
 
88
88
  if rules.empty?
89
- settings_rules = AppSec::Processor::RuleLoader.load_rules(ruleset: Datadog.configuration.appsec.ruleset)
89
+ settings_rules = AppSec::Processor::RuleLoader.load_rules(
90
+ telemetry: telemetry,
91
+ ruleset: Datadog.configuration.appsec.ruleset
92
+ )
90
93
 
91
94
  raise NoRulesError, 'no default rules available' unless settings_rules
92
95
 
@@ -99,9 +102,10 @@ module Datadog
99
102
  overrides: overrides,
100
103
  exclusions: exclusions,
101
104
  custom_rules: custom_rules,
105
+ telemetry: telemetry
102
106
  )
103
107
 
104
- Datadog::AppSec.reconfigure(ruleset: ruleset, actions: actions)
108
+ Datadog::AppSec.reconfigure(ruleset: ruleset, actions: actions, telemetry: telemetry)
105
109
  end
106
110
 
107
111
  [receiver]
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'processor'
4
-
5
3
  module Datadog
6
4
  module AppSec
7
5
  # Capture context essential to consistently call processor and report via traces
@@ -22,8 +20,7 @@ module Datadog
22
20
  def activate_scope(trace, service_entry_span, processor)
23
21
  raise ActiveScopeError, 'another scope is active, nested scopes are not supported' if active_scope
24
22
 
25
- context = Datadog::AppSec::Processor::Context.new(processor)
26
-
23
+ context = processor.new_context
27
24
  self.active_scope = new(trace, service_entry_span, context)
28
25
  end
29
26
 
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Datadog
4
+ module AppSec
5
+ module Utils
6
+ # Utility class to to AppSec-specific trace operations
7
+ class TraceOperation
8
+ def self.appsec_standalone_reject?(trace)
9
+ Datadog.configuration.appsec.standalone.enabled &&
10
+ (trace.nil? || trace.get_tag(Datadog::AppSec::Ext::TAG_DISTRIBUTED_APPSEC_EVENT) != '1')
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative 'utils/trace_operation'
4
+
3
5
  module Datadog
4
6
  module AppSec
5
7
  # Utilities for AppSec
@@ -4,6 +4,7 @@ require_relative 'appsec/configuration'
4
4
  require_relative 'appsec/extensions'
5
5
  require_relative 'appsec/scope'
6
6
  require_relative 'appsec/ext'
7
+ require_relative 'appsec/utils'
7
8
 
8
9
  module Datadog
9
10
  # Namespace for Datadog AppSec instrumentation
@@ -23,12 +24,12 @@ module Datadog
23
24
  appsec_component.processor if appsec_component
24
25
  end
25
26
 
26
- def reconfigure(ruleset:, actions:)
27
+ def reconfigure(ruleset:, actions:, telemetry:)
27
28
  appsec_component = components.appsec
28
29
 
29
30
  return unless appsec_component
30
31
 
31
- appsec_component.reconfigure(ruleset: ruleset, actions: actions)
32
+ appsec_component.reconfigure(ruleset: ruleset, actions: actions, telemetry: telemetry)
32
33
  end
33
34
 
34
35
  def reconfigure_lock(&block)
@@ -232,7 +232,32 @@ module Datadog
232
232
  end
233
233
 
234
234
  def should_use_uds?
235
- can_use_uds? && !mixed_http_and_uds?
235
+ # When we have mixed settings for http/https and uds, we print a warning
236
+ # and use the uds settings.
237
+ mixed_http_and_uds
238
+ can_use_uds?
239
+ end
240
+
241
+ def mixed_http_and_uds
242
+ return @mixed_http_and_uds if defined?(@mixed_http_and_uds)
243
+
244
+ @mixed_http_and_uds = (configured_hostname || configured_port) && can_use_uds?
245
+ if @mixed_http_and_uds
246
+ warn_if_configuration_mismatch(
247
+ [
248
+ DetectedConfiguration.new(
249
+ friendly_name: 'configuration for unix domain socket',
250
+ value: parsed_url.to_s,
251
+ ),
252
+ DetectedConfiguration.new(
253
+ friendly_name: 'configuration of hostname/port for http/https use',
254
+ value: "hostname: '#{hostname}', port: '#{port}'",
255
+ ),
256
+ ]
257
+ )
258
+ end
259
+
260
+ @mixed_http_and_uds
236
261
  end
237
262
 
238
263
  def can_use_uds?
@@ -307,30 +332,6 @@ module Datadog
307
332
  uri.scheme == 'unix'
308
333
  end
309
334
 
310
- # When we have mixed settings for http/https and uds, we print a warning and ignore the uds settings
311
- def mixed_http_and_uds?
312
- return @mixed_http_and_uds if defined?(@mixed_http_and_uds)
313
-
314
- @mixed_http_and_uds = (configured_hostname || configured_port) && can_use_uds?
315
-
316
- if @mixed_http_and_uds
317
- warn_if_configuration_mismatch(
318
- [
319
- DetectedConfiguration.new(
320
- friendly_name: 'configuration of hostname/port for http/https use',
321
- value: "hostname: '#{hostname}', port: '#{port}'",
322
- ),
323
- DetectedConfiguration.new(
324
- friendly_name: 'configuration for unix domain socket',
325
- value: parsed_url.to_s,
326
- ),
327
- ]
328
- )
329
- end
330
-
331
- @mixed_http_and_uds
332
- end
333
-
334
335
  # Represents a given configuration value and where we got it from
335
336
  class DetectedConfiguration
336
337
  attr_reader :friendly_name, :value
@@ -94,7 +94,9 @@ module Datadog
94
94
  # the Core resolver from within your product/component's namespace.
95
95
  agent_settings = AgentSettingsResolver.call(settings, logger: @logger)
96
96
 
97
- @remote = Remote::Component.build(settings, agent_settings)
97
+ @telemetry = self.class.build_telemetry(settings, agent_settings, @logger)
98
+
99
+ @remote = Remote::Component.build(settings, agent_settings, telemetry: telemetry)
98
100
  @tracer = self.class.build_tracer(settings, agent_settings, logger: @logger)
99
101
  @crashtracker = self.class.build_crashtracker(settings, agent_settings, logger: @logger)
100
102
 
@@ -107,8 +109,7 @@ module Datadog
107
109
 
108
110
  @runtime_metrics = self.class.build_runtime_metrics_worker(settings)
109
111
  @health_metrics = self.class.build_health_metrics(settings)
110
- @telemetry = self.class.build_telemetry(settings, agent_settings, logger)
111
- @appsec = Datadog::AppSec::Component.build_appsec_component(settings)
112
+ @appsec = Datadog::AppSec::Component.build_appsec_component(settings, telemetry: telemetry)
112
113
 
113
114
  self.class.configure_tracing(settings)
114
115
  end
@@ -410,10 +410,8 @@ module Datadog
410
410
  # The profiler gathers data by sending `SIGPROF` unix signals to Ruby application threads.
411
411
  #
412
412
  # We've discovered that this can trigger a bug in a number of Ruby APIs in the `Dir` class, as
413
- # described in https://github.com/DataDog/dd-trace-rb/issues/3450 . This workaround prevents the issue
414
- # from happening by monkey patching the affected APIs.
415
- #
416
- # (In the future, once a fix lands upstream, we'll disable this workaround for Rubies that don't need it)
413
+ # described in https://bugs.ruby-lang.org/issues/20586 .
414
+ # This was fixed for Ruby 3.4+, and this setting is a no-op for those versions.
417
415
  #
418
416
  # @default `DD_PROFILING_DIR_INTERRUPTION_WORKAROUND_ENABLED` environment variable as a boolean,
419
417
  # otherwise `true`
@@ -462,6 +460,72 @@ module Datadog
462
460
  end
463
461
  end
464
462
  end
463
+
464
+ # Enables GVL profiling. This will show when threads are waiting for GVL in the timeline view.
465
+ #
466
+ # This is a preview feature and disabled by default. It requires Ruby 3.2+.
467
+ #
468
+ # @default `DD_PROFILING_PREVIEW_GVL_ENABLED` environment variable as a boolean, otherwise `false`
469
+ option :preview_gvl_enabled do |o|
470
+ o.type :bool
471
+ o.env 'DD_PROFILING_PREVIEW_GVL_ENABLED'
472
+ o.default false
473
+ end
474
+
475
+ # Controls the smallest time period the profiler will report a thread waiting for the GVL.
476
+ #
477
+ # The default value was set to minimize overhead. Periods smaller than the set value will not be reported (e.g.
478
+ # the thread will be reported as whatever it was doing before it waited for the GVL).
479
+ #
480
+ # We do not recommend setting this to less than 1ms. Tweaking this value can increase application latency and
481
+ # memory use.
482
+ #
483
+ # @default 10_000_000 (10ms)
484
+ option :waiting_for_gvl_threshold_ns do |o|
485
+ o.type :int
486
+ o.default 10_000_000
487
+ end
488
+
489
+ # Controls if the profiler should attempt to read context from the otel library
490
+ #
491
+ # @default false
492
+ option :preview_otel_context_enabled do |o|
493
+ o.env 'DD_PROFILING_PREVIEW_OTEL_CONTEXT_ENABLED'
494
+ o.default false
495
+ o.env_parser do |value|
496
+ if value
497
+ value = value.strip.downcase
498
+ if ['only', 'both'].include?(value)
499
+ value
500
+ elsif ['true', '1'].include?(value)
501
+ 'both'
502
+ else
503
+ 'false'
504
+ end
505
+ end
506
+ end
507
+ o.setter do |value|
508
+ if value == true
509
+ :both
510
+ elsif ['only', 'both', :only, :both].include?(value)
511
+ value.to_sym
512
+ else
513
+ false
514
+ end
515
+ end
516
+ end
517
+
518
+ # Controls if the heap profiler should attempt to clean young objects after GC, rather than just at
519
+ # serialization time. This lowers memory usage and high percentile latency.
520
+ #
521
+ # Only takes effect when used together with `gc_enabled: true` and `experimental_heap_enabled: true`.
522
+ #
523
+ # @default false
524
+ option :heap_clean_after_gc_enabled do |o|
525
+ o.type :bool
526
+ o.env 'DD_PROFILING_HEAP_CLEAN_AFTER_GC_ENABLED'
527
+ o.default false
528
+ end
465
529
  end
466
530
 
467
531
  # @public_api
@@ -630,6 +694,33 @@ module Datadog
630
694
  end
631
695
  end
632
696
 
697
+ # The monotonic clock time provider used by Datadog. This option is internal and is used by `datadog-ci`
698
+ # gem to avoid traces' durations being skewed by timecop.
699
+ #
700
+ # It must respect the interface of [Datadog::Core::Utils::Time#get_time] method.
701
+ #
702
+ # For [Timecop](https://rubygems.org/gems/timecop), for example,
703
+ # `->(unit = :float_second) { ::Process.clock_gettime_without_mock(::Process::CLOCK_MONOTONIC, unit) }`
704
+ # allows Datadog features to use the real monotonic time when time is frozen with
705
+ # `Timecop.mock_process_clock = true`.
706
+ #
707
+ # @default `->(unit = :float_second) { ::Process.clock_gettime(::Process::CLOCK_MONOTONIC, unit)}`
708
+ # @return [Proc<Numeric>]
709
+ option :get_time_provider do |o|
710
+ o.default_proc { |unit = :float_second| ::Process.clock_gettime(::Process::CLOCK_MONOTONIC, unit) }
711
+ o.type :proc
712
+
713
+ o.after_set do |get_time_provider|
714
+ Core::Utils::Time.get_time_provider = get_time_provider
715
+ end
716
+
717
+ o.resetter do |_value|
718
+ ->(unit = :float_second) { ::Process.clock_gettime(::Process::CLOCK_MONOTONIC, unit) }.tap do |default|
719
+ Core::Utils::Time.get_time_provider = default
720
+ end
721
+ end
722
+ end
723
+
633
724
  # The `version` tag in Datadog. Use it to enable [Deployment Tracking](https://docs.datadoghq.com/tracing/deployment_tracking/).
634
725
  # @see https://docs.datadoghq.com/getting_started/tagging/unified_service_tagging
635
726
  # @default `DD_VERSION` environment variable, otherwise `nils`
@@ -836,7 +927,7 @@ module Datadog
836
927
  # Enables reporting of information when Ruby VM crashes.
837
928
  option :enabled do |o|
838
929
  o.type :bool
839
- o.default true
930
+ o.default false
840
931
  o.env 'DD_CRASHTRACKING_ENABLED'
841
932
  end
842
933
  end
@@ -278,9 +278,7 @@ module Datadog
278
278
  def handle_interrupt_shutdown!
279
279
  logger = Datadog.logger
280
280
  shutdown_thread = Thread.new { shutdown! }
281
- unless Gem::Version.new(RUBY_VERSION) < Gem::Version.new('2.3')
282
- shutdown_thread.name = Datadog::Core::Configuration.name
283
- end
281
+ shutdown_thread.name = Datadog::Core::Configuration.name
284
282
 
285
283
  print_message_treshold_seconds = 0.2
286
284
 
@@ -66,7 +66,8 @@ module Datadog
66
66
  def start
67
67
  Utils::AtForkMonkeyPatch.apply!
68
68
 
69
- start_or_update_on_fork(action: :start)
69
+ start_or_update_on_fork(action: :start, tags: tags)
70
+
70
71
  ONLY_ONCE.run do
71
72
  Utils::AtForkMonkeyPatch.at_fork(:child) do
72
73
  # Must NOT reference `self` here, as only the first instance will
@@ -77,8 +78,10 @@ module Datadog
77
78
  end
78
79
  end
79
80
 
80
- def update_on_fork
81
- start_or_update_on_fork(action: :update_on_fork)
81
+ def update_on_fork(settings: Datadog.configuration)
82
+ # Here we pick up the latest settings, so that we pick up any tags that change after forking
83
+ # such as the pid or runtime-id
84
+ start_or_update_on_fork(action: :update_on_fork, tags: TagBuilder.call(settings))
82
85
  end
83
86
 
84
87
  def stop
@@ -92,16 +95,16 @@ module Datadog
92
95
 
93
96
  attr_reader :tags, :agent_base_url, :ld_library_path, :path_to_crashtracking_receiver_binary, :logger
94
97
 
95
- def start_or_update_on_fork(action:)
98
+ def start_or_update_on_fork(action:, tags:)
96
99
  self.class._native_start_or_update_on_fork(
97
100
  action: action,
98
- exporter_configuration: [:agent, agent_base_url],
101
+ agent_base_url: agent_base_url,
99
102
  path_to_crashtracking_receiver_binary: path_to_crashtracking_receiver_binary,
100
103
  ld_library_path: ld_library_path,
101
104
  tags_as_array: tags.to_a,
102
105
  upload_timeout_seconds: 1
103
106
  )
104
- logger.debug("Crash tracking #{action} successfully")
107
+ logger.debug("Crash tracking action: #{action} successful")
105
108
  rescue => e
106
109
  logger.error("Failed to #{action} crash tracking: #{e.message}")
107
110
  end
@@ -25,9 +25,9 @@ module Datadog
25
25
  # 2. Checking if `Net::HTTP` is referring to the original one
26
26
  # => ::Net::HTTP.equal?(::WebMock::HttpLibAdapters::NetHttpAdapter::OriginalNetHTTP)
27
27
  def webmock_enabled?
28
- defined?(::WebMock::HttpLibAdapters::NetHttpAdapter) &&
28
+ !!(defined?(::WebMock::HttpLibAdapters::NetHttpAdapter) &&
29
29
  defined?(::Net::HTTP) &&
30
- ::Net::HTTP.equal?(::WebMock::HttpLibAdapters::NetHttpAdapter.instance_variable_get(:@webMockNetHTTP))
30
+ ::Net::HTTP.equal?(::WebMock::HttpLibAdapters::NetHttpAdapter.instance_variable_get(:@webMockNetHTTP)))
31
31
  end
32
32
 
33
33
  private
@@ -68,7 +68,7 @@ module Datadog
68
68
 
69
69
  # Check if we are running from `bin/cucumber` or `cucumber/rake/task`.
70
70
  def cucumber?
71
- defined?(::Cucumber::Cli)
71
+ !!defined?(::Cucumber::Cli)
72
72
  end
73
73
 
74
74
  # If this is a Rails application, use different heuristics to detect
@@ -80,7 +80,7 @@ module Datadog
80
80
  # detecting its presence is enough to deduct if this is a development environment.
81
81
  #
82
82
  # @see https://github.com/rails/spring/blob/48b299348ace2188444489a0c216a6f3e9687281/README.md?plain=1#L204-L207
83
- defined?(::Spring) || rails_env_development?
83
+ !!defined?(::Spring) || rails_env_development?
84
84
  end
85
85
 
86
86
  RAILS_ENV_DEVELOPMENT = Set['development', 'test'].freeze
@@ -94,7 +94,7 @@ module Datadog
94
94
  # it's common to have a custom "staging" environment, and such environment normally want to run as close
95
95
  # to production as possible.
96
96
  def rails_env_development?
97
- defined?(::Rails.env) && RAILS_ENV_DEVELOPMENT.include?(::Rails.env)
97
+ !!defined?(::Rails.env) && RAILS_ENV_DEVELOPMENT.include?(::Rails.env)
98
98
  end
99
99
  end
100
100
  end
@@ -52,6 +52,11 @@ module Datadog
52
52
  ::RubyVM::YJIT.runtime_stats[:yjit_alloc_size]
53
53
  end
54
54
 
55
+ # Ratio of YJIT-executed instructions
56
+ def ratio_in_yjit
57
+ ::RubyVM::YJIT.runtime_stats[:ratio_in_yjit]
58
+ end
59
+
55
60
  def available?
56
61
  defined?(::RubyVM::YJIT) \
57
62
  && ::RubyVM::YJIT.enabled? \
@@ -2,6 +2,7 @@
2
2
 
3
3
  require_relative '../utils/time'
4
4
  require_relative '../utils/only_once'
5
+ require_relative '../telemetry/logger'
5
6
  require_relative '../configuration/ext'
6
7
 
7
8
  require_relative 'ext'
@@ -100,6 +101,7 @@ module Datadog
100
101
  Datadog.logger.error(
101
102
  "Failed to send count stat. Cause: #{e.class.name} #{e.message} Source: #{Array(e.backtrace).first}"
102
103
  )
104
+ Telemetry::Logger.report(e, description: 'Failed to send count stat')
103
105
  end
104
106
 
105
107
  def distribution(stat, value = nil, options = nil, &block)
@@ -113,6 +115,7 @@ module Datadog
113
115
  Datadog.logger.error(
114
116
  "Failed to send distribution stat. Cause: #{e.class.name} #{e.message} Source: #{Array(e.backtrace).first}"
115
117
  )
118
+ Telemetry::Logger.report(e, description: 'Failed to send distribution stat')
116
119
  end
117
120
 
118
121
  def increment(stat, options = nil)
@@ -125,6 +128,7 @@ module Datadog
125
128
  Datadog.logger.error(
126
129
  "Failed to send increment stat. Cause: #{e.class.name} #{e.message} Source: #{Array(e.backtrace).first}"
127
130
  )
131
+ Telemetry::Logger.report(e, description: 'Failed to send increment stat')
128
132
  end
129
133
 
130
134
  def gauge(stat, value = nil, options = nil, &block)
@@ -138,6 +142,7 @@ module Datadog
138
142
  Datadog.logger.error(
139
143
  "Failed to send gauge stat. Cause: #{e.class.name} #{e.message} Source: #{Array(e.backtrace).first}"
140
144
  )
145
+ Telemetry::Logger.report(e, description: 'Failed to send gauge stat')
141
146
  end
142
147
 
143
148
  def time(stat, options = nil)
@@ -153,9 +158,11 @@ module Datadog
153
158
  distribution(stat, ((finished - start) * 1000), options)
154
159
  end
155
160
  rescue StandardError => e
161
+ # TODO: Likely to be redundant, since `distribution` handles its own errors.
156
162
  Datadog.logger.error(
157
163
  "Failed to send time stat. Cause: #{e.class.name} #{e.message} Source: #{Array(e.backtrace).first}"
158
164
  )
165
+ Telemetry::Logger.report(e, description: 'Failed to send time stat')
159
166
  end
160
167
  end
161
168