File: Circuits\CircuitActivitySource.cs
Web Access
Project: src\src\Components\Server\src\Microsoft.AspNetCore.Components.Server.csproj (Microsoft.AspNetCore.Components.Server)
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
 
using System.Diagnostics;
using Microsoft.AspNetCore.Components.Infrastructure.Server;
 
internal class CircuitActivitySource
{
    internal const string Name = "Microsoft.AspNetCore.Components.Server.Circuits";
    internal const string OnCircuitName = $"{Name}.CircuitStart";
 
    private ComponentsActivityLinkStore? _activityLinkStore;
 
    private ActivitySource ActivitySource { get; } = new ActivitySource(Name);
 
    public void Init(ComponentsActivityLinkStore store)
    {
        _activityLinkStore = store;
    }
 
    public CircuitActivityHandle StartCircuitActivity(string circuitId, ActivityContext httpActivityContext)
    {
        var activity = ActivitySource.CreateActivity(OnCircuitName, ActivityKind.Internal, parentId: null, null, null);
        if (activity is not null)
        {
            var signalRActivity = Activity.Current;
            activity.DisplayName = $"Circuit {circuitId ?? ""}";
            Activity.Current = null; // do not inherit the parent activity
            activity.Start();
 
            if (activity.IsAllDataRequested)
            {
                if (circuitId != null)
                {
                    activity.SetTag("aspnetcore.components.circuit.id", circuitId);
 
                    // store self link
                    _activityLinkStore.SetActivityContext(ComponentsActivityLinkStore.Circuit, activity.Context,
                        new KeyValuePair<string, object?>("aspnetcore.components.circuit.id", circuitId));
                }
                if (httpActivityContext != default)
                {
                    // store the http link
                    _activityLinkStore.SetActivityContext(ComponentsActivityLinkStore.Http, httpActivityContext, null);
                }
                if (signalRActivity != null && signalRActivity.Source.Name == "Microsoft.AspNetCore.SignalR.Server")
                {
                    // store the SignalR link
                    _activityLinkStore.SetActivityContext(ComponentsActivityLinkStore.SignalR, signalRActivity.Context, null);
                }
            }
            return new CircuitActivityHandle { Previous = signalRActivity, Activity = activity };
        }
        return default;
    }
 
    public void StopCircuitActivity(CircuitActivityHandle activityHandle, Exception? ex)
    {
        var activity = activityHandle.Activity;
        if (activity != null && !activity.IsStopped)
        {
            if (ex != null)
            {
                activity.SetTag("error.type", ex.GetType().FullName);
                activity.SetStatus(ActivityStatusCode.Error);
            }
            if (activity.IsAllDataRequested)
            {
                _activityLinkStore.AddActivityContexts(ComponentsActivityLinkStore.Circuit, activity);
            }
            activityHandle.Activity.Stop();
 
            if (Activity.Current == null && activityHandle.Previous != null && !activityHandle.Previous.IsStopped)
            {
                Activity.Current = activityHandle.Previous;
            }
        }
    }
}
 
/// <summary>
/// Named tuple for restoring the previous activity after stopping the current one.
/// </summary>
internal struct CircuitActivityHandle
{
    public Activity? Previous;
    public Activity? Activity;
}