Skip to content

Quick Start

Kieron Lanning edited this page Feb 8, 2026 · 1 revision

Quick Start Guide

Get started with Purview Telemetry Source Generator in 5 minutes! This guide walks you through creating your first telemetry-enabled application.

Prerequisites

  • .NET 8.0 or higher (or .NET Framework 4.8+)
  • Your favourite IDE (Visual Studio, Visual Studio Code, or Rider)

Step 1: Install the Package

Add the NuGet package to your project:

Option A: .NET CLI

dotnet add package Purview.Telemetry.SourceGenerator --version 4.0.0-prerelease.2

Option B: Package Manager Console

Install-Package Purview.Telemetry.SourceGenerator -Version 4.0.0-prerelease.2

Option C: Edit .csproj directly

<ItemGroup>
  <PackageReference Include="Purview.Telemetry.SourceGenerator" Version="4.0.0-prerelease.2">
    <PrivateAssets>all</PrivateAssets>
    <IncludeAssets>analyzers</IncludeAssets>
  </PackageReference>
</ItemGroup>

Step 2: Create Your First Telemetry Interface

Create a new file IOrderServiceTelemetry.cs:

using System.Diagnostics;
using Purview.Telemetry;

[ActivitySource("QuickStart.OrderService")]  // For distributed tracing
[Logger]                                      // For structured logging
[Meter("QuickStart.OrderService")]            // For metrics
public interface IOrderServiceTelemetry
{
    // Multi-target method: Creates Activity + Logs Info + Increments Counter
    [Activity]
    [Info]
    [AutoCounter]
    Activity? ProcessingOrder([Baggage] int orderId, [Tag] string customerName);

    // Event + Log
    [Event]
    [Debug]
    void OrderValidated(Activity? activity, [Tag] decimal totalAmount);

    // Event + Log
    [Event(ActivityStatusCode.Ok)]
    [Info]
    void OrderCompleted(Activity? activity, [Tag] TimeSpan processingTime);

    // Error logging
    [Error]
    [AutoCounter]
    void OrderFailed(Exception ex, int orderId);
}

What just happened?

  • [ActivitySource], [Logger], [Meter] - Tells the generator to create implementations for all three telemetry types
  • [Activity], [Info], [AutoCounter] - Multi-target attributes that generate code for all three types from a single method
  • [Baggage] - Data propagates across service boundaries
  • [Tag] - Local activity data (doesn't propagate)

Step 3: Register with Dependency Injection

In your Program.cs or Startup.cs:

using Microsoft.Extensions.DependencyInjection;

var builder = WebApplication.CreateBuilder(args);

// Register the telemetry interface
// The generator creates this extension method automatically!
builder.Services.AddOrderServiceTelemetry();

var app = builder.Build();

Step 4: Use It in Your Service

Create OrderService.cs:

public class OrderService
{
    private readonly IOrderServiceTelemetry _telemetry;
    private readonly IOrderRepository _repository;

    public OrderService(IOrderServiceTelemetry telemetry, IOrderRepository repository)
    {
        _telemetry = telemetry;
        _repository = repository;
    }

    public async Task<Order?> ProcessOrderAsync(int orderId, string customerName)
    {
        // Single call creates Activity + Logs + Increments counter!
        using var activity = _telemetry.ProcessingOrder(orderId, customerName);

        try
        {
            // Validate order
            var order = await _repository.GetOrderAsync(orderId);
            if (order == null)
            {
                _telemetry.OrderFailed(new Exception("Order not found"), orderId);
                return null;
            }

            // Add event to activity + log debug message
            _telemetry.OrderValidated(activity, order.TotalAmount);

            // Process payment, shipping, etc...
            await Task.Delay(100); // Simulated work

            var stopwatch = Stopwatch.StartNew();
            // ... more processing ...
            stopwatch.Stop();

            // Add event + log completion
            _telemetry.OrderCompleted(activity, stopwatch.Elapsed);

            return order;
        }
        catch (Exception ex)
        {
            // Log error + increment error counter
            _telemetry.OrderFailed(ex, orderId);
            throw;
        }
    }
}

Step 5: Configure OpenTelemetry (Optional but Recommended)

To view your telemetry, add OpenTelemetry exporters:

dotnet add package OpenTelemetry.Exporter.Console
dotnet add package OpenTelemetry.Extensions.Hosting

Configure in Program.cs:

using OpenTelemetry.Logs;
using OpenTelemetry.Metrics;
using OpenTelemetry.Trace;

var builder = WebApplication.CreateBuilder(args);

// Add OpenTelemetry
builder.Services.AddOpenTelemetry()
    .WithTracing(tracing => tracing
        .AddSource("QuickStart.OrderService")  // Match your ActivitySource name
        .AddConsoleExporter())
    .WithMetrics(metrics => metrics
        .AddMeter("QuickStart.OrderService")   // Match your Meter name - this defaults to the assembly name if not specified
        .AddConsoleExporter())
    .WithLogging(logging => logging
        .AddConsoleExporter());

builder.Services.AddOrderServiceTelemetry();

var app = builder.Build();

Step 6: Run and See It Work

Run your application and call the ProcessOrderAsync method. You'll see:

Console Output (Activity Trace):

Activity.TraceId:            80000000-0000-0000-0000-000000000001
Activity.SpanId:             8000000000000001
Activity.DisplayName:        ProcessingOrder
Activity.Kind:               Internal
Activity.StartTime:          2026-02-14T10:30:00.0000000Z
Activity.Duration:           00:00:00.1234567
Activity.Tags:
    order_id: 42
    customer_name: John Doe (Baggage)
Activity.Events:
    OrderValidated [10:30:00.050]
        total_amount: 99.99
    OrderCompleted [10:30:00.123]
        processing_time: 00:00:00.123

Console Output (Logging):

info: IOrderServiceTelemetry[0]
      ProcessingOrder: OrderId = 42, CustomerName = John Doe
      
dbug: IOrderServiceTelemetry[0]
      OrderValidated: TotalAmount = 99.99
      
info: IOrderServiceTelemetry[0]
      OrderCompleted: ProcessingTime = 00:00:00.123

Console Output (Metrics):

Meter: QuickStart.OrderService
  Instrument: order_service.processing_order (Counter)
    Value: 1

What's Next?

Learn More About Each Feature

Common Next Steps

1. Add More Telemetry

[ActivitySource("QuickStart.PaymentService")]
[Logger]
[Meter("QuickStart.PaymentService")]
public interface IPaymentServiceTelemetry
{
    [Activity(ActivityKind.Client)]
    [Info]
    [AutoCounter]
    Activity? ProcessingPayment([Baggage] Guid paymentId, [Tag] decimal amount);

    [Event]
    [Debug]
    void PaymentValidated(Activity? activity);

    [Event(ActivityStatusCode.Error)]
    [Error]
    void PaymentDeclined(Activity? activity, string reason);

    [Histogram]
    void PaymentDuration([InstrumentMeasurement] int milliseconds, [Tag] bool success);
}

2. Use Scoped Logging

[Logger]
public interface IDataServiceTelemetry
{
    // Returns IDisposable for automatic start/end logging
    [Info]
    IDisposable? FetchingDataFromDatabase(int recordId);

    [Debug]
    void RecordFetched(string recordType);
}

// Usage
public async Task<Data> GetDataAsync(int id)
{
    using (_telemetry.FetchingDataFromDatabase(id))  // Logs at start and end
    {
        var data = await _repository.GetAsync(id);
        _telemetry.RecordFetched(data.Type);
        return data;
    }
}

3. Add Metrics Only

[Meter("QuickStart.CacheService")]
public interface ICacheMetrics
{
    [AutoCounter]
    void CacheHit([Tag] string cacheKey);

    [AutoCounter]
    void CacheMiss([Tag] string cacheKey);

    [Histogram]
    void CacheLookupDuration([InstrumentMeasurement] int milliseconds);
}

4. Export to Real Observability Platform

Replace console exporters with:

Jaeger (Traces):

dotnet add package OpenTelemetry.Exporter.Jaeger
.WithTracing(tracing => tracing
    .AddSource("QuickStart.*")
    .AddJaegerExporter())

Prometheus (Metrics):

dotnet add package OpenTelemetry.Exporter.Prometheus.AspNetCore
.WithMetrics(metrics => metrics
    .AddMeter("QuickStart.*")
    .AddPrometheusExporter())

app.MapPrometheusScrapingEndpoint();

Azure Monitor (All):

dotnet add package Azure.Monitor.OpenTelemetry.Exporter
.UseAzureMonitor()

Inspecting Generated Code

Want to see what code the generator creates?

Add to your .csproj:

<PropertyGroup>
  <EmitCompilerGeneratedFiles>true</EmitCompilerGeneratedFiles>
</PropertyGroup>

Generated files appear in:

obj/Debug/net8.0/generated/Purview.Telemetry.SourceGenerator/

You'll find:

  • {NamespaceOrderServiceTelemetryCore.Activity.g.cs - Activity implementation
  • {Namespace}.OrderServiceTelemetryCore.Logging.g.cs - Logging implementation
  • {Namespace}.OrderServiceTelemetryCore.Metric.g.cs - Metrics implementation
  • {Namespace}.OrderServiceTelemetryCoreDIExtension.DependencyInjection.g.cs - DI registration

Complete Working Example

Here's a complete minimal application you can copy and run:

Program.cs:

using System.Diagnostics;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using OpenTelemetry.Logs;
using OpenTelemetry.Metrics;
using OpenTelemetry.Trace;
using Purview.Telemetry;

var builder = Host.CreateApplicationBuilder(args);

// Configure OpenTelemetry
builder.Services.AddOpenTelemetry()
    .WithTracing(t => t.AddSource("QuickStart").AddConsoleExporter())
    .WithMetrics(m => m.AddMeter("QuickStart").AddConsoleExporter())
    .WithLogging(l => l.AddConsoleExporter());

// Register telemetry
builder.Services.AddOrderServiceTelemetry();

// Register application service
builder.Services.AddSingleton<OrderService>();

var app = builder.Build();

// Run a test
var service = app.Services.GetRequiredService<OrderService>();
await service.ProcessOrderAsync(42, "John Doe");

Console.WriteLine("\nDone! Check the output above for telemetry.");

// Telemetry interface
[ActivitySource("QuickStart")]
[Logger]
[Meter("QuickStart")]
public interface IOrderServiceTelemetry
{
    [Activity]
    [Info]
    [AutoCounter]
    Activity? ProcessingOrder([Baggage] int orderId, [Tag] string customerName);

    [Event(ActivityStatusCode.Ok)]
    [Info]
    void OrderCompleted(Activity? activity, [Tag] TimeSpan duration);
}

// Application service
public class OrderService
{
    private readonly IOrderServiceTelemetry _telemetry;

    public OrderService(IOrderServiceTelemetry telemetry)
    {
        _telemetry = telemetry;
    }

    public async Task ProcessOrderAsync(int orderId, string customerName)
    {
        var sw = Stopwatch.StartNew();
        
        using var activity = _telemetry.ProcessingOrder(orderId, customerName);
        
        // Simulate work
        await Task.Delay(100);
        
        _telemetry.OrderCompleted(activity, sw.Elapsed);
    }
}

Run it:

dotnet run

Troubleshooting

"Type or namespace 'ActivitySourceAttribute' could not be found"

Solution: Add the using statement:

using Purview.Telemetry;

"No extension method 'Add{InterfaceName}'"

Solution: Rebuild the project to trigger source generation:

dotnet build

"No telemetry appears in console"

Solution: Ensure OpenTelemetry is configured with the correct source/meter names that match your interface attributes.

"Build warnings about unbounded enumeration"

Solution: Add [ExpandEnumerable] attribute with maximumValueCount:

[Info]
void LogItems([ExpandEnumerable(maximumValueCount: 100)] string[] items);

Next Steps

Need Help?

Clone this wiki locally