Skip to content

Commit bd94d24

Browse files
committed
Stabilize snapshot exploration tests and simplify config
Fix rebase fallout in the snapshot exploration test path and make the harness reliable again. Share the exploration CSV sink between snapshot and log uploaders, disable hands-off config for isolated test hosts, and fail fast when probes are defined but none are installed so bootstrap problems are surfaced instead of passing silently. Reduce the supported snapshot exploration configuration to ENABLED plus a single root path, derive the probes/report locations from that root, and keep extra tuning/debug switches out of the supported config surface. Clean up the snapshot-flow debug logging so it stays purely diagnostic and can be removed without affecting behavior.
1 parent 0552bcf commit bd94d24

36 files changed

Lines changed: 319 additions & 145 deletions

tracer/build/_build/Build.SnapshotExplorationTest.cs

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,7 @@ partial class Build
1818
const string SnapshotExplorationTestProbesFileName = "SnapshotExplorationTestProbes.csv";
1919
const string SnapshotExplorationTestReportFolderName = "SnapshotExplorationTestReport";
2020
const string SnapshotExplorationEnabledKey = "DD_INTERNAL_SNAPSHOT_EXPLORATION_TEST_ENABLED";
21-
const string SnapshotExplorationProbesFilePathKey = "DD_INTERNAL_SNAPSHOT_EXPLORATION_TEST_PROBES_FILE_PATH";
22-
const string SnapshotExplorationReportFolderPathKey = "DD_INTERNAL_SNAPSHOT_EXPLORATION_TEST_REPORT_FOLDER_PATH";
21+
const string SnapshotExplorationRootPathKey = "DD_INTERNAL_SNAPSHOT_EXPLORATION_TEST_ROOT_PATH";
2322
const char SpecialSeparator = '#';
2423

2524
readonly List<string> IgnoredNamespaces = new()
@@ -39,6 +38,15 @@ partial class Build
3938
"testhost"
4039
};
4140

41+
static string GetSnapshotExplorationRootPath(string testRootPath, TargetFramework framework)
42+
=> Path.Combine(testRootPath, SnapshotExplorationTestFolderName, framework);
43+
44+
static string GetSnapshotExplorationProbesFilePath(string snapshotExplorationRootPath)
45+
=> Path.Combine(snapshotExplorationRootPath, SnapshotExplorationTestProbesFileName);
46+
47+
static string GetSnapshotExplorationReportFolderPath(string snapshotExplorationRootPath)
48+
=> Path.Combine(snapshotExplorationRootPath, SnapshotExplorationTestReportFolderName);
49+
4250
void RunSnapshotExplorationTestsInternal()
4351
{
4452
if (ExplorationTestName.HasValue)
@@ -80,15 +88,16 @@ void RunSnapshotExplorationTest(ExplorationTestDescription testDescription)
8088
testDescription.IsSnapshotScenario = true;
8189
var envVariables = GetEnvironmentVariables(testDescription, framework);
8290
var testRootPath = testDescription.GetTestTargetPath(ExplorationTestsDirectory, framework, BuildConfiguration);
83-
FileSystemTasks.EnsureCleanDirectory(Path.Combine(testRootPath, SnapshotExplorationTestFolderName, framework, SnapshotExplorationTestReportFolderName));
91+
var snapshotExplorationRootPath = GetSnapshotExplorationRootPath(testRootPath, framework);
92+
FileSystemTasks.EnsureCleanDirectory(GetSnapshotExplorationReportFolderPath(snapshotExplorationRootPath));
8493

8594
var testStopwatch = Stopwatch.StartNew();
8695
Test(testDescription, framework, envVariables);
8796
testStopwatch.Stop();
8897

8998
VerifySnapshotExplorationTestResults(
90-
envVariables[SnapshotExplorationProbesFilePathKey],
91-
envVariables[SnapshotExplorationReportFolderPathKey],
99+
GetSnapshotExplorationProbesFilePath(snapshotExplorationRootPath),
100+
GetSnapshotExplorationReportFolderPath(snapshotExplorationRootPath),
92101
testStopwatch.Elapsed);
93102
}
94103
}
@@ -117,7 +126,8 @@ void CreateSnapshotExplorationTestCsv(ExplorationTestDescription testDescription
117126
foreach (var framework in frameworks)
118127
{
119128
var testRootPath = testDescription.GetTestTargetPath(ExplorationTestsDirectory, framework, BuildConfiguration);
120-
FileSystemTasks.EnsureCleanDirectory(Path.Combine(testRootPath, SnapshotExplorationTestFolderName, framework));
129+
var snapshotExplorationRootPath = GetSnapshotExplorationRootPath(testRootPath, framework);
130+
FileSystemTasks.EnsureCleanDirectory(snapshotExplorationRootPath);
121131
var tracerAssemblyPath = GetTracerAssemblyPath(framework);
122132
var tracer = Assembly.LoadFile(tracerAssemblyPath);
123133
var extractorType = tracer.GetType("Datadog.Trace.Debugger.Symbols.SymbolExtractor");
@@ -158,7 +168,7 @@ void CreateSnapshotExplorationTestCsv(ExplorationTestDescription testDescription
158168
}
159169
}
160170

161-
File.WriteAllText(Path.Combine(testRootPath, SnapshotExplorationTestFolderName, framework, SnapshotExplorationTestProbesFileName), csvBuilder.ToString());
171+
File.WriteAllText(GetSnapshotExplorationProbesFilePath(snapshotExplorationRootPath), csvBuilder.ToString());
162172
}
163173

164174
return;
@@ -802,6 +812,13 @@ public void VerifySnapshotExplorationTestResults(string probesFilePath, string r
802812
throw new Exception($"Snapshot exploration test failed: {invalidOrErrorProbes.Count} invalid snapshots, {failedDuringProcessing.Count} processing failures, {probeRelatedErrors.Count} probe errors, {criticalNativeFailures.Count} native rewriter failures, {skippedProbes.Count} signature mismatches");
803813
}
804814

815+
if (installedCount == 0 && definedProbes.Count > 0)
816+
{
817+
Logger.Error("║ RESULT: FAILED - No probes installed ║");
818+
Logger.Error("╚══════════════════════════════════════════════════════════════╝");
819+
throw new Exception("Snapshot exploration test failed: No probes were installed. Check debugger initialization and probe loading.");
820+
}
821+
805822
if (reportedCount == 0 && installedCount > 0)
806823
{
807824
Logger.Error("║ RESULT: FAILED - No snapshots collected ║");

tracer/build/_build/BuildVariables.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,12 @@ public void AddDebuggerEnvironmentVariables(Dictionary<string, string> envVars,
2020
if (description.IsSnapshotScenario)
2121
{
2222
envVars.Add("VSTEST_CONNECTION_TIMEOUT", "1800");
23+
// Snapshot exploration runs don't need hands-off config, and disabling it
24+
// avoids libdatadog startup crashes in isolated third-party test hosts.
25+
envVars.Add("DD_APPLICATION_MONITORING_CONFIG_FILE_ENABLED", "0");
2326
envVars.Add(SnapshotExplorationEnabledKey, "1");
2427
var testRootPath = description.GetTestTargetPath(ExplorationTestsDirectory, framework, BuildConfiguration);
25-
envVars.Add(SnapshotExplorationProbesFilePathKey, Path.Combine(testRootPath, SnapshotExplorationTestFolderName, framework, SnapshotExplorationTestProbesFileName));
26-
envVars.Add(SnapshotExplorationReportFolderPathKey, Path.Combine(testRootPath, SnapshotExplorationTestFolderName, framework, SnapshotExplorationTestReportFolderName));
28+
envVars.Add(SnapshotExplorationRootPathKey, GetSnapshotExplorationRootPath(testRootPath, framework));
2729
}
2830
else if (description.LineProbesEnabled)
2931
{

tracer/src/Datadog.Trace/Configuration/supported-configurations.yaml

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1163,6 +1163,24 @@ supportedConfigurations:
11631163
documentation: |-
11641164
Internal configuration key to optionally limit the maximum number of probes of each type.
11651165
Default value is <c>0</c>, no probe-count limit is enforced.
1166+
DD_INTERNAL_SNAPSHOT_EXPLORATION_TEST_ENABLED:
1167+
- implementation: A
1168+
type: boolean
1169+
default: 'false'
1170+
product: Debugger
1171+
const_name: IsSnapshotExplorationTestEnabled
1172+
documentation: |-
1173+
Internal configuration key to enable snapshot exploration test mode.
1174+
Default value is false (disabled).
1175+
DD_INTERNAL_SNAPSHOT_EXPLORATION_TEST_ROOT_PATH:
1176+
- implementation: A
1177+
type: string
1178+
default: null
1179+
product: Debugger
1180+
const_name: SnapshotExplorationTestRootPath
1181+
documentation: |-
1182+
Internal configuration key for the snapshot exploration test root path.
1183+
The tracer derives the probes CSV path and report output folder from this root.
11661184
DD_INTERNAL_PROFILING_NATIVE_ENGINE_PATH:
11671185
- implementation: A
11681186
type: string

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
namespace Datadog.Trace.Debugger;
1212

13-
internal record BoundLineProbeLocation
13+
internal sealed record BoundLineProbeLocation
1414
{
1515
public BoundLineProbeLocation(ProbeDefinition probe, Guid mvid, int methodToken, int bytecodeOffset, int lineNumber)
1616
{

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

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,11 @@ internal static DynamicInstrumentation CreateDynamicInstrumentation(IDiscoverySe
3131
{
3232
var snapshotSlicer = SnapshotSlicer.Create(debuggerSettings);
3333
var snapshotSink = SnapshotSink.Create(debuggerSettings, snapshotSlicer);
34-
var logSink = SnapshotSink.Create(debuggerSettings, snapshotSlicer);
34+
// Snapshot exploration tests write directly to a per-process CSV file, so both
35+
// uploaders must share the same sink/report writer instead of opening it twice.
36+
var logSink = debuggerSettings.IsSnapshotExplorationTestEnabled
37+
? snapshotSink
38+
: SnapshotSink.Create(debuggerSettings, snapshotSlicer);
3539
var diagnosticsSink = DiagnosticsSink.Create(serviceNameProvider, debuggerSettings);
3640

3741
var snapshotUploader = CreateSnapshotUploader(discoveryService, debuggerSettings, gitMetadataTagsProvider, GetApiFactory(tracerSettings, true), snapshotSink);
@@ -88,7 +92,7 @@ private static SnapshotUploader CreateSnapshotUploader(IDiscoveryService discove
8892
return debuggerSink;
8993
}
9094

91-
private static SnapshotUploader CreateLogUploader(IDiscoveryService discoveryService, DebuggerSettings debuggerSettings, IGitMetadataTagsProvider gitMetadataTagsProvider, IApiRequestFactory apiFactory, SnapshotSink snapshotSink)
95+
private static SnapshotUploader CreateLogUploader(IDiscoveryService discoveryService, DebuggerSettings debuggerSettings, IGitMetadataTagsProvider gitMetadataTagsProvider, IApiRequestFactory apiFactory, ISnapshotSink snapshotSink)
9296
{
9397
var logUploaderApi = DebuggerUploadApiFactory.CreateLogUploadApi(apiFactory, discoveryService, gitMetadataTagsProvider);
9498
var logBatchUploader = BatchUploader.Create(logUploaderApi);
@@ -110,10 +114,11 @@ private static DiagnosticsUploader CreateDiagnosticsUploader(IDiscoveryService d
110114

111115
internal static IDebuggerUploader CreateSymbolsUploader(IDiscoveryService discoveryService, IRcmSubscriptionManager remoteConfigurationManager, Func<string> serviceNameProvider, TracerSettings tracerSettings, DebuggerSettings settings, IGitMetadataTagsProvider gitMetadataTagsProvider)
112116
{
113-
if (settings.IsSnapshotExplorationTestEnabled)
117+
if (settings.IsSnapshotExplorationTestEnabled)
114118
{
115119
return NoOpSymbolUploader.Instance;
116120
}
121+
117122
var symbolBatchApi = DebuggerUploadApiFactory.CreateSymbolsUploadApi(GetApiFactory(tracerSettings, true), discoveryService, gitMetadataTagsProvider, serviceNameProvider, settings.SymbolDatabaseCompressionEnabled);
118123
var symbolsUploader = SymbolsUploader.Create(symbolBatchApi, discoveryService, remoteConfigurationManager, tracerSettings, settings, serviceNameProvider);
119124
return symbolsUploader;

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -704,7 +704,7 @@ private void ShutdownTasks(Exception? ex)
704704
public void InitForSnapshotExploration()
705705
{
706706
var tracerManager = TracerManager.Instance;
707-
var di = DebuggerFactory.CreateDynamicInstrumentation(new DiscoveryServiceMock(), RcmSubscriptionManager.Instance, tracerManager.Settings, ServiceName, DebuggerSettings, tracerManager.GitMetadataTagsProvider);
707+
var di = DebuggerFactory.CreateDynamicInstrumentation(new DiscoveryServiceMock(), RcmSubscriptionManager.Instance, tracerManager.Settings, ServiceNameProvider, DebuggerSettings, tracerManager.GitMetadataTagsProvider);
708708

709709
// Enable metrics collection and probe tracking for performance optimization
710710
if (!string.IsNullOrEmpty(DebuggerSettings.SnapshotExplorationTestReportFolderPath))
@@ -729,7 +729,7 @@ public void InitForSnapshotExploration()
729729

730730
static void WaitForProbeInstallation(int expectedCount, TimeSpan timeout)
731731
{
732-
var logDir = Environment.GetEnvironmentVariable("DD_TRACE_LOG_DIRECTORY")
732+
var logDir = EnvironmentHelpers.GetEnvironmentVariable(ConfigurationKeys.LogDirectory)
733733
?? Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), "Datadog .NET Tracer", "logs");
734734

735735
var deadline = DateTime.UtcNow + timeout;

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

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
using System;
99
using System.Collections.Generic;
10+
using System.IO;
1011
using System.Linq;
1112
using Datadog.Trace.Configuration;
1213
using Datadog.Trace.Configuration.Telemetry;
@@ -154,8 +155,7 @@ public DebuggerSettings(IConfigurationSource? source, IConfigurationTelemetry te
154155
SymbolDatabaseCompressionEnabled = config.WithKeys(ConfigurationKeys.Debugger.SymbolDatabaseCompressionEnabled).AsBool(true);
155156

156157
IsSnapshotExplorationTestEnabled = config.WithKeys(ConfigurationKeys.Debugger.IsSnapshotExplorationTestEnabled).AsBool(false);
157-
SnapshotExplorationTestProbesFilePath = config.WithKeys(ConfigurationKeys.Debugger.SnapshotExplorationTestProbesFilePath).AsString(string.Empty);
158-
SnapshotExplorationTestReportFolderPath = config.WithKeys(ConfigurationKeys.Debugger.SnapshotExplorationTestReportFolderPath).AsString(string.Empty);
158+
SnapshotExplorationTestRootPath = config.WithKeys(ConfigurationKeys.Debugger.SnapshotExplorationTestRootPath).AsString(string.Empty);
159159
}
160160

161161
internal ImmutableDynamicDebuggerSettings DynamicSettings { get; init; } = new();
@@ -204,9 +204,17 @@ public DebuggerSettings(IConfigurationSource? source, IConfigurationTelemetry te
204204

205205
public bool IsSnapshotExplorationTestEnabled { get; }
206206

207-
public string SnapshotExplorationTestProbesFilePath { get; }
207+
public string SnapshotExplorationTestRootPath { get; }
208208

209-
public string SnapshotExplorationTestReportFolderPath { get; }
209+
public string SnapshotExplorationTestProbesFilePath =>
210+
StringUtil.IsNullOrEmpty(SnapshotExplorationTestRootPath)
211+
? string.Empty
212+
: Path.Combine(SnapshotExplorationTestRootPath, "SnapshotExplorationTestProbes.csv");
213+
214+
public string SnapshotExplorationTestReportFolderPath =>
215+
StringUtil.IsNullOrEmpty(SnapshotExplorationTestRootPath)
216+
? string.Empty
217+
: Path.Combine(SnapshotExplorationTestRootPath, "SnapshotExplorationTestReport");
210218

211219
public static DebuggerSettings FromSource(IConfigurationSource source, IConfigurationTelemetry telemetry)
212220
{

tracer/src/Datadog.Trace/Debugger/DynamicInstrumentation.ExplorationTests.cs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616

1717
namespace Datadog.Trace.Debugger
1818
{
19-
internal partial class DynamicInstrumentation
19+
internal sealed partial class DynamicInstrumentation
2020
{
2121
// -------------------------
2222
// Helper: deterministic selection
@@ -49,9 +49,13 @@ private static string NormalizeForKey(string s)
4949
/// </summary>
5050
private static ulong Sha1ToUInt64(string s)
5151
{
52-
using var sha1 = SHA1.Create();
5352
var bytes = Encoding.UTF8.GetBytes(s);
53+
#if NET6_0_OR_GREATER
54+
var hash = SHA1.HashData(bytes); // 20 bytes
55+
#else
56+
using var sha1 = SHA1.Create();
5457
var hash = sha1.ComputeHash(bytes); // 20 bytes
58+
#endif
5559
return BitConverter.ToUInt64(hash, 0); // take first 8 bytes
5660
}
5761

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

Lines changed: 35 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030

3131
namespace Datadog.Trace.Debugger
3232
{
33-
internal partial class DynamicInstrumentation : IDisposable
33+
internal sealed partial class DynamicInstrumentation : IDisposable
3434
{
3535
private static readonly IDatadogLogger Log = DatadogLogging.GetLoggerFor(typeof(DynamicInstrumentation));
3636

@@ -288,7 +288,7 @@ private void SetRateLimit(ProbeDefinition probe)
288288
}
289289
}
290290

291-
private static string? JoinLogValues(string[]? values)
291+
private string? JoinLogValues(string[]? values)
292292
{
293293
return values is { Length: > 0 } ? string.Join(" | ", values) : null;
294294
}
@@ -609,25 +609,56 @@ private void AcceptRemovedConfiguration(List<RemoteConfigurationPath>? paths)
609609
_configurationUpdater.AcceptRemoved(paths);
610610
}
611611

612-
internal void AddSnapshot(ProbeInfo probe, string snapshot)
612+
internal void AddSnapshot(ProbeInfo probe, string? snapshot)
613613
{
614+
var snapshotFlowLogsEnabled = SnapshotFlowDebugLog.IsEnabled(Log);
615+
if (snapshotFlowLogsEnabled)
616+
{
617+
Log.Debug(
618+
"DynamicInstrumentation.AddSnapshot received payload probeId={ProbeId}, IsFullSnapshot={IsFullSnapshot}, IsDisposed={IsDisposed}, PayloadNull={PayloadNull}",
619+
property0: probe.ProbeId,
620+
property1: probe.IsFullSnapshot,
621+
property2: IsDisposed,
622+
property3: snapshot is null);
623+
}
624+
614625
if (IsDisposed)
615626
{
616627
return;
617628
}
618629

619630
if (!probe.IsFullSnapshot)
620631
{
632+
if (snapshotFlowLogsEnabled)
633+
{
634+
Log.Debug("DynamicInstrumentation.AddSnapshot routing payload to log uploader probeId={ProbeId}", probe.ProbeId);
635+
}
636+
621637
AddLog(probe, snapshot);
622638
return;
623639
}
624640

641+
if (snapshotFlowLogsEnabled)
642+
{
643+
Log.Debug("DynamicInstrumentation.AddSnapshot routing payload to snapshot uploader probeId={ProbeId}", probe.ProbeId);
644+
}
645+
625646
_snapshotUploader.Add(probe.ProbeId, snapshot);
626647
SetProbeStatusToEmitting(probe);
627648
}
628649

629-
internal void AddLog(ProbeInfo probe, string log)
650+
internal void AddLog(ProbeInfo probe, string? log)
630651
{
652+
var snapshotFlowLogsEnabled = SnapshotFlowDebugLog.IsEnabled(Log);
653+
if (snapshotFlowLogsEnabled)
654+
{
655+
Log.Debug(
656+
"DynamicInstrumentation.AddLog queueing payload probeId={ProbeId}, IsDisposed={IsDisposed}, PayloadNull={PayloadNull}",
657+
property0: probe.ProbeId,
658+
property1: IsDisposed,
659+
property2: log is null);
660+
}
661+
631662
if (IsDisposed)
632663
{
633664
return;

tracer/src/Datadog.Trace/Debugger/ExceptionAutoInstrumentation/ExceptionReplay.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ internal void EndRequest()
136136
ShadowStackHolder.ShadowStack?.Clear();
137137
}
138138

139-
internal void AddSnapshot(string probeId, string snapshot)
139+
internal void AddSnapshot(string probeId, string? snapshot)
140140
{
141141
if (_isDisabled)
142142
{

0 commit comments

Comments
 (0)