Skip to content

Commit 0a4d09b

Browse files
Create SettingsManager for managing mutable settings and ExporterSettings (#7695)
## Summary of changes - Introduces `SettingsManager` responsible for managing `MutableSettings` and `ExporterSettings` ## Reason for change We need to be notified about runtime changes to settings (i.e. config in code or remote config) but don't want to tear down the world and rebuild every time. `SettingsManager` is responsible for handling this. Consumers subscribe to changes and can be notified about updates. This is a first step which just introduces the type, but doesn't force users to consume changes or remove the current places settings are exposed. Instead, it just encapsulates the changes. ## Implementation details - Introduce `SettingsManager` - Move code duplicated in `DynamicConfigurationManager` and `ConfigureIntegration` into `SettingsManager` - Create a new instance of `SettingsManager` (and maintain it throughout the app lifetime) - Subscribe to changes one time in `TracerManager` to do the "full rebuild" - This is a stop gap before we use it "properly" and stop exposing the settings on `TracerSettings` ## Test coverage - Mostly a refactor so covered by integration tests - Unit tests for `SettingsManager` functionality ## Other details https://datadoghq.atlassian.net/browse/LANGPLAT-819 Part of a config stack - #7522 - #7525 - #7530 - #7532 - #7543 - #7544 - #7721 - #7722 - #7695 👈 - #7723 - #7724 - #7796 --------- Co-authored-by: Lucas Pimentel <[email protected]>
1 parent e31019e commit 0a4d09b

File tree

9 files changed

+373
-181
lines changed

9 files changed

+373
-181
lines changed

tracer/src/Datadog.Trace/ClrProfiler/AutoInstrumentation/ManualInstrumentation/Tracer/ConfigureIntegration.cs

Lines changed: 3 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -73,69 +73,10 @@ internal static void ConfigureSettingsWithManualOverrides(Dictionary<string, obj
7373
? new ManualInstrumentationLegacyConfigurationSource(values, isFromDefaults)
7474
: new ManualInstrumentationConfigurationSource(values, isFromDefaults);
7575

76-
// We need to save this immediately, even if there's no manifest changes in the final settings
77-
GlobalConfigurationSource.UpdateManualConfigurationSource(manualConfig);
78-
79-
var tracerSettings = Datadog.Trace.Tracer.Instance.Settings;
80-
var dynamicConfig = GlobalConfigurationSource.DynamicConfigurationSource;
81-
var initialSettings = isFromDefaults
82-
? tracerSettings.InitialMutableSettings
83-
: MutableSettings.CreateWithoutDefaultSources(tracerSettings);
84-
85-
// TODO: these will eventually live elsewhere
86-
var currentSettings = tracerSettings.MutableSettings;
87-
88-
var manualTelemetry = new ConfigurationTelemetry();
89-
var newMutableSettings = MutableSettings.CreateUpdatedMutableSettings(
90-
dynamicConfig,
91-
manualConfig,
92-
initialSettings,
93-
tracerSettings,
94-
manualTelemetry,
95-
new OverrideErrorLog()); // TODO: We'll later report these
96-
97-
var isSameMutableSettings = currentSettings.Equals(newMutableSettings);
98-
99-
// The only exporter setting we currently _allow_ to change is the AgentUri, but if that does change,
100-
// it can mean that _everything_ about the exporter settings changes. To minimize the work to do, and
101-
// to simplify comparisons, we try to read the agent url from the manual setting. If it's missing, not
102-
// set, or unchanged, there's no need to update the exporter settings. In the future, ExporterSettings
103-
// will live separate from TracerSettings entirely.
104-
var exporterTelemetry = new ConfigurationTelemetry();
105-
var newRawExporterSettings = ExporterSettings.Raw.CreateUpdatedFromManualConfig(
106-
tracerSettings.Exporter.RawSettings,
107-
manualConfig,
108-
exporterTelemetry,
109-
isFromDefaults);
110-
var isSameExporterSettings = tracerSettings.Exporter.RawSettings.Equals(newRawExporterSettings);
111-
112-
if (isSameMutableSettings && isSameExporterSettings)
76+
var wasUpdated = Datadog.Trace.Tracer.Instance.Settings.Manager.UpdateManualConfigurationSettings(manualConfig, TelemetryFactory.Config);
77+
if (wasUpdated)
11378
{
114-
Log.Debug("No changes detected in the new configuration in code");
115-
// Even though there were no "real" changes, there may be _effective_ changes in telemetry that
116-
// need to be recorded (e.g. the customer set the value in code but it was already set via
117-
// env vars). We _should_ record exporter settings too, but that introduces a bunch of complexity
118-
// which we'll resolve later anyway, so just have that gap for now (it's very niche).
119-
// If there are changes, they're recorded automatically in ConfigureInternal
120-
manualTelemetry.CopyTo(TelemetryFactory.Config);
121-
return;
79+
Log.Information("Setting updates made via configuration in code were applied");
12280
}
123-
124-
Log.Information("Applying new configuration in code");
125-
TracerSettings newSettings;
126-
if (isSameExporterSettings)
127-
{
128-
newSettings = tracerSettings with { MutableSettings = newMutableSettings };
129-
}
130-
else
131-
{
132-
var exporterSettings = new ExporterSettings(newRawExporterSettings, exporterTelemetry);
133-
newSettings = isSameMutableSettings
134-
? tracerSettings with { Exporter = exporterSettings }
135-
: tracerSettings with { MutableSettings = newMutableSettings, Exporter = exporterSettings };
136-
}
137-
138-
// Update the global instance
139-
Trace.Tracer.Configure(newSettings);
14081
}
14182
}

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

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -22,20 +22,13 @@ namespace Datadog.Trace.Configuration;
2222
/// </summary>
2323
internal class GlobalConfigurationSource
2424
{
25-
private static IConfigurationSource _dynamicConfigConfigurationSource = NullConfigurationSource.Instance;
26-
private static ManualInstrumentationConfigurationSourceBase _manualConfigurationSource = new ManualInstrumentationConfigurationSource(new Dictionary<string, object?>(), useDefaultSources: true);
27-
2825
/// <summary>
2926
/// Gets the configuration source instance.
3027
/// </summary>
3128
internal static IConfigurationSource Instance => CreationResult.ConfigurationSource;
3229

3330
internal static GlobalConfigurationSourceResult CreationResult { get; private set; } = CreateDefaultConfigurationSource();
3431

35-
internal static IConfigurationSource DynamicConfigurationSource => _dynamicConfigConfigurationSource;
36-
37-
internal static ManualInstrumentationConfigurationSourceBase ManualConfigurationSource => _manualConfigurationSource;
38-
3932
/// <summary>
4033
/// Creates a <see cref="IConfigurationSource"/> by combining environment variables,
4134
/// Precedence is as follows:
@@ -142,14 +135,4 @@ private static string GetCurrentDirectory()
142135
{
143136
return AppDomain.CurrentDomain.BaseDirectory ?? Directory.GetCurrentDirectory();
144137
}
145-
146-
public static void UpdateDynamicConfigConfigurationSource(IConfigurationSource dynamic)
147-
{
148-
Interlocked.Exchange(ref _dynamicConfigConfigurationSource, dynamic);
149-
}
150-
151-
public static void UpdateManualConfigurationSource(ManualInstrumentationConfigurationSourceBase manual)
152-
{
153-
Interlocked.Exchange(ref _manualConfigurationSource, manual);
154-
}
155138
}

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

Lines changed: 10 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313
using System.Threading;
1414
using System.Threading.Tasks;
1515
using Datadog.Trace.Configuration.ConfigurationSources;
16-
using Datadog.Trace.Configuration.ConfigurationSources.Telemetry;
1716
using Datadog.Trace.Configuration.Telemetry;
1817
using Datadog.Trace.Debugger;
1918
using Datadog.Trace.Debugger.Configurations;
@@ -68,79 +67,17 @@ public void Dispose()
6867
}
6968
}
7069

71-
internal static void OnlyForTests_ApplyConfiguration(IConfigurationSource dynamicConfig)
70+
internal static void OnlyForTests_ApplyConfiguration(IConfigurationSource dynamicConfig, TracerSettings tracerSettings)
7271
{
73-
OnConfigurationChanged(dynamicConfig);
72+
OnConfigurationChanged(dynamicConfig, tracerSettings);
7473
}
7574

76-
private static void OnConfigurationChanged(IConfigurationSource dynamicConfig)
75+
private static void OnConfigurationChanged(IConfigurationSource dynamicConfig, TracerSettings tracerSettings)
7776
{
78-
var tracerSettings = Tracer.Instance.Settings;
79-
var manualSource = GlobalConfigurationSource.ManualConfigurationSource;
80-
var mutableSettings = manualSource.UseDefaultSources
81-
? tracerSettings.InitialMutableSettings
82-
: MutableSettings.CreateWithoutDefaultSources(tracerSettings);
83-
84-
// We save this immediately, even if there's no manifest changes in the final settings
85-
GlobalConfigurationSource.UpdateDynamicConfigConfigurationSource(dynamicConfig);
86-
87-
OnConfigurationChanged(
88-
dynamicConfig,
89-
manualSource,
90-
mutableSettings,
91-
tracerSettings,
92-
// TODO: In the future this will 'live' elsewhere
93-
currentSettings: tracerSettings.MutableSettings,
94-
new ConfigurationTelemetry(),
95-
new OverrideErrorLog()); // TODO: We'll later report these
96-
}
97-
98-
private static void OnConfigurationChanged(
99-
IConfigurationSource dynamicConfig,
100-
ManualInstrumentationConfigurationSourceBase manualConfig,
101-
MutableSettings initialSettings,
102-
TracerSettings tracerSettings,
103-
MutableSettings currentSettings,
104-
ConfigurationTelemetry telemetry,
105-
OverrideErrorLog errorLog)
106-
{
107-
var newMutableSettings = MutableSettings.CreateUpdatedMutableSettings(
108-
dynamicConfig,
109-
manualConfig,
110-
initialSettings,
111-
tracerSettings,
112-
telemetry,
113-
errorLog);
114-
115-
TracerSettings newSettings;
116-
if (currentSettings.Equals(newMutableSettings))
117-
{
118-
Log.Debug("No changes detected in the new dynamic configuration");
119-
// Even though there were no "real" changes, there may be _effective_ changes in telemetry that
120-
// need to be recorded (e.g. the customer set the value in code but it was already set via
121-
// env vars). We _should_ record exporter settings too, but that introduces a bunch of complexity
122-
// which we'll resolve later anyway, so just have that gap for now (it's very niche).
123-
// If there are changes, they're recorded automatically in Tracer.Configure()
124-
telemetry.CopyTo(TelemetryFactory.Config);
125-
newSettings = tracerSettings;
126-
}
127-
else
77+
var wasUpdated = tracerSettings.Manager.UpdateDynamicConfigurationSettings(dynamicConfig, TelemetryFactory.Config);
78+
if (wasUpdated)
12879
{
129-
Log.Information("Applying new dynamic configuration");
130-
131-
newSettings = tracerSettings with { MutableSettings = newMutableSettings };
132-
133-
/*
134-
if (debugLogsEnabled != null && debugLogsEnabled.Value != GlobalSettings.Instance.DebugEnabled)
135-
{
136-
GlobalSettings.SetDebugEnabled(debugLogsEnabled.Value);
137-
Security.Instance.SetDebugEnabled(debugLogsEnabled.Value);
138-
139-
NativeMethods.UpdateSettings(new[] { ConfigurationKeys.DebugEnabled }, new[] { debugLogsEnabled.Value ? "1" : "0" });
140-
}
141-
*/
142-
143-
Tracer.Configure(newSettings);
80+
Log.Information("Setting updates made via dynamic configuration were applied");
14481
}
14582

14683
// TODO: This might not record the config in the correct order in future, but would require
@@ -173,7 +110,7 @@ private static void OnConfigurationChanged(
173110

174111
var newDebuggerSettings = oldDebuggerSettings with { DynamicSettings = dynamicDebuggerSettings };
175112

176-
DebuggerManager.Instance.UpdateConfiguration(newSettings, newDebuggerSettings)
113+
DebuggerManager.Instance.UpdateConfiguration(Tracer.Instance.Settings, newDebuggerSettings)
177114
.ContinueWith(t => Log.Error(t?.Exception, "Error updating dynamic configuration for debugger"), TaskContinuationOptions.OnlyOnFaulted);
178115
}
179116

@@ -247,7 +184,8 @@ private ApplyDetails[] ConfigurationUpdated(
247184
private void ApplyMergedConfiguration(List<RemoteConfiguration> remoteConfigurations)
248185
{
249186
// Get current service/environment for filtering
250-
var currentSettings = Tracer.Instance.CurrentTraceSettings.Settings;
187+
var tracer = Tracer.Instance;
188+
var currentSettings = tracer.CurrentTraceSettings.Settings;
251189

252190
var mergedConfigJToken = ApmTracingConfigMerger.MergeConfigurations(
253191
remoteConfigurations,
@@ -256,7 +194,7 @@ private void ApplyMergedConfiguration(List<RemoteConfiguration> remoteConfigurat
256194

257195
var configurationSource = new DynamicConfigConfigurationSource(mergedConfigJToken, ConfigurationOrigins.RemoteConfig);
258196

259-
OnConfigurationChanged(configurationSource);
197+
OnConfigurationChanged(configurationSource, tracer.Settings);
260198
}
261199
}
262200
}

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1087,6 +1087,13 @@ public static MutableSettings CreateWithoutDefaultSources(TracerSettings tracerS
10871087
new OverrideErrorLog(),
10881088
tracerSettings);
10891089

1090+
public static MutableSettings CreateForTesting(TracerSettings tracerSettings, Dictionary<string, object?> settings)
1091+
=> CreateInitialMutableSettings(
1092+
new DictionaryConfigurationSource(settings.ToDictionary(x => x.Key, x => x.Value?.ToString()!)),
1093+
new ConfigurationTelemetry(),
1094+
new OverrideErrorLog(),
1095+
tracerSettings);
1096+
10901097
private static ConfigurationBuilder.ClassConfigurationResultWithKey<IDictionary<string, string>> RemapOtelTags(
10911098
in ConfigurationBuilder.ClassConfigurationResultWithKey<IDictionary<string, string>> original)
10921099
{

0 commit comments

Comments
 (0)