Skip to content

Commit 79da0d6

Browse files
authored
Extract MutableSettings from TracerSettings (#7522)
## Summary of changes - Extract a `MutableSettings` type from `TracerSettings` - Extract a `Raw` type from `ExporterSettings` ## Reason for change We're working on refactoring how we handle dynamic/remote/config in code settings i.e. settings which can change at runtime. As a first step, this PR extracts those settings to their own type, called `MutableSettings` because they mutable during the lifetime of the app. > Feel free to suggest other names for this type, or we can alternatively bikeshed it later. Additionally, extracted the "raw" settings from `ExporterSettings`. These are the values which are read from config sources. The actual values of `ExporterSettings` are set based on these values, using a highly convoluted (backward compatible) series of methods, but the idea is: if the `Raw` settings haven't changed, the `ExporterSettings` haven't changed. > This isn't _strictly_ true due to the `File.Exists` call we have, but I believe this is good enough for our purposes. ## Implementation details - Create `MutableSettings` and move all the properties from `TracerSettings` that _can_ change to it. - Update `TracerSettings` to create an instance of `MutableSettings`, and simply pass-through properties to it. - This should mean existing functionality is unaffected by this PR - Implement `IEquatable<MutableSettings>` for future comparisons between `MutableSettings` instances - Unfortunately, can't use a `record` here or auto-gen the implementation, because we need to handle equivalence of the dictionaries. - Extract the "raw" setting reading to an `ExporterSettings` nested-type - Opted for nested here, because unlike `MutableSettings` (which will eventually live separately from `TracerSettings`) we won't expose `Raw` to consumers - they'll still use `ExporterSettings` ## Test coverage This is just a refactoring, so it's covered by existing tests. Additionally, I added a test for the `IEquatable` implementation (which is similar to the test we have for `ImmutableDynamicSettings`) to ensure the implementation is updated if we add more properties. ## Other details https://datadoghq.atlassian.net/browse/LANGPLAT-819 Part of a config stack - #7522 👈 - #7525 - #7530 - #7532 - #7543 - #7544
1 parent 2fe4a6d commit 79da0d6

File tree

9 files changed

+1908
-1294
lines changed

9 files changed

+1908
-1294
lines changed

tracer/src/Datadog.Trace/Configuration/DynamicConfigurationManager.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ private static void OnConfigurationChanged(ConfigurationBuilder settings)
6767
{
6868
var oldSettings = Tracer.Instance.Settings;
6969

70-
var headerTags = TracerSettings.InitializeHeaderTags(settings, ConfigurationKeys.HeaderTags, headerTagsNormalizationFixEnabled: true);
70+
var headerTags = MutableSettings.InitializeHeaderTags(settings, ConfigurationKeys.HeaderTags, headerTagsNormalizationFixEnabled: true);
7171
// var serviceNameMappings = TracerSettings.InitializeServiceNameMappings(settings, ConfigurationKeys.ServiceNameMappings);
7272

7373
var globalTags = settings.WithKeys(ConfigurationKeys.GlobalTags).AsDictionary();

tracer/src/Datadog.Trace/Configuration/ExporterSettings.cs

Lines changed: 118 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -84,52 +84,47 @@ internal ExporterSettings(IConfigurationSource? source, IConfigurationTelemetry
8484
/// Direct use in tests only.
8585
/// </summary>
8686
internal ExporterSettings(IConfigurationSource? source, Func<string, bool> fileExists, IConfigurationTelemetry telemetry)
87+
: this(new Raw(source ?? NullConfigurationSource.Instance, telemetry), fileExists, telemetry)
88+
{
89+
}
90+
91+
internal ExporterSettings(Raw rawSettings, Func<string, bool> fileExists, IConfigurationTelemetry telemetry)
8792
{
8893
_fileExists = fileExists;
8994
_telemetry = telemetry;
95+
RawSettings = rawSettings;
9096

9197
ValidationWarnings = new List<string>();
9298

93-
source ??= NullConfigurationSource.Instance;
94-
95-
// Get values from the config
96-
var config = new ConfigurationBuilder(source, telemetry);
97-
var traceAgentUrl = config.WithKeys(ConfigurationKeys.AgentUri).AsString();
98-
var tracesPipeName = config.WithKeys(ConfigurationKeys.TracesPipeName).AsString();
99-
var tracesUnixDomainSocketPath = config.WithKeys(ConfigurationKeys.TracesUnixDomainSocketPath).AsString();
100-
101-
var agentHost = config
102-
.WithKeys(ConfigurationKeys.AgentHost, "DD_TRACE_AGENT_HOSTNAME", "DATADOG_TRACE_AGENT_HOSTNAME")
103-
.AsString();
99+
var traceSettings = GetTraceTransport(
100+
agentUri: rawSettings.TraceAgentUri,
101+
tracesPipeName: rawSettings.TracesPipeName,
102+
agentHost: rawSettings.TraceAgentHost,
103+
agentPort: rawSettings.TraceAgentPort,
104+
tracesUnixDomainSocketPath: rawSettings.TracesUnixDomainSocketPath);
104105

105-
var agentPort = config
106-
.WithKeys(ConfigurationKeys.AgentPort, "DATADOG_TRACE_AGENT_PORT")
107-
.AsInt32();
108-
109-
var metricsUrl = config.WithKeys(ConfigurationKeys.MetricsUri).AsString();
110-
var dogStatsdPort = config.WithKeys(ConfigurationKeys.DogStatsdPort).AsInt32(0);
111-
var metricsPipeName = config.WithKeys(ConfigurationKeys.MetricsPipeName).AsString();
112-
var metricsUnixDomainSocketPath = config.WithKeys(ConfigurationKeys.MetricsUnixDomainSocketPath).AsString();
113-
114-
var traceSettings = GetTraceTransport(traceAgentUrl, tracesPipeName, agentHost, agentPort, tracesUnixDomainSocketPath);
115106
TracesTransport = traceSettings.Transport;
116107
TracesPipeName = traceSettings.PipeName;
117108
TracesUnixDomainSocketPath = traceSettings.UdsPath;
118109
AgentUri = traceSettings.AgentUri;
119110

120-
var metricsSettings = ConfigureMetricsTransport(metricsUrl, traceAgentUrl, agentHost, dogStatsdPort, metricsPipeName, metricsUnixDomainSocketPath);
111+
var metricsSettings = ConfigureMetricsTransport(
112+
metricsUrl: rawSettings.MetricsUrl,
113+
traceAgentUrl: rawSettings.TraceAgentUri,
114+
agentHost: rawSettings.TraceAgentHost,
115+
dogStatsdPort: rawSettings.DogStatsdPort,
116+
metricsPipeName: rawSettings.MetricsPipeName,
117+
metricsUnixDomainSocketPath: rawSettings.MetricsUnixDomainSocketPath);
118+
121119
MetricsHostname = metricsSettings.Hostname;
122120
MetricsUnixDomainSocketPath = metricsSettings.UdsPath;
123121
MetricsTransport = metricsSettings.Transport;
124122
MetricsPipeName = metricsSettings.PipeName;
125123
DogStatsdPort = metricsSettings.DogStatsdPort > 0
126124
? metricsSettings.DogStatsdPort
127-
: (dogStatsdPort > 0 ? dogStatsdPort : DefaultDogstatsdPort);
125+
: (rawSettings.DogStatsdPort > 0 ? rawSettings.DogStatsdPort : DefaultDogstatsdPort);
128126

129-
TracesPipeTimeoutMs = config
130-
.WithKeys(ConfigurationKeys.TracesPipeTimeoutMs)
131-
.AsInt32(500, value => value > 0)
132-
.Value;
127+
TracesPipeTimeoutMs = rawSettings.TracesPipeTimeoutMs;
133128
}
134129

135130
/// <summary>
@@ -217,6 +212,8 @@ internal ExporterSettings(IConfigurationSource? source, Func<string, bool> fileE
217212

218213
internal IConfigurationTelemetry Telemetry => _telemetry;
219214

215+
internal Raw RawSettings { get; }
216+
220217
// internal for testing
221218
internal static ExporterSettings Create(Dictionary<string, object?> settings)
222219
=> new(new DictionaryConfigurationSource(settings.ToDictionary(x => x.Key, x => x.Value?.ToString()!)), new ConfigurationTelemetry());
@@ -433,5 +430,99 @@ private void RecordTraceTransport(string transport, ConfigurationOrigins origin
433430
=> _telemetry.Record(ConfigTelemetryData.AgentTraceTransport, transport, recordValue: true, origin);
434431

435432
private readonly record struct MetricsTransportSettings(MetricsTransportType Transport, string Hostname = DefaultDogstatsdHostname, int DogStatsdPort = 0, string? UdsPath = null, string? PipeName = null);
433+
434+
/// <summary>
435+
/// These contain the "raw" settings loaded from config. If these don't change, the exporter settings also won't change
436+
/// </summary>
437+
internal record Raw
438+
{
439+
public Raw(IConfigurationSource source, IConfigurationTelemetry telemetry)
440+
{
441+
// Get values from the config
442+
var config = new ConfigurationBuilder(source, telemetry);
443+
TraceAgentUri = config.WithKeys(ConfigurationKeys.AgentUri).AsString();
444+
TracesPipeName = config.WithKeys(ConfigurationKeys.TracesPipeName).AsString();
445+
TracesUnixDomainSocketPath = config.WithKeys(ConfigurationKeys.TracesUnixDomainSocketPath).AsString();
446+
447+
TraceAgentHost = config
448+
.WithKeys(ConfigurationKeys.AgentHost, "DD_TRACE_AGENT_HOSTNAME", "DATADOG_TRACE_AGENT_HOSTNAME")
449+
.AsString();
450+
451+
TraceAgentPort = config
452+
.WithKeys(ConfigurationKeys.AgentPort, "DATADOG_TRACE_AGENT_PORT")
453+
.AsInt32();
454+
455+
MetricsUrl = config.WithKeys(ConfigurationKeys.MetricsUri).AsString();
456+
DogStatsdPort = config.WithKeys(ConfigurationKeys.DogStatsdPort).AsInt32(0);
457+
MetricsPipeName = config.WithKeys(ConfigurationKeys.MetricsPipeName).AsString();
458+
MetricsUnixDomainSocketPath = config.WithKeys(ConfigurationKeys.MetricsUnixDomainSocketPath).AsString();
459+
460+
TracesPipeTimeoutMs = config
461+
.WithKeys(ConfigurationKeys.TracesPipeTimeoutMs)
462+
.AsInt32(500, value => value > 0)
463+
.Value;
464+
}
465+
466+
/// <summary>
467+
/// Gets the Uri where the Tracer can connect to the Agent.
468+
/// </summary>
469+
/// <seealso cref="ConfigurationKeys.AgentUri"/>
470+
public string? TraceAgentUri { get; }
471+
472+
/// <summary>
473+
/// Gets the host where the Tracer can connect to the Agent.
474+
/// </summary>
475+
/// <seealso cref="ConfigurationKeys.AgentUri"/>
476+
public string? TraceAgentHost { get; }
477+
478+
/// <summary>
479+
/// Gets the port where the Tracer can connect to the Agent.
480+
/// </summary>
481+
/// <seealso cref="ConfigurationKeys.AgentUri"/>
482+
public int? TraceAgentPort { get; }
483+
484+
/// <summary>
485+
/// Gets the windows pipe name where the Tracer can connect to the Agent.
486+
/// </summary>
487+
/// <seealso cref="ConfigurationKeys.TracesPipeName"/>
488+
public string? TracesPipeName { get; }
489+
490+
/// <summary>
491+
/// Gets the timeout in milliseconds for the windows named pipe requests.
492+
/// Default is <c>100</c>.
493+
/// </summary>
494+
/// <seealso cref="ConfigurationKeys.TracesPipeTimeoutMs"/>
495+
public int TracesPipeTimeoutMs { get; }
496+
497+
/// <summary>
498+
/// Gets the Uri where the Tracer can connect to statsd.
499+
/// </summary>
500+
/// <seealso cref="ConfigurationKeys.AgentUri"/>
501+
public string? MetricsUrl { get; }
502+
503+
/// <summary>
504+
/// Gets the windows pipe name where the Tracer can send stats.
505+
/// Default is <c>null</c>.
506+
/// </summary>
507+
/// <seealso cref="ConfigurationKeys.MetricsPipeName"/>
508+
public string? MetricsPipeName { get; }
509+
510+
/// <summary>
511+
/// Gets the unix domain socket path where the Tracer can connect to the Agent.
512+
/// This parameter is deprecated and shall be removed. Consider using AgentUri instead
513+
/// </summary>
514+
public string? TracesUnixDomainSocketPath { get; }
515+
516+
/// <summary>
517+
/// Gets the unix domain socket path where the Tracer can send stats.
518+
/// </summary>
519+
/// <seealso cref="ConfigurationKeys.MetricsUnixDomainSocketPath"/>
520+
public string? MetricsUnixDomainSocketPath { get; }
521+
522+
/// <summary>
523+
/// Gets the port where the DogStatsd server is listening for connections.
524+
/// </summary>
525+
public int DogStatsdPort { get; }
526+
}
436527
}
437528
}

tracer/src/Datadog.Trace/Configuration/IntegrationSettings.cs

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
#nullable enable
77

8+
using System;
89
using System.Collections.Generic;
910
using Datadog.Trace.Configuration.Telemetry;
1011

@@ -13,7 +14,7 @@ namespace Datadog.Trace.Configuration
1314
/// <summary>
1415
/// Contains integration-specific settings.
1516
/// </summary>
16-
public class IntegrationSettings
17+
public class IntegrationSettings : IEquatable<IntegrationSettings>
1718
{
1819
/// <summary>
1920
/// Initializes a new instance of the <see cref="IntegrationSettings"/> class.
@@ -82,5 +83,51 @@ internal IntegrationSettings(string integrationName, IConfigurationSource? sourc
8283
/// that determines the sampling rate for this integration.
8384
/// </summary>
8485
public double AnalyticsSampleRate { get; }
86+
87+
/// <inheritdoc/>
88+
public bool Equals(IntegrationSettings? other)
89+
{
90+
if (other is null)
91+
{
92+
return false;
93+
}
94+
95+
if (ReferenceEquals(this, other))
96+
{
97+
return true;
98+
}
99+
100+
return IntegrationName == other.IntegrationName &&
101+
Enabled == other.Enabled &&
102+
AnalyticsEnabled == other.AnalyticsEnabled &&
103+
AnalyticsSampleRate.Equals(other.AnalyticsSampleRate);
104+
}
105+
106+
/// <inheritdoc/>
107+
public override bool Equals(object? obj)
108+
{
109+
if (obj is null)
110+
{
111+
return false;
112+
}
113+
114+
if (ReferenceEquals(this, obj))
115+
{
116+
return true;
117+
}
118+
119+
if (obj.GetType() != GetType())
120+
{
121+
return false;
122+
}
123+
124+
return Equals((IntegrationSettings)obj);
125+
}
126+
127+
/// <inheritdoc/>
128+
public override int GetHashCode()
129+
{
130+
return HashCode.Combine(IntegrationName, Enabled, AnalyticsEnabled, AnalyticsSampleRate);
131+
}
85132
}
86133
}

0 commit comments

Comments
 (0)