Skip to content

Commit 52ac681

Browse files
committed
new public interface Microsoft.AspNetCore.Components.IComponentsActivityLinkStore
1 parent 768834e commit 52ac681

File tree

13 files changed

+241
-140
lines changed

13 files changed

+241
-140
lines changed
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
using System.Diagnostics;
5+
6+
namespace Microsoft.AspNetCore.Components;
7+
8+
/// <summary>
9+
/// Helper for storing links between diagnostic activities in Blazor components.
10+
/// </summary>
11+
public interface IComponentsActivityLinkStore
12+
{
13+
/// <summary>
14+
/// Sets the activity context for a specific category.
15+
/// </summary>
16+
/// <param name="category">Category of the trace.</param>
17+
/// <param name="activityLink">Link to the trace.</param>
18+
/// <param name="tag">Optional tag metadata.</param>
19+
void SetActivityContext(int category, ActivityContext activityLink, KeyValuePair<string, object?>? tag);
20+
21+
/// <summary>
22+
/// Will add all activity contexts except the one specified by <paramref name="exceptCategory"/> to the <paramref name="targetActivity"/>.
23+
/// </summary>
24+
/// <param name="exceptCategory">Category of the target trace.</param>
25+
/// <param name="targetActivity">Activity to add links to.</param>
26+
void AddActivityContexts(int exceptCategory, Activity targetActivity);
27+
}
28+
29+
/// <summary>
30+
/// Helper for storing links between diagnostic activities in Blazor components.
31+
/// </summary>
32+
public static class ComponentsActivityCategory
33+
{
34+
/// <summary>
35+
/// Http trace.
36+
/// </summary>
37+
public const int Http = 0;
38+
/// <summary>
39+
/// SignalR trace.
40+
/// </summary>
41+
public const int SignalR = 1;
42+
/// <summary>
43+
/// Route trace.
44+
/// </summary>
45+
public const int Route = 2;
46+
/// <summary>
47+
/// Circuit trace.
48+
/// </summary>
49+
public const int Circuit = 3;
50+
51+
internal const int COUNT = 4;// keep this one bigger than the last linkable category index
52+
53+
/// <summary>
54+
/// Event trace.
55+
/// </summary>
56+
internal const int Event = 5; // not linkable
57+
}
58+
59+
internal class ComponentsActivityLinkStore : IComponentsActivityLinkStore
60+
{
61+
private readonly ActivityContext[] _activityLinks = new ActivityContext[ComponentsActivityCategory.COUNT];
62+
private readonly KeyValuePair<string, object?>?[] _activityTags = new KeyValuePair<string, object?>?[ComponentsActivityCategory.COUNT];
63+
64+
public void SetActivityContext(int category, ActivityContext activityLink, KeyValuePair<string, object?>? tag)
65+
{
66+
_activityLinks[category] = activityLink;
67+
_activityTags[category] = tag;
68+
}
69+
70+
public void AddActivityContexts(int exceptCategory, Activity targetActivity)
71+
{
72+
for (var i = 0; i < ComponentsActivityCategory.COUNT; i++)
73+
{
74+
if (i != exceptCategory)
75+
{
76+
if (_activityLinks[i] != default)
77+
{
78+
targetActivity.AddLink(new ActivityLink(_activityLinks[i]));
79+
}
80+
var tag = _activityTags[i];
81+
if (tag != null)
82+
{
83+
targetActivity.SetTag(tag.Value.Key, tag.Value.Value);
84+
}
85+
}
86+
}
87+
}
88+
}

src/Components/Components/src/ComponentsActivitySource.cs

Lines changed: 46 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,6 @@
55

66
namespace Microsoft.AspNetCore.Components;
77

8-
/// <summary>
9-
/// Named tuple for restoring the previous activity after stopping the current one.
10-
/// </summary>
11-
internal struct ComponentsActivityHandle
12-
{
13-
public Activity? Previous;
14-
public Activity? Activity;
15-
}
16-
178
/// <summary>
189
/// This is instance scoped per renderer
1910
/// </summary>
@@ -23,13 +14,15 @@ internal class ComponentsActivitySource
2314
internal const string OnRouteName = $"{Name}.RouteChange";
2415
internal const string OnEventName = $"{Name}.HandleEvent";
2516

26-
internal ActivityContext _httpActivityContext;
27-
internal ActivityContext _routeContext;
28-
internal ActivityContext _circuitActivityContext;
29-
internal string? _circuitId;
17+
private readonly IComponentsActivityLinkStore _activityLinkStore;
3018

3119
private ActivitySource ActivitySource { get; } = new ActivitySource(Name);
3220

21+
public ComponentsActivitySource(IComponentsActivityLinkStore activityLinkStore)
22+
{
23+
_activityLinkStore = activityLinkStore ?? throw new ArgumentNullException(nameof(activityLinkStore));
24+
}
25+
3326
public ComponentsActivityHandle StartRouteActivity(string componentType, string route)
3427
{
3528
var activity = ActivitySource.CreateActivity(OnRouteName, ActivityKind.Internal, parentId: null, null, null);
@@ -38,10 +31,6 @@ public ComponentsActivityHandle StartRouteActivity(string componentType, string
3831
var previousActivity = Activity.Current;
3932
if (activity.IsAllDataRequested)
4033
{
41-
if (_circuitId != null)
42-
{
43-
activity.SetTag("aspnetcore.components.circuit.id", _circuitId);
44-
}
4534
if (componentType != null)
4635
{
4736
activity.SetTag("aspnetcore.components.type", componentType);
@@ -54,28 +43,32 @@ public ComponentsActivityHandle StartRouteActivity(string componentType, string
5443
{
5544
activity.AddLink(new ActivityLink(previousActivity.Context));
5645
}
46+
47+
// store the link
48+
_activityLinkStore.SetActivityContext(ComponentsActivityCategory.Route, activity.Context,
49+
new KeyValuePair<string, object?>("aspnetcore.components.route", route));
5750
}
5851

5952
activity.DisplayName = $"Route {route ?? "[unknown path]"} -> {componentType ?? "[unknown component]"}";
6053
Activity.Current = null; // do not inherit the parent activity
6154
activity.Start();
62-
_routeContext = activity.Context;
6355
return new ComponentsActivityHandle { Activity = activity, Previous = previousActivity };
6456
}
6557
return default;
6658
}
6759

60+
public void StopRouteActivity(ComponentsActivityHandle activityHandle, Exception? ex)
61+
{
62+
StopComponentActivity(ComponentsActivityCategory.Route, activityHandle, ex);
63+
}
64+
6865
public ComponentsActivityHandle StartEventActivity(string? componentType, string? methodName, string? attributeName)
6966
{
7067
var activity = ActivitySource.CreateActivity(OnEventName, ActivityKind.Internal, parentId: null, null, null);
7168
if (activity is not null)
7269
{
7370
if (activity.IsAllDataRequested)
7471
{
75-
if (_circuitId != null)
76-
{
77-
activity.SetTag("aspnetcore.components.circuit.id", _circuitId);
78-
}
7972
if (componentType != null)
8073
{
8174
activity.SetTag("aspnetcore.components.type", componentType);
@@ -99,35 +92,38 @@ public ComponentsActivityHandle StartEventActivity(string? componentType, string
9992
return default;
10093
}
10194

102-
public void StopComponentActivity(ComponentsActivityHandle activityHandle, Exception? ex)
95+
public void StopEventActivity(ComponentsActivityHandle activityHandle, Exception? ex)
96+
{
97+
StopComponentActivity(ComponentsActivityCategory.Event, activityHandle, ex);
98+
}
99+
100+
public async Task CaptureEventStopAsync(Task task, ComponentsActivityHandle activityHandle)
101+
{
102+
try
103+
{
104+
await task;
105+
StopEventActivity(activityHandle, null);
106+
}
107+
catch (Exception ex)
108+
{
109+
StopEventActivity(activityHandle, ex);
110+
}
111+
}
112+
113+
private void StopComponentActivity(int category, ComponentsActivityHandle activityHandle, Exception? ex)
103114
{
104115
var activity = activityHandle.Activity;
105116
if (activity != null && !activity.IsStopped)
106117
{
107-
if (activity.IsAllDataRequested)
108-
{
109-
if (_circuitId != null)
110-
{
111-
activity.SetTag("aspnetcore.components.circuit.id", _circuitId);
112-
}
113-
if (_httpActivityContext != default)
114-
{
115-
activity.AddLink(new ActivityLink(_httpActivityContext));
116-
}
117-
if (_circuitActivityContext != default)
118-
{
119-
activity.AddLink(new ActivityLink(_circuitActivityContext));
120-
}
121-
if (_routeContext != default && activity.Context != _routeContext)
122-
{
123-
activity.AddLink(new ActivityLink(_routeContext));
124-
}
125-
}
126118
if (ex != null)
127119
{
128120
activity.SetTag("error.type", ex.GetType().FullName);
129121
activity.SetStatus(ActivityStatusCode.Error);
130122
}
123+
if (activity.IsAllDataRequested)
124+
{
125+
_activityLinkStore.AddActivityContexts(category, activity);
126+
}
131127
activity.Stop();
132128

133129
if (Activity.Current == null && activityHandle.Previous != null && !activityHandle.Previous.IsStopped)
@@ -136,17 +132,13 @@ public void StopComponentActivity(ComponentsActivityHandle activityHandle, Excep
136132
}
137133
}
138134
}
135+
}
139136

140-
public async Task CaptureEventStopAsync(Task task, ComponentsActivityHandle activityHandle)
141-
{
142-
try
143-
{
144-
await task;
145-
StopComponentActivity(activityHandle, null);
146-
}
147-
catch (Exception ex)
148-
{
149-
StopComponentActivity(activityHandle, ex);
150-
}
151-
}
137+
/// <summary>
138+
/// Named tuple for restoring the previous activity after stopping the current one.
139+
/// </summary>
140+
internal struct ComponentsActivityHandle
141+
{
142+
public Activity? Previous;
143+
public Activity? Activity;
152144
}

src/Components/Components/src/PublicAPI.Unshipped.txt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,12 @@
11
#nullable enable
2+
Microsoft.AspNetCore.Components.IComponentsActivityLinkStore
3+
Microsoft.AspNetCore.Components.IComponentsActivityLinkStore.AddActivityContexts(int exceptCategory, System.Diagnostics.Activity! targetActivity) -> void
4+
Microsoft.AspNetCore.Components.IComponentsActivityLinkStore.SetActivityContext(int category, System.Diagnostics.ActivityContext activityLink, System.Collections.Generic.KeyValuePair<string!, object?>? tag) -> void
5+
Microsoft.AspNetCore.Components.ComponentsActivityCategory
6+
const Microsoft.AspNetCore.Components.ComponentsActivityCategory.Http = 0 -> int
7+
const Microsoft.AspNetCore.Components.ComponentsActivityCategory.SignalR = 1 -> int
8+
const Microsoft.AspNetCore.Components.ComponentsActivityCategory.Route = 2 -> int
9+
const Microsoft.AspNetCore.Components.ComponentsActivityCategory.Circuit = 3 -> int
210
Microsoft.AspNetCore.Components.Routing.Router.NotFoundPage.get -> System.Type!
311
Microsoft.AspNetCore.Components.Routing.Router.NotFoundPage.set -> void
412
Microsoft.AspNetCore.Components.Infrastructure.ComponentsMetricsServiceCollectionExtensions

src/Components/Components/src/RegisterRenderingMetricsServiceCollectionExtensions.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ public static IServiceCollection AddComponentsTracing(
3939
IServiceCollection services)
4040
{
4141
services.TryAddScoped<ComponentsActivitySource>();
42+
services.TryAddScoped<IComponentsActivityLinkStore, ComponentsActivityLinkStore>();
4243

4344
return services;
4445
}

src/Components/Components/src/RenderTree/Renderer.cs

Lines changed: 1 addition & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -115,18 +115,6 @@ private static IComponentActivator GetComponentActivatorOrDefault(IServiceProvid
115115
?? new DefaultComponentActivator(serviceProvider);
116116
}
117117

118-
internal ActivityContext LinkActivityContexts(ActivityContext httpActivityContext, ActivityContext circuitActivityContext, string? circuitId)
119-
{
120-
if (ComponentActivitySource != null)
121-
{
122-
ComponentActivitySource._httpActivityContext = httpActivityContext;
123-
ComponentActivitySource._circuitActivityContext = circuitActivityContext;
124-
ComponentActivitySource._circuitId = circuitId;
125-
return ComponentActivitySource._routeContext;
126-
}
127-
return default;
128-
}
129-
130118
/// <summary>
131119
/// Gets the <see cref="Components.Dispatcher" /> associated with this <see cref="Renderer" />.
132120
/// </summary>
@@ -538,7 +526,7 @@ public virtual Task DispatchEventAsync(ulong eventHandlerId, EventFieldInfo? fie
538526

539527
if (ComponentActivitySource != null && activityHandle.Activity != null)
540528
{
541-
ComponentActivitySource.StopComponentActivity(activityHandle, e);
529+
ComponentActivitySource.StopEventActivity(activityHandle, e);
542530
}
543531

544532
HandleExceptionViaErrorBoundary(e, receiverComponentState);

src/Components/Components/src/Routing/Router.cs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,7 @@ internal virtual void Refresh(bool isNavigationIntercepted)
240240
endpointRouteData = RouteTable.ProcessParameters(endpointRouteData);
241241
_renderHandle.Render(Found(endpointRouteData));
242242

243-
_renderHandle.ComponentActivitySource?.StopComponentActivity(activityHandle, null);
243+
_renderHandle.ComponentActivitySource?.StopRouteActivity(activityHandle, null);
244244
return;
245245
}
246246

@@ -295,23 +295,23 @@ internal virtual void Refresh(bool isNavigationIntercepted)
295295
NavigationManager.NavigateTo(_locationAbsolute, forceLoad: true);
296296
}
297297
}
298-
_renderHandle.ComponentActivitySource?.StopComponentActivity(activityHandle, null);
298+
_renderHandle.ComponentActivitySource?.StopRouteActivity(activityHandle, null);
299299
}
300300

301301
private ComponentsActivityHandle RecordDiagnostics(string componentType, string template)
302302
{
303-
ComponentsActivityHandle activityWrapper = default;
303+
ComponentsActivityHandle activityHandle = default;
304304
if (_renderHandle.ComponentActivitySource != null)
305305
{
306-
activityWrapper = _renderHandle.ComponentActivitySource.StartRouteActivity(componentType, template);
306+
activityHandle = _renderHandle.ComponentActivitySource.StartRouteActivity(componentType, template);
307307
}
308308

309309
if (_renderHandle.ComponentMetrics != null && _renderHandle.ComponentMetrics.IsNavigationEnabled)
310310
{
311311
_renderHandle.ComponentMetrics.Navigation(componentType, template);
312312
}
313313

314-
return activityWrapper;
314+
return activityHandle;
315315
}
316316

317317
private static void DefaultNotFoundContent(RenderTreeBuilder builder)

0 commit comments

Comments
 (0)