diff --git a/src/Microsoft.Diagnostics.Runtime.Tests/src/FileLocatorTests.cs b/src/Microsoft.Diagnostics.Runtime.Tests/src/FileLocatorTests.cs
index 0d5484a4a..ede17910f 100644
--- a/src/Microsoft.Diagnostics.Runtime.Tests/src/FileLocatorTests.cs
+++ b/src/Microsoft.Diagnostics.Runtime.Tests/src/FileLocatorTests.cs
@@ -20,7 +20,7 @@ public class FileLocatorTests
internal static IFileLocator GetLocator()
{
- return SymbolGroup.CreateFromSymbolPath($"srv*{Helpers.TestWorkingDirectory}*http://msdl.microsoft.com/download/symbols", null);
+ return SymbolGroup.CreateFromSymbolPath($"srv*{Helpers.TestWorkingDirectory}*http://msdl.microsoft.com/download/symbols", true, null);
}
[Fact(Skip = "Touches network, don't run regularly.")]
diff --git a/src/Microsoft.Diagnostics.Runtime.Tests/src/TestTargets.cs b/src/Microsoft.Diagnostics.Runtime.Tests/src/TestTargets.cs
index d20664f80..4e014d088 100644
--- a/src/Microsoft.Diagnostics.Runtime.Tests/src/TestTargets.cs
+++ b/src/Microsoft.Diagnostics.Runtime.Tests/src/TestTargets.cs
@@ -109,7 +109,8 @@ private static DataTarget LoadDump(string path)
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
DataTarget dataTarget = DataTarget.LoadDump(path);
- dataTarget.FileLocator = SymbolGroup.CreateFromSymbolPath(string.Empty, null);
+ bool symTrace = CustomDataTarget.GetTraceEnvironmentVariable();
+ dataTarget.FileLocator = SymbolGroup.CreateFromSymbolPath(string.Empty, trace: symTrace, null);
return dataTarget;
}
else
diff --git a/src/Microsoft.Diagnostics.Runtime/CustomDataTarget.cs b/src/Microsoft.Diagnostics.Runtime/CustomDataTarget.cs
index 1dbbb9576..4fe6c5bb1 100644
--- a/src/Microsoft.Diagnostics.Runtime/CustomDataTarget.cs
+++ b/src/Microsoft.Diagnostics.Runtime/CustomDataTarget.cs
@@ -13,6 +13,11 @@ namespace Microsoft.Diagnostics.Runtime
///
public class CustomDataTarget : IDisposable
{
+ ///
+ /// The environment variable to set to true if.
+ ///
+ public const string TraceSymbolsEnvVariable = "ClrMD_TraceSymbolRequests";
+
///
/// The data reader that ClrMD will use to read data from the target.
///
@@ -80,6 +85,18 @@ protected virtual void Dispose(bool disposing)
}
}
+ internal static bool GetTraceEnvironmentVariable()
+ {
+ string? value = Environment.GetEnvironmentVariable(TraceSymbolsEnvVariable);
+ if (value is null)
+ return false;
+
+ if (bool.TryParse(value, out bool result))
+ return result;
+
+ return value.Equals("1", StringComparison.OrdinalIgnoreCase);
+ }
+
public override string ToString() => DataReader?.DisplayName ?? GetType().Name;
}
}
\ No newline at end of file
diff --git a/src/Microsoft.Diagnostics.Runtime/DataTarget.cs b/src/Microsoft.Diagnostics.Runtime/DataTarget.cs
index 9358288be..41d6b800c 100644
--- a/src/Microsoft.Diagnostics.Runtime/DataTarget.cs
+++ b/src/Microsoft.Diagnostics.Runtime/DataTarget.cs
@@ -69,7 +69,8 @@ public DataTarget(CustomDataTarget customTarget)
if (locator == null)
{
string sympath = Environment.GetEnvironmentVariable("_NT_SYMBOL_PATH") ?? "";
- locator = SymbolGroup.CreateFromSymbolPath(sympath, _target.SymbolTokenCredential);
+ bool symTrace = CustomDataTarget.GetTraceEnvironmentVariable();
+ locator = SymbolGroup.CreateFromSymbolPath(sympath, trace:symTrace, _target.SymbolTokenCredential);
}
FileLocator = locator;
@@ -80,7 +81,8 @@ public void SetSymbolPath(string symbolPath)
if (symbolPath is null)
throw new ArgumentNullException(nameof(symbolPath));
- FileLocator = SymbolGroup.CreateFromSymbolPath(symbolPath, _target.SymbolTokenCredential);
+ bool symTrace = CustomDataTarget.GetTraceEnvironmentVariable();
+ FileLocator = SymbolGroup.CreateFromSymbolPath(symbolPath, trace:symTrace, _target.SymbolTokenCredential);
}
public void Dispose()
diff --git a/src/Microsoft.Diagnostics.Runtime/Implementation/SymbolGroup.cs b/src/Microsoft.Diagnostics.Runtime/Implementation/SymbolGroup.cs
index 74fceaf93..5a90de7b5 100644
--- a/src/Microsoft.Diagnostics.Runtime/Implementation/SymbolGroup.cs
+++ b/src/Microsoft.Diagnostics.Runtime/Implementation/SymbolGroup.cs
@@ -87,7 +87,7 @@ private static FileSymbolCache GetDefaultCache()
return s_cache!;
}
- public static IFileLocator CreateFromSymbolPath(string symbolPath, TokenCredential? credential)
+ public static IFileLocator CreateFromSymbolPath(string symbolPath, bool trace, TokenCredential? credential)
{
FileSymbolCache defaultCache = GetDefaultCache();
List locators = new();
@@ -114,7 +114,7 @@ public static IFileLocator CreateFromSymbolPath(string symbolPath, TokenCredenti
{
if (IsUrl(server))
{
- SymbolServer symSvr = new(cache, server, credential);
+ SymbolServer symSvr = new(cache, server, trace, credential);
locators.Add(symSvr);
if (first)
@@ -142,7 +142,7 @@ public static IFileLocator CreateFromSymbolPath(string symbolPath, TokenCredenti
return single;
if (locators.Count == 0)
- return new SymbolServer(defaultCache, SymbolServer.Msdl, null);
+ return new SymbolServer(defaultCache, SymbolServer.Msdl, trace, null);
return new SymbolGroup(locators);
}
diff --git a/src/Microsoft.Diagnostics.Runtime/Implementation/SymbolServer.cs b/src/Microsoft.Diagnostics.Runtime/Implementation/SymbolServer.cs
index 90d718882..3a0db18a2 100644
--- a/src/Microsoft.Diagnostics.Runtime/Implementation/SymbolServer.cs
+++ b/src/Microsoft.Diagnostics.Runtime/Implementation/SymbolServer.cs
@@ -22,16 +22,18 @@ internal sealed class SymbolServer : FileLocatorBase
private readonly TokenCredential? _tokenCredential;
private AccessToken _accessToken;
private readonly FileSymbolCache _cache;
+ private readonly bool _trace;
private readonly HttpClient _http = new();
public string Server { get; private set; }
- internal SymbolServer(FileSymbolCache cache, string server, TokenCredential? credential)
+ internal SymbolServer(FileSymbolCache cache, string server, bool trace, TokenCredential? credential)
{
if (cache is null)
throw new ArgumentNullException(nameof(cache));
_cache = cache;
+ _trace = trace;
Server = server;
if (IsSymweb(server))
@@ -137,6 +139,10 @@ private static bool IsSymweb(string server)
_http.DefaultRequestHeaders.Add("Authorization", $"Bearer {accessToken}");
HttpResponseMessage response = await _http.GetAsync(fullPath).ConfigureAwait(false);
+
+ if (_trace)
+ Trace.WriteLine($"ClrMD symbol request: {fullPath} returned {response.StatusCode}");
+
if (response.IsSuccessStatusCode)
return await response.Content.ReadAsStreamAsync().ConfigureAwait(false);