Skip to content

[wip][nomerge] Add Tracing Configuration#126220

Draft
rosebyte wants to merge 4 commits intodotnet:mainfrom
rosebyte:experiment/tracing-configuration
Draft

[wip][nomerge] Add Tracing Configuration#126220
rosebyte wants to merge 4 commits intodotnet:mainfrom
rosebyte:experiment/tracing-configuration

Conversation

@rosebyte
Copy link
Copy Markdown
Member

@rosebyte rosebyte commented Mar 27, 2026

This pull request introduces a new extensibility model for configuring distributed tracing in the Microsoft.Extensions.Diagnostics.Abstractions library. It adds interfaces, options, rules, and extension methods to allow developers to register activity listeners and control which activities are enabled for tracing, with fine-grained rules and scopes.

The most important changes are:

Tracing extensibility model

  • Added the ITracingBuilder interface to provide a builder pattern for configuring tracing and registering IActivityListener implementations via dependency injection. [1] [2]
  • Introduced the IActivityListener interface, which allows custom listeners to receive activity lifecycle callbacks and participate in activity sampling. [1] [2]

Tracing configuration and rules

  • Added the TracingRule class and ActivitySourceScope enum to specify which activities are enabled for which listeners, supporting both global and DI-created activity sources. [1] [2] [3]
  • Introduced the TracingOptions class to hold a list of TracingRule objects, enabling configuration of tracing behavior. [1] [2]

Extension methods for configuration

  • Added TracingBuilderExtensions with methods to add/clear listeners and enable/disable tracing for specific sources, listeners, and scopes, both on the builder and options. [1] [2] [3]

new API surface

namespace Microsoft.Extensions.DependencyInjection
{
    public static class TracingServiceExtensions
    {
        // Adds tracing services to the specified <see cref="IServiceCollection"/>.
        public static ITracingBuilder AddTracing(this IServiceCollection services);

        // Adds tracing services and invokes tracing configuration.
        public static ITracingBuilder AddTracing(this IServiceCollection services, Action<ITracingBuilder> configure);
    }
}

namespace System.Diagnostics
{
    // A factory for creating <see cref="ActivitySource"/> instances.</summary>
    public interface IActivitySourceFactory : IDisposable
    {
        ActivitySource Create(ActivitySourceOptions options);
    }

    public static class ActivitySourceFactoryExtensions
    {
        // Creates an <see cref="ActivitySource"/> with the specified name, version, and tags.
        public static ActivitySource Create(this IActivitySourceFactory activitySourceFactory, string name, string? version = null, IEnumerable<KeyValuePair<string, object?>>? tags = null);
    }

    // Changed from sealed to non-sealed.
    public class ActivitySource : IDisposable
    {
        // Returns the scope object (particularly, the ActivitySourceFactory it was created by).
        public object? Scope { get; }

        // Updates an existing <see cref="ActivityListener"/> registration based on current listener configuration.
        // It lets the listener to accept of deny activity sources to be attached, detached or left unchanged.
        // Currently, there is only AddActivityListener which does undesirable side effects
        public static void UpdateActivityListener(ActivityListener listener);

        // Disposes the current source instance, we cache ActivitySource instances in the factory so we need 
        // this pattern together with unsealed ActivitySource to prevent consumers from premature disposal of them.
        protected virtual void Dispose(bool disposing);
    }

    public class ActivitySourceOptions
    {
        // The optional opaque object to attach to the <see cref="ActivitySource"/> (particularly, the ActivitySourceFactory it was created by).
        public object? Scope { get; set; }
    }
}

namespace Microsoft.Extensions.Diagnostics.Configuration
{
    // A builder to improve discoverability and to prevent polluting IServiceCollection by another batch of extension methods
    public interface ITracingBuilder
    {
        IServiceCollection Services { get; }
    }

    // DI friendly way to define activity listeners
    public interface IActivityListener
    {
        // listener identifier we can reference in configurations
        string Name { get; }

        // sampling is optional so we keep the way from ActivityListener where customers can skip them by returning null
        SampleActivity<string>? SampleUsingParentId { get; }
        SampleActivity<ActivityContext>? Sample { get; }

        // the rest of ActivityListener contract can be implemented as methods for convenience
        void ActivityStarted(Activity activity);
        void ActivityStopped(Activity activity);
        void ActivityExceptionRecorded(Activity activity, Exception exception, ref TagList tags);
    }

    // Represents scopes used by <see cref="TracingRule"/> to distinguish global vs local activity sources.
    [Flags]
    public enum ActivitySourceScope
    {
        // No scope is specified.
        None = 0,

        // ActivitySource instances created via constructors.
        Global,

        // ActivitySource instances created via <see cref="IActivitySourceFactory"/>.
        Local
    }

    // Contains a set of parameters used to determine which activities are enabled for which listeners.
    public class TracingRule
    {
        public TracingRule(string? activitySourceName, string? listenerName, bool enabled);
        public TracingRule(string? activitySourceName, string? listenerName, ActivitySourceScope scopes, bool enabled);

        // Gets the <see cref="ActivitySource.Name"/>, either exact or single-wildcard pattern.
        public string? ActivitySourceName { get; }

        // Gets the <see cref="IActivityListener.Name"/>, exact match.
        public string? ListenerName { get; }

        // Gets the configured scopes.
        public ActivitySourceScope Scopes { get; }

        // Gets whether matched activities are enabled.
        public bool Enabled { get; }
    }

    // Represents options for configuring the tracing system.
    public class TracingOptions
    {
        // Gets the list of activity rules that identifies which activity sources, activities, and listeners are enabled.
        public IList<TracingRule> Rules { get; }
    }

    // Extension methods for configuring tracing listeners and rules.
    public static partial class TracingBuilderExtensions
    {
        // registerd configuration for tracing
        public static ITracingBuilder AddConfiguration(this ITracingBuilder builder, IConfiguration configuration);
        
        // Registers a new listener type.</summary>
        public static ITracingBuilder AddListener<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] T>(this ITracingBuilder builder) where T : class, IActivityListener;

        // Registers a new listener type.</summary>
        public static ITracingBuilder AddListener<T>(this ITracingBuilder builder, Func<IServiceProvider, T> factory) where T : class, IActivityListener;

        // Registers a listener instance.</summary>
        public static ITracingBuilder AddListener(this ITracingBuilder builder, IActivityListener listener);

        // Removes all registered listeners.
        public static ITracingBuilder ClearListeners(this ITracingBuilder builder);

        // Sets activity enablement for a source, listener, and scopes.
        public static ITracingBuilder SetEnabled(this ITracingBuilder builder, bool enabled, string? activitySourceName = null, string? listenerName = null, ActivitySourceScope scopes = ActivitySourceScope.Local);

        // Sets activity enablement in options for a source, listener, and scopes.
        public static TracingOptions SetEnabled(this TracingOptions options, bool enabled, string? activitySourceName = null, string? listenerName = null, ActivitySourceScope scopes = ActivitySourceScope.Local);

        // Enables activities for a source, listener, and scopes.
        public static ITracingBuilder Enable(this ITracingBuilder builder, string? activitySourceName = null, string? listenerName = null, ActivitySourceScope scopes = ActivitySourceScope.Local);

        // Enables activities in options for a source, listener, and scopes.
        public static TracingOptions Enable(this TracingOptions options, string? activitySourceName = null, string? listenerName = null, ActivitySourceScope scopes = ActivitySourceScope.Local);

        // Disables activities for a source, listener, and scopes.
        public static ITracingBuilder Disable(this ITracingBuilder builder, string? activitySourceName = null, string? listenerName = null, ActivitySourceScope scopes = ActivitySourceScope.Local);

        // Disables activities in options for all listeners for a source.
        public static TracingOptions Disable(this TracingOptions options, string? activitySourceName = null, string? listenerName = null, ActivitySourceScope scopes = ActivitySourceScope.Local);
    }
}

@dotnet-policy-service
Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @steveisok, @dotnet/area-system-diagnostics-tracing
See info in area-owners.md if you want to be subscribed.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR introduces a configurable tracing extensibility model spanning System.Diagnostics.DiagnosticSource (ActivitySource updates + factory abstractions) and Microsoft.Extensions.Diagnostics(.Abstractions) (DI builder, options/rules, and configuration binding) to enable/disable tracing per listener/source and support DI-created (scoped) ActivitySources.

Changes:

  • Add IActivitySourceFactory + ActivitySourceOptions.Scope / ActivitySource.Scope to distinguish DI-created vs globally-constructed ActivitySources, and enable factory-managed lifetimes.
  • Add ActivitySource.UpdateActivityListener(...) to allow listeners to re-evaluate ShouldListenTo and update attached sources.
  • Add DI + configuration surface (ITracingBuilder, IActivityListener, TracingOptions/TracingRule, configuration binding + tests) to control tracing enablement via rules and config.

Reviewed changes

Copilot reviewed 24 out of 24 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
src/libraries/System.Diagnostics.DiagnosticSource/tests/ActivitySourceTests.cs Adds coverage for UpdateActivityListener behavior.
src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/IActivitySourceFactory.cs Introduces ActivitySource factory abstraction for DI/scoping.
src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/ActivitySourceOptions.cs Adds Scope to carry an opaque scoping marker into ActivitySource.
src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/ActivitySourceFactoryExtensions.cs Adds convenience Create(...) overload for factories.
src/libraries/System.Diagnostics.DiagnosticSource/src/System/Diagnostics/ActivitySource.cs Makes ActivitySource inheritable, adds Scope, adds UpdateActivityListener, and adds protected Dispose(bool).
src/libraries/System.Diagnostics.DiagnosticSource/src/System.Diagnostics.DiagnosticSource.csproj Includes new DiagnosticSource compile items.
src/libraries/System.Diagnostics.DiagnosticSource/ref/System.Diagnostics.DiagnosticSourceActivity.cs Updates public ref surface for new/changed ActivitySource APIs and new factory types.
src/libraries/Microsoft.Extensions.Diagnostics/tests/TracingConfigurationSampleTests.cs Adds end-to-end tests demonstrating configuration + rule behavior and scope distinctions.
src/libraries/Microsoft.Extensions.Diagnostics/src/Tracing/TracingServiceExtensions.cs Adds AddTracing(...) service registration entrypoints and startup activation.
src/libraries/Microsoft.Extensions.Diagnostics/src/Tracing/DefaultActivitySourceFactory.cs Implements IActivitySourceFactory with caching and rules-driven listener enablement.
src/libraries/Microsoft.Extensions.Diagnostics/src/Tracing/Configuration/TracingConfigureOptions.cs Binds configuration keys into TracingOptions.Rules.
src/libraries/Microsoft.Extensions.Diagnostics/src/Tracing/Configuration/TracingConfiguration.cs Wraps configuration instances for later merging.
src/libraries/Microsoft.Extensions.Diagnostics/src/Tracing/Configuration/TracingBuilderExtensions.cs Adds AddConfiguration(...) for ITracingBuilder.
src/libraries/Microsoft.Extensions.Diagnostics/src/Tracing/Configuration/ActivityListenerConfigurationFactory.cs Merges per-listener configuration from multiple registrations.
src/libraries/Microsoft.Extensions.Diagnostics/ref/Microsoft.Extensions.Diagnostics.cs Adds public ref surface for tracing DI extensions.
src/libraries/Microsoft.Extensions.Diagnostics.Abstractions/tests/TracingBuilderExtensionsRulesTests.cs Unit tests for builder/options rule extension methods.
src/libraries/Microsoft.Extensions.Diagnostics.Abstractions/src/Tracing/TracingRule.cs Defines rule model for enablement matching.
src/libraries/Microsoft.Extensions.Diagnostics.Abstractions/src/Tracing/TracingOptions.cs Adds options container for tracing rules.
src/libraries/Microsoft.Extensions.Diagnostics.Abstractions/src/Tracing/TracingBuilderExtensions.Rules.cs Adds rule authoring helpers on builder/options.
src/libraries/Microsoft.Extensions.Diagnostics.Abstractions/src/Tracing/TracingBuilderExtensions.Listeners.cs Adds listener registration/clearing helpers on builder.
src/libraries/Microsoft.Extensions.Diagnostics.Abstractions/src/Tracing/ITracingBuilder.cs Introduces builder abstraction for tracing configuration.
src/libraries/Microsoft.Extensions.Diagnostics.Abstractions/src/Tracing/IActivityListener.cs Introduces DI-friendly activity listener abstraction.
src/libraries/Microsoft.Extensions.Diagnostics.Abstractions/src/Tracing/ActivitySourceScope.cs Adds scope enum to distinguish global vs DI-created sources.
src/libraries/Microsoft.Extensions.Diagnostics.Abstractions/ref/Microsoft.Extensions.Diagnostics.Abstractions.cs Adds public ref surface for the new abstractions and extension methods.

/// <summary>
/// Update the <see cref="ActivityListener"/> object to start or stop listening to the <see cref="Activity"/> events based on the listener configuration.
/// </summary>
/// <param name="listener"></param>
Copy link

Copilot AI Mar 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The XML docs for UpdateActivityListener have an empty <param name="listener"> element. Please describe what the listener represents (and any expectations, e.g., that it must have ShouldListenTo configured) so the public API docs are complete.

Suggested change
/// <param name="listener"></param>
/// <param name="listener">The <see cref="ActivityListener"/> instance whose configuration, in particular its <see cref="ActivityListener.ShouldListenTo"/> callback, determines which <see cref="ActivitySource"/> instances it should listen to.</param>

Copilot uses AI. Check for mistakes.

protected override void Dispose(bool disposing)
{
// no-op, disallow users from disposing of the meters created from the factory.
Copy link

Copilot AI Mar 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comment appears to be copied from the metrics factory: FactoryActivitySource.Dispose says "meters" but this type represents activity sources. Please update the comment to avoid confusion when debugging/discovering the intent of the override.

Suggested change
// no-op, disallow users from disposing of the meters created from the factory.
// no-op, disallow users from disposing of the activity sources created by the factory.

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants