Skip to content

Commit 57d5335

Browse files
committed
Initialize SymbolUploader only if DI is explicitly enabled
1 parent 92514e2 commit 57d5335

File tree

3 files changed

+57
-17
lines changed

3 files changed

+57
-17
lines changed

tracer/src/Datadog.Trace/Debugger/DebuggerManager.cs

Lines changed: 34 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -41,13 +41,15 @@ internal class DebuggerManager
4141
private readonly TaskCompletionSource<bool> _processExit;
4242
private volatile bool _isDebuggerEndpointAvailable;
4343
private int _initialized;
44+
private int _symDbInitialized;
4445
private volatile TaskCompletionSource<bool>? _diDebounceGate;
4546
private volatile DynamicInstrumentation? _dynamicInstrumentation;
4647
private int _diState; // 0 = disabled, 1 = initializing, 2 = initialized
4748

4849
private DebuggerManager(DebuggerSettings debuggerSettings, ExceptionReplaySettings exceptionReplaySettings)
4950
{
5051
_initialized = 0;
52+
_symDbInitialized = 0;
5153
_isDebuggerEndpointAvailable = false;
5254
DebuggerSettings = debuggerSettings;
5355
ExceptionReplaySettings = exceptionReplaySettings;
@@ -157,6 +159,8 @@ private Task UpdateProductsState(TracerSettings tracerSettings, DebuggerSettings
157159

158160
OneTimeSetup(tracerSettings);
159161

162+
InitializeSymbolUploaderIfNeeded(tracerSettings, newDebuggerSettings);
163+
160164
lock (_syncLock)
161165
{
162166
if (_processExit.Task.IsCompleted)
@@ -181,19 +185,31 @@ private void OneTimeSetup(TracerSettings tracerSettings)
181185

182186
LifetimeManager.Instance.AddShutdownTask(ShutdownTasks);
183187
SetGeneralConfig(tracerSettings, DebuggerSettings);
184-
InitializeSymbolUploader(tracerSettings);
185188
if (tracerSettings.StartupDiagnosticLogEnabled)
186189
{
187190
_ = Task.Run(WriteStartupDebuggerDiagnosticLog);
188191
}
189192
}
190193

191-
private void InitializeSymbolUploader(TracerSettings tracerSettings)
194+
private void InitializeSymbolUploaderIfNeeded(TracerSettings tracerSettings, DebuggerSettings newDebuggerSettings)
192195
{
193196
try
194197
{
195-
if (_processExit.Task.IsCompleted || !DebuggerSettings.SymbolDatabaseUploadEnabled)
198+
if (_processExit.Task.IsCompleted)
199+
{
200+
return;
201+
}
202+
203+
if (Interlocked.CompareExchange(ref _symDbInitialized, 1, 0) != 0)
204+
{
205+
// Once created, the symbol uploader persists even if DI is later disabled
206+
return;
207+
}
208+
209+
if (!DebuggerSettings.SymbolDatabaseUploadEnabled
210+
|| !newDebuggerSettings.DynamicInstrumentationCanBeEnabled)
196211
{
212+
// explicitly disabled via local env var or DI can not be enabled
197213
return;
198214
}
199215

@@ -203,14 +219,21 @@ private void InitializeSymbolUploader(TracerSettings tracerSettings)
203219
return;
204220
}
205221

222+
if (!newDebuggerSettings.DynamicInstrumentationEnabled
223+
&& newDebuggerSettings.DynamicSettings.DynamicInstrumentationEnabled != true)
224+
{
225+
return;
226+
}
227+
228+
// initialize symbol database uploader only if DI is enabled locally or remotely
206229
var tracerManager = TracerManager.Instance;
207-
SymbolsUploader = DebuggerFactory.CreateSymbolsUploader(tracerManager.DiscoveryService, RcmSubscriptionManager.Instance, ServiceName, tracerSettings, DebuggerSettings, tracerManager.GitMetadataTagsProvider);
208-
_ = SymbolsUploader.StartFlushingAsync()
209-
.ContinueWith(
210-
t => Log.Error(t?.Exception, "Failed to initialize symbol uploader"),
211-
CancellationToken.None,
212-
TaskContinuationOptions.OnlyOnFaulted,
213-
TaskScheduler.Default);
230+
this.SymbolsUploader = DebuggerFactory.CreateSymbolsUploader(tracerManager.DiscoveryService, RcmSubscriptionManager.Instance, this.ServiceName, tracerSettings, this.DebuggerSettings, tracerManager.GitMetadataTagsProvider);
231+
_ = this.SymbolsUploader.StartFlushingAsync()
232+
.ContinueWith(
233+
t => Log.Error(t?.Exception, "Failed to initialize symbol uploader"),
234+
CancellationToken.None,
235+
TaskContinuationOptions.OnlyOnFaulted,
236+
TaskScheduler.Default);
214237
}
215238
catch (Exception ex)
216239
{
@@ -377,7 +400,7 @@ private bool ShouldSkipDiUpdate(bool requested, bool current, DebuggerSettings d
377400
{
378401
if (requested && !debuggerSettings.DynamicInstrumentationCanBeEnabled)
379402
{
380-
Log.Debug("Code Origin can't be enabled because the local environment variable is set to false");
403+
Log.Debug("Dynamic Instrumentation can't be enabled because the local environment variable is set to false");
381404
return true;
382405
}
383406

tracer/test/Datadog.Trace.Debugger.IntegrationTests/DebuggerManagerDynamicTests.cs

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -66,9 +66,15 @@ await RunDynamicConfigurationTest(
6666
// Initially, no DI objects should exist
6767
memoryAssertions.NoObjectsExist<DynamicInstrumentation>();
6868
memoryAssertions.NoObjectsExist<LineProbeResolver>();
69+
memoryAssertions.NoObjectsExist<Symbols.SymbolsUploader>();
6970
},
7071
remoteConfig: new { DD_DYNAMIC_INSTRUMENTATION_ENABLED = true },
71-
DynamicInstrumentationEnabledLogEntry);
72+
DynamicInstrumentationEnabledLogEntry,
73+
finalMemoryAssertions: memoryAssertions =>
74+
{
75+
// After enabling DI via remote config, symbol uploader should be created
76+
memoryAssertions.ObjectsExist<Symbols.SymbolsUploader>();
77+
});
7278
}
7379

7480
[SkippableFact]
@@ -107,7 +113,7 @@ public async Task DebuggerManager_CodeOrigin_StartDisabled_EnabledViaRemoteConfi
107113

108114
SetEnvironmentVariable(ConfigurationKeys.Rcm.RemoteConfigurationEnabled, "true");
109115

110-
await this.RunDynamicConfigurationTest(
116+
await RunDynamicConfigurationTest(
111117
false,
112118
initialMemoryAssertions: memoryAssertions =>
113119
{
@@ -140,6 +146,7 @@ await RunDynamicConfigurationTest(
140146
memoryAssertions.NoObjectsExist<SpanCodeOrigin.SpanCodeOrigin>();
141147
memoryAssertions.NoObjectsExist<SnapshotSink>();
142148
memoryAssertions.NoObjectsExist<LineProbeResolver>();
149+
memoryAssertions.NoObjectsExist<Symbols.SymbolsUploader>();
143150
},
144151
remoteConfig: new
145152
{
@@ -156,6 +163,7 @@ await RunDynamicConfigurationTest(
156163
memoryAssertions.ObjectsExist<SpanCodeOrigin.SpanCodeOrigin>();
157164
memoryAssertions.ObjectsExist<SnapshotSink>();
158165
memoryAssertions.ObjectsExist<LineProbeResolver>();
166+
memoryAssertions.ObjectsExist<Symbols.SymbolsUploader>();
159167
});
160168
}
161169

@@ -169,6 +177,7 @@ public async Task DebuggerManager_DynamicInstrumentation_StartEnabled_DisabledVi
169177
#if NET8_0_OR_GREATER
170178
Skip.If(!EnvironmentTools.IsTestTarget64BitProcess());
171179
#endif
180+
172181
// Start with DI enabled via environment variable
173182
SetEnvironmentVariable(ConfigurationKeys.Debugger.DynamicInstrumentationEnabled, "true");
174183
SetEnvironmentVariable(ConfigurationKeys.Rcm.RemoteConfigurationEnabled, "true");
@@ -181,9 +190,16 @@ await RunDynamicConfigurationTest(
181190
memoryAssertions.ObjectsExist<DynamicInstrumentation>();
182191
memoryAssertions.ObjectsExist<SnapshotSink>();
183192
memoryAssertions.ObjectsExist<LineProbeResolver>();
193+
memoryAssertions.ObjectsExist<Symbols.SymbolsUploader>();
184194
},
185195
remoteConfig: new { DD_DYNAMIC_INSTRUMENTATION_ENABLED = false },
186-
$"Dynamic Instrumentation {DisabledByRemoteConfiguration}");
196+
$"Dynamic Instrumentation {DisabledByRemoteConfiguration}",
197+
finalMemoryAssertions: memoryAssertions =>
198+
{
199+
// After disabling DI, symbol uploader should still exist (it's not disposed when DI is disabled)
200+
// This is because symbol uploader initialization is one-time only
201+
memoryAssertions.ObjectsExist<Symbols.SymbolsUploader>();
202+
});
187203
}
188204

189205
[SkippableFact]
@@ -200,7 +216,7 @@ public async Task DebuggerManager_ExceptionReplay_StartEnabled_DisabledViaRemote
200216
SetEnvironmentVariable(ConfigurationKeys.Debugger.ExceptionReplayEnabled, "true");
201217
SetEnvironmentVariable(ConfigurationKeys.Rcm.RemoteConfigurationEnabled, "true");
202218

203-
await this.RunDynamicConfigurationTest(
219+
await RunDynamicConfigurationTest(
204220
true,
205221
initialMemoryAssertions: memoryAssertions =>
206222
{
@@ -225,7 +241,7 @@ public async Task DebuggerManager_CodeOrigin_StartEnabled_DisabledViaRemoteConfi
225241
SetEnvironmentVariable(ConfigurationKeys.Rcm.RemoteConfigurationEnabled, "true");
226242
SetEnvironmentVariable(ConfigurationKeys.Debugger.CodeOriginForSpansEnabled, "true");
227243

228-
await this.RunDynamicConfigurationTest(
244+
await RunDynamicConfigurationTest(
229245
true,
230246
initialMemoryAssertions: memoryAssertions =>
231247
{

tracer/test/Datadog.Trace.Debugger.IntegrationTests/DebuggerManagerTests.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ public DebuggerManagerTests(ITestOutputHelper output)
4646
public async Task DebuggerManager_AllFeaturesByDefault_NoDebuggerObjectsCreated()
4747
{
4848
#if NET8_0_OR_GREATER
49+
4950
// These tests often hang on x86 on .NET 8+. Needs investigation
5051
Skip.If(!EnvironmentTools.IsTestTarget64BitProcess());
5152
#endif
@@ -55,8 +56,8 @@ await RunDebuggerManagerTestWithMemoryAssertions(memoryAssertions =>
5556
memoryAssertions.NoObjectsExist<LineProbeResolver>();
5657
memoryAssertions.NoObjectsExist<DynamicInstrumentation>();
5758
memoryAssertions.NoObjectsExist<ExceptionAutoInstrumentation.ExceptionReplay>();
59+
memoryAssertions.NoObjectsExist<Symbols.SymbolsUploader>();
5860
memoryAssertions.ObjectsExist<SpanCodeOrigin.SpanCodeOrigin>();
59-
memoryAssertions.ObjectsExist<Symbols.SymbolsUploader>();
6061
});
6162
}
6263

0 commit comments

Comments
 (0)