From a5ea6edaa163fe3b13f79796330b99e7bc7ab289 Mon Sep 17 00:00:00 2001 From: "Calvin A. Allen" Date: Tue, 6 Jan 2026 10:37:42 -0500 Subject: [PATCH 1/2] feat(telemetry): add Otel4Vsix integration - Add CodingWithCalvin.Otel4Vsix package reference (v0.2.2) - Configure telemetry in ProjectRenamifierPackage with Honeycomb export - Add HoneycombConfig.cs for API key placeholder - Instrument Execute command with activity tracking - Instrument RenameProject with comprehensive telemetry: - Track project names (old/new) - Log rename start, success, and cancellation - Track step completion and failures - Record exceptions with rollback attempts - Add proper telemetry shutdown in Dispose - Remove explicit DeployExtension (VsixSdk handles this) --- .../CodingWithCalvin.ProjectRenamifier.csproj | 9 ++--- .../Commands/RenamifyProjectCommand.cs | 40 ++++++++++++++++--- .../HoneycombConfig.cs | 7 ++++ .../ProjectRenamifierPackage.cs | 29 ++++++++++++++ 4 files changed, 74 insertions(+), 11 deletions(-) create mode 100644 src/CodingWithCalvin.ProjectRenamifier/HoneycombConfig.cs 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..6a22663 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,7 +67,10 @@ private void RenameProject(Project project, DTE2 dte) { ThreadHelper.ThrowIfNotOnUIThread(); + using var activity = VsixTelemetry.StartCommandActivity("ProjectRenamifier.RenameProject"); + var currentName = Path.GetFileNameWithoutExtension(project.FullName); + activity?.SetTag("project.current_name", currentName); var dialog = new RenameProjectDialog(currentName); @@ -75,6 +82,7 @@ private void RenameProject(Project project, DTE2 dte) if (dialog.ShowDialog() != true) { + VsixTelemetry.LogInformation("Rename cancelled by user for project {ProjectName}", currentName); return; } @@ -82,6 +90,9 @@ private void RenameProject(Project project, DTE2 dte) var projectFilePath = project.FullName; var originalProjectFilePath = projectFilePath; + activity?.SetTag("project.new_name", newName); + VsixTelemetry.LogInformation("Renaming project from {OldName} to {NewName}", currentName, newName); + // Show progress dialog var progressDialog = new RenameProgressDialog(currentName); var progressHelper = new WindowInteropHelper(progressDialog) @@ -93,7 +104,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 +183,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 from {OldName} to {NewName}", currentName, newName); } catch (Exception ex) { @@ -179,6 +194,18 @@ 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" }, + { "project.old_name", currentName }, + { "project.new_name", newName }, + { "step.index", stepIndex } + }); + // Attempt rollback if project was removed but not re-added if (projectRemovedFromSolution && !projectReaddedToSolution) { @@ -187,13 +214,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 at {ProjectPath}", currentProjectPath); } } - 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 From 9f7da93595f7507dde746f37eefaffb4bf0c100f Mon Sep 17 00:00:00 2001 From: "Calvin A. Allen" Date: Tue, 6 Jan 2026 11:05:53 -0500 Subject: [PATCH 2/2] fix(telemetry): remove sensitive data from telemetry Remove project names and file paths from telemetry tags and logs to avoid sending potentially sensitive information. --- .../Commands/RenamifyProjectCommand.cs | 15 +++++---------- 1 file changed, 5 insertions(+), 10 deletions(-) diff --git a/src/CodingWithCalvin.ProjectRenamifier/Commands/RenamifyProjectCommand.cs b/src/CodingWithCalvin.ProjectRenamifier/Commands/RenamifyProjectCommand.cs index 6a22663..f1fc5b5 100644 --- a/src/CodingWithCalvin.ProjectRenamifier/Commands/RenamifyProjectCommand.cs +++ b/src/CodingWithCalvin.ProjectRenamifier/Commands/RenamifyProjectCommand.cs @@ -70,9 +70,7 @@ private void RenameProject(Project project, DTE2 dte) using var activity = VsixTelemetry.StartCommandActivity("ProjectRenamifier.RenameProject"); var currentName = Path.GetFileNameWithoutExtension(project.FullName); - activity?.SetTag("project.current_name", currentName); - - var dialog = new RenameProjectDialog(currentName); + var dialog = new RenameProjectDialog(currentName); // Set the owner to the VS main window for proper modal behavior var helper = new WindowInteropHelper(dialog) @@ -82,7 +80,7 @@ private void RenameProject(Project project, DTE2 dte) if (dialog.ShowDialog() != true) { - VsixTelemetry.LogInformation("Rename cancelled by user for project {ProjectName}", currentName); + VsixTelemetry.LogInformation("Rename cancelled by user"); return; } @@ -90,8 +88,7 @@ private void RenameProject(Project project, DTE2 dte) var projectFilePath = project.FullName; var originalProjectFilePath = projectFilePath; - activity?.SetTag("project.new_name", newName); - VsixTelemetry.LogInformation("Renaming project from {OldName} to {NewName}", currentName, newName); + VsixTelemetry.LogInformation("Renaming project"); // Show progress dialog var progressDialog = new RenameProgressDialog(currentName); @@ -186,7 +183,7 @@ private void RenameProject(Project project, DTE2 dte) activity?.SetTag("rename.success", true); activity?.SetTag("rename.steps_completed", stepIndex); - VsixTelemetry.LogInformation("Successfully renamed project from {OldName} to {NewName}", currentName, newName); + VsixTelemetry.LogInformation("Successfully renamed project"); } catch (Exception ex) { @@ -201,8 +198,6 @@ private void RenameProject(Project project, DTE2 dte) VsixTelemetry.TrackException(ex, new Dictionary { { "operation.name", "RenameProject" }, - { "project.old_name", currentName }, - { "project.new_name", newName }, { "step.index", stepIndex } }); @@ -215,7 +210,7 @@ private void RenameProject(Project project, DTE2 dte) var currentProjectPath = File.Exists(projectFilePath) ? projectFilePath : originalProjectFilePath; if (File.Exists(currentProjectPath)) { SolutionFolderService.AddProjectToSolution(dte.Solution, currentProjectPath, parentSolutionFolder); - VsixTelemetry.LogInformation("Rollback: Re-added project at {ProjectPath}", currentProjectPath); + VsixTelemetry.LogInformation("Rollback: Re-added project"); } } catch (Exception rollbackEx)