diff --git a/src/Compilers/Core/Portable/CodeAnalysisEventSource.Common.cs b/src/Compilers/Core/Portable/CodeAnalysisEventSource.Common.cs index b8e9e1df6ab39..4e3dba61cd567 100644 --- a/src/Compilers/Core/Portable/CodeAnalysisEventSource.Common.cs +++ b/src/Compilers/Core/Portable/CodeAnalysisEventSource.Common.cs @@ -11,8 +11,9 @@ internal sealed partial class CodeAnalysisEventSource : EventSource { public static class Keywords { - public const EventKeywords Performance = (EventKeywords)1; - public const EventKeywords Correctness = (EventKeywords)2; + public const EventKeywords Performance = (EventKeywords)0b001; + public const EventKeywords Correctness = (EventKeywords)0b010; + public const EventKeywords AnalyzerLoading = (EventKeywords)0b100; } public static class Tasks @@ -100,18 +101,87 @@ internal unsafe void NodeTransform(int nodeHashCode, string name, string tableTy [Event(8, Message = "Server compilation {0} completed", Keywords = Keywords.Performance, Level = EventLevel.Informational, Opcode = EventOpcode.Stop, Task = Tasks.Compilation)] internal void StopServerCompilation(string name) => WriteEvent(8, name); - [Event(9, Message = "ALC for directory '{0}' created", Keywords = Keywords.Performance, Level = EventLevel.Informational, Opcode = EventOpcode.Start, Task = Tasks.AnalyzerAssemblyLoader)] - internal void CreateAssemblyLoadContext(string directory) => WriteEvent(9, directory); + [Event(9, Message = "ALC for directory '{0}' created", Keywords = Keywords.AnalyzerLoading, Level = EventLevel.Informational, Opcode = EventOpcode.Start, Task = Tasks.AnalyzerAssemblyLoader)] + internal void CreateAssemblyLoadContext(string directory, string? alc) => WriteEvent(9, directory, alc); - [Event(10, Message = "ALC for directory '{0}' disposed", Keywords = Keywords.Performance, Level = EventLevel.Informational, Opcode = EventOpcode.Stop, Task = Tasks.AnalyzerAssemblyLoader)] - internal void DisposeAssemblyLoadContext(string directory) => WriteEvent(10, directory); + [Event(10, Message = "ALC for directory '{0}' disposed", Keywords = Keywords.AnalyzerLoading, Level = EventLevel.Informational, Opcode = EventOpcode.Stop, Task = Tasks.AnalyzerAssemblyLoader)] + internal void DisposeAssemblyLoadContext(string directory, string? alc) => WriteEvent(10, directory, alc); - [Event(11, Message = "ALC for directory '{0}' disposal failed with exception '{1}'", Keywords = Keywords.Performance, Level = EventLevel.Error, Opcode = EventOpcode.Stop, Task = Tasks.AnalyzerAssemblyLoader)] - internal void DisposeAssemblyLoadContextException(string directory, string errorMessage) => WriteEvent(11, directory, errorMessage); + [Event(11, Message = "ALC for directory '{0}' disposal failed with exception '{1}'", Keywords = Keywords.AnalyzerLoading, Level = EventLevel.Error, Opcode = EventOpcode.Stop, Task = Tasks.AnalyzerAssemblyLoader)] + internal void DisposeAssemblyLoadContextException(string directory, string errorMessage, string? alc) => WriteEvent(11, directory, errorMessage, alc); - [Event(12, Message = "CreateNonLockingLoader", Keywords = Keywords.Performance, Level = EventLevel.Informational, Task = Tasks.AnalyzerAssemblyLoader)] + [Event(12, Message = "CreateNonLockingLoader", Keywords = Keywords.AnalyzerLoading, Level = EventLevel.Informational, Task = Tasks.AnalyzerAssemblyLoader)] internal void CreateNonLockingLoader(string directory) => WriteEvent(12, directory); + [Event(13, Message = "Request add Analyzer reference '{0}' to project '{1}'", Keywords = Keywords.AnalyzerLoading, Level = EventLevel.Informational)] + internal void AnalyzerReferenceRequestAddToProject(string path, string projectName) => WriteEvent(13, path, projectName); + + [Event(14, Message = "Analyzer reference '{0}' was added to project '{1}'", Keywords = Keywords.AnalyzerLoading, Level = EventLevel.Informational)] + internal void AnalyzerReferenceAddedToProject(string path, string projectName) => WriteEvent(14, path, projectName); + + [Event(15, Message = "Request remove Analyzer reference '{0}' from project '{1}'", Keywords = Keywords.AnalyzerLoading, Level = EventLevel.Informational)] + internal void AnalyzerReferenceRequestRemoveFromProject(string path, string projectName) => WriteEvent(15, path, projectName); + + [Event(16, Message = "Analyzer reference '{0}' was removed from project '{1}'", Keywords = Keywords.AnalyzerLoading, Level = EventLevel.Informational)] + internal void AnalyzerReferenceRemovedFromProject(string path, string projectName) => WriteEvent(16, path, projectName); + + [Event(17, Message = "Analyzer reference was redirected by '{0}' from '{1}' to '{2}' for project '{3}'", Keywords = Keywords.AnalyzerLoading, Level = EventLevel.Verbose, Task = Tasks.BuildStateTable)] + internal unsafe void AnanlyzerReferenceRedirected(string redirectorType, string originalPath, string newPath, string project) + { + if (IsEnabled()) + { + fixed (char* redirectorTypeBytes = redirectorType) + fixed (char* originalPathBytes = originalPath) + fixed (char* newPathBytes = newPath) + fixed (char* projectBytes = project) + { + Span data = + [ + GetEventDataForString(redirectorType, redirectorTypeBytes), + GetEventDataForString(originalPath, originalPathBytes), + GetEventDataForString(newPath, newPathBytes), + GetEventDataForString(project, projectBytes), + ]; + + fixed (EventData* dataPtr = data) + { + WriteEventCore(eventId: 17, data.Length, dataPtr); + } + } + } + } + + [Event(18, Message = "ALC for directory '{0}': Assembly '{1}' was resolved by '{2}' ", Keywords = Keywords.AnalyzerLoading, Level = EventLevel.Informational)] + internal unsafe void ResolvedAssembly(string directory, string assemblyName, string resolver, string filePath, string alc) + { + if (IsEnabled()) + { + fixed (char* directoryBytes = directory) + fixed (char* assemblyNameBytes = assemblyName) + fixed (char* resolverBytes = resolver) + fixed (char* filePathBytes = filePath) + fixed (char* alcBytes = alc) + { + Span data = + [ + GetEventDataForString(directory, directoryBytes), + GetEventDataForString(assemblyName, assemblyNameBytes), + GetEventDataForString(resolver, resolverBytes), + GetEventDataForString(filePath, filePathBytes), + GetEventDataForString(alc, alcBytes), + ]; + + fixed (EventData* dataPtr = data) + { + WriteEventCore(eventId: 18, data.Length, dataPtr); + } + } + } + } + + [Event(19, Message = "ALC for directory '{0}': Failed to resolve assembly '{1}' ", Keywords = Keywords.AnalyzerLoading, Level = EventLevel.Informational)] + internal unsafe void ResolveAssemblyFailed(string directory, string assemblyName) => WriteEvent(19, directory, assemblyName); + private static unsafe EventData GetEventDataForString(string value, char* ptr) { fixed (char* ptr2 = value) diff --git a/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerAssemblyLoader.Core.cs b/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerAssemblyLoader.Core.cs index a4b6fb9a55513..1fe98873aa0da 100644 --- a/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerAssemblyLoader.Core.cs +++ b/src/Compilers/Core/Portable/DiagnosticAnalyzer/AnalyzerAssemblyLoader.Core.cs @@ -87,8 +87,8 @@ private partial Assembly Load(AssemblyName assemblyName, string resolvedPath) { if (!_loadContextByDirectory.TryGetValue(fullDirectoryPath, out loadContext)) { - CodeAnalysisEventSource.Log.CreateAssemblyLoadContext(fullDirectoryPath); loadContext = new DirectoryLoadContext(fullDirectoryPath, this); + CodeAnalysisEventSource.Log.CreateAssemblyLoadContext(fullDirectoryPath, loadContext.ToString()); _loadContextByDirectory[fullDirectoryPath] = loadContext; } } @@ -179,11 +179,11 @@ private partial void DisposeWorker() try { context.Unload(); - CodeAnalysisEventSource.Log.DisposeAssemblyLoadContext(context.Directory); + CodeAnalysisEventSource.Log.DisposeAssemblyLoadContext(context.Directory, context.ToString()); } catch (Exception ex) when (FatalError.ReportAndCatch(ex, ErrorSeverity.Critical)) { - CodeAnalysisEventSource.Log.DisposeAssemblyLoadContextException(context.Directory, ex.ToString()); + CodeAnalysisEventSource.Log.DisposeAssemblyLoadContextException(context.Directory, ex.ToString(), context.ToString()); } } @@ -209,10 +209,12 @@ public DirectoryLoadContext(string directory, AnalyzerAssemblyLoader loader) var assembly = resolver.Resolve(_loader, assemblyName, this, Directory); if (assembly is not null) { + CodeAnalysisEventSource.Log.ResolvedAssembly(Directory, assemblyName.ToString(), resolver.GetType().Name, assembly.Location, GetLoadContext(assembly)!.ToString()); return assembly; } } + CodeAnalysisEventSource.Log.ResolveAssemblyFailed(Directory, assemblyName.ToString()); return null; } diff --git a/src/Compilers/Core/Portable/DiagnosticAnalyzer/IAnalyzerPathResolver.cs b/src/Compilers/Core/Portable/DiagnosticAnalyzer/IAnalyzerPathResolver.cs index 513b7fd7d20eb..de498db0836d2 100644 --- a/src/Compilers/Core/Portable/DiagnosticAnalyzer/IAnalyzerPathResolver.cs +++ b/src/Compilers/Core/Portable/DiagnosticAnalyzer/IAnalyzerPathResolver.cs @@ -16,7 +16,7 @@ namespace Microsoft.CodeAnalysis { /// - /// This interface gives the host the ability to control the actaul path used to load an analyzer into the + /// This interface gives the host the ability to control the actual path used to load an analyzer into the /// compiler. /// /// Instances of these types are considered in the order they are added to the . diff --git a/src/Workspaces/Core/Portable/Workspace/ProjectSystem/ProjectSystemProject.cs b/src/Workspaces/Core/Portable/Workspace/ProjectSystem/ProjectSystemProject.cs index a08fc177c1c92..4f6e9559d07bf 100644 --- a/src/Workspaces/Core/Portable/Workspace/ProjectSystem/ProjectSystemProject.cs +++ b/src/Workspaces/Core/Portable/Workspace/ProjectSystem/ProjectSystemProject.cs @@ -1054,6 +1054,7 @@ private void OnDynamicFileInfoUpdated(object? sender, string dynamicFilePath) public void AddAnalyzerReference(string fullPath) { CompilerPathUtilities.RequireAbsolutePath(fullPath, nameof(fullPath)); + CodeAnalysisEventSource.Log.AnalyzerReferenceRequestAddToProject(fullPath, DisplayName); var mappedPaths = GetMappedAnalyzerPaths(fullPath); @@ -1084,6 +1085,7 @@ public void AddAnalyzerReference(string fullPath) // Are we adding one we just recently removed? If so, we can just keep using that one, and avoid // removing it once we apply the batch _projectAnalyzerPaths.Add(mappedFullPath); + CodeAnalysisEventSource.Log.AnalyzerReferenceAddedToProject(mappedFullPath, DisplayName); if (!_analyzersRemovedInBatch.Remove(mappedFullPath)) _analyzersAddedInBatch.Add(mappedFullPath); @@ -1098,6 +1100,8 @@ public void RemoveAnalyzerReference(string fullPath) if (string.IsNullOrEmpty(fullPath)) throw new ArgumentException("message", nameof(fullPath)); + CodeAnalysisEventSource.Log.AnalyzerReferenceRequestRemoveFromProject(fullPath, DisplayName); + var mappedPaths = GetMappedAnalyzerPaths(fullPath); bool containsSdkCodeStyleAnalyzers; @@ -1125,6 +1129,7 @@ public void RemoveAnalyzerReference(string fullPath) foreach (var mappedFullPath in mappedPaths) { _projectAnalyzerPaths.Remove(mappedFullPath); + CodeAnalysisEventSource.Log.AnalyzerReferenceRemovedFromProject(fullPath, DisplayName); // This analyzer may be one we've just added in the same batch; in that case, just don't add it in // the first place. @@ -1175,6 +1180,7 @@ private OneOrMany GetMappedAnalyzerPaths(string fullPath) if (redirectedPath == null) { redirectedPath = currentlyRedirectedPath; + CodeAnalysisEventSource.Log.AnanlyzerReferenceRedirected(redirector.GetType().Name, fullPath, redirectedPath, DisplayName); } else if (redirectedPath != currentlyRedirectedPath) {