Skip to content

Commit 0f3d48a

Browse files
committed
navigation draft
1 parent 4c75495 commit 0f3d48a

File tree

12 files changed

+279
-188
lines changed

12 files changed

+279
-188
lines changed
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
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+
/// This is instance scoped per renderer
10+
/// </summary>
11+
internal class ComponentsActivitySource
12+
{
13+
internal const string Name = "Microsoft.AspNetCore.Components";
14+
internal const string OnEventName = $"{Name}.OnEvent";
15+
internal const string OnNavigationName = $"{Name}.OnNavigation";
16+
17+
public static ActivitySource ActivitySource { get; } = new ActivitySource(Name);
18+
19+
private Activity? _routeActivity;
20+
21+
public void StartRouteActivity(string componentType, string route)
22+
{
23+
StopRouteActivity();
24+
25+
IEnumerable<KeyValuePair<string, object?>> tags =
26+
[
27+
new("component.type", componentType ?? "unknown"),
28+
new("route", route ?? "unknown"),
29+
];
30+
var parentActivity = Activity.Current;
31+
IEnumerable<ActivityLink>? links = parentActivity is not null ? [new ActivityLink(parentActivity.Context)] : null;
32+
33+
var activity = ActivitySource.CreateActivity(OnEventName, ActivityKind.Server, parentId: null, tags, links);
34+
if (activity is not null)
35+
{
36+
activity.DisplayName = $"NAVIGATE {route ?? "unknown"} -> {componentType ?? "unknown"}";
37+
activity.Start();
38+
_routeActivity = activity;
39+
}
40+
}
41+
42+
public void StopRouteActivity()
43+
{
44+
if (_routeActivity != null)
45+
{
46+
_routeActivity.Stop();
47+
_routeActivity = null;
48+
return;
49+
}
50+
}
51+
52+
public Activity? StartEventActivity(string? componentType, string? methodName, string? attributeName)
53+
{
54+
IEnumerable<KeyValuePair<string, object?>> tags =
55+
[
56+
new("component.type", componentType ?? "unknown"),
57+
new("component.method", methodName ?? "unknown"),
58+
new("attribute.name", attributeName ?? "unknown"),
59+
];
60+
List<ActivityLink>? links = new List<ActivityLink>();
61+
var parentActivity = Activity.Current;
62+
if (parentActivity is not null)
63+
{
64+
links.Add(new ActivityLink(parentActivity.Context));
65+
}
66+
if (_routeActivity is not null)
67+
{
68+
links.Add(new ActivityLink(_routeActivity.Context));
69+
}
70+
71+
var activity = ActivitySource.CreateActivity(OnEventName, ActivityKind.Server, parentId: null, tags, links);
72+
if (activity is not null)
73+
{
74+
activity.DisplayName = $"EVENT {attributeName ?? "unknown"} -> {componentType ?? "unknown"}.{methodName ?? "unknown"}";
75+
activity.Start();
76+
}
77+
return activity;
78+
}
79+
80+
public static void FailEventActivity(Activity activity, Exception ex)
81+
{
82+
if (!activity.IsStopped)
83+
{
84+
activity.SetTag("error.type", ex.GetType().FullName);
85+
activity.SetStatus(ActivityStatusCode.Error);
86+
activity.Stop();
87+
}
88+
}
89+
90+
public static async Task CaptureEventStopAsync(Task task, Activity activity)
91+
{
92+
try
93+
{
94+
await task;
95+
activity.Stop();
96+
}
97+
catch (Exception ex)
98+
{
99+
FailEventActivity(activity, ex);
100+
}
101+
}
102+
}

src/Components/Components/src/Rendering/RenderingMetrics.cs renamed to src/Components/Components/src/ComponentsMetrics.cs

Lines changed: 31 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,18 @@
33

44
using System.Diagnostics;
55
using System.Diagnostics.Metrics;
6+
using Microsoft.AspNetCore.Components;
67
using Microsoft.AspNetCore.Http;
78

8-
namespace Microsoft.AspNetCore.Components.Rendering;
9+
namespace Microsoft.AspNetCore.Components;
910

10-
internal sealed class RenderingMetrics : IDisposable
11+
internal sealed class ComponentsMetrics : IDisposable
1112
{
12-
public const string MeterName = "Microsoft.AspNetCore.Components.Rendering";
13+
public const string MeterName = "Microsoft.AspNetCore.Components";
1314
private readonly Meter _meter;
1415

16+
private readonly Counter<long> _navigationCount;
17+
1518
private readonly Histogram<double> _eventSyncDuration;
1619
private readonly Histogram<double> _eventAsyncDuration;
1720
private readonly Counter<long> _eventException;
@@ -25,6 +28,8 @@ internal sealed class RenderingMetrics : IDisposable
2528
private readonly Histogram<double> _batchDuration;
2629
private readonly Counter<long> _batchException;
2730

31+
public bool IsNavigationEnabled => _navigationCount.Enabled;
32+
2833
public bool IsEventDurationEnabled => _eventSyncDuration.Enabled || _eventAsyncDuration.Enabled;
2934
public bool IsEventExceptionEnabled => _eventException.Enabled;
3035

@@ -36,43 +41,48 @@ internal sealed class RenderingMetrics : IDisposable
3641
public bool IsBatchDurationEnabled => _batchDuration.Enabled;
3742
public bool IsBatchExceptionEnabled => _batchException.Enabled;
3843

39-
public RenderingMetrics(IMeterFactory meterFactory)
44+
public ComponentsMetrics(IMeterFactory meterFactory)
4045
{
4146
Debug.Assert(meterFactory != null);
4247

4348
_meter = meterFactory.Create(MeterName);
4449

50+
_navigationCount = _meter.CreateCounter<long>(
51+
"aspnetcore.components.navigation.count",
52+
unit: "{exceptions}",
53+
description: "Total number of route changes.");
54+
4555
_eventSyncDuration = _meter.CreateHistogram(
46-
"aspnetcore.components.rendering.event.synchronous.duration",
56+
"aspnetcore.components.event.synchronous.duration",
4757
unit: "s",
4858
description: "Duration of processing browser event synchronously.",
4959
advice: new InstrumentAdvice<double> { HistogramBucketBoundaries = MetricsConstants.ShortSecondsBucketBoundaries });
5060

5161
_eventAsyncDuration = _meter.CreateHistogram(
52-
"aspnetcore.components.rendering.event.asynchronous.duration",
62+
"aspnetcore.components.event.asynchronous.duration",
5363
unit: "s",
5464
description: "Duration of processing browser event asynchronously.",
5565
advice: new InstrumentAdvice<double> { HistogramBucketBoundaries = MetricsConstants.ShortSecondsBucketBoundaries });
5666

5767
_eventException = _meter.CreateCounter<long>(
58-
"aspnetcore.components.rendering.event.exception",
68+
"aspnetcore.components.event.exception",
5969
unit: "{exceptions}",
6070
description: "Total number of exceptions during browser event processing.");
6171

6272
_parametersSyncDuration = _meter.CreateHistogram(
63-
"aspnetcore.components.rendering.parameters.synchronous.duration",
73+
"aspnetcore.components.parameters.synchronous.duration",
6474
unit: "s",
6575
description: "Duration of processing component parameters synchronously.",
6676
advice: new InstrumentAdvice<double> { HistogramBucketBoundaries = MetricsConstants.ShortSecondsBucketBoundaries });
6777

6878
_parametersAsyncDuration = _meter.CreateHistogram(
69-
"aspnetcore.components.rendering.parameters.asynchronous.duration",
79+
"aspnetcore.components.parameters.asynchronous.duration",
7080
unit: "s",
7181
description: "Duration of processing component parameters asynchronously.",
7282
advice: new InstrumentAdvice<double> { HistogramBucketBoundaries = MetricsConstants.ShortSecondsBucketBoundaries });
7383

7484
_parametersException = _meter.CreateCounter<long>(
75-
"aspnetcore.components.rendering.parameters.exception",
85+
"aspnetcore.components.parameters.exception",
7686
unit: "{exceptions}",
7787
description: "Total number of exceptions during processing component parameters.");
7888

@@ -94,6 +104,17 @@ public RenderingMetrics(IMeterFactory meterFactory)
94104
description: "Total number of exceptions during batch rendering.");
95105
}
96106

107+
public void Navigation(string componentType, string route)
108+
{
109+
var tags = new TagList
110+
{
111+
{ "component.type", componentType ?? "unknown" },
112+
{ "route", route ?? "unknown" },
113+
};
114+
115+
_navigationCount.Add(1, tags);
116+
}
117+
97118
public void EventDurationSync(long startTimestamp, string? componentType, string? methodName, string? attributeName)
98119
{
99120
var tags = new TagList

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
#nullable enable
22
Microsoft.AspNetCore.Components.Routing.Router.NotFoundPage.get -> System.Type!
33
Microsoft.AspNetCore.Components.Routing.Router.NotFoundPage.set -> void
4-
Microsoft.AspNetCore.Components.Infrastructure.RenderingMetricsServiceCollectionExtensions
4+
Microsoft.AspNetCore.Components.Infrastructure.ComponentsMetricsServiceCollectionExtensions
55
Microsoft.AspNetCore.Components.NavigationManager.OnNotFound -> System.EventHandler<Microsoft.AspNetCore.Components.Routing.NotFoundEventArgs!>!
66
Microsoft.AspNetCore.Components.NavigationManager.NotFound() -> void
77
Microsoft.AspNetCore.Components.Routing.IHostEnvironmentNavigationManager.Initialize(string! baseUri, string! uri, System.Func<string!, System.Threading.Tasks.Task!>! onNavigateTo) -> void
@@ -14,7 +14,7 @@ Microsoft.AspNetCore.Components.SupplyParameterFromPersistentComponentStateAttri
1414
Microsoft.AspNetCore.Components.SupplyParameterFromPersistentComponentStateAttribute.SupplyParameterFromPersistentComponentStateAttribute() -> void
1515
Microsoft.Extensions.DependencyInjection.SupplyParameterFromPersistentComponentStateProviderServiceCollectionExtensions
1616
static Microsoft.AspNetCore.Components.Infrastructure.RegisterPersistentComponentStateServiceCollectionExtensions.AddPersistentServiceRegistration<TService>(Microsoft.Extensions.DependencyInjection.IServiceCollection! services, Microsoft.AspNetCore.Components.IComponentRenderMode! componentRenderMode) -> Microsoft.Extensions.DependencyInjection.IServiceCollection!
17-
static Microsoft.AspNetCore.Components.Infrastructure.RenderingMetricsServiceCollectionExtensions.AddRenderingMetrics(Microsoft.Extensions.DependencyInjection.IServiceCollection! services) -> Microsoft.Extensions.DependencyInjection.IServiceCollection!
18-
static Microsoft.AspNetCore.Components.Infrastructure.RenderingMetricsServiceCollectionExtensions.AddRenderingTracing(Microsoft.Extensions.DependencyInjection.IServiceCollection! services) -> Microsoft.Extensions.DependencyInjection.IServiceCollection!
17+
static Microsoft.AspNetCore.Components.Infrastructure.ComponentsMetricsServiceCollectionExtensions.AddComponentsMetrics(Microsoft.Extensions.DependencyInjection.IServiceCollection! services) -> Microsoft.Extensions.DependencyInjection.IServiceCollection!
18+
static Microsoft.AspNetCore.Components.Infrastructure.ComponentsMetricsServiceCollectionExtensions.AddComponentsTracing(Microsoft.Extensions.DependencyInjection.IServiceCollection! services) -> Microsoft.Extensions.DependencyInjection.IServiceCollection!
1919
static Microsoft.Extensions.DependencyInjection.SupplyParameterFromPersistentComponentStateProviderServiceCollectionExtensions.AddSupplyValueFromPersistentComponentStateProvider(this Microsoft.Extensions.DependencyInjection.IServiceCollection! services) -> Microsoft.Extensions.DependencyInjection.IServiceCollection!
2020
virtual Microsoft.AspNetCore.Components.RenderTree.Renderer.SignalRendererToFinishRendering() -> void

src/Components/Components/src/RegisterRenderingMetricsServiceCollectionExtensions.cs

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
// The .NET Foundation licenses this file to you under the MIT license.
33

44
using System.Diagnostics.Metrics;
5-
using Microsoft.AspNetCore.Components.Rendering;
65
using Microsoft.Extensions.DependencyInjection;
76
using Microsoft.Extensions.DependencyInjection.Extensions;
87

@@ -11,22 +10,22 @@ namespace Microsoft.AspNetCore.Components.Infrastructure;
1110
/// <summary>
1211
/// Infrastructure APIs for registering diagnostic metrics.
1312
/// </summary>
14-
public static class RenderingMetricsServiceCollectionExtensions
13+
public static class ComponentsMetricsServiceCollectionExtensions
1514
{
1615
/// <summary>
1716
/// Registers component rendering metrics
1817
/// </summary>
1918
/// <param name="services">The <see cref="IServiceCollection"/>.</param>
2019
/// <returns>The <see cref="IServiceCollection"/>.</returns>
21-
public static IServiceCollection AddRenderingMetrics(
20+
public static IServiceCollection AddComponentsMetrics(
2221
IServiceCollection services)
2322
{
2423
// do not register IConfigureOptions<StartupValidatorOptions> multiple times
2524
if (!IsMeterFactoryRegistered(services))
2625
{
2726
services.AddMetrics();
2827
}
29-
services.TryAddSingleton<RenderingMetrics>();
28+
services.TryAddSingleton<ComponentsMetrics>();
3029

3130
return services;
3231
}
@@ -36,10 +35,10 @@ public static IServiceCollection AddRenderingMetrics(
3635
/// </summary>
3736
/// <param name="services">The <see cref="IServiceCollection"/>.</param>
3837
/// <returns>The <see cref="IServiceCollection"/>.</returns>
39-
public static IServiceCollection AddRenderingTracing(
38+
public static IServiceCollection AddComponentsTracing(
4039
IServiceCollection services)
4140
{
42-
services.TryAddSingleton<RenderingActivitySource>();
41+
services.TryAddScoped<ComponentsActivitySource>();
4342

4443
return services;
4544
}

src/Components/Components/src/RenderHandle.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ internal RenderHandle(Renderer renderer, int componentId)
2121
_componentId = componentId;
2222
}
2323

24+
internal ComponentsMetrics? ComponentMetrics => _renderer?.ComponentMetrics;
25+
internal ComponentsActivitySource? ComponentActivitySource => _renderer?.ComponentActivitySource;
26+
2427
/// <summary>
2528
/// Gets the <see cref="Components.Dispatcher" /> associated with the component.
2629
/// </summary>

0 commit comments

Comments
 (0)