Skip to content

Commit 3903c40

Browse files
committed
work in progress
1 parent 047246c commit 3903c40

File tree

13 files changed

+279
-208
lines changed

13 files changed

+279
-208
lines changed

src/Components/Components/src/ComponentsActivitySource.cs

Lines changed: 36 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -5,76 +5,31 @@
55

66
namespace Microsoft.AspNetCore.Components;
77

8+
internal struct ComponentsActivityWrapper
9+
{
10+
public Activity? Previous;
11+
public Activity? Activity;
12+
}
13+
814
/// <summary>
915
/// This is instance scoped per renderer
1016
/// </summary>
1117
internal class ComponentsActivitySource
1218
{
1319
internal const string Name = "Microsoft.AspNetCore.Components";
14-
internal const string OnCircuitName = $"{Name}.CircuitStart";
1520
internal const string OnRouteName = $"{Name}.RouteChange";
1621
internal const string OnEventName = $"{Name}.HandleEvent";
1722

18-
private ActivityContext _httpContext;
19-
private ActivityContext _circuitContext;
20-
private string? _circuitId;
23+
internal ActivityContext _httpContext;
24+
internal ActivityContext _circuitContext;
25+
internal string? _circuitId;
26+
2127
private ActivityContext _routeContext;
2228

2329
private ActivitySource ActivitySource { get; } = new ActivitySource(Name);
2430

25-
public static ActivityContext CaptureHttpContext()
26-
{
27-
var parentActivity = Activity.Current;
28-
if (parentActivity is not null && parentActivity.OperationName == "Microsoft.AspNetCore.Hosting.HttpRequestIn" && parentActivity.Recorded)
29-
{
30-
return parentActivity.Context;
31-
}
32-
return default;
33-
}
34-
35-
public Activity? StartCircuitActivity(string circuitId, ActivityContext httpContext)
36-
{
37-
_circuitId = circuitId;
38-
39-
var activity = ActivitySource.CreateActivity(OnCircuitName, ActivityKind.Internal, parentId: null, null, null);
40-
if (activity is not null)
41-
{
42-
if (activity.IsAllDataRequested)
43-
{
44-
if (_circuitId != null)
45-
{
46-
activity.SetTag("aspnetcore.components.circuit.id", _circuitId);
47-
}
48-
if (httpContext != default)
49-
{
50-
activity.AddLink(new ActivityLink(httpContext));
51-
}
52-
}
53-
activity.DisplayName = $"Circuit {circuitId ?? ""}";
54-
activity.Start();
55-
_circuitContext = activity.Context;
56-
}
57-
return activity;
58-
}
59-
60-
public void FailCircuitActivity(Activity? activity, Exception ex)
61-
{
62-
_circuitContext = default;
63-
if (activity != null && !activity.IsStopped)
64-
{
65-
activity.SetTag("error.type", ex.GetType().FullName);
66-
activity.SetStatus(ActivityStatusCode.Error);
67-
activity.Stop();
68-
}
69-
}
70-
71-
public Activity? StartRouteActivity(string componentType, string route)
31+
public ComponentsActivityWrapper StartRouteActivity(string componentType, string route)
7232
{
73-
if (_httpContext == default)
74-
{
75-
_httpContext = CaptureHttpContext();
76-
}
77-
7833
var activity = ActivitySource.CreateActivity(OnRouteName, ActivityKind.Internal, parentId: null, null, null);
7934
if (activity is not null)
8035
{
@@ -103,13 +58,16 @@ public void FailCircuitActivity(Activity? activity, Exception ex)
10358
}
10459

10560
activity.DisplayName = $"Route {route ?? "[unknown path]"} -> {componentType ?? "[unknown component]"}";
61+
var previousActivity = Activity.Current;
62+
Activity.Current = null; // do not inherit the parent activity
10663
activity.Start();
10764
_routeContext = activity.Context;
65+
return new ComponentsActivityWrapper { Activity = activity, Previous = previousActivity };
10866
}
109-
return activity;
67+
return default;
11068
}
11169

112-
public Activity? StartEventActivity(string? componentType, string? methodName, string? attributeName)
70+
public ComponentsActivityWrapper StartEventActivity(string? componentType, string? methodName, string? attributeName)
11371
{
11472
var activity = ActivitySource.CreateActivity(OnEventName, ActivityKind.Internal, parentId: null, null, null);
11573
if (activity is not null)
@@ -147,31 +105,42 @@ public void FailCircuitActivity(Activity? activity, Exception ex)
147105
}
148106

149107
activity.DisplayName = $"Event {attributeName ?? "[unknown attribute]"} -> {componentType ?? "[unknown component]"}.{methodName ?? "[unknown method]"}";
108+
var previousActivity = Activity.Current;
109+
Activity.Current = null; // do not inherit the parent activity
150110
activity.Start();
111+
return new ComponentsActivityWrapper { Activity = activity, Previous = previousActivity };
151112
}
152-
return activity;
113+
return default;
153114
}
154115

155-
public static void FailEventActivity(Activity? activity, Exception ex)
116+
public static void StopComponentActivity(ComponentsActivityWrapper wrapper, Exception? ex)
156117
{
157-
if (activity != null && !activity.IsStopped)
118+
if (wrapper.Activity != null && !wrapper.Activity.IsStopped)
158119
{
159-
activity.SetTag("error.type", ex.GetType().FullName);
160-
activity.SetStatus(ActivityStatusCode.Error);
161-
activity.Stop();
120+
if (ex != null)
121+
{
122+
wrapper.Activity.SetTag("error.type", ex.GetType().FullName);
123+
wrapper.Activity.SetStatus(ActivityStatusCode.Error);
124+
}
125+
wrapper.Activity.Stop();
126+
127+
if (Activity.Current == null && wrapper.Previous != null && !wrapper.Previous.IsStopped)
128+
{
129+
Activity.Current = wrapper.Previous;
130+
}
162131
}
163132
}
164133

165-
public static async Task CaptureEventStopAsync(Task task, Activity? activity)
134+
public static async Task CaptureEventStopAsync(Task task, ComponentsActivityWrapper wrapper)
166135
{
167136
try
168137
{
169138
await task;
170-
activity?.Stop();
139+
StopComponentActivity(wrapper, null);
171140
}
172141
catch (Exception ex)
173142
{
174-
FailEventActivity(activity, ex);
143+
StopComponentActivity(wrapper, ex);
175144
}
176145
}
177146
}

src/Components/Components/src/Microsoft.AspNetCore.Components.csproj

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,6 @@
7979

8080
<ItemGroup>
8181
<InternalsVisibleTo Include="Microsoft.AspNetCore.Components.Web" />
82-
<InternalsVisibleTo Include="Microsoft.AspNetCore.Components.Server" />
8382
<InternalsVisibleTo Include="Microsoft.AspNetCore.Blazor.Build.Tests" />
8483
<InternalsVisibleTo Include="Microsoft.AspNetCore.Components.Authorization.Tests" />
8584
<InternalsVisibleTo Include="Microsoft.AspNetCore.Components.Forms.Tests" />

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

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,6 @@ public Renderer(IServiceProvider serviceProvider, ILoggerFactory loggerFactory,
9696
_componentFactory = new ComponentFactory(componentActivator, this);
9797
_componentsMetrics = serviceProvider.GetService<ComponentsMetrics>();
9898
_componentsActivitySource = serviceProvider.GetService<ComponentsActivitySource>();
99-
10099
ServiceProviderCascadingValueSuppliers = serviceProvider.GetService<ICascadingValueSupplier>() is null
101100
? Array.Empty<ICascadingValueSupplier>()
102101
: serviceProvider.GetServices<ICascadingValueSupplier>().ToArray();
@@ -115,6 +114,16 @@ private static IComponentActivator GetComponentActivatorOrDefault(IServiceProvid
115114
?? new DefaultComponentActivator(serviceProvider);
116115
}
117116

117+
internal void SetCircuitActivityContext(ActivityContext httpContext, ActivityContext circuitContext, string circuitId)
118+
{
119+
if (ComponentActivitySource != null)
120+
{
121+
ComponentActivitySource._httpContext = httpContext;
122+
ComponentActivitySource._circuitContext = circuitContext;
123+
ComponentActivitySource._circuitId = circuitId;
124+
}
125+
}
126+
118127
/// <summary>
119128
/// Gets the <see cref="Components.Dispatcher" /> associated with this <see cref="Renderer" />.
120129
/// </summary>
@@ -448,14 +457,14 @@ public virtual Task DispatchEventAsync(ulong eventHandlerId, EventFieldInfo? fie
448457
var (renderedByComponentId, callback, attributeName) = GetRequiredEventBindingEntry(eventHandlerId);
449458

450459
// collect trace
451-
Activity? activity = null;
460+
ComponentsActivityWrapper wrapper = default;
452461
string receiverName = null;
453462
string methodName = null;
454463
if (ComponentActivitySource != null)
455464
{
456465
receiverName ??= (callback.Receiver?.GetType() ?? callback.Delegate.Target?.GetType())?.FullName;
457466
methodName ??= callback.Delegate.Method?.Name;
458-
activity = ComponentActivitySource.StartEventActivity(receiverName, methodName, attributeName);
467+
wrapper = ComponentActivitySource.StartEventActivity(receiverName, methodName, attributeName);
459468
}
460469

461470
var eventStartTimestamp = ComponentMetrics != null && ComponentMetrics.IsEventEnabled ? Stopwatch.GetTimestamp() : 0;
@@ -506,13 +515,13 @@ public virtual Task DispatchEventAsync(ulong eventHandlerId, EventFieldInfo? fie
506515
{
507516
receiverName ??= (callback.Receiver?.GetType() ?? callback.Delegate.Target?.GetType())?.FullName;
508517
methodName ??= callback.Delegate.Method?.Name;
509-
_ = ComponentMetrics.CaptureEventDuration(task, eventStartTimestamp, receiverName, methodName, attributeName);
518+
_ = ComponentMetrics.CaptureEventDuration(task, eventStartTimestamp, null, null, attributeName);
510519
}
511520

512521
// stop activity/trace
513-
if (ComponentActivitySource != null && activity != null)
522+
if (ComponentActivitySource != null && wrapper.Activity != null)
514523
{
515-
_ = ComponentsActivitySource.CaptureEventStopAsync(task, activity);
524+
_ = ComponentsActivitySource.CaptureEventStopAsync(task, wrapper);
516525
}
517526
}
518527
catch (Exception e)
@@ -521,12 +530,12 @@ public virtual Task DispatchEventAsync(ulong eventHandlerId, EventFieldInfo? fie
521530
{
522531
receiverName ??= (callback.Receiver?.GetType() ?? callback.Delegate.Target?.GetType())?.FullName;
523532
methodName ??= callback.Delegate.Method?.Name;
524-
ComponentMetrics.FailEventSync(e, eventStartTimestamp, receiverName, methodName, attributeName);
533+
ComponentMetrics.FailEventSync(e, eventStartTimestamp, null, null, attributeName);
525534
}
526535

527-
if (ComponentActivitySource != null && activity != null)
536+
if (ComponentActivitySource != null && wrapper.Activity != null)
528537
{
529-
ComponentsActivitySource.FailEventActivity(activity, e);
538+
ComponentsActivitySource.StopComponentActivity(wrapper, e);
530539
}
531540

532541
HandleExceptionViaErrorBoundary(e, receiverComponentState);

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

Lines changed: 11 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -223,12 +223,12 @@ internal virtual void Refresh(bool isNavigationIntercepted)
223223
var relativePath = NavigationManager.ToBaseRelativePath(_locationAbsolute.AsSpan());
224224
var locationPathSpan = TrimQueryOrHash(relativePath);
225225
var locationPath = $"/{locationPathSpan}";
226-
Activity? activity;
226+
ComponentsActivityWrapper activityWrapper;
227227

228228
// In order to avoid routing twice we check for RouteData
229229
if (RoutingStateProvider?.RouteData is { } endpointRouteData)
230230
{
231-
activity = RecordDiagnostics(endpointRouteData.PageType.FullName, endpointRouteData.Template);
231+
activityWrapper = RecordDiagnostics(endpointRouteData.PageType.FullName, endpointRouteData.Template);
232232

233233
// Other routers shouldn't provide RouteData, this is specific to our router component
234234
// and must abide by our syntax and behaviors.
@@ -241,7 +241,7 @@ internal virtual void Refresh(bool isNavigationIntercepted)
241241
endpointRouteData = RouteTable.ProcessParameters(endpointRouteData);
242242
_renderHandle.Render(Found(endpointRouteData));
243243

244-
activity?.Stop();
244+
ComponentsActivitySource.StopComponentActivity(activityWrapper, null);
245245
return;
246246
}
247247

@@ -258,7 +258,7 @@ internal virtual void Refresh(bool isNavigationIntercepted)
258258
$"does not implement {typeof(IComponent).FullName}.");
259259
}
260260

261-
activity = RecordDiagnostics(context.Handler.FullName, context.Entry.RoutePattern.RawText);
261+
activityWrapper = RecordDiagnostics(context.Handler.FullName, context.Entry.RoutePattern.RawText);
262262

263263
Log.NavigatingToComponent(_logger, context.Handler, locationPath, _baseUri);
264264

@@ -279,7 +279,7 @@ internal virtual void Refresh(bool isNavigationIntercepted)
279279
{
280280
if (!isNavigationIntercepted)
281281
{
282-
activity = RecordDiagnostics("NotFound", "NotFound");
282+
activityWrapper = RecordDiagnostics("NotFound", "NotFound");
283283

284284
Log.DisplayingNotFound(_logger, locationPath, _baseUri);
285285

@@ -290,30 +290,29 @@ internal virtual void Refresh(bool isNavigationIntercepted)
290290
}
291291
else
292292
{
293-
activity = RecordDiagnostics("External", "External");
293+
activityWrapper = RecordDiagnostics("External", "External");
294294

295295
Log.NavigatingToExternalUri(_logger, _locationAbsolute, locationPath, _baseUri);
296296
NavigationManager.NavigateTo(_locationAbsolute, forceLoad: true);
297297
}
298298
}
299-
activity?.Stop();
300-
299+
ComponentsActivitySource.StopComponentActivity(activityWrapper, null);
301300
}
302301

303-
private Activity? RecordDiagnostics(string componentType, string template)
302+
private ComponentsActivityWrapper RecordDiagnostics(string componentType, string template)
304303
{
305-
Activity? activity = null;
304+
ComponentsActivityWrapper activityWrapper = default;
306305
if (_renderHandle.ComponentActivitySource != null)
307306
{
308-
activity = _renderHandle.ComponentActivitySource.StartRouteActivity(componentType, template);
307+
activityWrapper = _renderHandle.ComponentActivitySource.StartRouteActivity(componentType, template);
309308
}
310309

311310
if (_renderHandle.ComponentMetrics != null && _renderHandle.ComponentMetrics.IsNavigationEnabled)
312311
{
313312
_renderHandle.ComponentMetrics.Navigation(componentType, template);
314313
}
315314

316-
return activity;
315+
return activityWrapper;
317316
}
318317

319318
private static void DefaultNotFoundContent(RenderTreeBuilder builder)

0 commit comments

Comments
 (0)