datadog 2.3.0 → 2.5.0

Sign up to get free protection for your applications and to get access to all the features.
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