Skip to content

Commit fe93861

Browse files
authored
Minor IConfigurationSource clean up (#7327)
## Summary of changes - Remove unused methods in `IConfigurationSource` - Add a test for the recording of "error" telemetry in configuration sources ## Reason for change I'm working on some things for configuration, and needed to do a bit of cleanup first. Nothing major here. ## Implementation details - Delete unused `CompositeConfigurationSource.Insert()` method - Delete unused `IConfigurationSource.IsPresent` method - Add a test that we record "invalid" errors, and that the final telemetry value is the "real" value ## Test coverage Covered by existing + a new one
1 parent 58b4e14 commit fe93861

File tree

8 files changed

+95
-76
lines changed

8 files changed

+95
-76
lines changed

tracer/src/Datadog.Trace/Configuration/ConfigurationSources/CompositeConfigurationSource.cs

Lines changed: 1 addition & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,7 @@
1010
using System.Linq;
1111
using Datadog.Trace.Configuration.ConfigurationSources.Telemetry;
1212
using Datadog.Trace.Configuration.Telemetry;
13-
using Datadog.Trace.ExtensionMethods;
1413
using Datadog.Trace.SourceGenerators;
15-
using Datadog.Trace.Telemetry;
16-
using Datadog.Trace.Telemetry.Metrics;
17-
using Datadog.Trace.Util;
1814

1915
namespace Datadog.Trace.Configuration
2016
{
@@ -41,34 +37,18 @@ public CompositeConfigurationSource(IEnumerable<IConfigurationSource> sources)
4137
/// <param name="source">The configuration source to add.</param>
4238
public void Add(IConfigurationSource source)
4339
{
44-
if (source == null) { ThrowHelper.ThrowArgumentNullException(nameof(source)); }
40+
if (source == null!) { ThrowHelper.ThrowArgumentNullException(nameof(source)); }
4541

4642
_sources.Add(source);
4743
}
4844

49-
/// <summary>
50-
/// Inserts an element into the <see cref="Datadog.Trace.Configuration.CompositeConfigurationSource"/> at the specified index.
51-
/// </summary>
52-
/// <param name="index">The zero-based index at which <paramref name="item"/> should be inserted.</param>
53-
/// <param name="item">The configuration source to insert.</param>
54-
public void Insert(int index, IConfigurationSource item)
55-
{
56-
if (item == null) { ThrowHelper.ThrowArgumentNullException(nameof(item)); }
57-
58-
_sources.Insert(index, item);
59-
}
60-
6145
/// <inheritdoc />
6246
IEnumerator<IConfigurationSource> IEnumerable<IConfigurationSource>.GetEnumerator() => _sources.GetEnumerator();
6347

6448
/// <inheritdoc />
6549
[PublicApi]
6650
IEnumerator IEnumerable.GetEnumerator() => _sources.GetEnumerator();
6751

68-
/// <inheritdoc />
69-
public bool IsPresent(string key)
70-
=> _sources.Select(source => source.IsPresent(key)).FirstOrDefault(value => value);
71-
7252
/// <inheritdoc />
7353
public ConfigurationResult<string> GetString(string key, IConfigurationTelemetry telemetry, Func<string, bool>? validator, bool recordValue)
7454
=> _sources

tracer/src/Datadog.Trace/Configuration/ConfigurationSources/DictionaryObjectConfigurationSource.cs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,6 @@ public DictionaryObjectConfigurationSource(IReadOnlyDictionary<string, object?>
3333
protected virtual bool TryGetValue(string key, out object? value)
3434
=> Dictionary.TryGetValue(key, out value);
3535

36-
public bool IsPresent(string key) => Dictionary.ContainsKey(key);
37-
3836
public ConfigurationResult<string> GetString(string key, IConfigurationTelemetry telemetry, Func<string, bool>? validator, bool recordValue)
3937
{
4038
if (TryGetValue(key, out var objValue) && objValue is not null)

tracer/src/Datadog.Trace/Configuration/ConfigurationSources/IConfigurationSource.cs

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,6 @@ namespace Datadog.Trace.Configuration;
1818
/// </summary>
1919
public interface IConfigurationSource
2020
{
21-
/// <summary>
22-
/// Gets whether the specified key is present in the source.
23-
/// </summary>
24-
/// <param name="key">The key that identifies the setting.</param>
25-
/// <returns><c>true</c> if the key is present in the source, false otherwise.</returns>
26-
bool IsPresent(string key);
27-
2821
/// <summary>
2922
/// Gets the <see cref="string"/> value of
3023
/// the setting with the specified key.

tracer/src/Datadog.Trace/Configuration/ConfigurationSources/JsonConfigurationSource.cs

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -96,14 +96,6 @@ internal static JsonConfigurationSource FromFile(string filename, ConfigurationO
9696
: token.Value<T>();
9797
}
9898

99-
/// <inheritdoc />
100-
public bool IsPresent(string key)
101-
{
102-
JToken? token = SelectToken(key);
103-
104-
return token is not null;
105-
}
106-
10799
/// <inheritdoc />
108100
public ConfigurationResult<string> GetString(string key, IConfigurationTelemetry telemetry, Func<string, bool>? validator, bool recordValue)
109101
{

tracer/src/Datadog.Trace/Configuration/ConfigurationSources/NullConfigurationSource.cs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,6 @@ internal class NullConfigurationSource : IConfigurationSource
1616
{
1717
public static readonly NullConfigurationSource Instance = new();
1818

19-
public bool IsPresent(string key) => false;
20-
2119
public ConfigurationResult<string> GetString(string key, IConfigurationTelemetry telemetry, Func<string, bool>? validator, bool recordValue)
2220
=> ConfigurationResult<string>.NotFound();
2321

tracer/src/Datadog.Trace/Configuration/ConfigurationSources/StringConfigurationSource.cs

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -114,14 +114,6 @@ internal abstract class StringConfigurationSource : IConfigurationSource
114114

115115
protected abstract string? GetString(string key);
116116

117-
/// <inheritdoc />
118-
public bool IsPresent(string key)
119-
{
120-
var value = GetString(key);
121-
122-
return value is not null;
123-
}
124-
125117
/// <inheritdoc />
126118
public ConfigurationResult<string> GetString(string key, IConfigurationTelemetry telemetry, Func<string, bool>? validator, bool recordValue)
127119
{

tracer/src/Datadog.Trace/Configuration/ConfigurationSources/Telemetry/ConfigurationBuilder.cs

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ private static bool TryHandleResult<T>(
6666
bool recordValue,
6767
Func<DefaultResult<T>>? getDefaultValue,
6868
[NotNullIfNotNull(nameof(getDefaultValue))] out T? value)
69+
where T : notnull
6970
{
7071
if (result is { Result: { } ddResult, IsValid: true })
7172
{
@@ -85,11 +86,7 @@ private static bool TryHandleResult<T>(
8586
var defaultValue = getDefaultValue();
8687
RecordTelemetry(telemetry, key, recordValue, defaultValue);
8788

88-
// The compiler complains about this, because technically you _could_ call it as `TryHandleResult<int?>` (for example)
89-
// in which case Func<DefaultResult<T>> _could_ return a `null` value, so the `[NotNullIfNotNull]` annotation
90-
// would be wrong. In practice, we control the calls to this method, and we know that T is always non-null
91-
// so it's safe to use the dammit here.
92-
value = defaultValue.Result!;
89+
value = defaultValue.Result;
9390
return true;
9491
}
9592

@@ -186,6 +183,7 @@ public string AsString(string defaultValue, Func<string, bool>? validator)
186183
// We have to use different methods for class/struct when we _don't_ have a null value, because NRTs don't work properly otherwise
187184
[return: NotNullIfNotNull(nameof(getDefaultValue))]
188185
public T GetAs<T>(Func<DefaultResult<T>> getDefaultValue, Func<T, bool>? validator, Func<string, ParsingResult<T>> converter)
186+
where T : notnull
189187
{
190188
var result = GetAs(validator, converter);
191189
return TryHandleResult(Telemetry, Key, result, recordValue: true, getDefaultValue, out var value)

tracer/test/Datadog.Trace.Tests/Configuration/CompositeConfigurationSourceTests.cs

Lines changed: 91 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,9 @@
55

66
using System.Collections.Generic;
77
using System.Collections.Specialized;
8+
using System.Linq;
89
using Datadog.Trace.Configuration;
10+
using Datadog.Trace.Configuration.ConfigurationSources.Telemetry;
911
using Datadog.Trace.Configuration.Telemetry;
1012
using Datadog.Trace.Telemetry;
1113
using FluentAssertions;
@@ -137,7 +139,7 @@ public void AttemptsToGrabStringFromEverySource(string key)
137139
{
138140
var telemetry = new StubTelemetry();
139141
var actual = _source.GetString(key, telemetry, validator: null, recordValue: true);
140-
telemetry.Accesses[key].Should().Be(1);
142+
telemetry.GetInstanceCount(key).Should().Be(1);
141143
}
142144

143145
[Theory]
@@ -160,7 +162,7 @@ public void AttemptsToGrabIntFromEverySource(string key)
160162
{
161163
var telemetry = new StubTelemetry();
162164
var actual = _source.GetInt32(key, telemetry, validator: null);
163-
telemetry.Accesses[key].Should().Be(1);
165+
telemetry.GetInstanceCount(key).Should().Be(1);
164166
}
165167

166168
[Theory]
@@ -183,7 +185,7 @@ public void AttemptsToGrabDoubleFromEverySource(string key)
183185
{
184186
var telemetry = new StubTelemetry();
185187
var actual = _source.GetDouble(key, telemetry, validator: null);
186-
telemetry.Accesses[key].Should().Be(1);
188+
telemetry.GetInstanceCount(key).Should().Be(1);
187189
}
188190

189191
[Theory]
@@ -206,7 +208,7 @@ public void AttemptsToGrabBoolFromEverySource(string key)
206208
{
207209
var telemetry = new StubTelemetry();
208210
var actual = _source.GetBool(key, telemetry, validator: null);
209-
telemetry.Accesses[key].Should().Be(1);
211+
telemetry.GetInstanceCount(key).Should().Be(1);
210212
}
211213

212214
[Theory]
@@ -229,30 +231,105 @@ public void AttemptsToGrabDictionaryFromEverySource(string key)
229231
{
230232
var telemetry = new StubTelemetry();
231233
var actual = _source.GetDictionary(key, telemetry, validator: null);
232-
telemetry.Accesses[key].Should().Be(1);
234+
telemetry.GetInstanceCount(key).Should().Be(1);
235+
}
236+
237+
[Fact]
238+
public void Telemetry_WhenMissingDoesNotRecordTelemetry()
239+
{
240+
var telemetry = new StubTelemetry();
241+
const string key = "int_value";
242+
var source = new CompositeConfigurationSource()
243+
{
244+
new NameValueConfigurationSource(new(), ConfigurationOrigins.Calculated),
245+
new NameValueConfigurationSource(new() { { "something_else", "456" } }, ConfigurationOrigins.EnvVars),
246+
new NameValueConfigurationSource(new(), ConfigurationOrigins.AppConfig),
247+
};
248+
249+
// not present
250+
var actual = source.GetInt32(key, telemetry, validator: null);
251+
actual.Should().Be(ConfigurationResult<int>.NotFound());
252+
253+
// final telemetry value should be the "real" value
254+
telemetry.Telemetry.Should().BeEmpty();
255+
}
256+
257+
[Fact]
258+
public void Telemetry_WhenErrorRecordsTelemetry()
259+
{
260+
var telemetry = new StubTelemetry();
261+
const string key = "int_value";
262+
var source = new CompositeConfigurationSource()
263+
{
264+
new NameValueConfigurationSource(new(), ConfigurationOrigins.Calculated),
265+
new NameValueConfigurationSource(new() { { key, "not_an_int" } }, ConfigurationOrigins.DdConfig),
266+
new NameValueConfigurationSource(new(), ConfigurationOrigins.AppConfig),
267+
};
268+
269+
// no valid value
270+
var actual = source.GetInt32(key, telemetry, validator: null);
271+
actual.Should().Be(ConfigurationResult<int>.NotFound());
272+
273+
// only telemetry value should be the error
274+
telemetry.Telemetry.Should()
275+
.ContainSingle()
276+
.Which.Should()
277+
.BeEquivalentTo(new ConfigurationTelemetryTests.ConfigDto(key, "not_an_int", ConfigurationOrigins.DdConfig, true, TelemetryErrorCode.ParsingInt32Error));
278+
}
279+
280+
[Fact]
281+
public void RecordsTelemetry_WhenPresentInMultipleSources()
282+
{
283+
var telemetry = new StubTelemetry();
284+
const string key = "int_value";
285+
var source = new CompositeConfigurationSource()
286+
{
287+
new NameValueConfigurationSource(new(), ConfigurationOrigins.Calculated),
288+
new NameValueConfigurationSource(new() { { key, "not_an_int" } }, ConfigurationOrigins.DdConfig),
289+
new NameValueConfigurationSource(new() { { key, "123" } }, ConfigurationOrigins.Code),
290+
new NameValueConfigurationSource(new(), ConfigurationOrigins.AppConfig),
291+
new NameValueConfigurationSource(new() { { key, "not_an_int" } }, ConfigurationOrigins.RemoteConfig),
292+
new NameValueConfigurationSource(new() { { key, "456" } }, ConfigurationOrigins.EnvVars),
293+
};
294+
295+
// first wins
296+
var expected = 123;
297+
var actual = source.GetInt32(key, telemetry, validator: null);
298+
actual.Should().Be(ConfigurationResult<int>.Valid(expected));
299+
300+
// final telemetry value should be the "real" value
301+
telemetry.Telemetry.Last().Value.Should().Be(expected);
302+
303+
// telemetry records the first error, and then the successful value
304+
telemetry.Telemetry.Should()
305+
.BeEquivalentTo(
306+
[
307+
new ConfigurationTelemetryTests.ConfigDto(key, "not_an_int", ConfigurationOrigins.DdConfig, true, TelemetryErrorCode.ParsingInt32Error),
308+
new ConfigurationTelemetryTests.ConfigDto(key, 123, ConfigurationOrigins.Code, true, null),
309+
]);
233310
}
234311

235312
internal class StubTelemetry : IConfigurationTelemetry
236313
{
237-
public Dictionary<string, int> Accesses { get; } = new();
314+
public List<ConfigurationTelemetryTests.ConfigDto> Telemetry { get; } = new();
238315

239316
public void Record(string key, string value, bool recordValue, ConfigurationOrigins origin, TelemetryErrorCode? error = null)
240-
=> IncrementAccess(key);
317+
=> Telemetry.Add(new(key, value, origin, recordValue, error));
241318

242319
public void Record(string key, bool value, ConfigurationOrigins origin, TelemetryErrorCode? error = null)
243-
=> IncrementAccess(key);
320+
=> Telemetry.Add(new(key, value, origin, recordValue: true, error));
244321

245322
public void Record(string key, double value, ConfigurationOrigins origin, TelemetryErrorCode? error = null)
246-
=> IncrementAccess(key);
323+
=> Telemetry.Add(new(key, value, origin, recordValue: true, error));
247324

248325
public void Record(string key, int value, ConfigurationOrigins origin, TelemetryErrorCode? error = null)
249-
=> IncrementAccess(key);
326+
=> Telemetry.Add(new(key, value, origin, recordValue: true, error));
250327

251328
public void Record(string key, double? value, ConfigurationOrigins origin, TelemetryErrorCode? error = null)
252-
=> IncrementAccess(key);
329+
=> Telemetry.Add(new(key, value, origin, recordValue: true, error));
253330

254331
public void Record(string key, int? value, ConfigurationOrigins origin, TelemetryErrorCode? error = null)
255-
=> IncrementAccess(key);
332+
=> Telemetry.Add(new(key, value, origin, recordValue: true, error));
256333

257334
public ICollection<ConfigurationKeyValue> GetData() => null;
258335

@@ -264,16 +341,7 @@ public void SetErrorOnCurrentEntry(string key, TelemetryErrorCode error)
264341
{
265342
}
266343

267-
private void IncrementAccess(string key)
268-
{
269-
if (Accesses.TryGetValue(key, out var i))
270-
{
271-
Accesses[key] = i + 1;
272-
}
273-
else
274-
{
275-
Accesses[key] = 1;
276-
}
277-
}
344+
public int GetInstanceCount(string key)
345+
=> Telemetry.Count(x => x.Name == key);
278346
}
279347
}

0 commit comments

Comments
 (0)