datadog 2.20.0 → 2.22.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 (109) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +73 -1
  3. data/README.md +0 -1
  4. data/ext/LIBDATADOG_DEVELOPMENT.md +60 -0
  5. data/ext/datadog_profiling_native_extension/collectors_discrete_dynamic_sampler.c +1 -1
  6. data/ext/libdatadog_api/ddsketch.c +106 -0
  7. data/ext/libdatadog_api/init.c +3 -0
  8. data/ext/libdatadog_api/library_config.c +35 -27
  9. data/ext/libdatadog_api/process_discovery.c +24 -18
  10. data/ext/libdatadog_extconf_helpers.rb +1 -1
  11. data/lib/datadog/appsec/api_security/endpoint_collection/grape_route_serializer.rb +26 -0
  12. data/lib/datadog/appsec/api_security/endpoint_collection/rails_collector.rb +59 -0
  13. data/lib/datadog/appsec/api_security/endpoint_collection/rails_route_serializer.rb +29 -0
  14. data/lib/datadog/appsec/api_security/endpoint_collection/sinatra_route_serializer.rb +26 -0
  15. data/lib/datadog/appsec/api_security/endpoint_collection.rb +10 -0
  16. data/lib/datadog/appsec/api_security/route_extractor.rb +6 -2
  17. data/lib/datadog/appsec/assets/waf_rules/README.md +30 -36
  18. data/lib/datadog/appsec/assets/waf_rules/recommended.json +359 -4
  19. data/lib/datadog/appsec/assets/waf_rules/strict.json +43 -2
  20. data/lib/datadog/appsec/autoload.rb +1 -1
  21. data/lib/datadog/appsec/compressed_json.rb +1 -1
  22. data/lib/datadog/appsec/configuration/settings.rb +9 -0
  23. data/lib/datadog/appsec/contrib/active_record/instrumentation.rb +3 -1
  24. data/lib/datadog/appsec/contrib/excon/ssrf_detection_middleware.rb +3 -2
  25. data/lib/datadog/appsec/contrib/faraday/ssrf_detection_middleware.rb +3 -1
  26. data/lib/datadog/appsec/contrib/graphql/gateway/watcher.rb +3 -1
  27. data/lib/datadog/appsec/contrib/rack/gateway/watcher.rb +9 -4
  28. data/lib/datadog/appsec/contrib/rack/request_middleware.rb +5 -1
  29. data/lib/datadog/appsec/contrib/rails/gateway/watcher.rb +7 -2
  30. data/lib/datadog/appsec/contrib/rails/patcher.rb +30 -0
  31. data/lib/datadog/appsec/contrib/rest_client/request_ssrf_detection_patch.rb +3 -1
  32. data/lib/datadog/appsec/contrib/sinatra/gateway/watcher.rb +10 -4
  33. data/lib/datadog/appsec/event.rb +12 -14
  34. data/lib/datadog/appsec/metrics/collector.rb +19 -3
  35. data/lib/datadog/appsec/metrics/telemetry_exporter.rb +2 -1
  36. data/lib/datadog/appsec/monitor/gateway/watcher.rb +4 -4
  37. data/lib/datadog/appsec/remote.rb +25 -13
  38. data/lib/datadog/appsec/security_engine/result.rb +28 -9
  39. data/lib/datadog/appsec/security_engine/runner.rb +17 -7
  40. data/lib/datadog/appsec/security_event.rb +5 -7
  41. data/lib/datadog/core/configuration/agent_settings_resolver.rb +4 -4
  42. data/lib/datadog/core/configuration/components.rb +22 -8
  43. data/lib/datadog/core/configuration/config_helper.rb +100 -0
  44. data/lib/datadog/core/configuration/deprecations.rb +36 -0
  45. data/lib/datadog/core/configuration/ext.rb +0 -1
  46. data/lib/datadog/core/configuration/option.rb +38 -43
  47. data/lib/datadog/core/configuration/option_definition.rb +0 -9
  48. data/lib/datadog/core/configuration/options.rb +1 -5
  49. data/lib/datadog/core/configuration/settings.rb +10 -6
  50. data/lib/datadog/core/configuration/stable_config.rb +10 -0
  51. data/lib/datadog/core/configuration/supported_configurations.rb +337 -0
  52. data/lib/datadog/core/configuration.rb +2 -2
  53. data/lib/datadog/core/ddsketch.rb +21 -0
  54. data/lib/datadog/core/deprecations.rb +2 -2
  55. data/lib/datadog/core/environment/ext.rb +0 -2
  56. data/lib/datadog/core/environment/git.rb +2 -2
  57. data/lib/datadog/core/environment/variable_helpers.rb +3 -3
  58. data/lib/datadog/core/environment/yjit.rb +2 -1
  59. data/lib/datadog/core/metrics/client.rb +2 -2
  60. data/lib/datadog/core/pin.rb +4 -8
  61. data/lib/datadog/core/process_discovery/tracer_memfd.rb +2 -4
  62. data/lib/datadog/core/process_discovery.rb +48 -23
  63. data/lib/datadog/core/remote/component.rb +4 -6
  64. data/lib/datadog/core/runtime/ext.rb +0 -1
  65. data/lib/datadog/core/telemetry/component.rb +11 -0
  66. data/lib/datadog/core/telemetry/emitter.rb +6 -6
  67. data/lib/datadog/core/telemetry/event/app_endpoints_loaded.rb +30 -0
  68. data/lib/datadog/core/telemetry/event/app_started.rb +2 -2
  69. data/lib/datadog/core/telemetry/event.rb +1 -0
  70. data/lib/datadog/core/transport/response.rb +4 -1
  71. data/lib/datadog/core/utils/network.rb +19 -0
  72. data/lib/datadog/core.rb +2 -0
  73. data/lib/datadog/di/boot.rb +5 -3
  74. data/lib/datadog/di/component.rb +14 -0
  75. data/lib/datadog/di/context.rb +70 -0
  76. data/lib/datadog/di/el/compiler.rb +164 -0
  77. data/lib/datadog/di/el/evaluator.rb +159 -0
  78. data/lib/datadog/di/el/expression.rb +42 -0
  79. data/lib/datadog/di/el.rb +5 -0
  80. data/lib/datadog/di/error.rb +25 -0
  81. data/lib/datadog/di/instrumenter.rb +101 -32
  82. data/lib/datadog/di/probe.rb +35 -15
  83. data/lib/datadog/di/probe_builder.rb +39 -1
  84. data/lib/datadog/di/probe_file_loader.rb +1 -1
  85. data/lib/datadog/di/probe_manager.rb +3 -2
  86. data/lib/datadog/di/probe_notification_builder.rb +50 -51
  87. data/lib/datadog/di/serializer.rb +151 -7
  88. data/lib/datadog/opentelemetry/sdk/configurator.rb +1 -1
  89. data/lib/datadog/profiling/collectors/info.rb +1 -1
  90. data/lib/datadog/profiling/ext.rb +2 -1
  91. data/lib/datadog/profiling/http_transport.rb +1 -1
  92. data/lib/datadog/profiling/tasks/exec.rb +2 -2
  93. data/lib/datadog/tracing/component.rb +6 -17
  94. data/lib/datadog/tracing/configuration/dynamic.rb +2 -2
  95. data/lib/datadog/tracing/configuration/ext.rb +0 -3
  96. data/lib/datadog/tracing/configuration/settings.rb +15 -10
  97. data/lib/datadog/tracing/contrib/component.rb +2 -2
  98. data/lib/datadog/tracing/contrib/graphql/configuration/settings.rb +7 -0
  99. data/lib/datadog/tracing/contrib/graphql/ext.rb +1 -0
  100. data/lib/datadog/tracing/contrib/graphql/unified_trace.rb +63 -27
  101. data/lib/datadog/tracing/contrib/rack/request_queue.rb +1 -0
  102. data/lib/datadog/tracing/contrib/rack/trace_proxy_middleware.rb +7 -1
  103. data/lib/datadog/tracing/contrib/rails/ext.rb +2 -1
  104. data/lib/datadog/tracing/contrib/rails/integration.rb +1 -1
  105. data/lib/datadog/tracing/contrib/span_attribute_schema.rb +1 -1
  106. data/lib/datadog/tracing/metadata/ext.rb +8 -0
  107. data/lib/datadog/version.rb +1 -1
  108. metadata +25 -9
  109. data/ext/libdatadog_api/macos_development.md +0 -26
@@ -3,7 +3,7 @@
3
3
  module Datadog
4
4
  module AppSec
5
5
  # A class that represents a security event of any kind. It could be an event
6
- # representing an attack or fingerprinting results as derivatives or an API
6
+ # representing an attack or fingerprinting results as attributes or an API
7
7
  # security check with extracted schema.
8
8
  class SecurityEvent
9
9
  SCHEMA_KEY_PREFIX = '_dd.appsec.s.'
@@ -17,22 +17,20 @@ module Datadog
17
17
  @span = span
18
18
  end
19
19
 
20
- def attack?
21
- return @is_attack if defined?(@is_attack)
22
-
23
- @is_attack = @waf_result.is_a?(SecurityEngine::Result::Match)
20
+ def keep?
21
+ @waf_result.keep?
24
22
  end
25
23
 
26
24
  def schema?
27
25
  return @has_schema if defined?(@has_schema)
28
26
 
29
- @has_schema = @waf_result.derivatives.any? { |name, _| name.start_with?(SCHEMA_KEY_PREFIX) }
27
+ @has_schema = @waf_result.attributes.any? { |name, _| name.start_with?(SCHEMA_KEY_PREFIX) }
30
28
  end
31
29
 
32
30
  def fingerprint?
33
31
  return @has_fingerprint if defined?(@has_fingerprint)
34
32
 
35
- @has_fingerprint = @waf_result.derivatives.any? { |name, _| name.start_with?(FINGERPRINT_KEY_PREFIX) }
33
+ @has_fingerprint = @waf_result.attributes.any? { |name, _| name.start_with?(FINGERPRINT_KEY_PREFIX) }
36
34
  end
37
35
  end
38
36
  end
@@ -68,7 +68,7 @@ module Datadog
68
68
  ),
69
69
  DetectedConfiguration.new(
70
70
  friendly_name: "#{Datadog::Core::Configuration::Ext::Agent::ENV_DEFAULT_HOST} environment variable",
71
- value: ENV[Datadog::Core::Configuration::Ext::Agent::ENV_DEFAULT_HOST]
71
+ value: DATADOG_ENV[Datadog::Core::Configuration::Ext::Agent::ENV_DEFAULT_HOST]
72
72
  )
73
73
  )
74
74
  end
@@ -87,7 +87,7 @@ module Datadog
87
87
  ),
88
88
  try_parsing_as_integer(
89
89
  friendly_name: "#{Datadog::Core::Configuration::Ext::Agent::ENV_DEFAULT_PORT} environment variable",
90
- value: ENV[Datadog::Core::Configuration::Ext::Agent::ENV_DEFAULT_PORT],
90
+ value: DATADOG_ENV[Datadog::Core::Configuration::Ext::Agent::ENV_DEFAULT_PORT],
91
91
  )
92
92
  )
93
93
  end
@@ -118,7 +118,7 @@ module Datadog
118
118
  try_parsing_as_integer(
119
119
  friendly_name: "#{Datadog::Core::Configuration::Ext::Agent::ENV_DEFAULT_TIMEOUT_SECONDS} " \
120
120
  'environment variable',
121
- value: ENV[Datadog::Core::Configuration::Ext::Agent::ENV_DEFAULT_TIMEOUT_SECONDS],
121
+ value: DATADOG_ENV[Datadog::Core::Configuration::Ext::Agent::ENV_DEFAULT_TIMEOUT_SECONDS],
122
122
  )
123
123
  )
124
124
  end
@@ -256,7 +256,7 @@ module Datadog
256
256
  def parsed_url
257
257
  return @parsed_url if defined?(@parsed_url)
258
258
 
259
- unparsed_url_from_env = ENV[Datadog::Core::Configuration::Ext::Agent::ENV_DEFAULT_URL]
259
+ unparsed_url_from_env = DATADOG_ENV[Datadog::Core::Configuration::Ext::Agent::ENV_DEFAULT_URL]
260
260
 
261
261
  @parsed_url =
262
262
  if unparsed_url_from_env
@@ -3,6 +3,7 @@
3
3
  require_relative 'agent_settings_resolver'
4
4
  require_relative 'components_state'
5
5
  require_relative 'ext'
6
+ require_relative 'deprecations'
6
7
  require_relative '../diagnostics/environment_logger'
7
8
  require_relative '../diagnostics/health'
8
9
  require_relative '../logger'
@@ -25,8 +26,6 @@ module Datadog
25
26
  # Global components for the trace library.
26
27
  class Components
27
28
  class << self
28
- include Datadog::Tracing::Component
29
-
30
29
  def build_health_metrics(settings, logger, telemetry)
31
30
  settings = settings.health_metrics
32
31
  options = {enabled: settings.enabled}
@@ -78,10 +77,9 @@ module Datadog
78
77
  end
79
78
  end
80
79
 
81
- include Datadog::Tracing::Component::InstanceMethods
82
-
83
80
  attr_reader \
84
81
  :health_metrics,
82
+ :settings,
85
83
  :logger,
86
84
  :remote,
87
85
  :profiler,
@@ -95,8 +93,11 @@ module Datadog
95
93
  :agent_info
96
94
 
97
95
  def initialize(settings)
96
+ @settings = settings
98
97
  @logger = self.class.build_logger(settings)
99
98
  @environment_logger_extra = {}
99
+ StableConfig.log_result(@logger)
100
+ Deprecations.log_deprecations_from_all_sources(@logger)
100
101
 
101
102
  # This agent_settings is intended for use within Core. If you require
102
103
  # agent_settings within a product outside of core you should extend
@@ -109,7 +110,7 @@ module Datadog
109
110
  @telemetry = self.class.build_telemetry(settings, agent_settings, @logger)
110
111
 
111
112
  @remote = Remote::Component.build(settings, agent_settings, logger: @logger, telemetry: telemetry)
112
- @tracer = self.class.build_tracer(settings, agent_settings, logger: @logger)
113
+ @tracer = Datadog::Tracing::Component.build_tracer(settings, agent_settings, logger: @logger)
113
114
  @crashtracker = self.class.build_crashtracker(settings, agent_settings, logger: @logger)
114
115
 
115
116
  @profiler, profiler_logger_extra = Datadog::Profiling::Component.build_profiler_component(
@@ -126,9 +127,17 @@ module Datadog
126
127
  @dynamic_instrumentation = Datadog::DI::Component.build(settings, agent_settings, @logger, telemetry: telemetry)
127
128
  @error_tracking = Datadog::ErrorTracking::Component.build(settings, @tracer, @logger)
128
129
  @environment_logger_extra[:dynamic_instrumentation_enabled] = !!@dynamic_instrumentation
129
- @process_discovery_fd = Core::ProcessDiscovery.get_and_store_metadata(settings, @logger)
130
130
 
131
- self.class.configure_tracing(settings)
131
+ # Configure non-privileged components.
132
+ Datadog::Tracing::Contrib::Component.configure(settings)
133
+ end
134
+
135
+ # Hot-swaps with a new sampler.
136
+ # This operation acquires the Components lock to ensure
137
+ # there is no concurrent modification of the sampler.
138
+ def reconfigure_sampler(settings = Datadog.configuration)
139
+ sampler = Datadog::Tracing::Component.build_sampler(settings)
140
+ Datadog.send(:safely_synchronize) { tracer.sampler.sampler = sampler }
132
141
  end
133
142
 
134
143
  # Starts up components
@@ -155,6 +164,11 @@ module Datadog
155
164
  remote&.start
156
165
  end
157
166
 
167
+ # This should stay here, not in initialize. During reconfiguration, the order of the calls is:
168
+ # initialize new components, shutdown old components, startup new components.
169
+ # Because this is a singleton, if we call it in initialize, it will be shutdown right away.
170
+ Core::ProcessDiscovery.publish(settings)
171
+
158
172
  Core::Diagnostics::EnvironmentLogger.collect_and_log!(@environment_logger_extra)
159
173
  end
160
174
 
@@ -210,7 +224,7 @@ module Datadog
210
224
  telemetry.emit_closing! unless replacement&.telemetry&.enabled
211
225
  telemetry.shutdown!
212
226
 
213
- @process_discovery_fd&.shutdown!
227
+ Core::ProcessDiscovery.shutdown!
214
228
  end
215
229
 
216
230
  # Returns the current state of various components.
@@ -0,0 +1,100 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'supported_configurations'
4
+ require_relative '../logger'
5
+
6
+ module Datadog
7
+ module Core
8
+ module Configuration
9
+ class ConfigHelper
10
+ def initialize(
11
+ source_env: ENV,
12
+ supported_configurations: SUPPORTED_CONFIGURATIONS,
13
+ aliases: ALIASES,
14
+ alias_to_canonical: ALIAS_TO_CANONICAL,
15
+ raise_on_unknown_env_var: false
16
+ )
17
+ @source_env = source_env
18
+ @supported_configurations = supported_configurations
19
+ @aliases = aliases
20
+ @alias_to_canonical = alias_to_canonical
21
+ @raise_on_unknown_env_var = raise_on_unknown_env_var
22
+ end
23
+
24
+ def [](name)
25
+ get_environment_variable(name)
26
+ end
27
+
28
+ def fetch(name, default_value = UNSET)
29
+ if (item = get_environment_variable(name))
30
+ return item
31
+ end
32
+
33
+ return yield(name) if block_given?
34
+ return default_value unless default_value == UNSET
35
+
36
+ raise KeyError, "key not found: #{name}"
37
+ end
38
+
39
+ def key?(name)
40
+ !get_environment_variable(name).nil?
41
+ end
42
+
43
+ alias_method :has_key?, :key?
44
+ alias_method :include?, :key?
45
+ alias_method :member?, :key?
46
+
47
+ # Returns the environment variable value if the environment variable is a supported Datadog configuration (starts with DD_ or OTEL_)
48
+ # or if it is not a Datadog configuration. Otherwise, it returns nil.
49
+ #
50
+ # @param name [String] Environment variable name
51
+ # @param default_value [String, nil] Default value to return if the environment variable is not set
52
+ # @param source_env [Hash[String, String]] Environment variables to use
53
+ # @return [String, nil] The environment variable value
54
+ # @raise [RuntimeError] if the configuration is not supported
55
+ def get_environment_variable(name, default_value = nil, source_env: @source_env)
56
+ # datadog-ci-rb is using dd-trace-rb config DSL, which uses this method.
57
+ # Until we've correctly implemented support for datadog-ci-rb, we disable config inversion if ci is enabled.
58
+ if !defined?(::Datadog::CI) &&
59
+ (name.start_with?('DD_', 'OTEL_') || @alias_to_canonical[name]) &&
60
+ !@supported_configurations[name]
61
+ if defined?(@raise_on_unknown_env_var) && @raise_on_unknown_env_var # Only enabled for tests!
62
+ if @alias_to_canonical[name]
63
+ raise "Please use #{@alias_to_canonical[name]} instead of #{name}. See docs/AccessEnvironmentVariables.md for details."
64
+ else
65
+ raise "Missing #{name} env/configuration in \"supported-configurations.json\" file. See docs/AccessEnvironmentVariables.md for details."
66
+ end
67
+ end
68
+ # TODO: Send telemetry to know if we ever miss an env var
69
+ return nil
70
+ end
71
+
72
+ env_value = source_env[name]
73
+ if env_value.nil? && @aliases[name]
74
+ @aliases[name].each do |alias_name|
75
+ return source_env[alias_name] if source_env[alias_name]
76
+ end
77
+ end
78
+
79
+ env_value || default_value
80
+ end
81
+
82
+ # Only used in error message creation. Match get_environment_variable logic to return the resolved environment variable name.
83
+ def resolve_env(name, source_env: @source_env)
84
+ if source_env[name].nil? && @aliases[name]
85
+ @aliases[name].each do |alias_name|
86
+ return alias_name if source_env[alias_name]
87
+ end
88
+ end
89
+
90
+ name
91
+ end
92
+
93
+ # Anchor object that represents an undefined default value.
94
+ # This is necessary because `nil` is a valid default value.
95
+ UNSET = Object.new
96
+ private_constant :UNSET
97
+ end
98
+ end
99
+ end
100
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'supported_configurations'
4
+ require_relative '../logger'
5
+ require_relative '../utils/only_once'
6
+
7
+ module Datadog
8
+ module Core
9
+ module Configuration
10
+ module Deprecations
11
+ LOG_DEPRECATIONS_ONLY_ONCE = Datadog::Core::Utils::OnlyOnce.new
12
+
13
+ def self.log_deprecations_from_all_sources(logger, deprecations: DEPRECATIONS, alias_to_canonical: ALIAS_TO_CANONICAL)
14
+ LOG_DEPRECATIONS_ONLY_ONCE.run do
15
+ log_deprecated_environment_variables(logger, ENV, 'environment', deprecations, alias_to_canonical)
16
+ customer_config = StableConfig.configuration.dig(:local, :config)
17
+ log_deprecated_environment_variables(logger, customer_config, 'local', deprecations, alias_to_canonical) if customer_config
18
+ fleet_config = StableConfig.configuration.dig(:fleet, :config)
19
+ log_deprecated_environment_variables(logger, fleet_config, 'fleet', deprecations, alias_to_canonical) if fleet_config
20
+ end
21
+ end
22
+
23
+ private_class_method def self.log_deprecated_environment_variables(logger, source_env, source_name, deprecations, alias_to_canonical)
24
+ deprecations.each do |deprecated_env_var, message|
25
+ next unless source_env.key?(deprecated_env_var)
26
+
27
+ Datadog::Core.log_deprecation(disallowed_next_major: false, logger: logger) do
28
+ "#{deprecated_env_var} #{source_name} variable is deprecated" +
29
+ (alias_to_canonical[deprecated_env_var] ? ", use #{alias_to_canonical[deprecated_env_var]} instead." : ". #{message}.")
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -9,7 +9,6 @@ module Datadog
9
9
  # @public_api
10
10
  module Diagnostics
11
11
  ENV_DEBUG_ENABLED = 'DD_TRACE_DEBUG'
12
- ENV_OTEL_LOG_LEVEL = 'OTEL_LOG_LEVEL'
13
12
  ENV_HEALTH_METRICS_ENABLED = 'DD_HEALTH_METRICS_ENABLED'
14
13
  ENV_STARTUP_LOGS_ENABLED = 'DD_TRACE_STARTUP_LOGS'
15
14
  end
@@ -15,7 +15,7 @@ module Datadog
15
15
  # @!attribute [r] precedence_set
16
16
  # When this option was last set, what was the value precedence used?
17
17
  # @return [Precedence::Value]
18
- attr_reader :definition, :precedence_set, :resolved_env
18
+ attr_reader :definition, :precedence_set
19
19
 
20
20
  # Option setting precedence.
21
21
  module Precedence
@@ -68,7 +68,6 @@ module Datadog
68
68
  @context = context
69
69
  @value = nil
70
70
  @is_set = false
71
- @resolved_env = nil
72
71
 
73
72
  # One value is stored per precedence, to allow unsetting a higher
74
73
  # precedence value and falling back to a lower precedence one.
@@ -84,7 +83,7 @@ module Datadog
84
83
  #
85
84
  # @param value [Object] the new value to be associated with this option
86
85
  # @param precedence [Precedence] from what precedence order this new value comes from
87
- def set(value, precedence: Precedence::PROGRAMMATIC, resolved_env: nil)
86
+ def set(value, precedence: Precedence::PROGRAMMATIC)
88
87
  # Is there a higher precedence value set?
89
88
  if @precedence_set > precedence
90
89
  # This should be uncommon, as higher precedence values tend to
@@ -103,7 +102,7 @@ module Datadog
103
102
  return @value
104
103
  end
105
104
 
106
- internal_set(value, precedence, resolved_env)
105
+ internal_set(value, precedence)
107
106
  end
108
107
 
109
108
  def unset(precedence)
@@ -121,7 +120,7 @@ module Datadog
121
120
  # Look for value that is set.
122
121
  # The hash `@value_per_precedence` has a custom default value of `UNSET`.
123
122
  if (value = @value_per_precedence[p]) != UNSET
124
- internal_set(value, p, nil)
123
+ internal_set(value, p)
125
124
  return nil
126
125
  end
127
126
  end
@@ -189,7 +188,7 @@ module Datadog
189
188
  values = value.split(',') # By default we only want to support comma separated strings
190
189
 
191
190
  values.each_with_object({}) do |v, hash| # $ Hash[String, String]
192
- v.gsub!(/\A[\s,]*|[\s,]*\Z/, '')
191
+ v.gsub!(/\A[\s,]*+|[\s,]*+\Z/, '')
193
192
  next if v.empty?
194
193
 
195
194
  pair = v.split(':', 2)
@@ -203,7 +202,7 @@ module Datadog
203
202
  values = value.split(',')
204
203
 
205
204
  values.each_with_object([]) do |v, arr| # $ Array[String]
206
- v.gsub!(/\A[\s,]*|[\s,]*\Z/, '')
205
+ v.gsub!(/\A[\s,]*+|[\s,]*+\Z/, '')
207
206
  next if v.empty?
208
207
 
209
208
  arr << v
@@ -281,12 +280,11 @@ module Datadog
281
280
  end
282
281
 
283
282
  # Directly manipulates the current value and currently set precedence.
284
- def internal_set(value, precedence, resolved_env)
283
+ def internal_set(value, precedence)
285
284
  old_value = @value
286
285
  (@value = context_exec(validate_type(value), old_value, &definition.setter)).tap do |v|
287
286
  @is_set = true
288
287
  @precedence_set = precedence
289
- @resolved_env = resolved_env
290
288
  # Store original value to ensure we can always safely call `#internal_set`
291
289
  # when restoring a value from `@value_per_precedence`, and we are only running `definition.setter`
292
290
  # on the original value, not on a value that has already been processed by `definition.setter`.
@@ -308,59 +306,56 @@ module Datadog
308
306
  end
309
307
 
310
308
  def set_env_value
311
- value, resolved_env = get_value_and_resolved_env_from(ENV)
312
- set(value, precedence: Precedence::ENVIRONMENT, resolved_env: resolved_env) unless value.nil?
309
+ value = get_value_from_env
310
+ set(value, precedence: Precedence::ENVIRONMENT) unless value.nil?
313
311
  end
314
312
 
315
313
  def set_customer_stable_config_value
316
314
  customer_config = StableConfig.configuration.dig(:local, :config)
317
315
  return if customer_config.nil?
318
316
 
319
- value, resolved_env = get_value_and_resolved_env_from(customer_config, source: 'local stable config')
320
- set(value, precedence: Precedence::LOCAL_STABLE, resolved_env: resolved_env) unless value.nil?
317
+ value = get_value_from(customer_config, 'local')
318
+ set(value, precedence: Precedence::LOCAL_STABLE) unless value.nil?
321
319
  end
322
320
 
323
321
  def set_fleet_stable_config_value
324
322
  fleet_config = StableConfig.configuration.dig(:fleet, :config)
325
323
  return if fleet_config.nil?
326
324
 
327
- value, resolved_env = get_value_and_resolved_env_from(fleet_config, source: 'fleet stable config')
328
- set(value, precedence: Precedence::FLEET_STABLE, resolved_env: resolved_env) unless value.nil?
325
+ value = get_value_from(fleet_config, 'fleet')
326
+ set(value, precedence: Precedence::FLEET_STABLE) unless value.nil?
329
327
  end
330
328
 
331
- def get_value_and_resolved_env_from(env_vars, source: 'environment variable')
332
- value = nil
333
- resolved_env = nil
329
+ def get_value_from_env
330
+ env = definition.env
331
+ return unless env
334
332
 
335
- if definition.env
336
- # @type var env_and_aliases: Array[String]
337
- env_and_aliases = Array(definition.env)
338
- env_and_aliases.each do |env|
339
- env_value = env_vars[env]
340
- next if env_value.nil?
341
-
342
- resolved_env = env
343
- value = coerce_env_variable(env_value)
344
- break
345
- end
346
- end
347
-
348
- deprecated_env = definition.deprecated_env ? env_vars[definition.deprecated_env] : nil
349
- if value.nil? && deprecated_env
350
- resolved_env = definition.deprecated_env
351
- value = coerce_env_variable(deprecated_env)
333
+ value = DATADOG_ENV[env]
334
+ coerce_env_variable(value) unless value.nil?
335
+ rescue ArgumentError
336
+ # This will be raised when the type is set to :int or :float but an invalid env var value is provided.
337
+ raise ArgumentError,
338
+ # ArgumentError will be thrown from coerce_env_variable, so we've already checked that env is not nil.
339
+ # @type var env: String
340
+ "Expected environment variable #{DATADOG_ENV.resolve_env(env)} " \
341
+ "to be a #{definition.type}, but '#{value}' was provided."
342
+ end
352
343
 
353
- Datadog::Core.log_deprecation do
354
- "#{definition.deprecated_env} #{source} is deprecated, use #{definition.env} instead."
355
- end
356
- end
344
+ def get_value_from(source_env, source_name)
345
+ env = definition.env
346
+ return unless env
357
347
 
358
- [value, resolved_env]
348
+ # An instance of ConfigHelper could be used with any Hash but this is the only place where
349
+ # it's used with something else than ENV, let's keep it simple for now by overriding the source_env parameter.
350
+ value = DATADOG_ENV.get_environment_variable(env, source_env: source_env)
351
+ coerce_env_variable(value) unless value.nil?
359
352
  rescue ArgumentError
360
- env_value = resolved_env ? env_vars[resolved_env] : nil
353
+ # This will be raised when the type is set to :int or :float but an invalid env var value is provided.
361
354
  raise ArgumentError,
362
- "Expected #{source} #{resolved_env} to be a #{definition.type}, " \
363
- "but '#{env_value}' was provided"
355
+ # ArgumentError will be thrown from coerce_env_variable, so we've already checked that env is not nil.
356
+ # @type var env: String
357
+ "Expected #{source_name} configuration file variable #{DATADOG_ENV.resolve_env(env, source_env: source_env)} " \
358
+ "to be a #{definition.type}, but '#{value}' was provided."
364
359
  end
365
360
 
366
361
  # Anchor object that represents a value that is not set.
@@ -13,7 +13,6 @@ module Datadog
13
13
  :default,
14
14
  :default_proc,
15
15
  :env,
16
- :deprecated_env,
17
16
  :env_parser,
18
17
  :name,
19
18
  :after_set,
@@ -26,7 +25,6 @@ module Datadog
26
25
  @default = meta[:default]
27
26
  @default_proc = meta[:default_proc]
28
27
  @env = meta[:env]
29
- @deprecated_env = meta[:deprecated_env]
30
28
  @env_parser = meta[:env_parser]
31
29
  @name = name.to_sym
32
30
  @after_set = meta[:after_set]
@@ -51,7 +49,6 @@ module Datadog
51
49
 
52
50
  def initialize(name, options = {})
53
51
  @env = nil
54
- @deprecated_env = nil
55
52
  @env_parser = nil
56
53
  @default = nil
57
54
  @default_proc = nil
@@ -75,10 +72,6 @@ module Datadog
75
72
  @env = value
76
73
  end
77
74
 
78
- def deprecated_env(value) # standard:disable Style/TrivialAccessors
79
- @deprecated_env = value
80
- end
81
-
82
75
  # Invoked when the option is first read, and {#env} is defined.
83
76
  # The block provided is only invoked if the environment variable is present (not-nil).
84
77
  def env_parser(&block)
@@ -123,7 +116,6 @@ module Datadog
123
116
  default(options[:default]) if options.key?(:default)
124
117
  default_proc(&options[:default_proc]) if options.key?(:default_proc)
125
118
  env(options[:env]) if options.key?(:env)
126
- deprecated_env(options[:deprecated_env]) if options.key?(:deprecated_env)
127
119
  env_parser(&options[:env_parser]) if options.key?(:env_parser)
128
120
  after_set(&options[:after_set]) if options.key?(:after_set)
129
121
  resetter(&options[:resetter]) if options.key?(:resetter)
@@ -140,7 +132,6 @@ module Datadog
140
132
  default: @default,
141
133
  default_proc: @default_proc,
142
134
  env: @env,
143
- deprecated_env: @deprecated_env,
144
135
  env_parser: @env_parser,
145
136
  after_set: @after_set,
146
137
  resetter: @resetter,
@@ -73,7 +73,7 @@ module Datadog
73
73
  end
74
74
 
75
75
  def set_option(name, value, precedence: Configuration::Option::Precedence::PROGRAMMATIC)
76
- resolve_option(name).set(value, precedence: precedence, resolved_env: resolved_env(name))
76
+ resolve_option(name).set(value, precedence: precedence)
77
77
  end
78
78
 
79
79
  def unset_option(name, precedence: Configuration::Option::Precedence::PROGRAMMATIC)
@@ -122,10 +122,6 @@ module Datadog
122
122
  options[name] = definition.build(self)
123
123
  end
124
124
 
125
- def resolved_env(name)
126
- options[name].resolved_env if options.key?(name)
127
- end
128
-
129
125
  def assert_valid_option!(name)
130
126
  raise(InvalidOptionError, "#{self.class.name} doesn't define the option: #{name}") unless option_defined?(name)
131
127
  end
@@ -122,8 +122,8 @@ module Datadog
122
122
  # @default `DD_TRACE_DEBUG` environment variable, otherwise `false`
123
123
  # @return [Boolean]
124
124
  option :debug do |o|
125
- o.env [Datadog::Core::Configuration::Ext::Diagnostics::ENV_DEBUG_ENABLED,
126
- Datadog::Core::Configuration::Ext::Diagnostics::ENV_OTEL_LOG_LEVEL]
125
+ # Note: Alias (OTEL_LOG_LEVEL) defined in supported-configurations.json
126
+ o.env Datadog::Core::Configuration::Ext::Diagnostics::ENV_DEBUG_ENABLED
127
127
  o.default false
128
128
  o.type :bool
129
129
  o.env_parser do |value|
@@ -212,6 +212,7 @@ module Datadog
212
212
  # Log level for `Datadog.logger`.
213
213
  # @see Logger::Severity
214
214
  # @return Logger::Severity
215
+ # TODO: Add environment variable for this `DD_TRACE_LOG_LEVEL`
215
216
  option :level, default: ::Logger::INFO
216
217
  end
217
218
 
@@ -485,7 +486,7 @@ module Datadog
485
486
  # @default `DD_PROFILING_GVL_ENABLED` environment variable as a boolean, otherwise `true`
486
487
  option :gvl_enabled do |o|
487
488
  o.type :bool
488
- o.deprecated_env 'DD_PROFILING_PREVIEW_GVL_ENABLED'
489
+ # Note: Deprecated alias (DD_PROFILING_PREVIEW_GVL_ENABLED) defined in supported-configurations.json
489
490
  o.env 'DD_PROFILING_GVL_ENABLED'
490
491
  o.default true
491
492
  end
@@ -604,7 +605,8 @@ module Datadog
604
605
 
605
606
  option :experimental_runtime_id_enabled do |o|
606
607
  o.type :bool
607
- o.env ['DD_TRACE_EXPERIMENTAL_RUNTIME_ID_ENABLED', 'DD_RUNTIME_METRICS_RUNTIME_ID_ENABLED']
608
+ # Note: Alias (DD_TRACE_EXPERIMENTAL_RUNTIME_ID_ENABLED) defined in supported-configurations.json
609
+ o.env 'DD_RUNTIME_METRICS_RUNTIME_ID_ENABLED'
608
610
  o.default false
609
611
  end
610
612
 
@@ -620,7 +622,8 @@ module Datadog
620
622
  o.type :string, nilable: true
621
623
 
622
624
  # NOTE: service also gets set as a side effect of tags. See the WORKAROUND note in #initialize for details.
623
- o.env [Core::Environment::Ext::ENV_SERVICE, Core::Environment::Ext::ENV_OTEL_SERVICE]
625
+ # Note: Alias (OTEL_SERVICE_NAME) defined in supported-configurations.json
626
+ o.env Core::Environment::Ext::ENV_SERVICE
624
627
  o.default Core::Environment::Ext::FALLBACK_SERVICE_NAME
625
628
 
626
629
  # There's a few cases where we don't want to use the fallback service name, so this helper allows us to get a
@@ -655,7 +658,8 @@ module Datadog
655
658
  # @return [Hash<String,String>]
656
659
  option :tags do |o|
657
660
  o.type :hash, nilable: true
658
- o.env [Core::Environment::Ext::ENV_TAGS, Core::Environment::Ext::ENV_OTEL_RESOURCE_ATTRIBUTES]
661
+ # Note: Alias (OTEL_RESOURCE_ATTRIBUTES) defined in supported-configurations.json
662
+ o.env Core::Environment::Ext::ENV_TAGS
659
663
  o.env_parser do |env_value|
660
664
  # Parses a string containing key-value pairs and returns a hash.
661
665
  # Key-value pairs are delimited by ':' OR `=`, and pairs are separated by whitespace, comma, OR BOTH.
@@ -1,10 +1,14 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require_relative '../utils/only_once'
4
+
3
5
  module Datadog
4
6
  module Core
5
7
  module Configuration
6
8
  # Import config from config files (fleet automation)
7
9
  module StableConfig
10
+ LOG_ONLY_ONCE = Utils::OnlyOnce.new
11
+
8
12
  def self.extract_configuration
9
13
  if (libdatadog_api_failure = Datadog::Core::LIBDATADOG_API_FAILURE)
10
14
  Datadog.config_init_logger.debug("Cannot enable stable config: #{libdatadog_api_failure}")
@@ -16,6 +20,12 @@ module Datadog
16
20
  def self.configuration
17
21
  @configuration ||= StableConfig.extract_configuration
18
22
  end
23
+
24
+ def self.log_result(logger)
25
+ LOG_ONLY_ONCE.run do
26
+ logger.debug(configuration[:logs]) if configuration[:logs]
27
+ end
28
+ end
19
29
  end
20
30
  end
21
31
  end