diff --git a/lib/datadog/core/configuration/option.rb b/lib/datadog/core/configuration/option.rb index a28e0fc61b5..2b41479504d 100644 --- a/lib/datadog/core/configuration/option.rb +++ b/lib/datadog/core/configuration/option.rb @@ -14,7 +14,7 @@ class Option # @!attribute [r] precedence_set # When this option was last set, what was the value precedence used? # @return [Precedence::Value] - attr_reader :definition, :precedence_set + attr_reader :definition, :precedence_set, :resolved_env # Option setting precedence. module Precedence @@ -50,6 +50,7 @@ def initialize(definition, context) @context = context @value = nil @is_set = false + @resolved_env = nil # One value is stored per precedence, to allow unsetting a higher # precedence value and falling back to a lower precedence one. @@ -65,7 +66,7 @@ def initialize(definition, context) # # @param value [Object] the new value to be associated with this option # @param precedence [Precedence] from what precedence order this new value comes from - def set(value, precedence: Precedence::PROGRAMMATIC) + def set(value, precedence: Precedence::PROGRAMMATIC, resolved_env: nil) # Is there a higher precedence value set? if @precedence_set > precedence # This should be uncommon, as higher precedence values tend to @@ -84,7 +85,7 @@ def set(value, precedence: Precedence::PROGRAMMATIC) return @value end - internal_set(value, precedence) + internal_set(value, precedence, resolved_env) end def unset(precedence) @@ -102,7 +103,7 @@ def unset(precedence) # Look for value that is set. # The hash `@value_per_precedence` has a custom default value of `UNSET`. if (value = @value_per_precedence[p]) != UNSET - internal_set(value, p) + internal_set(value, p, nil) return nil end end @@ -260,11 +261,12 @@ def validate(type, value) end # Directly manipulates the current value and currently set precedence. - def internal_set(value, precedence) + def internal_set(value, precedence, resolved_env) old_value = @value (@value = context_exec(validate_type(value), old_value, &definition.setter)).tap do |v| @is_set = true @precedence_set = precedence + @resolved_env = resolved_env # Store original value to ensure we can always safely call `#internal_set` # when restoring a value from `@value_per_precedence`, and we are only running `definition.setter` # on the original value, not on a valud that has already been processed by `definition.setter`. @@ -284,16 +286,21 @@ def context_eval(&block) def set_value_from_env_or_default value = nil precedence = nil - effective_env = nil + resolved_env = nil - if definition.env && ENV[definition.env] - effective_env = definition.env - value = coerce_env_variable(ENV[definition.env]) - precedence = Precedence::PROGRAMMATIC + if definition.env + Array(definition.env).each do |env| + next if ENV[env].nil? + + resolved_env = env + value = coerce_env_variable(ENV[env]) + precedence = Precedence::PROGRAMMATIC + break + end end if value.nil? && definition.deprecated_env && ENV[definition.deprecated_env] - effective_env = definition.deprecated_env + resolved_env = definition.deprecated_env value = coerce_env_variable(ENV[definition.deprecated_env]) precedence = Precedence::PROGRAMMATIC @@ -304,11 +311,11 @@ def set_value_from_env_or_default option_value = value.nil? ? default_value : value - set(option_value, precedence: precedence || Precedence::DEFAULT) + set(option_value, precedence: precedence || Precedence::DEFAULT, resolved_env: resolved_env) rescue ArgumentError raise ArgumentError, - "Expected environment variable #{effective_env} to be a #{@definition.type}, " \ - "but '#{ENV[effective_env]}' was provided" + "Expected environment variable #{resolved_env} to be a #{@definition.type}, " \ + "but '#{ENV[resolved_env]}' was provided" end # Anchor object that represents a value that is not set. diff --git a/lib/datadog/core/configuration/options.rb b/lib/datadog/core/configuration/options.rb index 8e1c8772cdc..07f7591e3c4 100644 --- a/lib/datadog/core/configuration/options.rb +++ b/lib/datadog/core/configuration/options.rb @@ -68,7 +68,7 @@ def options end def set_option(name, value, precedence: Configuration::Option::Precedence::PROGRAMMATIC) - resolve_option(name).set(value, precedence: precedence) + resolve_option(name).set(value, precedence: precedence, resolved_env: resolved_env(name)) end def unset_option(name, precedence: Configuration::Option::Precedence::PROGRAMMATIC) @@ -116,6 +116,10 @@ def resolve_option(name) options[name] = definition.build(self) end + def resolved_env(name) + return options[name].resolved_env if options.key?(name) + end + def assert_valid_option!(name) raise(InvalidOptionError, "#{self.class.name} doesn't define the option: #{name}") unless option_defined?(name) end diff --git a/spec/datadog/core/configuration/option_spec.rb b/spec/datadog/core/configuration/option_spec.rb index d84aa576ba9..76a3b1f2fee 100644 --- a/spec/datadog/core/configuration/option_spec.rb +++ b/spec/datadog/core/configuration/option_spec.rb @@ -839,6 +839,35 @@ end end + context 'when env is an Array' do + let(:env) { ['TEST_ENV_VAR', 'TEST_ENV_VAR2'] } + let(:setter) { proc { |value| value } } + + around do |example| + ClimateControl.modify(set_envs) { example.run } + end + + context 'and the first environmet variable is set' do + let(:set_envs) { { 'TEST_ENV_VAR' => 'val1' } } + it { is_expected.to eq('val1') } + end + + context 'and the second environmet variable is set' do + let(:set_envs) { { 'TEST_ENV_VAR2' => 'val2' } } + it { is_expected.to eq('val2') } + end + + context 'and both environmet variables are set' do + let(:set_envs) { { 'TEST_ENV_VAR' => 'val1', 'TEST_ENV_VAR2' => 'val2' } } + it { is_expected.to eq('val1') } + end + + context 'and environmet variables are not set' do + let(:set_envs) { {} } + it { is_expected.to be(default) } + end + end + context 'when deprecated_env is defined' do before do allow(Datadog.logger).to receive(:warn) # For deprecation warnings