CodingWithCalvin.Otel4Vsix 0.2.2

dotnet add package CodingWithCalvin.Otel4Vsix --version 0.2.2
                    
NuGet\Install-Package CodingWithCalvin.Otel4Vsix -Version 0.2.2
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="CodingWithCalvin.Otel4Vsix" Version="0.2.2" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="CodingWithCalvin.Otel4Vsix" Version="0.2.2" />
                    
Directory.Packages.props
<PackageReference Include="CodingWithCalvin.Otel4Vsix" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add CodingWithCalvin.Otel4Vsix --version 0.2.2
                    
#r "nuget: CodingWithCalvin.Otel4Vsix, 0.2.2"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package CodingWithCalvin.Otel4Vsix@0.2.2
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=CodingWithCalvin.Otel4Vsix&version=0.2.2
                    
Install as a Cake Addin
#tool nuget:?package=CodingWithCalvin.Otel4Vsix&version=0.2.2
                    
Install as a Cake Tool

<p align="center"> <img src="assets/icon.png" alt="Otel4Vsix Logo" width="128" height="128"> </p>

<h1 align="center">🔭 Otel4Vsix</h1>

<p align="center"> <a href="https://github.com/CodingWithCalvin/Otel4Vsix/actions/workflows/build.yml"><img src="https://img.shields.io/github/actions/workflow/status/CodingWithCalvin/Otel4Vsix/build.yml?style=for-the-badge&label=Build" alt="Build"></a> <a href="https://www.nuget.org/packages/CodingWithCalvin.Otel4Vsix/"><img src="https://img.shields.io/nuget/v/CodingWithCalvin.Otel4Vsix?style=for-the-badge&logo=nuget" alt="NuGet"></a> <a href="https://www.nuget.org/packages/CodingWithCalvin.Otel4Vsix/"><img src="https://img.shields.io/nuget/dt/CodingWithCalvin.Otel4Vsix?style=for-the-badge&logo=nuget&label=Downloads" alt="NuGet Downloads"></a> <a href="https://opensource.org/licenses/MIT"><img src="https://img.shields.io/badge/License-MIT-yellow?style=for-the-badge" alt="License: MIT"></a> </p>

<p align="center"> 🚀 <strong>Add OpenTelemetry observability to your Visual Studio extensions in minutes!</strong> </p>

Otel4Vsix is a powerful yet simple library that brings distributed tracing, metrics, logging, and exception tracking to your VSIX extensions with minimal configuration. See exactly what's happening inside your extension! 👀


✨ Features

Feature Description
📊 Distributed Tracing Track operations across your extension with spans and activities
📈 Metrics Counters, histograms, and gauges for performance monitoring
📝 Structured Logging OpenTelemetry-integrated logging via ILogger
💥 Exception Tracking Automatic and manual exception capture with full context
🔌 Multiple Export Modes OTLP (gRPC/HTTP) for production, Debug output for development
🎯 VS-Specific Helpers Pre-configured spans for commands, tool windows, and documents
🏗️ Fluent Builder API Clean, chainable configuration
🔧 Auto-Detection Automatically captures VS version, edition, OS, and architecture

📦 Installation

Package Manager

Install-Package CodingWithCalvin.Otel4Vsix

.NET CLI

dotnet add package CodingWithCalvin.Otel4Vsix

PackageReference

<PackageReference Include="CodingWithCalvin.Otel4Vsix" Version="1.0.0" />

🚀 Quick Start

1️⃣ Initialize Telemetry

In your Visual Studio extension's InitializeAsync method:

using CodingWithCalvin.Otel4Vsix;

protected override async Task InitializeAsync(
    CancellationToken cancellationToken,
    IProgress<ServiceProgressData> progress)
{
    await JoinableTaskFactory.SwitchToMainThreadAsync();

    VsixTelemetry.Configure()
        .WithServiceName("MyAwesomeExtension")
        .WithServiceVersion("1.0.0")
        .WithVisualStudioAttributes(this)  // 🪄 Auto-captures VS version & edition!
        .WithEnvironmentAttributes()        // 🖥️ Auto-captures OS & architecture!
        .WithOtlpHttp("https://api.honeycomb.io")
        .WithHeader("x-honeycomb-team", "your-api-key")
        .Initialize();
}

2️⃣ Shutdown on Dispose

protected override void Dispose(bool disposing)
{
    if (disposing)
    {
        VsixTelemetry.Shutdown();
    }
    base.Dispose(disposing);
}

🎉 That's it! Your extension is now observable!


🎛️ Telemetry Modes

Otel4Vsix supports multiple telemetry modes to fit your workflow:

Mode Description
Auto 🤖 Default - Uses OTLP if endpoint configured, otherwise Debug output
Debug 🐛 Outputs to VS Output window (visible when debugging)
Otlp 📡 Exports via OTLP protocol to your collector
Disabled 🔇 No telemetry collection

💡 Pro Tip: Development vs Production

var builder = VsixTelemetry.Configure()
    .WithServiceName(Vsix.Name)
    .WithServiceVersion(Vsix.Version)
    .WithVisualStudioAttributes(this)
    .WithEnvironmentAttributes();

#if !DEBUG
// 📡 Only send to collector in Release builds
builder
    .WithOtlpHttp("https://api.honeycomb.io")
    .WithHeader("x-honeycomb-team", apiKey);
#endif

builder.Initialize();

In Debug builds, telemetry automatically outputs to the VS Output window! 🔍


📊 Usage

🔍 Tracing

Create spans to track operations and their duration:

// 🎯 Simple span
using var activity = VsixTelemetry.Tracer.StartActivity("ProcessFile");
activity?.SetTag("file.path", filePath);
activity?.SetTag("file.size", fileSize);

// ⚡ VS command span (with pre-configured attributes)
using var commandSpan = VsixTelemetry.StartCommandActivity("MyExtension.DoSomething");

// 🪆 Nested spans for detailed tracing
using var outer = VsixTelemetry.Tracer.StartActivity("LoadProject");
{
    using var inner = VsixTelemetry.Tracer.StartActivity("ParseProjectFile");
    // ... parse logic
}
⚠️ Error Handling in Spans
using var activity = VsixTelemetry.StartActivity("RiskyOperation");
try
{
    // Your code here
}
catch (Exception ex)
{
    activity?.SetStatus(ActivityStatusCode.Error, ex.Message);
    activity?.RecordException(ex);
    throw;
}

📈 Metrics

Record counters, histograms, and gauges:

// 🔢 Counter - track occurrences
var commandCounter = VsixTelemetry.GetOrCreateCounter<long>(
    "extension.commands.executed",
    "{command}",
    "Number of commands executed");

commandCounter?.Add(1,
    new KeyValuePair<string, object>("command.name", "FormatDocument"));

// 📊 Histogram - track distributions (e.g., durations)
var durationHistogram = VsixTelemetry.GetOrCreateHistogram<double>(
    "extension.operation.duration",
    "ms",
    "Duration of operations in milliseconds");

var stopwatch = Stopwatch.StartNew();
// ... do work ...
stopwatch.Stop();
durationHistogram?.Record(stopwatch.ElapsedMilliseconds,
    new KeyValuePair<string, object>("operation.name", "BuildSolution"));

📝 Logging

Structured logging with OpenTelemetry integration:

// 📢 Quick logging methods
VsixTelemetry.LogInformation("Processing file: {FilePath}", filePath);
VsixTelemetry.LogWarning("File not found, using default: {DefaultPath}", defaultPath);
VsixTelemetry.LogError(ex, "Failed to process {FileName}", fileName);

// 🏷️ Create a typed logger for your class
public class MyToolWindow
{
    private readonly ILogger<MyToolWindow> _logger = VsixTelemetry.CreateLogger<MyToolWindow>();

    public void DoWork()
    {
        _logger.LogDebug("Starting work...");
        // ...
        _logger.LogInformation("Work completed successfully! 🎉");
    }
}

💥 Exception Tracking

Track exceptions with full context:

// 🎯 Manual exception tracking
try
{
    // risky operation
}
catch (Exception ex)
{
    VsixTelemetry.TrackException(ex);
    // Handle or rethrow
}

// 📋 With additional context
catch (Exception ex)
{
    VsixTelemetry.TrackException(ex, new Dictionary<string, object>
    {
        { "operation.name", "LoadProject" },
        { "project.path", projectPath },
        { "user.action", "OpenSolution" }
    });
    throw;
}

💡 Note: Global unhandled exceptions are automatically captured when EnableGlobalExceptionHandler is true (default).


⚙️ Configuration Options

🏗️ Fluent Builder Methods

Method Description
WithServiceName(name) Set the service name for identification
WithServiceVersion(version) Set the service version
WithVisualStudioAttributes(serviceProvider) 🪄 Auto-capture VS version & edition
WithVisualStudioAttributes(version, edition) Manually set VS attributes
WithEnvironmentAttributes() 🖥️ Auto-capture OS version & architecture
WithResourceAttribute(key, value) Add custom resource attributes
WithOtlpHttp(endpoint) Configure OTLP HTTP export
WithOtlpGrpc(endpoint) Configure OTLP gRPC export
WithHeader(key, value) Add headers for OTLP requests
WithMode(mode) Set telemetry mode (Auto/Debug/Otlp/Disabled)
WithTracing(enabled) Enable/disable tracing
WithMetrics(enabled) Enable/disable metrics
WithLogging(enabled) Enable/disable logging
WithTraceSamplingRatio(ratio) Set trace sampling (0.0 - 1.0)
WithGlobalExceptionHandler(enabled) Enable/disable auto exception capture
WithExceptionFilter(filter) Filter which exceptions to track
WithExportTimeout(ms) Set export timeout in milliseconds
Initialize() 🚀 Initialize telemetry

📋 Auto-Captured Attributes

When using the helper methods, these attributes are automatically captured:

Attribute Source Example
vs.version WithVisualStudioAttributes() "17.12.35521.163"
vs.edition WithVisualStudioAttributes() "Enterprise"
os.version WithEnvironmentAttributes() "10.0.22631.0"
host.arch WithEnvironmentAttributes() "X64" or "Arm64"

🔌 Supported Backends

Otel4Vsix exports telemetry via OTLP, which is supported by:

Backend Link
🐝 Honeycomb honeycomb.io
🔵 Azure Monitor Application Insights
🐕 Datadog datadoghq.com
🟡 Jaeger jaegertracing.io
🔴 Grafana Tempo grafana.com/oss/tempo
📮 Zipkin zipkin.io
☁️ AWS X-Ray aws.amazon.com/xray
🌐 Google Cloud Trace cloud.google.com/trace
🔧 Any OTLP-compatible collector

📋 Example: Full Production Setup

using CodingWithCalvin.Otel4Vsix;

public sealed class MyExtensionPackage : AsyncPackage
{
    protected override async Task InitializeAsync(
        CancellationToken cancellationToken,
        IProgress<ServiceProgressData> progress)
    {
        await JoinableTaskFactory.SwitchToMainThreadAsync();

        var builder = VsixTelemetry.Configure()
            .WithServiceName("MyExtension")
            .WithServiceVersion(Vsix.Version)
            .WithVisualStudioAttributes(this)
            .WithEnvironmentAttributes()
            .WithResourceAttribute("deployment.environment", "production")
            .WithTraceSamplingRatio(0.1)  // Sample 10% of traces
            .WithExceptionFilter(ex => ex is not OperationCanceledException);

#if !DEBUG
        builder
            .WithOtlpHttp("https://api.honeycomb.io")
            .WithHeader("x-honeycomb-team", Config.HoneycombApiKey);
#endif

        builder.Initialize();

        // ... rest of initialization
    }

    protected override void Dispose(bool disposing)
    {
        if (disposing)
        {
            VsixTelemetry.Shutdown();
        }
        base.Dispose(disposing);
    }
}

📋 Requirements

Requirement Version
.NET Framework 4.8
Visual Studio 2022 or later

🤝 Contributing

Contributions are welcome! 🎉

  1. 🍴 Fork the repository
  2. 🌿 Create your feature branch (git checkout -b feature/AmazingFeature)
  3. 💾 Commit your changes (git commit -m 'Add some AmazingFeature')
  4. 📤 Push to the branch (git push origin feature/AmazingFeature)
  5. 🔃 Open a Pull Request

👥 Contributors

CalvinAllen


📄 License

This project is licensed under the MIT License - see the LICENSE file for details.


🙏 Acknowledgments

Product Compatible and additional computed target framework versions.
.NET Framework net48 is compatible.  net481 was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
0.2.2 232 1/6/2026
0.2.1 89 1/6/2026
0.2.0 131 12/30/2025