From 6b1451be7e5de048fc92faa9c5357a63d01eb77a Mon Sep 17 00:00:00 2001 From: Lee Culver Date: Thu, 20 Jun 2024 14:42:04 -0700 Subject: [PATCH] Add symbol tracing environment variable Setting ClrMD_TraceSymbolRequests=1 will now produce Trace messages of all symbol server requests. --- .../src/FileLocatorTests.cs | 2 +- .../src/TestTargets.cs | 3 ++- .../CustomDataTarget.cs | 17 +++++++++++++++++ src/Microsoft.Diagnostics.Runtime/DataTarget.cs | 6 ++++-- .../Implementation/SymbolGroup.cs | 6 +++--- .../Implementation/SymbolServer.cs | 8 +++++++- 6 files changed, 34 insertions(+), 8 deletions(-) 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);