diff --git a/src/CodingWithCalvin.GitRanger/CodingWithCalvin.GitRanger.csproj b/src/CodingWithCalvin.GitRanger/CodingWithCalvin.GitRanger.csproj
index a0b659b..7d9d29e 100644
--- a/src/CodingWithCalvin.GitRanger/CodingWithCalvin.GitRanger.csproj
+++ b/src/CodingWithCalvin.GitRanger/CodingWithCalvin.GitRanger.csproj
@@ -9,11 +9,8 @@
bin/$(Configuration)/
-
- True
-
-
+
diff --git a/src/CodingWithCalvin.GitRanger/Commands/BlameCommands.cs b/src/CodingWithCalvin.GitRanger/Commands/BlameCommands.cs
index e23aab8..14479ca 100644
--- a/src/CodingWithCalvin.GitRanger/Commands/BlameCommands.cs
+++ b/src/CodingWithCalvin.GitRanger/Commands/BlameCommands.cs
@@ -1,7 +1,9 @@
using System;
+using System.Collections.Generic;
using System.ComponentModel.Design;
using System.Threading.Tasks;
using CodingWithCalvin.GitRanger.Options;
+using CodingWithCalvin.Otel4Vsix;
using Community.VisualStudio.Toolkit;
using Microsoft.VisualStudio.Shell;
using Task = System.Threading.Tasks.Task;
@@ -60,6 +62,8 @@ private static void OnToggleInlineBlame(object sender, EventArgs e)
{
ThreadHelper.ThrowIfNotOnUIThread();
+ using var activity = VsixTelemetry.StartCommandActivity("GitRanger.ToggleInlineBlame");
+
var options = GeneralOptions.Instance;
if (options != null)
{
@@ -67,6 +71,8 @@ private static void OnToggleInlineBlame(object sender, EventArgs e)
options.Save();
var status = options.EnableInlineBlame ? "enabled" : "disabled";
+ activity?.SetTag("inline_blame.enabled", options.EnableInlineBlame);
+ VsixTelemetry.LogInformation("Inline blame {Status}", status);
VS.StatusBar.ShowMessageAsync($"Git Ranger: Inline blame {status}").FireAndForget();
}
}
@@ -91,6 +97,8 @@ private static void OnToggleBlameGutter(object sender, EventArgs e)
{
ThreadHelper.ThrowIfNotOnUIThread();
+ using var activity = VsixTelemetry.StartCommandActivity("GitRanger.ToggleBlameGutter");
+
var options = GeneralOptions.Instance;
if (options != null)
{
@@ -98,6 +106,8 @@ private static void OnToggleBlameGutter(object sender, EventArgs e)
options.Save();
var status = options.EnableBlameGutter ? "enabled" : "disabled";
+ activity?.SetTag("blame_gutter.enabled", options.EnableBlameGutter);
+ VsixTelemetry.LogInformation("Blame gutter {Status}", status);
VS.StatusBar.ShowMessageAsync($"Git Ranger: Blame gutter {status}").FireAndForget();
}
}
@@ -119,6 +129,8 @@ private static async void OnCopyCommitSha(object sender, EventArgs e)
{
await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();
+ using var activity = VsixTelemetry.StartCommandActivity("GitRanger.CopyCommitSha");
+
try
{
var docView = await VS.Documents.GetActiveDocumentViewAsync();
@@ -129,24 +141,34 @@ private static async void OnCopyCommitSha(object sender, EventArgs e)
if (string.IsNullOrEmpty(filePath))
return;
- // Get the current line
+ // Get the current line
var caretPosition = docView.TextView.Caret.Position.BufferPosition;
var lineNumber = docView.TextView.TextSnapshot.GetLineNumberFromPosition(caretPosition.Position) + 1;
+ activity?.SetTag("line.number", lineNumber);
+
// Get blame for this line
var blameInfo = GitRangerPackage.BlameService?.GetBlameForLine(filePath, lineNumber);
if (blameInfo != null)
{
System.Windows.Clipboard.SetText(blameInfo.CommitSha);
+ activity?.SetTag("commit.sha", blameInfo.ShortSha);
+ VsixTelemetry.LogInformation("Copied commit SHA {CommitSha} to clipboard", blameInfo.ShortSha);
await VS.StatusBar.ShowMessageAsync($"Git Ranger: Copied commit SHA {blameInfo.ShortSha} to clipboard");
}
else
{
+ VsixTelemetry.LogInformation("No blame information available for line {LineNumber}", lineNumber);
await VS.StatusBar.ShowMessageAsync("Git Ranger: No blame information available for this line");
}
}
catch (Exception ex)
{
+ activity?.RecordError(ex);
+ VsixTelemetry.TrackException(ex, new Dictionary
+ {
+ { "operation.name", "CopyCommitSha" }
+ });
await VS.StatusBar.ShowMessageAsync($"Git Ranger: Error copying commit SHA - {ex.Message}");
}
}
diff --git a/src/CodingWithCalvin.GitRanger/GitRangerPackage.cs b/src/CodingWithCalvin.GitRanger/GitRangerPackage.cs
index acb85cd..fbc3c42 100644
--- a/src/CodingWithCalvin.GitRanger/GitRangerPackage.cs
+++ b/src/CodingWithCalvin.GitRanger/GitRangerPackage.cs
@@ -5,6 +5,7 @@
using CodingWithCalvin.GitRanger.Commands;
using CodingWithCalvin.GitRanger.Options;
using CodingWithCalvin.GitRanger.Services;
+using CodingWithCalvin.Otel4Vsix;
using Community.VisualStudio.Toolkit;
using Microsoft.VisualStudio;
using Microsoft.VisualStudio.Shell;
@@ -85,16 +86,32 @@ protected override async Task InitializeAsync(CancellationToken cancellationToke
{
await base.InitializeAsync(cancellationToken, progress);
+ // Switch to the main thread for telemetry initialization
+ await JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken);
+
+ // Initialize telemetry
+ 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();
+
// Initialize services
await InitializeServicesAsync();
- // Switch to the main thread for command registration
- await JoinableTaskFactory.SwitchToMainThreadAsync(cancellationToken);
-
// Register commands
await RegisterCommandsAsync();
// Log successful initialization
+ VsixTelemetry.LogInformation("Git Ranger initialized successfully");
await VS.StatusBar.ShowMessageAsync("Git Ranger initialized successfully");
}
@@ -133,6 +150,16 @@ private async Task RegisterCommandsAsync()
await BlameCommands.InitializeAsync(this);
// Note: HistoryCommands and GraphCommands are not registered yet (coming soon)
}
+
+ protected override void Dispose(bool disposing)
+ {
+ if (disposing)
+ {
+ VsixTelemetry.Shutdown();
+ }
+
+ base.Dispose(disposing);
+ }
}
///
diff --git a/src/CodingWithCalvin.GitRanger/HoneycombConfig.cs b/src/CodingWithCalvin.GitRanger/HoneycombConfig.cs
new file mode 100644
index 0000000..d0a04f1
--- /dev/null
+++ b/src/CodingWithCalvin.GitRanger/HoneycombConfig.cs
@@ -0,0 +1,7 @@
+namespace CodingWithCalvin.GitRanger
+{
+ internal static class HoneycombConfig
+ {
+ public const string ApiKey = "PLACEHOLDER";
+ }
+}
diff --git a/src/CodingWithCalvin.GitRanger/Services/BlameService.cs b/src/CodingWithCalvin.GitRanger/Services/BlameService.cs
index 35c0b09..3c627a3 100644
--- a/src/CodingWithCalvin.GitRanger/Services/BlameService.cs
+++ b/src/CodingWithCalvin.GitRanger/Services/BlameService.cs
@@ -1,11 +1,11 @@
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
-using System.Diagnostics;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using CodingWithCalvin.GitRanger.Core.Models;
+using CodingWithCalvin.Otel4Vsix;
namespace CodingWithCalvin.GitRanger.Services
{
@@ -38,21 +38,28 @@ public BlameService(GitService gitService, ThemeService themeService)
/// Blame line information, or empty if not available.
public IReadOnlyList GetBlame(string filePath)
{
- if (string.IsNullOrEmpty(filePath))
+ using var activity = VsixTelemetry.StartCommandActivity("BlameService.GetBlame");
+
+ if (string.IsNullOrEmpty(filePath))
return Array.Empty();
// Check cache
if (_cache.TryGetValue(filePath, out var cached) && !cached.IsExpired)
{
+ activity?.SetTag("cache.hit", true);
return cached.Lines;
}
+ activity?.SetTag("cache.hit", false);
+
// Load synchronously
var lines = _gitService.GetBlame(filePath).ToList();
// Update cache
_cache[filePath] = new BlameCache(lines);
+ activity?.SetTag("lines.count", lines.Count);
+
return lines;
}
@@ -73,11 +80,11 @@ public Task> GetBlameAsync(string filePath, Cancell
/// The file path.
public void LoadBlameInBackground(string filePath)
{
- Debug.WriteLine($"[GitRanger] BlameService.LoadBlameInBackground - FilePath: {filePath}");
+ using var activity = VsixTelemetry.StartCommandActivity("BlameService.LoadBlameInBackground");
- if (string.IsNullOrEmpty(filePath))
+ if (string.IsNullOrEmpty(filePath))
{
- Debug.WriteLine("[GitRanger] BlameService.LoadBlameInBackground - FilePath is empty");
+ VsixTelemetry.LogInformation("LoadBlameInBackground - FilePath is empty");
return;
}
@@ -85,16 +92,17 @@ public void LoadBlameInBackground(string filePath)
{
try
{
- Debug.WriteLine($"[GitRanger] BlameService.LoadBlameInBackground - Starting GetBlame for {filePath}");
+ VsixTelemetry.LogInformation("Loading blame for file");
var lines = GetBlame(filePath);
- Debug.WriteLine($"[GitRanger] BlameService.LoadBlameInBackground - Got {lines.Count} lines");
+ VsixTelemetry.LogInformation("Loaded {LineCount} blame lines", lines.Count);
BlameLoaded?.Invoke(this, new BlameLoadedEventArgs(filePath, lines));
- Debug.WriteLine("[GitRanger] BlameService.LoadBlameInBackground - BlameLoaded event fired");
}
catch (Exception ex)
{
- Debug.WriteLine($"[GitRanger] BlameService.LoadBlameInBackground - ERROR: {ex.Message}");
- Debug.WriteLine($"[GitRanger] BlameService.LoadBlameInBackground - StackTrace: {ex.StackTrace}");
+ VsixTelemetry.TrackException(ex, new Dictionary
+ {
+ { "operation.name", "LoadBlameInBackground" },
+ });
}
});
}