diff --git a/src/CodingWithCalvin.ProjectRenamifier/CodingWithCalvin.ProjectRenamifier.csproj b/src/CodingWithCalvin.ProjectRenamifier/CodingWithCalvin.ProjectRenamifier.csproj index 7ee50f9..4f1186c 100644 --- a/src/CodingWithCalvin.ProjectRenamifier/CodingWithCalvin.ProjectRenamifier.csproj +++ b/src/CodingWithCalvin.ProjectRenamifier/CodingWithCalvin.ProjectRenamifier.csproj @@ -1,4 +1,4 @@ - + net48 @@ -9,11 +9,8 @@ true - - True - - + @@ -29,4 +26,4 @@ - + \ No newline at end of file diff --git a/src/CodingWithCalvin.ProjectRenamifier/Commands/RenamifyProjectCommand.cs b/src/CodingWithCalvin.ProjectRenamifier/Commands/RenamifyProjectCommand.cs index 9d02678..f1fc5b5 100644 --- a/src/CodingWithCalvin.ProjectRenamifier/Commands/RenamifyProjectCommand.cs +++ b/src/CodingWithCalvin.ProjectRenamifier/Commands/RenamifyProjectCommand.cs @@ -1,9 +1,11 @@ +using System.Collections.Generic; using System.ComponentModel.Design; using System.IO; using System.Windows.Interop; using System.Windows.Threading; using CodingWithCalvin.ProjectRenamifier.Dialogs; using CodingWithCalvin.ProjectRenamifier.Services; +using CodingWithCalvin.Otel4Vsix; using EnvDTE; using EnvDTE80; @@ -44,6 +46,8 @@ private void Execute(object sender, EventArgs e) { ThreadHelper.ThrowIfNotOnUIThread(); + using var activity = VsixTelemetry.StartCommandActivity("ProjectRenamifier.Execute"); + if (!(ServiceProvider.GetService(typeof(DTE)) is DTE2 dte)) { return; @@ -63,9 +67,10 @@ private void RenameProject(Project project, DTE2 dte) { ThreadHelper.ThrowIfNotOnUIThread(); - var currentName = Path.GetFileNameWithoutExtension(project.FullName); + using var activity = VsixTelemetry.StartCommandActivity("ProjectRenamifier.RenameProject"); - var dialog = new RenameProjectDialog(currentName); + var currentName = Path.GetFileNameWithoutExtension(project.FullName); + var dialog = new RenameProjectDialog(currentName); // Set the owner to the VS main window for proper modal behavior var helper = new WindowInteropHelper(dialog) @@ -75,6 +80,7 @@ private void RenameProject(Project project, DTE2 dte) if (dialog.ShowDialog() != true) { + VsixTelemetry.LogInformation("Rename cancelled by user"); return; } @@ -82,6 +88,8 @@ private void RenameProject(Project project, DTE2 dte) var projectFilePath = project.FullName; var originalProjectFilePath = projectFilePath; + VsixTelemetry.LogInformation("Renaming project"); + // Show progress dialog var progressDialog = new RenameProgressDialog(currentName); var progressHelper = new WindowInteropHelper(progressDialog) @@ -93,7 +101,7 @@ private void RenameProject(Project project, DTE2 dte) var stepIndex = 0; var projectRemovedFromSolution = false; var projectReaddedToSolution = false; - System.Collections.Generic.List referencingProjects = null; + List referencingProjects = null; Project parentSolutionFolder = null; try @@ -172,6 +180,10 @@ private void RenameProject(Project project, DTE2 dte) DoEvents(); System.Threading.Thread.Sleep(500); progressDialog.Close(); + + activity?.SetTag("rename.success", true); + activity?.SetTag("rename.steps_completed", stepIndex); + VsixTelemetry.LogInformation("Successfully renamed project"); } catch (Exception ex) { @@ -179,6 +191,16 @@ private void RenameProject(Project project, DTE2 dte) progressDialog.FailStep(stepIndex, ex.Message); DoEvents(); + activity?.RecordError(ex); + activity?.SetTag("rename.success", false); + activity?.SetTag("rename.failed_step", stepIndex); + + VsixTelemetry.TrackException(ex, new Dictionary + { + { "operation.name", "RenameProject" }, + { "step.index", stepIndex } + }); + // Attempt rollback if project was removed but not re-added if (projectRemovedFromSolution && !projectReaddedToSolution) { @@ -187,13 +209,16 @@ private void RenameProject(Project project, DTE2 dte) // Try to re-add the project at its current location var currentProjectPath = File.Exists(projectFilePath) ? projectFilePath : originalProjectFilePath; if (File.Exists(currentProjectPath)) - { - SolutionFolderService.AddProjectToSolution(dte.Solution, currentProjectPath, parentSolutionFolder); + { SolutionFolderService.AddProjectToSolution(dte.Solution, currentProjectPath, parentSolutionFolder); + VsixTelemetry.LogInformation("Rollback: Re-added project"); } } - catch + catch (Exception rollbackEx) { - // Rollback failed, nothing more we can do + VsixTelemetry.TrackException(rollbackEx, new Dictionary + { + { "operation.name", "RenameProject.Rollback" } + }); } } diff --git a/src/CodingWithCalvin.ProjectRenamifier/HoneycombConfig.cs b/src/CodingWithCalvin.ProjectRenamifier/HoneycombConfig.cs new file mode 100644 index 0000000..6c0725c --- /dev/null +++ b/src/CodingWithCalvin.ProjectRenamifier/HoneycombConfig.cs @@ -0,0 +1,7 @@ +namespace CodingWithCalvin.ProjectRenamifier +{ + internal static class HoneycombConfig + { + public const string ApiKey = "PLACEHOLDER"; + } +} diff --git a/src/CodingWithCalvin.ProjectRenamifier/ProjectRenamifierPackage.cs b/src/CodingWithCalvin.ProjectRenamifier/ProjectRenamifierPackage.cs index e01cc7a..c5f6713 100644 --- a/src/CodingWithCalvin.ProjectRenamifier/ProjectRenamifierPackage.cs +++ b/src/CodingWithCalvin.ProjectRenamifier/ProjectRenamifierPackage.cs @@ -3,6 +3,7 @@ global using Task = System.Threading.Tasks.Task; using System.Runtime.InteropServices; using System.Threading; +using CodingWithCalvin.Otel4Vsix; namespace CodingWithCalvin.ProjectRenamifier { @@ -14,10 +15,38 @@ public sealed class ProjectRenamifierPackage : AsyncPackage { protected override async Task InitializeAsync(CancellationToken cancellationToken, IProgress progress) { + await JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken); + + var builder = VsixTelemetry.Configure() + .WithServiceName(VsixInfo.DisplayName) + .WithServiceVersion(VsixInfo.Version) + .WithVisualStudioAttributes(this) + .WithEnvironmentAttributes(); + +#if !DEBUG + builder + .WithOtlpHttp("https://api.honeycomb.io") + .WithHeader("x-honeycomb-team", HoneycombConfig.ApiKey); +#endif + + builder.Initialize(); + await Task.Run(() => { RenamifyProjectCommand.Initialize(this); }); + + VsixTelemetry.LogInformation("Project Renamifier initialized successfully"); + } + + protected override void Dispose(bool disposing) + { + if (disposing) + { + VsixTelemetry.Shutdown(); + } + + base.Dispose(disposing); } } } \ No newline at end of file