-
Notifications
You must be signed in to change notification settings - Fork 2
Quick Start
Get started with Purview Telemetry Source Generator in 5 minutes! This guide walks you through creating your first telemetry-enabled application.
- .NET 8.0 or higher (or .NET Framework 4.8+)
- Your favourite IDE (Visual Studio, Visual Studio Code, or Rider)
Add the NuGet package to your project:
dotnet add package Purview.Telemetry.SourceGenerator --version 4.0.0-prerelease.2Install-Package Purview.Telemetry.SourceGenerator -Version 4.0.0-prerelease.2<ItemGroup>
<PackageReference Include="Purview.Telemetry.SourceGenerator" Version="4.0.0-prerelease.2">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>analyzers</IncludeAssets>
</PackageReference>
</ItemGroup>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)
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();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;
}
}
}To view your telemetry, add OpenTelemetry exporters:
dotnet add package OpenTelemetry.Exporter.Console
dotnet add package OpenTelemetry.Extensions.HostingConfigure 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();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
- Activities - Deep dive into distributed tracing
- Logging - Structured logging with Generation v2
- Metrics - Counters, histograms, and observables
- Multi-Targeting - Combine telemetry types
[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);
}[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;
}
}[Meter("QuickStart.CacheService")]
public interface ICacheMetrics
{
[AutoCounter]
void CacheHit([Tag] string cacheKey);
[AutoCounter]
void CacheMiss([Tag] string cacheKey);
[Histogram]
void CacheLookupDuration([InstrumentMeasurement] int milliseconds);
}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()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
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 runSolution: Add the using statement:
using Purview.Telemetry;Solution: Rebuild the project to trigger source generation:
dotnet buildSolution: Ensure OpenTelemetry is configured with the correct source/meter names that match your interface attributes.
Solution: Add [ExpandEnumerable] attribute with maximumValueCount:
[Info]
void LogItems([ExpandEnumerable(maximumValueCount: 100)] string[] items);- Getting Started Guide - Comprehensive walkthrough with more examples
- Sample Application - Full .NET Aspire sample with all features
- Breaking Changes - Migrating from v3 to v4
- Migration Guides - Migrate from manual ILogger or ActivitySource
- API Reference - Complete attribute reference
- Check the FAQ for common questions
- Review Diagnostics for analyzer warnings and errors
- See Generated Output for code examples
- Explore the Sample Application for real-world usage
Important
Consider helping children around the world affected by conflict. You can donate any amount to War Child here - any amount can help save a life.
Purview Telemetry Source Generator v4.0.0-prerelease.1 | Home | Getting Started | FAQ | Breaking Changes | GitHub