Telemetry SourceGenerator
Purview Telemetry Source Generator
Section titled “Purview Telemetry Source Generator”Generates ActivitySource, ILogger, and Metrics based telemetry from methods you define on an interface.
Current Version: 5.0.0-prerelease.1
This approach allows for:
- Zero boilerplate - define methods on an interface, get full telemetry implementation generated
- Multi-target generation - generate Activities, Logging, and Metrics from a single interface
- Testable - easy mocking/substitution for unit testing (sample project)
- DI-ready - automatic dependency injection registration helpers
- OpenTelemetry-aligned - defaults to OpenTelemetry semantic conventions for better observability
Supported Frameworks
Section titled “Supported Frameworks”- .NET Framework 4.8 or higher
- .NET 8 or higher
Documentation
Section titled “Documentation”Getting Started
Section titled “Getting Started”- Getting Started - Quick start guide with practical examples
- Sample Application - Full .NET Aspire demo application
Core Features
Section titled “Core Features”- Activities - Distributed tracing generation with ActivitySource
- Logging - Structured logging generation with ILogger
- Generation v2 - Default mode with Microsoft.Extensions.Telemetry.Abstractions
- Generation v1 - Legacy high-performance logging mode
- Metrics - Metrics generation (Counters, Histograms, Observables)
- Multi-Targeting - Combine Activities + Logging + Metrics in one interface
Configuration
Section titled “Configuration”- Generation Options - Control class names, DI, and code generation
- TagAttribute - Adding tags/properties to telemetry
- Generated Output - Examples of generated code
Reference
Section titled “Reference”- FAQ - Frequently asked questions and troubleshooting
- Diagnostics - Analyzer warnings and errors
- Breaking Changes - Migration guide for v3 → v4 and earlier versions
- Performance - Full cross-runtime benchmark results
Contributing
Section titled “Contributing”- Contributing - Development setup, changeset workflow, and release process
Migration & Breaking Changes
Section titled “Migration & Breaking Changes”Upgrading from v3? See the Breaking Changes guide for:
- Namespace Consolidation - All attributes now in
Purview.Telemetry - OpenTelemetry-Aligned Naming - New default naming conventions
All marker attributes are generated as conditional, meaning they will not be present in your build. However, you can define PURVIEW_TELEMETRY_ATTRIBUTES as a build constant to retain them. They are generated as internal to avoid exposing them outside of the assembly.
Reference in your .csproj or Directory.Build.props file:
<PackageReference Include="Purview.Telemetry.SourceGenerator" Version="5.0.0-prerelease.1"> <PrivateAssets>all</PrivateAssets> <IncludeAssets>analyzers</IncludeAssets></PackageReference>Basic Examples
Section titled “Basic Examples”The following examples all contain explicit definitions, meaning each example explicitly applies the appropriate attributes. Inferring certain actions or values is also supported and will be detailed in each sub-section.
The documentation for each generation target (activity, logging and metrics) contains information on what can be inferred.
By default each interface used as a source for generation includes an extension method for registering it with an IServiceCollection instance. More details can be found in Generation.
An example project is available in the samples folder. Information can be found here.
Activities
Section titled “Activities”Basic example of an activity-based telemetry interface.
There is one Activity (GettingItemFromCache) and four events. Calling these will add an ActivityEvent to the activity parameter. Alternatively, if no Activity is passed in, the Activity.Current will be used in it’s place.
There is also a ‘context’ method, that will add its properties as either tags or baggage to the current Activity.
The [Tag] and [Baggage] attributes on the parameters will add the values to the Activity or ActivityEvent.
[ActivitySource("some-activity")]interface IActivityTelemetry{ [Activity] Activity? GettingItemFromCache([Baggage]string key, [Tag]string itemType);
[Event("cachemiss")] void Miss(Activity? activity);
[Event("cachehit")] void Hit(Activity? activity);
[Event] void Error(Activity? activity, Exception ex);
[Event] void Finished(Activity? activity, [Tag]TimeSpan duration);
[Context] void AdditionalInfo(Activity? activity, string state);}More information can be found here.
Logging
Section titled “Logging”Basic example of a structured logging-based interface.
All of the parameters are passed into the logger methods as properties.
[Logger]interface ILoggingTelemetry{ [Log] IDisposable? ProcessingWorkItem(Guid id);
[Log(LogLevel.Trace)] void ProcessingItemType(ItemTypes itemType);
[Error] void FailedToProcessWorkItem(Exception ex);
[Info] void ProcessingComplete(bool success, TimeSpan duration);}More information can be found here, including the different types of code generation, and how to disable logging generation when the Microsoft.Extensions.Logging types are unavailable.
Metrics
Section titled “Metrics”This example shows each meter type currently supported. Note the Counter attribute is demoed twice. Once with AutoIncrement set to true, this means the measurement value is automatically set to increment by 1 each time the method is called. In the other example (where AutoIncrement is false, which is the default) the measurement value is specified explicitly as a parameter using the InstrumentMeasurementAttribute.
As with activities, you can add a [Tag] to the parameters and they’ll be included at recording time for the instrument.
[Meter]interface IMeterTelemetry{ [AutoCounter] void AutoIncrementMeter([Tag]string someValue);
[Counter(AutoIncrement = true)] void AutoIncrementCounterMeter([Tag]string someValue);
[Counter] void CounterMeter([InstrumentMeasurement]int measurement, [Tag]float someValue);
[AutoCounter] void AutoCounterMeter([Tag]float someValue);
[Histogram] void HistogramMeter([InstrumentMeasurement]int measurement, [Tag]int someValue, [Tag]bool anotherValue);
[ObservableCounter] void ObservableCounterMeter(Func<float> measurement, [Tag]double someValue);
[ObservableGauge] void ObservableGaugeMeter(Func<Measurement<float>> measurement, [Tag]double someValue);
[ObservableUpDownCounter] void ObservableUpDownCounter(Func<IEnumerable<Measurement<byte>>> measurement, [Tag]double someValue);
[UpDownCounter] void UpDownCounterMeter([InstrumentMeasurement]decimal measurement, [Tag]byte someValue);}More information can be found here.
Multi-Targeting
Section titled “Multi-Targeting”In this example, all method-based targets are explicitly set as inferring their usage is not support when using multi-targeting.
[ActivitySource("multi-targeting")][Logger][Meter]interface IServiceTelemetry{ [Activity] [Trace] Activity? StartAnActivity(string tagStringParam, [Baggage]int entityId);
[Event] [Info] void AnInterestingEvent(Activity? activity, float aTagValue);
[Error] [Event] [AutoCounter] void AnError(Activity? activity, Exception ex);
[Context] [AutoCounter] [Debug] void InterestingInfo(Activity? activity, float anotherTagValue, int intTagValue);
[Histogram] [Trace] void ProcessingEntity(int entityId, string property1);
[Info] [Counter] void ACounter([Tag]int value);}More information can be found here.