Skip to content

Generated Output

Kieron Lanning edited this page Mar 16, 2026 · 16 revisions

Generated Output Examples

This page shows what code the Purview Telemetry Source Generator creates from your interface definitions. All examples are taken from the SampleApp.APIService project in this repository with EmitCompilerGeneratedFiles enabled.

Input Interface

The following multi-target interface (IEntityStoreTelemetry) is the source for all generated output shown on this page:

using System.Diagnostics;
using Purview.Telemetry;

[ActivitySource]
[Logger]
[Meter]
interface IEntityStoreTelemetry
{
    [Activity]
    [Info]
    [AutoCounter]
    Activity? GettingEntityFromStore(int entityId, [Baggage] string serviceUrl);

    [Event]
    [Trace]
    void GetDuration(Activity? activity, int durationInMS);

    [Context]
    void RetrievedEntity(Activity? activity, float totalValue, int lastUpdatedByUserId);

    [Warning]
    void EntityNotFound(int entityId);

    [Histogram]
    void RecordEntitySize(int sizeInBytes);
}

Generated files appear in obj/Debug|Release/net*/generated/Purview.Telemetry.SourceGenerator/ when EmitCompilerGeneratedFiles is enabled.


Activity Generation

File: EntityStoreTelemetryCore.Activity.g.cs

[EditorBrowsable(EditorBrowsableState.Never)]
[ExcludeFromCodeCoverage]
[GeneratedCode("Purview.Telemetry.SourceGenerator", "...")]
sealed partial class EntityStoreTelemetryCore : global::IEntityStoreTelemetry
{
    readonly static global::System.Diagnostics.ActivitySource _activitySource =
        new("sample-weather-app-api");

    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    private global::System.Diagnostics.Activity? GettingEntityFromStore_Activity(
        int entityId, string serviceUrl)
    {
        if (!_activitySource.HasListeners())
            return null;

        global::System.Diagnostics.Activity? activity = _activitySource.StartActivity(
            "GettingEntityFromStore", ActivityKind.Internal,
            parentId: default, tags: default, links: default, startTime: default);

        if (activity != null)
        {
            activity.SetTag("entity_id", entityId);
            activity.SetBaggage("service_url", serviceUrl);
        }

        return activity;
    }

    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    private void GetDuration_Activity(Activity? activity, int durationInMS)
    {
        if (!_activitySource.HasListeners())
            return;

        if (activity != null)
        {
            var tagsCollection = new ActivityTagsCollection();
            tagsCollection.Add("duration_in_ms", durationInMS);

            activity.AddEvent(new ActivityEvent(
                name: "GetDuration", timestamp: default, tags: tagsCollection));
        }
    }

    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public void RetrievedEntity(Activity? activity, float totalValue, int lastUpdatedByUserId)
    {
        if (!_activitySource.HasListeners())
            return;

        if (activity != null)
        {
            activity.SetTag("total_value", totalValue);
            activity.SetTag("last_updated_by_user_id", lastUpdatedByUserId);
        }
    }
}

[Context] methods are emitted directly as public methods (no private helper) because they have no logging or metrics target and can short-circuit immediately on HasListeners().


Logging Generation

File: EntityStoreTelemetryCore.Logging.g.cs

Uses the v1 (LoggerMessage.Define) pattern (v2 requires Microsoft.Extensions.Telemetry.Abstractions):

sealed partial class EntityStoreTelemetryCore : global::IEntityStoreTelemetry
{
    readonly global::Microsoft.Extensions.Logging.ILogger<global::IEntityStoreTelemetry> _logger;

    static readonly Action<ILogger, int, string, Exception?> _gettingEntityFromStoreAction =
        LoggerMessage.Define<int, string>(
            LogLevel.Information,
            new EventId(106573457, "GettingEntityFromStore"),
            "GettingEntityFromStore: EntityId = {EntityId}, ServiceUrl = {ServiceUrl}");

    static readonly Action<ILogger, int, Exception?> _getDurationAction =
        LoggerMessage.Define<int>(
            LogLevel.Trace,
            new EventId(2132566653, "GetDuration"),
            "GetDuration: DurationInMS = {DurationInMS}");

    static readonly Action<ILogger, int, Exception?> _entityNotFoundAction =
        LoggerMessage.Define<int>(
            LogLevel.Warning,
            new EventId(173845223, "EntityNotFound"),
            "EntityNotFound: EntityId = {EntityId}");

    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    private void GettingEntityFromStore_Logging(int entityId, string serviceUrl)
    {
        if (!_logger.IsEnabled(LogLevel.Information))
            return;
        _gettingEntityFromStoreAction(_logger, entityId, serviceUrl, null);
    }

    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    private void GetDuration_Logging(int durationInMS)
    {
        if (!_logger.IsEnabled(LogLevel.Trace))
            return;
        _getDurationAction(_logger, durationInMS, null);
    }

    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public void EntityNotFound(int entityId)
    {
        if (!_logger.IsEnabled(LogLevel.Warning))
            return;
        _entityNotFoundAction(_logger, entityId, null);
    }
}

Log-only methods ([Warning] void EntityNotFound(...)) are emitted directly as public methods without a private helper.


Metrics Generation

File: EntityStoreTelemetryCore.Metric.g.cs

sealed partial class EntityStoreTelemetryCore : global::IEntityStoreTelemetry
{
    global::System.Diagnostics.Metrics.Meter _meter = default!;
    global::System.Diagnostics.Metrics.Counter<int> _gettingEntityFromStoreInstrument = default!;
    global::System.Diagnostics.Metrics.Histogram<int> _recordEntitySizeInstrument = default!;

    void InitializeMeters(IMeterFactory meterFactory)
    {
        if (_meter != null)
            throw new Exception("The meters have already been initialized.");

        var meterTags = new Dictionary<string, object?>();
        PopulateMeterTags(meterTags);
        _meter = meterFactory.Create(new MeterOptions("SampleApp.APIService")
        {
            Version = null,
            Tags = meterTags
        });

        var counterTags = new Dictionary<string, object?>();
        PopulateGettingEntityFromStoreTags(counterTags);
        _gettingEntityFromStoreInstrument = _meter.CreateCounter<int>(
            "entity_store.getting_entity_from_store", unit: null,
            description: null, tags: counterTags);

        var histTags = new Dictionary<string, object?>();
        PopulateRecordEntitySizeTags(histTags);
        _recordEntitySizeInstrument = _meter.CreateHistogram<int>(
            "entity_store.record_entity_size", unit: null,
            description: null, tags: histTags);
    }

    partial void PopulateMeterTags(Dictionary<string, object?> meterTags);
    partial void PopulateGettingEntityFromStoreTags(Dictionary<string, object?> instrumentTags);
    partial void PopulateRecordEntitySizeTags(Dictionary<string, object?> instrumentTags);

    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    private void GettingEntityFromStore_Metrics(int entityId, string serviceUrl)
    {
        _gettingEntityFromStoreInstrument.Add(1,
            new KeyValuePair<string, object?>("entity_id", entityId),
            new KeyValuePair<string, object?>("service_url", serviceUrl));
    }

    [MethodImpl(MethodImplOptions.AggressiveInlining)]
    public void RecordEntitySize(int sizeInBytes)
    {
        _recordEntitySizeInstrument.Record(sizeInBytes);
    }
}

Metric-only methods ([Histogram] void RecordEntitySize(...)) are emitted as public methods directly. The partial Populate*Tags methods let you add static per-instrument tags at startup.


Multi-Target Orchestration

For multi-target methods, a public method is generated that calls the per-target private helpers:

sealed partial class EntityStoreTelemetryCore : global::IEntityStoreTelemetry
{
    // Multi-target: Activity + Logging + Metrics
    public Activity? GettingEntityFromStore(int entityId, string serviceUrl)
    {
        var activityResult = GettingEntityFromStore_Activity(entityId, serviceUrl);
        GettingEntityFromStore_Logging(entityId, serviceUrl);
        GettingEntityFromStore_Metrics(entityId, serviceUrl);
        return activityResult;
    }

    // Multi-target: ActivityEvent + Logging
    public void GetDuration(Activity? activity, int durationInMS)
    {
        GetDuration_Activity(activity, durationInMS);
        GetDuration_Logging(durationInMS);
    }
}

Dependency Injection

File: EntityStoreTelemetryCoreDIExtension.DependencyInjection.g.cs

namespace Microsoft.Extensions.DependencyInjection
{
    [EditorBrowsable(EditorBrowsableState.Never)]
    [ExcludeFromCodeCoverage]
    [GeneratedCode("Purview.Telemetry.SourceGenerator", "...")]
    static class EntityStoreTelemetryCoreDIExtension
    {
        [MethodImpl(MethodImplOptions.AggressiveInlining)]
        public static IServiceCollection AddEntityStoreTelemetry(
            this IServiceCollection services)
        {
            return services.AddSingleton<global::IEntityStoreTelemetry,
                                         global::EntityStoreTelemetryCore>();
        }
    }
}

Register with:

builder.Services.AddEntityStoreTelemetry();

The generated constructor accepts ILogger<IEntityStoreTelemetry> and IMeterFactory, injected automatically.


TelemetryNames

File: SampleApp.APIService.TelemetryNames.g.cs

A static class listing all ActivitySource and Meter names used by the assembly — useful for OpenTelemetry configuration:

namespace SampleApp.APIService
{
    [EditorBrowsable(EditorBrowsableState.Never)]
    [ExcludeFromCodeCoverage]
    [GeneratedCode("Purview.Telemetry.SourceGenerator", "...")]
    static class TelemetryNames
    {
        public static readonly string[] MeterNames = new string[]
        {
            "SampleApp.APIService"
        };

        public static readonly string[] ActivitySourceNames = new string[]
        {
            "sample-weather-app-api"
        };
    }
}

Use these names when configuring OpenTelemetry exporters:

builder.Services.AddOpenTelemetry()
    .WithTracing(t => {
        foreach (var name in SampleApp.APIService.TelemetryNames.ActivitySourceNames)
            t.AddSource(name);
    })
    .WithMetrics(m => {
        foreach (var name in SampleApp.APIService.TelemetryNames.MeterNames)
            m.AddMeter(name);
    });

Clone this wiki locally