Skip to content

Commit 94b3397

Browse files
andrewlockveerbia
authored andcommitted
Make ExporterSettings properly immutable and remove ImmutableExporterSettings (#6408)
## Summary of changes Merge `ExporterSettings` with `ImmutableExporterSettings` ## Reason for change This stack of PRs is about doing one-shot configuration instead of mutation. We never mutate these in the tracer after creation, so there's no need for the separate types. ## Implementation details - Made the properties in `ExporterSettings` get-only. This required quite a lot of work because we were doing a lot of mutating of the settings in the "helper" functions. - I only _lightly_ refactored those methods (as much as possible) to avoid setting the properties in the functions and instead returning the details to set later. - These are prime candidates for some _much_ heavier refactoring later, but I didn't want to get bogged down with that in this PR - Replace all usages of `Immutable*` with `ExporterSettings` - Replace usages of `AgentUriInternal` with `AgentUri` - Move `Immutable*Tests` into appropriate file and tweak - Replace mutations with initialization ## Test coverage All covered by existing details ## Other details Part of Stack - #6370 - #6376 - #6385 - #6386 - #6397 - #6399 - #6400 - #6405 - #6408 👈 This PR - #6415
1 parent 019f234 commit 94b3397

File tree

28 files changed

+233
-574
lines changed

28 files changed

+233
-574
lines changed

tracer/src/Datadog.Trace.Tools.Runner/Utils.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -425,7 +425,7 @@ public static string GetEnvironmentVariable(string key, string defaultValue = nu
425425
using (cts.Token.Register(
426426
() =>
427427
{
428-
WriteError($"Error connecting to the Datadog Agent at {tracerSettings.Exporter.AgentUriInternal}.");
428+
WriteError($"Error connecting to the Datadog Agent at {tracerSettings.Exporter.AgentUri}.");
429429
tcs.TrySetResult(null);
430430
}))
431431
{

tracer/src/Datadog.Trace.Tools.dd_dotnet/ExporterSettings.cs

+15-9
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,6 @@ public partial class ExporterSettings
2121
private readonly Func<string, bool> _fileExists = File.Exists;
2222
private readonly DummyTelemetry _telemetry = new();
2323

24-
private Uri _agentUri;
25-
2624
/// <summary>
2725
/// Initializes a new instance of the <see cref="ExporterSettings"/> class.
2826
/// </summary>
@@ -37,7 +35,11 @@ public ExporterSettings(IConfigurationSource? configuration)
3735

3836
int.TryParse(agentPortStr, out var agentPort);
3937

40-
ConfigureTraceTransport(agentUri, tracePipeName, agentHost, agentPort, unixDomainSocketPath);
38+
var traceSettings = GetTraceTransport(agentUri, tracePipeName, agentHost, agentPort, unixDomainSocketPath);
39+
TracesTransport = traceSettings.Transport;
40+
TracesPipeName = traceSettings.PipeName;
41+
TracesUnixDomainSocketPath = traceSettings.UdsPath;
42+
AgentUri = traceSettings.AgentUri;
4143
}
4244

4345
/// <summary>
@@ -46,23 +48,27 @@ public ExporterSettings(IConfigurationSource? configuration)
4648
/// <param name="agentUri">Agent URI</param>
4749
public ExporterSettings(string agentUri)
4850
{
49-
ConfigureTraceTransport(agentUri, null, null, null, null);
51+
var traceSettings = GetTraceTransport(agentUri, null, null, null, null);
52+
TracesTransport = traceSettings.Transport;
53+
TracesPipeName = traceSettings.PipeName;
54+
TracesUnixDomainSocketPath = traceSettings.UdsPath;
55+
AgentUri = traceSettings.AgentUri;
5056
}
5157

5258
internal enum TelemetryErrorCode
5359
{
5460
PotentiallyInvalidUdsPath
5561
}
5662

57-
internal Uri AgentUri => _agentUri;
63+
internal Uri AgentUri { get; }
5864

59-
private List<string> ValidationWarnings { get; set; } = new();
65+
private List<string> ValidationWarnings { get; } = new();
6066

61-
internal TracesTransportType TracesTransport { get; private set; }
67+
internal TracesTransportType TracesTransport { get; }
6268

63-
internal string? TracesPipeName { get; private set; }
69+
internal string? TracesPipeName { get; }
6470

65-
internal string? TracesUnixDomainSocketPath { get; private set; }
71+
internal string? TracesUnixDomainSocketPath { get; }
6672

6773
private static string? GetValue(IConfigurationSource? configuration, params string[] keys)
6874
{

tracer/src/Datadog.Trace/Agent/AgentTransportStrategy.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,10 @@ internal static class AgentTransportStrategy
3131
/// <param name="getHttpHeaderHelper">A func that returns an <see cref="HttpHeaderHelperBase"/> for use
3232
/// with <see cref="DatadogHttpClient"/></param>
3333
/// <param name="getBaseEndpoint">A func that returns the endpoint to send requests to for a given "base" endpoint.
34-
/// The base endpoint will be <see cref="ImmutableExporterSettings.AgentUri" /> for TCP requests and
34+
/// The base endpoint will be <see cref="ExporterSettings.AgentUri" /> for TCP requests and
3535
/// http://localhost/ for named pipes/UDS</param>
3636
public static IApiRequestFactory Get(
37-
ImmutableExporterSettings settings,
37+
ExporterSettings settings,
3838
string productName,
3939
TimeSpan? tcpTimeout,
4040
KeyValuePair<string, string>[] defaultAgentHeaders,

tracer/src/Datadog.Trace/Agent/DiscoveryService/DiscoveryService.cs

+2-2
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ public DiscoveryService(
7777
SupportedTracerFlareEndpoint,
7878
};
7979

80-
public static DiscoveryService Create(ImmutableExporterSettings exporterSettings)
80+
public static DiscoveryService Create(ExporterSettings exporterSettings)
8181
=> Create(
8282
exporterSettings,
8383
tcpTimeout: TimeSpan.FromSeconds(15),
@@ -86,7 +86,7 @@ public static DiscoveryService Create(ImmutableExporterSettings exporterSettings
8686
recheckIntervalMs: 30_000);
8787

8888
public static DiscoveryService Create(
89-
ImmutableExporterSettings exporterSettings,
89+
ExporterSettings exporterSettings,
9090
TimeSpan tcpTimeout,
9191
int initialRetryDelayMs,
9292
int maxRetryDelayMs,

tracer/src/Datadog.Trace/Agent/TracesTransportStrategy.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ namespace Datadog.Trace.Agent
1111
{
1212
internal static class TracesTransportStrategy
1313
{
14-
public static IApiRequestFactory Get(ImmutableExporterSettings settings)
14+
public static IApiRequestFactory Get(ExporterSettings settings)
1515
=> AgentTransportStrategy.Get(
1616
settings,
1717
productName: "trace",

tracer/src/Datadog.Trace/Ci/Agent/Payloads/EventPlatformPayload.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,7 @@ private void EnsureUrl()
158158
break;
159159
case TracesTransportType.Default:
160160
default:
161-
builder = new UriBuilder(_settings.TracerSettings.Exporter.AgentUriInternal);
161+
builder = new UriBuilder(_settings.TracerSettings.Exporter.AgentUri);
162162
break;
163163
}
164164

tracer/src/Datadog.Trace/Ci/CIVisibility.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ public static void Initialize()
110110
else
111111
{
112112
discoveryService = DiscoveryService.Create(
113-
new ImmutableExporterSettings(settings.TracerSettings.Exporter, true),
113+
settings.TracerSettings.Exporter,
114114
tcpTimeout: TimeSpan.FromSeconds(5),
115115
initialRetryDelayMs: 10,
116116
maxRetryDelayMs: 1000,

tracer/src/Datadog.Trace/ClrProfiler/AutoInstrumentation/ManualInstrumentation/Configuration/TracerSettings/PopulateDictionaryIntegration.cs

+1-1
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ internal static CallTargetState OnMethodBegin<TTarget>(Dictionary<string, object
4545
internal static void PopulateSettings(Dictionary<string, object?> values, Trace.Configuration.TracerSettings settings)
4646
{
4747
// record all the settings in the dictionary
48-
values[TracerSettingKeyConstants.AgentUriKey] = settings.Exporter.AgentUriInternal;
48+
values[TracerSettingKeyConstants.AgentUriKey] = settings.Exporter.AgentUri;
4949
#pragma warning disable CS0618 // Type or member is obsolete
5050
values[TracerSettingKeyConstants.AnalyticsEnabledKey] = settings.AnalyticsEnabled;
5151
#pragma warning restore CS0618 // Type or member is obsolete

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

+40-38
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,12 @@ namespace Datadog.Trace.Configuration
2020
public partial class ExporterSettings
2121
{
2222
/// <summary>
23-
/// The default host value for <see cref="AgentUriInternal"/>.
23+
/// The default host value for <see cref="AgentUri"/>.
2424
/// </summary>
2525
public const string DefaultAgentHost = "localhost";
2626

2727
/// <summary>
28-
/// The default port value for <see cref="AgentUriInternal"/>.
28+
/// The default port value for <see cref="AgentUri"/>.
2929
/// </summary>
3030
public const int DefaultAgentPort = 8126;
3131

@@ -39,8 +39,7 @@ public partial class ExporterSettings
3939
/// </summary>
4040
internal const string DefaultTracesUnixDomainSocket = "/var/run/datadog/apm.socket";
4141

42-
[MemberNotNull(nameof(_agentUri))]
43-
private void ConfigureTraceTransport(string? agentUri, string? tracesPipeName, string? agentHost, int? agentPort, string? tracesUnixDomainSocketPath)
42+
private TraceTransportSettings GetTraceTransport(string? agentUri, string? tracesPipeName, string? agentHost, int? agentPort, string? tracesUnixDomainSocketPath)
4443
{
4544
var origin = ConfigurationOrigins.Default; // default because only called from constructor
4645

@@ -49,37 +48,37 @@ private void ConfigureTraceTransport(string? agentUri, string? tracesPipeName, s
4948
// For other cases (eg a configured unix domain socket path not found), we don't fallback as the problem could be fixed outside the application.
5049
if (!string.IsNullOrWhiteSpace(agentUri))
5150
{
52-
if (TrySetAgentUriAndTransport(agentUri!, origin))
51+
if (TryGetAgentUriAndTransport(agentUri!, origin, out var settings))
5352
{
54-
return;
53+
return settings;
5554
}
5655
}
5756

5857
if (!string.IsNullOrWhiteSpace(tracesPipeName))
5958
{
60-
TracesTransport = TracesTransportType.WindowsNamedPipe;
61-
TracesPipeName = tracesPipeName;
6259
RecordTraceTransport(nameof(TracesTransportType.WindowsNamedPipe), origin);
6360

6461
// The Uri isn't needed anymore in that case, just populating it for retro compatibility.
6562
if (!Uri.TryCreate($"http://{agentHost ?? DefaultAgentHost}:{agentPort ?? DefaultAgentPort}", UriKind.Absolute, out var uri))
6663
{
67-
// fallback so _agentUri is always non-null
64+
// fallback so AgentUri is always non-null
6865
uri = CreateDefaultUri();
6966
}
7067

71-
SetAgentUriReplacingLocalhost(uri, origin);
72-
return;
68+
return new TraceTransportSettings(
69+
TracesTransportType.WindowsNamedPipe,
70+
GetAgentUriReplacingLocalhost(uri, origin),
71+
PipeName: tracesPipeName);
7372
}
7473

7574
// This property shouldn't have been introduced. We need to remove it as part of 3.0
7675
// But while it's here, we need to handle it properly
7776
if (!string.IsNullOrWhiteSpace(tracesUnixDomainSocketPath))
7877
{
7978
#if NETCOREAPP3_1_OR_GREATER
80-
if (TrySetAgentUriAndTransport(UnixDomainSocketPrefix + tracesUnixDomainSocketPath, origin))
79+
if (TryGetAgentUriAndTransport(UnixDomainSocketPrefix + tracesUnixDomainSocketPath, origin, out var settings))
8180
{
82-
return;
81+
return settings;
8382
}
8483
#else
8584
// .NET Core 2.1 and .NET FX don't support Unix Domain Sockets
@@ -99,9 +98,9 @@ private void ConfigureTraceTransport(string? agentUri, string? tracesPipeName, s
9998
// The agent will fail to start if it can not bind a port, so we need to override 8126 to prevent port conflict
10099
// Port 0 means it will pick some random available port
101100

102-
if (TrySetAgentUriAndTransport(agentHost ?? DefaultAgentHost, agentPort ?? DefaultAgentPort))
101+
if (TryGetAgentUriAndTransport(agentHost ?? DefaultAgentHost, agentPort ?? DefaultAgentPort, out var settings))
103102
{
104-
return;
103+
return settings;
105104
}
106105
}
107106

@@ -111,45 +110,44 @@ private void ConfigureTraceTransport(string? agentUri, string? tracesPipeName, s
111110
{
112111
// setting the urls as well for retro compatibility in the almost impossible case where someone
113112
// used this config and accessed the AgentUri property as well (to avoid a potential null ref)
114-
// Using Set not TrySet because we know this is a valid Uri and ensures _agentUri is always non-null
115-
SetAgentUriAndTransport(new Uri(UnixDomainSocketPrefix + DefaultTracesUnixDomainSocket), origin);
116-
return;
113+
// Using Get not TryGet because we know this is a valid Uri and ensures _agentUri is always non-null
114+
return GetAgentUriAndTransport(new Uri(UnixDomainSocketPrefix + DefaultTracesUnixDomainSocket), origin);
117115
}
118116
#endif
119117

120118
ValidationWarnings.Add("No transport configuration found, using default values");
121119

122120
// we know this URL is valid so don't use TrySet, otherwise can't guarantee _agentUri is non null
123-
SetAgentUriAndTransport(CreateDefaultUri(), origin);
121+
return GetAgentUriAndTransport(CreateDefaultUri(), origin);
124122
}
125123

126-
[MemberNotNullWhen(true, nameof(_agentUri))]
127-
private bool TrySetAgentUriAndTransport(string host, int port)
124+
private bool TryGetAgentUriAndTransport(string host, int port, out TraceTransportSettings settings)
128125
{
129-
return TrySetAgentUriAndTransport($"http://{host}:{port}", ConfigurationOrigins.Default); // default because only called from constructor
126+
return TryGetAgentUriAndTransport($"http://{host}:{port}", ConfigurationOrigins.Default, out settings); // default because only called from constructor
130127
}
131128

132-
[MemberNotNullWhen(true, nameof(_agentUri))]
133-
private bool TrySetAgentUriAndTransport(string url, ConfigurationOrigins origin)
129+
private bool TryGetAgentUriAndTransport(string url, ConfigurationOrigins origin, out TraceTransportSettings settings)
134130
{
135131
if (!Uri.TryCreate(url, UriKind.Absolute, out var uri))
136132
{
137133
ValidationWarnings.Add($"The Uri: '{url}' is not valid. It won't be taken into account to send traces. Note that only absolute urls are accepted.");
134+
settings = default;
138135
return false;
139136
}
140137

141-
SetAgentUriAndTransport(uri, ConfigurationOrigins.Default); // default because only called from constructor
138+
settings = GetAgentUriAndTransport(uri, ConfigurationOrigins.Default); // default because only called from constructor
142139
return true;
143140
}
144141

145-
[MemberNotNull(nameof(_agentUri))]
146-
private void SetAgentUriAndTransport(Uri uri, ConfigurationOrigins origin)
142+
private TraceTransportSettings GetAgentUriAndTransport(Uri uri, ConfigurationOrigins origin)
147143
{
144+
TracesTransportType transport;
145+
string? udsPath;
148146
if (uri.OriginalString.StartsWith(UnixDomainSocketPrefix, StringComparison.OrdinalIgnoreCase))
149147
{
150148
#if NETCOREAPP3_1_OR_GREATER
151-
TracesTransport = TracesTransportType.UnixDomainSocket;
152-
TracesUnixDomainSocketPath = uri.PathAndQuery;
149+
transport = TracesTransportType.UnixDomainSocket;
150+
udsPath = uri.PathAndQuery;
153151

154152
var absoluteUri = uri.AbsoluteUri.Replace(UnixDomainSocketPrefix, string.Empty);
155153
bool potentiallyInvalid = false;
@@ -184,39 +182,43 @@ private void SetAgentUriAndTransport(Uri uri, ConfigurationOrigins origin)
184182
recordValue: true,
185183
origin,
186184
TelemetryErrorCode.UdsOnUnsupportedPlatform);
187-
SetAgentUriAndTransport(CreateDefaultUri(), ConfigurationOrigins.Calculated);
188-
return;
185+
return GetAgentUriAndTransport(CreateDefaultUri(), ConfigurationOrigins.Calculated);
189186
#endif
190187
}
191188
else
192189
{
193-
TracesTransport = TracesTransportType.Default;
190+
transport = TracesTransportType.Default;
191+
udsPath = null;
194192
RecordTraceTransport(nameof(TracesTransportType.Default), origin);
195193
}
196194

197-
SetAgentUriReplacingLocalhost(uri, origin);
195+
var agentUri = GetAgentUriReplacingLocalhost(uri, origin);
196+
return new(transport, agentUri, UdsPath: udsPath);
198197
}
199198

200-
[MemberNotNull(nameof(_agentUri))]
201-
private void SetAgentUriReplacingLocalhost(Uri uri, ConfigurationOrigins origin)
199+
private Uri GetAgentUriReplacingLocalhost(Uri uri, ConfigurationOrigins origin)
202200
{
201+
Uri agentUri;
203202
if (string.Equals(uri.Host, "localhost", StringComparison.OrdinalIgnoreCase))
204203
{
205204
// Replace localhost with 127.0.0.1 to avoid DNS resolution.
206205
// When ipv6 is enabled, localhost is first resolved to ::1, which fails
207206
// because the trace agent is only bound to ipv4.
208207
// This causes delays when sending traces.
209208
var builder = new UriBuilder(uri) { Host = "127.0.0.1" };
210-
_agentUri = builder.Uri;
209+
agentUri = builder.Uri;
211210
}
212211
else
213212
{
214-
_agentUri = uri;
213+
agentUri = uri;
215214
}
216215

217-
_telemetry.Record(ConfigurationKeys.AgentUri, _agentUri.ToString(), recordValue: true, origin);
216+
_telemetry.Record(ConfigurationKeys.AgentUri, agentUri.ToString(), recordValue: true, origin);
217+
return agentUri;
218218
}
219219

220220
private Uri CreateDefaultUri() => new Uri($"http://{DefaultAgentHost}:{DefaultAgentPort}");
221+
222+
private readonly record struct TraceTransportSettings(TracesTransportType Transport, Uri AgentUri, string? UdsPath = null, string? PipeName = null);
221223
}
222224
}

0 commit comments

Comments
 (0)