ScopedActivityListener Class

Captures the Activity instances started within the current asynchronous scope.

public sealed class ScopedActivityListener : IDisposable

Remarks

An ActivityListener is global: it observes every activity created in the process. This type registers such a listener but only reports the activities started by the asynchronous flow that created it, using an AsyncLocal<T>. Disposing the instance unregisters the listener.

The membership of an activity is decided when it starts, because an activity is frequently stopped on another thread, where the asynchronous scope is no longer available. As a consequence, the activities that are still running when the listener is disposed are never reported.

The captured activities are live references, not snapshots: their tags, status and duration are only final once they are stopped.

While the listener is registered, ActivitySource.HasListeners returns true for every matching source in the whole process. The libraries that check it, such as HttpClient or ASP.NET Core, switch to their instrumented code path, so HttpClient starts sending the traceparent header for the requests made inside the scope. Use ScopedActivityListenerOptions.SourceNames to reduce the number of matching sources.

Example

using var source = new ActivitySource("Sample.ScopedActivityListener");
using var listener = new ScopedActivityListener(new() { SourceNames = ["Sample.ScopedActivityListener"] });

// Code that starts activities, such as a call to an instrumented library
using (source.StartActivity("DoWork"))
{
    await Task.Delay(10);
}

var activity = Assert.Single(listener.Activities);
Assert.Equal("DoWork", activity.OperationName);
Assert.True(activity.Duration > TimeSpan.Zero);
Implements

Constructors

NameDescription
ScopedActivityListener()Initializes a new instance of the ScopedActivityListener class listening to every ActivitySource.
ScopedActivityListener(ScopedActivityListenerOptions?)Initializes a new instance of the ScopedActivityListener class.

ScopedActivityListener overloads

ScopedActivityListener()

ScopedActivityListener.cs

Initializes a new instance of the ScopedActivityListener class listening to every ActivitySource.

public ScopedActivityListener()

ScopedActivityListener(ScopedActivityListenerOptions?)

ScopedActivityListener.cs

Initializes a new instance of the ScopedActivityListener class.

public ScopedActivityListener(ScopedActivityListenerOptions? options)
Parameters
options ScopedActivityListenerOptions?
The options of the listener, or null to use the default options.

Properties

NameDescription
ActivitiesGets the activities captured so far, in completion order. The collection is safe to enumerate while new activities are captured.

Gets the activities captured so far, in completion order. The collection is safe to enumerate while new activities are captured.

public IReadOnlyCollection<Activity> Activities { get; }

Methods

NameDescription
Dispose()Unregisters the listener and completes the enumerations started by ScopedActivityListener.GetActivitiesAsync.
GetActivitiesAsync(CancellationToken)Streams the activities of the scope as they complete.

Unregisters the listener and completes the enumerations started by ScopedActivityListener.GetActivitiesAsync.

public void Dispose()

GetActivitiesAsync(CancellationToken)

ScopedActivityListener.cs

Streams the activities of the scope as they complete.

public IAsyncEnumerable<Activity> GetActivitiesAsync(CancellationToken cancellationToken = default)

Parameters

cancellationToken CancellationToken
A token to stop the enumeration.

Returns

IAsyncEnumerable<Activity> The activities already captured, followed by the activities completing afterwards. The enumeration ends when the listener is disposed. Multiple enumerations can run concurrently, and each of them reports every activity.

Events

NameDescription
ActivityStartedOccurs when an activity of the scope starts. The event is raised synchronously on the thread starting the activity, so its tags, status and duration are not set yet. The exceptions thrown by the handlers are ignored to avoid breaking the observed code.
ActivityStoppedOccurs when an activity of the scope stops. The event is raised synchronously on the thread stopping the activity. The exceptions thrown by the handlers are ignored to avoid breaking the observed code.

ActivityStarted

Occurs when an activity of the scope starts. The event is raised synchronously on the thread starting the activity, so its tags, status and duration are not set yet. The exceptions thrown by the handlers are ignored to avoid breaking the observed code.

public event EventHandler<ActivityEventArgs>? ActivityStarted

ActivityStopped

Occurs when an activity of the scope stops. The event is raised synchronously on the thread stopping the activity. The exceptions thrown by the handlers are ignored to avoid breaking the observed code.

public event EventHandler<ActivityEventArgs>? ActivityStopped