datadog 2.10.0 → 2.12.2

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 (140) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +72 -1
  3. data/ext/datadog_profiling_native_extension/collectors_stack.c +3 -3
  4. data/ext/datadog_profiling_native_extension/collectors_thread_context.c +44 -1
  5. data/ext/datadog_profiling_native_extension/extconf.rb +4 -0
  6. data/ext/datadog_profiling_native_extension/gvl_profiling_helper.c +2 -0
  7. data/ext/datadog_profiling_native_extension/gvl_profiling_helper.h +0 -8
  8. data/ext/datadog_profiling_native_extension/heap_recorder.c +1 -1
  9. data/ext/datadog_profiling_native_extension/private_vm_api_access.c +64 -0
  10. data/ext/datadog_profiling_native_extension/private_vm_api_access.h +7 -0
  11. data/ext/datadog_profiling_native_extension/profiling.c +7 -0
  12. data/ext/libdatadog_api/crashtracker.c +4 -4
  13. data/ext/libdatadog_extconf_helpers.rb +1 -1
  14. data/lib/datadog/appsec/configuration/settings.rb +64 -11
  15. data/lib/datadog/appsec/contrib/active_record/instrumentation.rb +23 -6
  16. data/lib/datadog/appsec/contrib/active_record/patcher.rb +63 -15
  17. data/lib/datadog/appsec/contrib/devise/configuration.rb +76 -0
  18. data/lib/datadog/appsec/contrib/devise/event.rb +4 -7
  19. data/lib/datadog/appsec/contrib/devise/patcher/authenticatable_patch.rb +16 -21
  20. data/lib/datadog/appsec/contrib/devise/patcher/registration_controller_patch.rb +8 -15
  21. data/lib/datadog/appsec/contrib/devise/patcher/rememberable_patch.rb +1 -1
  22. data/lib/datadog/appsec/contrib/devise/patcher.rb +0 -3
  23. data/lib/datadog/appsec/contrib/devise/tracking.rb +1 -1
  24. data/lib/datadog/appsec/contrib/excon/integration.rb +41 -0
  25. data/lib/datadog/appsec/contrib/excon/patcher.rb +28 -0
  26. data/lib/datadog/appsec/contrib/excon/ssrf_detection_middleware.rb +43 -0
  27. data/lib/datadog/appsec/contrib/faraday/connection_patch.rb +22 -0
  28. data/lib/datadog/appsec/contrib/faraday/integration.rb +42 -0
  29. data/lib/datadog/appsec/contrib/faraday/patcher.rb +53 -0
  30. data/lib/datadog/appsec/contrib/faraday/rack_builder_patch.rb +22 -0
  31. data/lib/datadog/appsec/contrib/faraday/ssrf_detection_middleware.rb +42 -0
  32. data/lib/datadog/appsec/contrib/graphql/gateway/watcher.rb +10 -12
  33. data/lib/datadog/appsec/contrib/graphql/patcher.rb +0 -3
  34. data/lib/datadog/appsec/contrib/rack/ext.rb +20 -0
  35. data/lib/datadog/appsec/contrib/rack/gateway/watcher.rb +84 -72
  36. data/lib/datadog/appsec/contrib/rack/patcher.rb +0 -3
  37. data/lib/datadog/appsec/contrib/rack/request_middleware.rb +3 -0
  38. data/lib/datadog/appsec/contrib/rails/gateway/watcher.rb +20 -25
  39. data/lib/datadog/appsec/contrib/rails/patcher.rb +0 -3
  40. data/lib/datadog/appsec/contrib/rest_client/integration.rb +45 -0
  41. data/lib/datadog/appsec/contrib/rest_client/patcher.rb +28 -0
  42. data/lib/datadog/appsec/contrib/rest_client/request_ssrf_detection_patch.rb +39 -0
  43. data/lib/datadog/appsec/contrib/sinatra/gateway/watcher.rb +38 -49
  44. data/lib/datadog/appsec/contrib/sinatra/patcher.rb +0 -3
  45. data/lib/datadog/appsec/instrumentation/gateway/middleware.rb +24 -0
  46. data/lib/datadog/appsec/instrumentation/gateway.rb +17 -22
  47. data/lib/datadog/appsec/monitor/gateway/watcher.rb +19 -25
  48. data/lib/datadog/appsec/processor/rule_merger.rb +2 -1
  49. data/lib/datadog/appsec/remote.rb +11 -0
  50. data/lib/datadog/appsec.rb +3 -0
  51. data/lib/datadog/core/configuration/components.rb +17 -10
  52. data/lib/datadog/core/configuration/ext.rb +1 -1
  53. data/lib/datadog/core/configuration/option_definition.rb +2 -0
  54. data/lib/datadog/core/configuration/settings.rb +22 -6
  55. data/lib/datadog/core/encoding.rb +16 -0
  56. data/lib/datadog/core/environment/agent_info.rb +77 -0
  57. data/lib/datadog/core/metrics/client.rb +9 -8
  58. data/lib/datadog/core/remote/client.rb +5 -4
  59. data/lib/datadog/core/remote/component.rb +14 -12
  60. data/lib/datadog/core/remote/negotiation.rb +1 -1
  61. data/lib/datadog/core/remote/transport/http/api.rb +13 -18
  62. data/lib/datadog/core/remote/transport/http/config.rb +0 -18
  63. data/lib/datadog/core/remote/transport/http/negotiation.rb +1 -18
  64. data/lib/datadog/core/remote/transport/http.rb +6 -40
  65. data/lib/datadog/core/remote/transport/negotiation.rb +13 -1
  66. data/lib/datadog/core/remote/worker.rb +10 -7
  67. data/lib/datadog/core/telemetry/component.rb +5 -1
  68. data/lib/datadog/core/telemetry/event.rb +5 -0
  69. data/lib/datadog/core/telemetry/worker.rb +9 -5
  70. data/lib/datadog/core/transport/http/adapters/unix_socket.rb +1 -1
  71. data/lib/datadog/{tracing → core}/transport/http/api/instance.rb +1 -1
  72. data/lib/datadog/{tracing → core}/transport/http/api/spec.rb +1 -1
  73. data/lib/datadog/{tracing → core}/transport/http/builder.rb +37 -17
  74. data/lib/datadog/core/transport/http.rb +38 -0
  75. data/lib/datadog/core/transport/response.rb +4 -0
  76. data/lib/datadog/core/workers/runtime_metrics.rb +1 -1
  77. data/lib/datadog/di/code_tracker.rb +15 -8
  78. data/lib/datadog/di/component.rb +2 -3
  79. data/lib/datadog/di/configuration/settings.rb +14 -0
  80. data/lib/datadog/di/contrib.rb +2 -0
  81. data/lib/datadog/di/logger.rb +30 -0
  82. data/lib/datadog/di/probe.rb +3 -6
  83. data/lib/datadog/di/probe_manager.rb +5 -2
  84. data/lib/datadog/di/probe_notifier_worker.rb +35 -8
  85. data/lib/datadog/di/remote.rb +3 -3
  86. data/lib/datadog/di/transport/diagnostics.rb +61 -0
  87. data/lib/datadog/di/transport/http/api.rb +52 -0
  88. data/lib/datadog/di/transport/http/client.rb +46 -0
  89. data/lib/datadog/di/transport/http/diagnostics.rb +92 -0
  90. data/lib/datadog/di/transport/http/input.rb +94 -0
  91. data/lib/datadog/di/transport/http.rb +105 -0
  92. data/lib/datadog/di/transport/input.rb +61 -0
  93. data/lib/datadog/di/utils.rb +91 -0
  94. data/lib/datadog/di.rb +5 -1
  95. data/lib/datadog/profiling/component.rb +2 -8
  96. data/lib/datadog/profiling/load_native_extension.rb +1 -33
  97. data/lib/datadog/tracing/component.rb +1 -0
  98. data/lib/datadog/tracing/configuration/ext.rb +1 -0
  99. data/lib/datadog/tracing/contrib/extensions.rb +14 -0
  100. data/lib/datadog/tracing/contrib/graphql/configuration/error_extension_env_parser.rb +21 -0
  101. data/lib/datadog/tracing/contrib/graphql/configuration/settings.rb +11 -0
  102. data/lib/datadog/tracing/contrib/graphql/ext.rb +5 -0
  103. data/lib/datadog/tracing/contrib/graphql/unified_trace.rb +102 -11
  104. data/lib/datadog/tracing/contrib/rack/header_collection.rb +11 -1
  105. data/lib/datadog/tracing/contrib/rack/middlewares.rb +1 -1
  106. data/lib/datadog/tracing/contrib/span_attribute_schema.rb +6 -1
  107. data/lib/datadog/tracing/metadata/metastruct.rb +36 -0
  108. data/lib/datadog/tracing/metadata/metastruct_tagging.rb +42 -0
  109. data/lib/datadog/tracing/metadata.rb +2 -0
  110. data/lib/datadog/tracing/span.rb +10 -1
  111. data/lib/datadog/tracing/span_operation.rb +6 -1
  112. data/lib/datadog/tracing/sync_writer.rb +9 -4
  113. data/lib/datadog/tracing/tracer.rb +15 -7
  114. data/lib/datadog/tracing/transport/http/api.rb +11 -2
  115. data/lib/datadog/tracing/transport/http/traces.rb +0 -3
  116. data/lib/datadog/tracing/transport/http.rb +7 -31
  117. data/lib/datadog/tracing/transport/serializable_trace.rb +11 -5
  118. data/lib/datadog/tracing/transport/traces.rb +25 -8
  119. data/lib/datadog/tracing/workers/trace_writer.rb +10 -3
  120. data/lib/datadog/tracing/workers.rb +5 -4
  121. data/lib/datadog/tracing/writer.rb +12 -4
  122. data/lib/datadog/version.rb +2 -2
  123. metadata +37 -29
  124. data/ext/datadog_profiling_loader/datadog_profiling_loader.c +0 -142
  125. data/ext/datadog_profiling_loader/extconf.rb +0 -60
  126. data/lib/datadog/appsec/contrib/graphql/reactive/multiplex.rb +0 -46
  127. data/lib/datadog/appsec/contrib/patcher.rb +0 -12
  128. data/lib/datadog/appsec/contrib/rack/reactive/request.rb +0 -69
  129. data/lib/datadog/appsec/contrib/rack/reactive/request_body.rb +0 -47
  130. data/lib/datadog/appsec/contrib/rack/reactive/response.rb +0 -53
  131. data/lib/datadog/appsec/contrib/rails/reactive/action.rb +0 -53
  132. data/lib/datadog/appsec/contrib/sinatra/reactive/routed.rb +0 -48
  133. data/lib/datadog/appsec/monitor/reactive/set_user.rb +0 -45
  134. data/lib/datadog/appsec/reactive/address_hash.rb +0 -22
  135. data/lib/datadog/appsec/reactive/engine.rb +0 -47
  136. data/lib/datadog/appsec/reactive/subscriber.rb +0 -19
  137. data/lib/datadog/core/remote/transport/http/api/instance.rb +0 -39
  138. data/lib/datadog/core/remote/transport/http/api/spec.rb +0 -21
  139. data/lib/datadog/core/remote/transport/http/builder.rb +0 -219
  140. data/lib/datadog/di/transport.rb +0 -79
@@ -1,35 +1,29 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative 'gateway/middleware'
4
+
3
5
  module Datadog
4
6
  module AppSec
5
7
  # Instrumentation for AppSec
6
8
  module Instrumentation
7
9
  # Instrumentation gateway implementation
8
10
  class Gateway
9
- # Instrumentation gateway middleware
10
- class Middleware
11
- attr_reader :key, :block
12
-
13
- def initialize(key, &block)
14
- @key = key
15
- @block = block
16
- end
17
-
18
- def call(stack, env)
19
- @block.call(stack, env)
20
- end
21
- end
22
-
23
- private_constant :Middleware
24
-
25
11
  def initialize
26
12
  @middlewares = Hash.new { |h, k| h[k] = [] }
13
+ @pushed_events = {}
27
14
  end
28
15
 
16
+ # NOTE: Be careful with pushed names because every pushed event name
17
+ # is recorded in order to provide an ability to any subscriber
18
+ # to check wether an arbitrary event had happened.
19
+ #
20
+ # WARNING: If we start pushing generated names we should consider
21
+ # limiting the storage of pushed names.
29
22
  def push(name, env, &block)
30
- block ||= -> {}
23
+ @pushed_events[name] = true
31
24
 
32
- middlewares_for_name = middlewares[name]
25
+ block ||= -> {}
26
+ middlewares_for_name = @middlewares[name]
33
27
 
34
28
  return [block.call, nil] if middlewares_for_name.empty?
35
29
 
@@ -48,14 +42,15 @@ module Datadog
48
42
  end
49
43
 
50
44
  def watch(name, key, &block)
51
- @middlewares[name] << Middleware.new(key, &block) unless middlewares[name].any? { |m| m.key == key }
45
+ @middlewares[name] << Middleware.new(key, &block) unless @middlewares[name].any? { |m| m.key == key }
52
46
  end
53
47
 
54
- private
55
-
56
- attr_reader :middlewares
48
+ def pushed?(name)
49
+ @pushed_events.key?(name)
50
+ end
57
51
  end
58
52
 
53
+ # NOTE: This left as-is and will be depricated soon.
59
54
  def self.gateway
60
55
  @gateway ||= Gateway.new # TODO: not thread safe
61
56
  end
@@ -1,8 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative '../../instrumentation/gateway'
4
- require_relative '../../reactive/engine'
5
- require_relative '../reactive/set_user'
6
4
 
7
5
  module Datadog
8
6
  module AppSec
@@ -19,31 +17,27 @@ module Datadog
19
17
 
20
18
  def watch_user_id(gateway = Instrumentation.gateway)
21
19
  gateway.watch('identity.set_user', :appsec) do |stack, user|
22
- event = nil
23
20
  context = Datadog::AppSec.active_context
24
- engine = AppSec::Reactive::Engine.new
25
-
26
- Monitor::Reactive::SetUser.subscribe(engine, context) do |result|
27
- if result.match?
28
- # TODO: should this hash be an Event instance instead?
29
- event = {
30
- waf_result: result,
31
- trace: context.trace,
32
- span: context.span,
33
- user: user,
34
- actions: result.actions
35
- }
36
-
37
- # We want to keep the trace in case of security event
38
- context.trace.keep! if context.trace
39
- Datadog::AppSec::Event.tag_and_keep!(context, result)
40
- context.events << event
41
-
42
- Datadog::AppSec::ActionsHandler.handle(result.actions)
43
- end
44
- end
45
21
 
46
- Monitor::Reactive::SetUser.publish(engine, user)
22
+ persistent_data = {
23
+ 'usr.id' => user.id
24
+ }
25
+
26
+ result = context.run_waf(persistent_data, {}, Datadog.configuration.appsec.waf_timeout)
27
+
28
+ if result.match?
29
+ Datadog::AppSec::Event.tag_and_keep!(context, result)
30
+
31
+ context.events << {
32
+ waf_result: result,
33
+ trace: context.trace,
34
+ span: context.span,
35
+ user: user,
36
+ actions: result.actions
37
+ }
38
+
39
+ Datadog::AppSec::ActionsHandler.handle(result.actions)
40
+ end
47
41
 
48
42
  stack.call(user)
49
43
  end
@@ -22,7 +22,7 @@ module Datadog
22
22
  # TODO: `processors` and `scanners` are not provided by the caller, consider removing them
23
23
  def merge(
24
24
  telemetry:,
25
- rules:, data: [], overrides: [], exclusions: [], custom_rules: [],
25
+ rules:, actions: [], data: [], overrides: [], exclusions: [], custom_rules: [],
26
26
  processors: nil, scanners: nil
27
27
  )
28
28
  processors ||= begin
@@ -54,6 +54,7 @@ module Datadog
54
54
  combined_exclusions = combine_exclusions(exclusions) if exclusions.any?
55
55
  combined_custom_rules = combine_custom_rules(custom_rules) if custom_rules.any?
56
56
 
57
+ combined_rules['actions'] = actions if actions.any?
57
58
  combined_rules['rules_data'] = combined_data if combined_data
58
59
  combined_rules['rules_override'] = combined_overrides if combined_overrides
59
60
  combined_rules['exclusions'] = combined_exclusions if combined_exclusions
@@ -53,10 +53,12 @@ module Datadog
53
53
  end
54
54
 
55
55
  # rubocop:disable Metrics/MethodLength
56
+ # rubocop:disable Metrics/CyclomaticComplexity
56
57
  def receivers(telemetry)
57
58
  return [] unless remote_features_enabled?
58
59
 
59
60
  matcher = Core::Remote::Dispatcher::Matcher::Product.new(ASM_PRODUCTS)
61
+ # rubocop:disable Metrics/BlockLength
60
62
  receiver = Core::Remote::Dispatcher::Receiver.new(matcher) do |repository, changes|
61
63
  changes.each do |change|
62
64
  Datadog.logger.debug { "remote config change: '#{change.path}'" }
@@ -67,6 +69,7 @@ module Datadog
67
69
  data = []
68
70
  overrides = []
69
71
  exclusions = []
72
+ actions = []
70
73
 
71
74
  repository.contents.each do |content|
72
75
  parsed_content = parse_content(content)
@@ -80,6 +83,7 @@ module Datadog
80
83
  overrides << parsed_content['rules_override'] if parsed_content['rules_override']
81
84
  exclusions << parsed_content['exclusions'] if parsed_content['exclusions']
82
85
  custom_rules << parsed_content['custom_rules'] if parsed_content['custom_rules']
86
+ actions.concat(parsed_content['actions']) if parsed_content['actions']
83
87
  end
84
88
  end
85
89
 
@@ -97,6 +101,7 @@ module Datadog
97
101
  ruleset = AppSec::Processor::RuleMerger.merge(
98
102
  rules: rules,
99
103
  data: data,
104
+ actions: actions,
100
105
  overrides: overrides,
101
106
  exclusions: exclusions,
102
107
  custom_rules: custom_rules,
@@ -104,11 +109,17 @@ module Datadog
104
109
  )
105
110
 
106
111
  Datadog::AppSec.reconfigure(ruleset: ruleset, telemetry: telemetry)
112
+
113
+ repository.contents.each do |content|
114
+ content.applied if ASM_PRODUCTS.include?(content.path.product)
115
+ end
107
116
  end
117
+ # rubocop:enable Metrics/BlockLength
108
118
 
109
119
  [receiver]
110
120
  end
111
121
  # rubocop:enable Metrics/MethodLength
122
+ # rubocop:enable Metrics/CyclomaticComplexity
112
123
 
113
124
  private
114
125
 
@@ -68,5 +68,8 @@ require_relative 'appsec/contrib/rails/integration'
68
68
  require_relative 'appsec/contrib/active_record/integration'
69
69
  require_relative 'appsec/contrib/devise/integration'
70
70
  require_relative 'appsec/contrib/graphql/integration'
71
+ require_relative 'appsec/contrib/faraday/integration'
72
+ require_relative 'appsec/contrib/excon/integration'
73
+ require_relative 'appsec/contrib/rest_client/integration'
71
74
 
72
75
  require_relative 'appsec/autoload'
@@ -16,6 +16,8 @@ require_relative '../../appsec/component'
16
16
  require_relative '../../di/component'
17
17
  require_relative '../crashtracking/component'
18
18
 
19
+ require_relative '../environment/agent_info'
20
+
19
21
  module Datadog
20
22
  module Core
21
23
  module Configuration
@@ -24,12 +26,12 @@ module Datadog
24
26
  class << self
25
27
  include Datadog::Tracing::Component
26
28
 
27
- def build_health_metrics(settings)
29
+ def build_health_metrics(settings, logger)
28
30
  settings = settings.health_metrics
29
31
  options = { enabled: settings.enabled }
30
32
  options[:statsd] = settings.statsd unless settings.statsd.nil?
31
33
 
32
- Core::Diagnostics::Health::Metrics.new(**options)
34
+ Core::Diagnostics::Health::Metrics.new(logger: logger, **options)
33
35
  end
34
36
 
35
37
  def build_logger(settings)
@@ -39,19 +41,20 @@ module Datadog
39
41
  logger
40
42
  end
41
43
 
42
- def build_runtime_metrics(settings)
44
+ def build_runtime_metrics(settings, logger)
43
45
  options = { enabled: settings.runtime_metrics.enabled }
44
46
  options[:statsd] = settings.runtime_metrics.statsd unless settings.runtime_metrics.statsd.nil?
45
47
  options[:services] = [settings.service] unless settings.service.nil?
46
48
 
47
- Core::Runtime::Metrics.new(**options)
49
+ Core::Runtime::Metrics.new(logger: logger, **options)
48
50
  end
49
51
 
50
- def build_runtime_metrics_worker(settings)
52
+ def build_runtime_metrics_worker(settings, logger)
51
53
  # NOTE: Should we just ignore building the worker if its not enabled?
52
54
  options = settings.runtime_metrics.opts.merge(
53
55
  enabled: settings.runtime_metrics.enabled,
54
- metrics: build_runtime_metrics(settings)
56
+ metrics: build_runtime_metrics(settings, logger),
57
+ logger: logger,
55
58
  )
56
59
 
57
60
  Core::Workers::RuntimeMetrics.new(options)
@@ -85,7 +88,8 @@ module Datadog
85
88
  :tracer,
86
89
  :crashtracker,
87
90
  :dynamic_instrumentation,
88
- :appsec
91
+ :appsec,
92
+ :agent_info
89
93
 
90
94
  def initialize(settings)
91
95
  @logger = self.class.build_logger(settings)
@@ -96,9 +100,12 @@ module Datadog
96
100
  # the Core resolver from within your product/component's namespace.
97
101
  agent_settings = AgentSettingsResolver.call(settings, logger: @logger)
98
102
 
103
+ # Exposes agent capability information for detection by any components
104
+ @agent_info = Core::Environment::AgentInfo.new(agent_settings)
105
+
99
106
  @telemetry = self.class.build_telemetry(settings, agent_settings, @logger)
100
107
 
101
- @remote = Remote::Component.build(settings, agent_settings, telemetry: telemetry)
108
+ @remote = Remote::Component.build(settings, agent_settings, logger: @logger, telemetry: telemetry)
102
109
  @tracer = self.class.build_tracer(settings, agent_settings, logger: @logger)
103
110
  @crashtracker = self.class.build_crashtracker(settings, agent_settings, logger: @logger)
104
111
 
@@ -110,8 +117,8 @@ module Datadog
110
117
  )
111
118
  @environment_logger_extra.merge!(profiler_logger_extra) if profiler_logger_extra
112
119
 
113
- @runtime_metrics = self.class.build_runtime_metrics_worker(settings)
114
- @health_metrics = self.class.build_health_metrics(settings)
120
+ @runtime_metrics = self.class.build_runtime_metrics_worker(settings, @logger)
121
+ @health_metrics = self.class.build_health_metrics(settings, @logger)
115
122
  @appsec = Datadog::AppSec::Component.build_appsec_component(settings, telemetry: telemetry)
116
123
  @dynamic_instrumentation = Datadog::DI::Component.build(settings, agent_settings, @logger, telemetry: telemetry)
117
124
  @environment_logger_extra[:dynamic_instrumentation_enabled] = !!@dynamic_instrumentation
@@ -37,7 +37,7 @@ module Datadog
37
37
  module UnixSocket
38
38
  ADAPTER = :unix
39
39
  DEFAULT_PATH = '/var/run/datadog/apm.socket'
40
- DEFAULT_TIMEOUT_SECONDS = 1
40
+ DEFAULT_TIMEOUT_SECONDS = 30
41
41
  end
42
42
  end
43
43
  end
@@ -79,6 +79,8 @@ module Datadog
79
79
  @deprecated_env = value
80
80
  end
81
81
 
82
+ # Invoked when the option is first read, and {#env} is defined.
83
+ # The block provided is only invoked if the environment variable is present (not-nil).
82
84
  def env_parser(&block)
83
85
  @env_parser = block
84
86
  end
@@ -461,15 +461,31 @@ module Datadog
461
461
  end
462
462
  end
463
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`
464
+ # @deprecated Use {:gvl_enabled} instead.
469
465
  option :preview_gvl_enabled do |o|
470
466
  o.type :bool
471
- o.env 'DD_PROFILING_PREVIEW_GVL_ENABLED'
472
467
  o.default false
468
+ o.after_set do |_, _, precedence|
469
+ unless precedence == Datadog::Core::Configuration::Option::Precedence::DEFAULT
470
+ Datadog.logger.warn(
471
+ 'The profiling.advanced.preview_gvl_enabled setting has been deprecated for removal and ' \
472
+ 'no longer does anything. Please remove it from your Datadog.configure block. ' \
473
+ 'GVL profiling is now controlled by the profiling.advanced.gvl_enabled setting instead.'
474
+ )
475
+ end
476
+ end
477
+ end
478
+
479
+ # Controls GVL profiling. This will show when threads are waiting for GVL in the timeline view.
480
+ #
481
+ # This feature requires Ruby 3.2+.
482
+ #
483
+ # @default `DD_PROFILING_GVL_ENABLED` environment variable as a boolean, otherwise `true`
484
+ option :gvl_enabled do |o|
485
+ o.type :bool
486
+ o.deprecated_env 'DD_PROFILING_PREVIEW_GVL_ENABLED'
487
+ o.env 'DD_PROFILING_GVL_ENABLED'
488
+ o.default true
473
489
  end
474
490
 
475
491
  # Controls the smallest time period the profiler will report a thread waiting for the GVL.
@@ -10,6 +10,7 @@ module Datadog
10
10
  # Encoder interface that provides the logic to encode traces and service
11
11
  # @abstract
12
12
  module Encoder
13
+ # :nocov:
13
14
  def content_type
14
15
  raise NotImplementedError
15
16
  end
@@ -23,6 +24,13 @@ module Datadog
23
24
  def encode(_)
24
25
  raise NotImplementedError
25
26
  end
27
+
28
+ # Deserializes a value serialized with {#encode}.
29
+ # This method is used for debugging purposes.
30
+ def decode(_)
31
+ raise NotImplementedError
32
+ end
33
+ # :nocov:
26
34
  end
27
35
 
28
36
  # Encoder for the JSON format
@@ -41,6 +49,10 @@ module Datadog
41
49
  JSON.dump(obj)
42
50
  end
43
51
 
52
+ def decode(obj)
53
+ JSON.parse(obj)
54
+ end
55
+
44
56
  def join(encoded_data)
45
57
  "[#{encoded_data.join(',')}]"
46
58
  end
@@ -62,6 +74,10 @@ module Datadog
62
74
  MessagePack.pack(obj)
63
75
  end
64
76
 
77
+ def decode(obj)
78
+ MessagePack.unpack(obj)
79
+ end
80
+
65
81
  def join(encoded_data)
66
82
  packer = MessagePack::Packer.new
67
83
  packer.write_array_header(encoded_data.size)
@@ -0,0 +1,77 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Datadog
4
+ module Core
5
+ module Environment
6
+ # Retrieves the agent's `/info` endpoint data.
7
+ # This data can be used to determine the capabilities of the local Datadog agent.
8
+ #
9
+ # @example Example response payload
10
+ # {
11
+ # "version" : "7.57.2",
12
+ # "git_commit" : "38ba0c7",
13
+ # "endpoints" : [ "/v0.4/traces", "/v0.4/services", "/v0.7/traces", "/v0.7/config" ],
14
+ # "client_drop_p0s" : true,
15
+ # "span_meta_structs" : true,
16
+ # "long_running_spans" : true,
17
+ # "evp_proxy_allowed_headers" : [ "Content-Type", "Accept-Encoding", "Content-Encoding", "User-Agent" ],
18
+ # "config" : {
19
+ # "default_env" : "none",
20
+ # "target_tps" : 10,
21
+ # "max_eps" : 200,
22
+ # "receiver_port" : 8126,
23
+ # "receiver_socket" : "/var/run/datadog/apm.socket",
24
+ # "connection_limit" : 0,
25
+ # "receiver_timeout" : 0,
26
+ # "max_request_bytes" : 26214400,
27
+ # "statsd_port" : 8125,
28
+ # "analyzed_spans_by_service" : { },
29
+ # "obfuscation" : {
30
+ # "elastic_search" : true,
31
+ # "mongo" : true,
32
+ # "sql_exec_plan" : false,
33
+ # "sql_exec_plan_normalize" : false,
34
+ # "http" : {
35
+ # "remove_query_string" : false,
36
+ # "remove_path_digits" : false
37
+ # },
38
+ # "remove_stack_traces" : false,
39
+ # "redis" : {
40
+ # "Enabled" : true,
41
+ # "RemoveAllArgs" : false
42
+ # },
43
+ # "memcached" : {
44
+ # "Enabled" : true,
45
+ # "KeepCommand" : false
46
+ # }
47
+ # }
48
+ # },
49
+ # "peer_tags" : null
50
+ # }
51
+ #
52
+ # @see https://github.com/DataDog/datadog-agent/blob/f07df0a3c1fca0c83b5a15f553bd994091b0c8ac/pkg/trace/api/info.go#L20
53
+ class AgentInfo
54
+ attr_reader :agent_settings
55
+
56
+ def initialize(agent_settings)
57
+ @agent_settings = agent_settings
58
+ @client = Remote::Transport::HTTP.root(agent_settings: agent_settings)
59
+ end
60
+
61
+ # Fetches the information from the agent.
62
+ # @return [Datadog::Core::Remote::Transport::HTTP::Negotiation::Response] the response from the agent
63
+ # @return [nil] if an error occurred while fetching the information
64
+ def fetch
65
+ res = @client.send_info
66
+ return unless res.ok?
67
+
68
+ res
69
+ end
70
+
71
+ def ==(other)
72
+ other.is_a?(self.class) && other.agent_settings == agent_settings
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end
@@ -21,9 +21,10 @@ module Datadog
21
21
  extend Options
22
22
  extend Helpers
23
23
 
24
- attr_reader :statsd
24
+ attr_reader :statsd, :logger
25
25
 
26
- def initialize(statsd: nil, enabled: true, **_)
26
+ def initialize(logger:, statsd: nil, enabled: true, **_)
27
+ @logger = logger
27
28
  @statsd =
28
29
  if supported?
29
30
  statsd || default_statsd_client
@@ -98,7 +99,7 @@ module Datadog
98
99
 
99
100
  statsd.count(stat, value, metric_options(options))
100
101
  rescue StandardError => e
101
- Datadog.logger.error(
102
+ logger.error(
102
103
  "Failed to send count stat. Cause: #{e.class.name} #{e.message} Source: #{Array(e.backtrace).first}"
103
104
  )
104
105
  Telemetry::Logger.report(e, description: 'Failed to send count stat')
@@ -112,7 +113,7 @@ module Datadog
112
113
 
113
114
  statsd.distribution(stat, value, metric_options(options))
114
115
  rescue StandardError => e
115
- Datadog.logger.error(
116
+ logger.error(
116
117
  "Failed to send distribution stat. Cause: #{e.class.name} #{e.message} Source: #{Array(e.backtrace).first}"
117
118
  )
118
119
  Telemetry::Logger.report(e, description: 'Failed to send distribution stat')
@@ -125,7 +126,7 @@ module Datadog
125
126
 
126
127
  statsd.increment(stat, metric_options(options))
127
128
  rescue StandardError => e
128
- Datadog.logger.error(
129
+ logger.error(
129
130
  "Failed to send increment stat. Cause: #{e.class.name} #{e.message} Source: #{Array(e.backtrace).first}"
130
131
  )
131
132
  Telemetry::Logger.report(e, description: 'Failed to send increment stat')
@@ -139,7 +140,7 @@ module Datadog
139
140
 
140
141
  statsd.gauge(stat, value, metric_options(options))
141
142
  rescue StandardError => e
142
- Datadog.logger.error(
143
+ logger.error(
143
144
  "Failed to send gauge stat. Cause: #{e.class.name} #{e.message} Source: #{Array(e.backtrace).first}"
144
145
  )
145
146
  Telemetry::Logger.report(e, description: 'Failed to send gauge stat')
@@ -159,7 +160,7 @@ module Datadog
159
160
  end
160
161
  rescue StandardError => e
161
162
  # TODO: Likely to be redundant, since `distribution` handles its own errors.
162
- Datadog.logger.error(
163
+ logger.error(
163
164
  "Failed to send time stat. Cause: #{e.class.name} #{e.message} Source: #{Array(e.backtrace).first}"
164
165
  )
165
166
  Telemetry::Logger.report(e, description: 'Failed to send time stat')
@@ -194,7 +195,7 @@ module Datadog
194
195
 
195
196
  def ignored_statsd_warning
196
197
  IGNORED_STATSD_ONLY_ONCE.run do
197
- Datadog.logger.warn(
198
+ logger.warn(
198
199
  'Ignoring user-supplied statsd instance as currently-installed version of dogstastd-ruby is incompatible. ' \
199
200
  "To fix this, ensure that you have `gem 'dogstatsd-ruby', '~> 5.3'` on your Gemfile or gems.rb file."
200
201
  )
@@ -13,10 +13,11 @@ module Datadog
13
13
  class TransportError < StandardError; end
14
14
  class SyncError < StandardError; end
15
15
 
16
- attr_reader :transport, :repository, :id, :dispatcher
16
+ attr_reader :transport, :repository, :id, :dispatcher, :logger
17
17
 
18
- def initialize(transport, capabilities, repository: Configuration::Repository.new)
18
+ def initialize(transport, capabilities, logger:, repository: Configuration::Repository.new)
19
19
  @transport = transport
20
+ @logger = logger
20
21
 
21
22
  @repository = repository
22
23
  @id = SecureRandom.uuid
@@ -40,7 +41,7 @@ module Datadog
40
41
  def process_response(response)
41
42
  # when response is completely empty, do nothing as in: leave as is
42
43
  if response.empty?
43
- Datadog.logger.debug { 'remote: empty response => NOOP' }
44
+ logger.debug { 'remote: empty response => NOOP' }
44
45
 
45
46
  return
46
47
  end
@@ -112,7 +113,7 @@ module Datadog
112
113
  end
113
114
 
114
115
  if changes.empty?
115
- Datadog.logger.debug { 'remote: no changes' }
116
+ logger.debug { 'remote: no changes' }
116
117
  else
117
118
  dispatcher.dispatch(changes, repository)
118
119
  end
@@ -13,22 +13,24 @@ module Datadog
13
13
  # Configures the HTTP transport to communicate with the agent
14
14
  # to fetch and sync the remote configuration
15
15
  class Component
16
- attr_reader :client, :healthy
16
+ attr_reader :logger, :client, :healthy
17
+
18
+ def initialize(settings, capabilities, agent_settings, logger:)
19
+ @logger = logger
17
20
 
18
- def initialize(settings, capabilities, agent_settings)
19
21
  transport_options = {}
20
22
  transport_options[:agent_settings] = agent_settings if agent_settings
21
23
 
22
24
  negotiation = Negotiation.new(settings, agent_settings)
23
- transport_v7 = Datadog::Core::Remote::Transport::HTTP.v7(**transport_options.dup)
25
+ transport_v7 = Datadog::Core::Remote::Transport::HTTP.v7(**transport_options) # steep:ignore
24
26
 
25
27
  @barrier = Barrier.new(settings.remote.boot_timeout_seconds)
26
28
 
27
- @client = Client.new(transport_v7, capabilities)
29
+ @client = Client.new(transport_v7, capabilities, logger: logger)
28
30
  @healthy = false
29
- Datadog.logger.debug { "new remote configuration client: #{@client.id}" }
31
+ logger.debug { "new remote configuration client: #{@client.id}" }
30
32
 
31
- @worker = Worker.new(interval: settings.remote.poll_interval_seconds) do
33
+ @worker = Worker.new(interval: settings.remote.poll_interval_seconds, logger: logger) do
32
34
  unless @healthy || negotiation.endpoint?('/v0.7/config')
33
35
  @barrier.lift
34
36
 
@@ -40,7 +42,7 @@ module Datadog
40
42
  @healthy ||= true
41
43
  rescue Client::SyncError => e
42
44
  # Transient errors due to network or agent. Logged the error but not via telemetry
43
- Datadog.logger.error do
45
+ logger.error do
44
46
  "remote worker client sync error: #{e.message} location: #{Array(e.backtrace).first}. skipping sync"
45
47
  end
46
48
  rescue StandardError => e
@@ -50,15 +52,15 @@ module Datadog
50
52
  negotiation = Negotiation.new(settings, agent_settings)
51
53
 
52
54
  # Transient errors due to network or agent. Logged the error but not via telemetry
53
- Datadog.logger.error do
55
+ logger.error do
54
56
  "remote worker error: #{e.class.name} #{e.message} location: #{Array(e.backtrace).first}. "\
55
57
  'reseting client state'
56
58
  end
57
59
 
58
60
  # client state is unknown, state might be corrupted
59
- @client = Client.new(transport_v7, capabilities)
61
+ @client = Client.new(transport_v7, capabilities, logger: logger)
60
62
  @healthy = false
61
- Datadog.logger.debug { "new remote configuration client: #{@client.id}" }
63
+ logger.debug { "new remote configuration client: #{@client.id}" }
62
64
 
63
65
  # TODO: bail out if too many errors?
64
66
  end
@@ -152,10 +154,10 @@ module Datadog
152
154
  #
153
155
  # Those checks are instead performed inside the worker loop.
154
156
  # This allows users to upgrade their agent while keeping their application running.
155
- def build(settings, agent_settings, telemetry:)
157
+ def build(settings, agent_settings, logger:, telemetry:)
156
158
  return unless settings.remote.enabled
157
159
 
158
- new(settings, Client::Capabilities.new(settings, telemetry), agent_settings)
160
+ new(settings, Client::Capabilities.new(settings, telemetry), agent_settings, logger: logger)
159
161
  end
160
162
  end
161
163
  end
@@ -11,7 +11,7 @@ module Datadog
11
11
  transport_options = {}
12
12
  transport_options[:agent_settings] = agent_settings if agent_settings
13
13
 
14
- @transport_root = Datadog::Core::Remote::Transport::HTTP.root(**transport_options.dup)
14
+ @transport_root = Datadog::Core::Remote::Transport::HTTP.root(**transport_options) # steep:ignore
15
15
  @logged = suppress_logging
16
16
  end
17
17