Zircon.Diagnostics 2.0.0

dotnet add package Zircon.Diagnostics --version 2.0.0
                    
NuGet\Install-Package Zircon.Diagnostics -Version 2.0.0
                    
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="Zircon.Diagnostics" Version="2.0.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Zircon.Diagnostics" Version="2.0.0" />
                    
Directory.Packages.props
<PackageReference Include="Zircon.Diagnostics" />
                    
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 Zircon.Diagnostics --version 2.0.0
                    
#r "nuget: Zircon.Diagnostics, 2.0.0"
                    
#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 Zircon.Diagnostics@2.0.0
                    
#: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=Zircon.Diagnostics&version=2.0.0
                    
Install as a Cake Addin
#tool nuget:?package=Zircon.Diagnostics&version=2.0.0
                    
Install as a Cake Tool

Zircon.Diagnostics

Diagnostic extensions for OpenTelemetry activities including exception tagging and status management following OpenTelemetry semantic conventions.

Features

  • OpenTelemetry Compliance: Follows OpenTelemetry semantic conventions for exception handling
  • Activity Enhancement: Extends System.Diagnostics.Activity with exception-specific functionality
  • Null Safety: Safe handling of null Activity instances
  • Comprehensive Exception Data: Captures exception message, stack trace, and type information
  • Status Management: Automatically sets activity status to Error when exceptions occur

Installation

dotnet add package Zircon.Diagnostics

Usage

Basic Exception Handling

using System.Diagnostics;
using Zircon.Diagnostics;

public class OrderService
{
    private static readonly ActivitySource ActivitySource = new("OrderService");
    
    public async Task ProcessOrderAsync(Order order)
    {
        using var activity = ActivitySource.StartActivity("ProcessOrder");
        
        try
        {
            // Process the order
            await ValidateOrder(order);
            await SaveOrder(order);
            await SendConfirmation(order);
        }
        catch (Exception ex)
        {
            // This will add exception tags and set status to Error
            activity.SetExceptionTags(ex);
            throw; // Re-throw to maintain exception flow
        }
    }
}

Web API Integration

[ApiController]
[Route("api/[controller]")]
public class ProductsController : ControllerBase
{
    private static readonly ActivitySource ActivitySource = new("ProductsApi");
    
    [HttpPost]
    public async Task<IActionResult> CreateProduct([FromBody] CreateProductRequest request)
    {
        using var activity = ActivitySource.StartActivity("CreateProduct");
        activity?.SetTag("product.name", request.Name);
        
        try
        {
            var product = await _productService.CreateProductAsync(request);
            activity?.SetTag("product.id", product.Id.ToString());
            
            return Created($"/api/products/{product.Id}", product);
        }
        catch (ValidationException ex)
        {
            activity.SetExceptionTags(ex);
            return BadRequest(ex.Message);
        }
        catch (Exception ex)
        {
            activity.SetExceptionTags(ex);
            return StatusCode(500, "An error occurred while creating the product");
        }
    }
}

Middleware Integration

public class ExceptionHandlingMiddleware
{
    private readonly RequestDelegate _next;
    private readonly ILogger<ExceptionHandlingMiddleware> _logger;
    
    public ExceptionHandlingMiddleware(RequestDelegate next, ILogger<ExceptionHandlingMiddleware> logger)
    {
        _next = next;
        _logger = logger;
    }
    
    public async Task InvokeAsync(HttpContext context)
    {
        try
        {
            await _next(context);
        }
        catch (Exception ex)
        {
            // Get current activity and add exception information
            Activity.Current.SetExceptionTags(ex);
            
            _logger.LogError(ex, "An unhandled exception occurred");
            
            context.Response.StatusCode = 500;
            await context.Response.WriteAsync("Internal Server Error");
        }
    }
}

Background Service Usage

public class DataProcessingService : BackgroundService
{
    private static readonly ActivitySource ActivitySource = new("DataProcessing");
    
    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        while (!stoppingToken.IsCancellationRequested)
        {
            using var activity = ActivitySource.StartActivity("ProcessBatch");
            
            try
            {
                await ProcessNextBatch();
                activity?.SetStatus(ActivityStatusCode.Ok);
            }
            catch (Exception ex)
            {
                activity.SetExceptionTags(ex);
                // Log and continue processing
                _logger.LogError(ex, "Error processing batch");
            }
            
            await Task.Delay(TimeSpan.FromMinutes(5), stoppingToken);
        }
    }
}

Extension Methods

SetExceptionTags

public static void SetExceptionTags(this Activity? activity, Exception ex)

Description: Sets exception-related tags on an activity following OpenTelemetry semantic conventions.

Parameters:

  • activity: The activity to set tags on (null-safe)
  • ex: The exception to extract information from

Tags Added:

  • exception.message: The exception message
  • exception.stacktrace: The full exception string (including stack trace)
  • exception.type: The full type name of the exception

Additional Actions:

  • Sets the activity status to ActivityStatusCode.Error

OpenTelemetry Semantic Conventions

This package follows the OpenTelemetry Semantic Conventions for Exceptions:

Tag Description Example
exception.message The exception message "Validation failed for field 'Email'"
exception.stacktrace Full exception details Full stack trace string
exception.type Exception type name "System.ArgumentNullException"

Configuration with OpenTelemetry

ASP.NET Core Setup

public void ConfigureServices(IServiceCollection services)
{
    services.AddOpenTelemetry()
        .ConfigureResource(resource => resource.AddService("MyService"))
        .WithTracing(tracing => tracing
            .AddAspNetCoreInstrumentation()
            .AddHttpClientInstrumentation()
            .AddSource("OrderService") // Add your custom activity sources
            .AddSource("ProductsApi")
            .AddJaegerExporter());
}

Console Application Setup

using var tracerProvider = TracerProviderBuilder.Create()
    .AddSource("DataProcessing")
    .SetSampler(new AlwaysOnSampler())
    .AddConsoleExporter()
    .Build();

// Your application code here

Advanced Usage

Custom Exception Handling

public class BusinessLogicService
{
    private static readonly ActivitySource ActivitySource = new("BusinessLogic");
    
    public async Task ProcessBusinessRuleAsync(BusinessRequest request)
    {
        using var activity = ActivitySource.StartActivity("ProcessBusinessRule");
        activity?.SetTag("rule.type", request.RuleType);
        
        try
        {
            await ValidateBusinessRules(request);
            await ExecuteBusinessLogic(request);
        }
        catch (BusinessRuleException ex)
        {
            activity.SetExceptionTags(ex);
            activity?.SetTag("business.rule.violation", ex.RuleName);
            throw;
        }
        catch (Exception ex)
        {
            activity.SetExceptionTags(ex);
            activity?.SetTag("error.category", "system");
            throw;
        }
    }
}

Conditional Exception Tagging

public class PaymentService
{
    public async Task ProcessPaymentAsync(PaymentRequest request)
    {
        using var activity = ActivitySource.StartActivity("ProcessPayment");
        
        try
        {
            await ChargeCard(request);
        }
        catch (PaymentDeclinedException ex)
        {
            activity.SetExceptionTags(ex);
            activity?.SetTag("payment.declined.reason", ex.DeclineReason);
            // Don't re-throw - this is expected behavior
            
            return new PaymentResult { Success = false, Reason = ex.DeclineReason };
        }
        catch (Exception ex)
        {
            activity.SetExceptionTags(ex);
            throw; // Unexpected errors should be thrown
        }
    }
}

Integration with Logging

public class ServiceWithLogging
{
    private readonly ILogger<ServiceWithLogging> _logger;
    
    public async Task ProcessAsync()
    {
        using var activity = ActivitySource.StartActivity("Process");
        var correlationId = Guid.NewGuid().ToString();
        activity?.SetTag("correlation.id", correlationId);
        
        try
        {
            await DoWork();
        }
        catch (Exception ex)
        {
            activity.SetExceptionTags(ex);
            
            // Log with correlation ID from activity
            _logger.LogError(ex, "Processing failed for correlation {CorrelationId}", correlationId);
            
            throw;
        }
    }
}

Best Practices

  1. Always Re-throw: Use SetExceptionTags for observability but still re-throw exceptions to maintain proper error flow
  2. Add Context Tags: Include relevant business context tags before handling exceptions
  3. Use in Finally Blocks: Consider using in finally blocks for cleanup operations
  4. Null Safety: The extension method handles null activities gracefully
  5. Consistent Activity Sources: Use consistent activity source names across your application
  6. Structured Logging: Combine with structured logging for comprehensive observability

Performance Considerations

  • The extension method performs minimal work and has negligible performance impact
  • Activity tag operations are optimized by the underlying OpenTelemetry libraries
  • Consider sampling strategies for high-throughput applications
  • Exception tags are only set when exceptions actually occur, so normal operation has no overhead

Monitoring and Alerting

With proper OpenTelemetry configuration, you can:

  • Set up alerts on high exception rates
  • Create dashboards showing exception types and frequencies
  • Trace request flows that include exceptions
  • Correlate exceptions across multiple services
  • Monitor error rates by service, endpoint, or business operation

License

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

Product Compatible and additional computed target framework versions.
.NET net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • net10.0

    • No dependencies.

NuGet packages (1)

Showing the top 1 NuGet packages that depend on Zircon.Diagnostics:

Package Downloads
Zircon.EntityFramework.Migrations

Package Description

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
2.0.0 98 2/8/2026
1.1.0 96 2/7/2026
1.0.0 88 2/7/2026