From 88cd5fbabe24947efee1ecbfa3e21d14d2e78a7e Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Wed, 16 Jul 2025 16:05:06 +0200 Subject: [PATCH 1/5] - split aspnetcore.components.render_diff into aspnetcore.components.render_diff.duration and aspnetcore.components.render_diff.size - rename aspnetcore.components.navigation to aspnetcore.components.navigate to match the trace name - rename aspnetcore.components.event_handler to aspnetcore.components.handle_event.duration to match the trace name - rename aspnetcore.components.update_parameters to aspnetcore.components.update_parameters.duration - update unit tests --- .../Components/src/ComponentsMetrics.cs | 40 ++++++----------- .../Components/test/ComponentsMetricsTest.cs | 45 ++++++++++--------- src/Shared/Metrics/MetricsConstants.cs | 3 ++ 3 files changed, 39 insertions(+), 49 deletions(-) diff --git a/src/Components/Components/src/ComponentsMetrics.cs b/src/Components/Components/src/ComponentsMetrics.cs index 712d9e395b4c..684776729ccd 100644 --- a/src/Components/Components/src/ComponentsMetrics.cs +++ b/src/Components/Components/src/ComponentsMetrics.cs @@ -20,6 +20,7 @@ internal sealed class ComponentsMetrics : IDisposable private readonly Histogram _eventDuration; private readonly Histogram _parametersDuration; private readonly Histogram _batchDuration; + private readonly Histogram _batchSize; public bool IsNavigationEnabled => _navigationCount.Enabled; @@ -37,27 +38,33 @@ public ComponentsMetrics(IMeterFactory meterFactory) _lifeCycleMeter = meterFactory.Create(LifecycleMeterName); _navigationCount = _meter.CreateCounter( - "aspnetcore.components.navigation", + "aspnetcore.components.navigate", unit: "{route}", description: "Total number of route changes."); _eventDuration = _meter.CreateHistogram( - "aspnetcore.components.event_handler", + "aspnetcore.components.handle_event.duration", unit: "s", description: "Duration of processing browser event. It includes business logic of the component but not affected child components.", advice: new InstrumentAdvice { HistogramBucketBoundaries = MetricsConstants.ShortSecondsBucketBoundaries }); _parametersDuration = _lifeCycleMeter.CreateHistogram( - "aspnetcore.components.update_parameters", + "aspnetcore.components.update_parameters.duration", unit: "s", description: "Duration of processing component parameters. It includes business logic of the component.", advice: new InstrumentAdvice { HistogramBucketBoundaries = MetricsConstants.BlazorRenderingSecondsBucketBoundaries }); _batchDuration = _lifeCycleMeter.CreateHistogram( - "aspnetcore.components.render_diff", + "aspnetcore.components.render_diff.duration", unit: "s", description: "Duration of rendering component tree and producing HTML diff. It includes business logic of the changed components.", advice: new InstrumentAdvice { HistogramBucketBoundaries = MetricsConstants.BlazorRenderingSecondsBucketBoundaries }); + + _batchSize = _lifeCycleMeter.CreateHistogram( + "aspnetcore.components.render_diff.size", + unit: "{elements}", + description: "Number of HTML elements modified during rendering of batch of changes.", + advice: new InstrumentAdvice { HistogramBucketBoundaries = MetricsConstants.BlazorRenderingDiffLengthBucketBoundaries }); } public void Navigation(string componentType, string route) @@ -137,10 +144,7 @@ public void FailParametersSync(Exception ex, long startTimestamp, string? compon public async Task CaptureBatchDuration(Task task, long startTimestamp, int diffLength) { - var tags = new TagList - { - { "aspnetcore.components.diff.length", BucketDiffLength(diffLength) } - }; + var tags = new TagList(); try { @@ -152,6 +156,7 @@ public async Task CaptureBatchDuration(Task task, long startTimestamp, int diffL } var duration = Stopwatch.GetElapsedTime(startTimestamp); _batchDuration.Record(duration.TotalSeconds, tags); + _batchSize.Record(diffLength); } public void FailBatchSync(Exception ex, long startTimestamp) @@ -159,30 +164,11 @@ public void FailBatchSync(Exception ex, long startTimestamp) var duration = Stopwatch.GetElapsedTime(startTimestamp); var tags = new TagList { - { "aspnetcore.components.diff.length", 0 }, { "error.type", ex.GetType().FullName ?? "unknown" } }; _batchDuration.Record(duration.TotalSeconds, tags); } - private static int BucketDiffLength(int diffLength) - { - return diffLength switch - { - <= 1 => 1, - <= 2 => 2, - <= 5 => 5, - <= 10 => 10, - <= 20 => 20, - <= 50 => 50, - <= 100 => 100, - <= 500 => 500, - <= 1000 => 1000, - <= 10000 => 10000, - _ => 10001, - }; - } - public void Dispose() { _meter.Dispose(); diff --git a/src/Components/Components/test/ComponentsMetricsTest.cs b/src/Components/Components/test/ComponentsMetricsTest.cs index e8b466d5e45d..8293874cab14 100644 --- a/src/Components/Components/test/ComponentsMetricsTest.cs +++ b/src/Components/Components/test/ComponentsMetricsTest.cs @@ -39,7 +39,7 @@ public void Navigation_RecordsMetric() // Arrange var componentsMetrics = new ComponentsMetrics(_meterFactory); using var navigationCounter = new MetricCollector(_meterFactory, - ComponentsMetrics.MeterName, "aspnetcore.components.navigation"); + ComponentsMetrics.MeterName, "aspnetcore.components.navigate"); // Act componentsMetrics.Navigation("TestComponent", "/test-route"); @@ -61,7 +61,7 @@ public void IsNavigationEnabled_ReturnsCorrectState() // Create a collector to ensure the meter is enabled using var navigationCounter = new MetricCollector(_meterFactory, - ComponentsMetrics.MeterName, "aspnetcore.components.navigation"); + ComponentsMetrics.MeterName, "aspnetcore.components.navigate"); // Act & Assert Assert.True(componentsMetrics.IsNavigationEnabled); @@ -73,7 +73,7 @@ public async Task CaptureEventDuration_RecordsSuccessMetric() // Arrange var componentsMetrics = new ComponentsMetrics(_meterFactory); using var eventDurationHistogram = new MetricCollector(_meterFactory, - ComponentsMetrics.MeterName, "aspnetcore.components.event_handler"); + ComponentsMetrics.MeterName, "aspnetcore.components.handle_event.duration"); // Act var startTimestamp = Stopwatch.GetTimestamp(); @@ -98,7 +98,7 @@ public async Task CaptureEventDuration_RecordsErrorMetric() // Arrange var componentsMetrics = new ComponentsMetrics(_meterFactory); using var eventDurationHistogram = new MetricCollector(_meterFactory, - ComponentsMetrics.MeterName, "aspnetcore.components.event_handler"); + ComponentsMetrics.MeterName, "aspnetcore.components.handle_event.duration"); // Act var startTimestamp = Stopwatch.GetTimestamp(); @@ -123,7 +123,7 @@ public void FailEventSync_RecordsErrorMetric() // Arrange var componentsMetrics = new ComponentsMetrics(_meterFactory); using var eventDurationHistogram = new MetricCollector(_meterFactory, - ComponentsMetrics.MeterName, "aspnetcore.components.event_handler"); + ComponentsMetrics.MeterName, "aspnetcore.components.handle_event.duration"); var exception = new InvalidOperationException(); // Act @@ -150,7 +150,7 @@ public void IsEventEnabled_ReturnsCorrectState() // Create a collector to ensure the meter is enabled using var eventDurationHistogram = new MetricCollector(_meterFactory, - ComponentsMetrics.MeterName, "aspnetcore.components.event_handler"); + ComponentsMetrics.MeterName, "aspnetcore.components.handle_event.duration"); // Act & Assert Assert.True(componentsMetrics.IsEventEnabled); @@ -162,7 +162,7 @@ public async Task CaptureParametersDuration_RecordsSuccessMetric() // Arrange var componentsMetrics = new ComponentsMetrics(_meterFactory); using var parametersDurationHistogram = new MetricCollector(_meterFactory, - ComponentsMetrics.LifecycleMeterName, "aspnetcore.components.update_parameters"); + ComponentsMetrics.LifecycleMeterName, "aspnetcore.components.update_parameters.duration"); // Act var startTimestamp = Stopwatch.GetTimestamp(); @@ -184,7 +184,7 @@ public async Task CaptureParametersDuration_RecordsErrorMetric() // Arrange var componentsMetrics = new ComponentsMetrics(_meterFactory); using var parametersDurationHistogram = new MetricCollector(_meterFactory, - ComponentsMetrics.LifecycleMeterName, "aspnetcore.components.update_parameters"); + ComponentsMetrics.LifecycleMeterName, "aspnetcore.components.update_parameters.duration"); // Act var startTimestamp = Stopwatch.GetTimestamp(); @@ -207,7 +207,7 @@ public void FailParametersSync_RecordsErrorMetric() // Arrange var componentsMetrics = new ComponentsMetrics(_meterFactory); using var parametersDurationHistogram = new MetricCollector(_meterFactory, - ComponentsMetrics.LifecycleMeterName, "aspnetcore.components.update_parameters"); + ComponentsMetrics.LifecycleMeterName, "aspnetcore.components.update_parameters.duration"); var exception = new InvalidOperationException(); // Act @@ -231,7 +231,7 @@ public void IsParametersEnabled_ReturnsCorrectState() // Create a collector to ensure the meter is enabled using var parametersDurationHistogram = new MetricCollector(_meterFactory, - ComponentsMetrics.LifecycleMeterName, "aspnetcore.components.update_parameters"); + ComponentsMetrics.LifecycleMeterName, "aspnetcore.components.update_parameters.duration"); // Act & Assert Assert.True(componentsMetrics.IsParametersEnabled); @@ -243,7 +243,7 @@ public async Task CaptureBatchDuration_RecordsSuccessMetric() // Arrange var componentsMetrics = new ComponentsMetrics(_meterFactory); using var batchDurationHistogram = new MetricCollector(_meterFactory, - ComponentsMetrics.LifecycleMeterName, "aspnetcore.components.render_diff"); + ComponentsMetrics.LifecycleMeterName, "aspnetcore.components.render_diff.duration"); // Act var startTimestamp = Stopwatch.GetTimestamp(); @@ -255,7 +255,6 @@ public async Task CaptureBatchDuration_RecordsSuccessMetric() Assert.Single(measurements); Assert.True(measurements[0].Value > 0); - Assert.Equal(50, Assert.Contains("aspnetcore.components.diff.length", measurements[0].Tags)); Assert.DoesNotContain("error.type", measurements[0].Tags); } @@ -265,7 +264,7 @@ public async Task CaptureBatchDuration_RecordsErrorMetric() // Arrange var componentsMetrics = new ComponentsMetrics(_meterFactory); using var batchDurationHistogram = new MetricCollector(_meterFactory, - ComponentsMetrics.LifecycleMeterName, "aspnetcore.components.render_diff"); + ComponentsMetrics.LifecycleMeterName, "aspnetcore.components.render_diff.duration"); // Act var startTimestamp = Stopwatch.GetTimestamp(); @@ -278,7 +277,6 @@ await componentsMetrics.CaptureBatchDuration(Task.FromException(new InvalidOpera Assert.Single(measurements); Assert.True(measurements[0].Value > 0); - Assert.Equal(50, Assert.Contains("aspnetcore.components.diff.length", measurements[0].Tags)); Assert.Equal("System.InvalidOperationException", Assert.Contains("error.type", measurements[0].Tags)); } @@ -288,7 +286,7 @@ public void FailBatchSync_RecordsErrorMetric() // Arrange var componentsMetrics = new ComponentsMetrics(_meterFactory); using var batchDurationHistogram = new MetricCollector(_meterFactory, - ComponentsMetrics.LifecycleMeterName, "aspnetcore.components.render_diff"); + ComponentsMetrics.LifecycleMeterName, "aspnetcore.components.render_diff.duration"); var exception = new InvalidOperationException(); // Act @@ -300,7 +298,6 @@ public void FailBatchSync_RecordsErrorMetric() Assert.Single(measurements); Assert.True(measurements[0].Value > 0); - Assert.Equal(0, Assert.Contains("aspnetcore.components.diff.length", measurements[0].Tags)); Assert.Equal("System.InvalidOperationException", Assert.Contains("error.type", measurements[0].Tags)); } @@ -312,7 +309,7 @@ public void IsBatchEnabled_ReturnsCorrectState() // Create a collector to ensure the meter is enabled using var batchDurationHistogram = new MetricCollector(_meterFactory, - ComponentsMetrics.LifecycleMeterName, "aspnetcore.components.render_diff"); + ComponentsMetrics.LifecycleMeterName, "aspnetcore.components.render_diff.duration"); // Act & Assert Assert.True(componentsMetrics.IsBatchEnabled); @@ -324,13 +321,15 @@ public async Task ComponentLifecycle_RecordsAllMetricsCorrectly() // Arrange var componentsMetrics = new ComponentsMetrics(_meterFactory); using var navigationCounter = new MetricCollector(_meterFactory, - ComponentsMetrics.MeterName, "aspnetcore.components.navigation"); + ComponentsMetrics.MeterName, "aspnetcore.components.navigate"); using var eventDurationHistogram = new MetricCollector(_meterFactory, - ComponentsMetrics.MeterName, "aspnetcore.components.event_handler"); + ComponentsMetrics.MeterName, "aspnetcore.components.handle_event.duration"); using var parametersDurationHistogram = new MetricCollector(_meterFactory, - ComponentsMetrics.LifecycleMeterName, "aspnetcore.components.update_parameters"); + ComponentsMetrics.LifecycleMeterName, "aspnetcore.components.update_parameters.duration"); using var batchDurationHistogram = new MetricCollector(_meterFactory, - ComponentsMetrics.LifecycleMeterName, "aspnetcore.components.render_diff"); + ComponentsMetrics.LifecycleMeterName, "aspnetcore.components.render_diff.duration"); + using var batchSizeHistogram = new MetricCollector(_meterFactory, + ComponentsMetrics.LifecycleMeterName, "aspnetcore.components.render_diff.size"); // Act - Simulate a component lifecycle // 1. Navigation @@ -357,11 +356,13 @@ await componentsMetrics.CaptureEventDuration(Task.CompletedTask, startTimestamp2 var eventMeasurements = eventDurationHistogram.GetMeasurementSnapshot(); var parametersMeasurements = parametersDurationHistogram.GetMeasurementSnapshot(); var batchMeasurements = batchDurationHistogram.GetMeasurementSnapshot(); + var batchSizeMeasurements = batchSizeHistogram.GetMeasurementSnapshot(); Assert.Single(navigationMeasurements); Assert.Single(eventMeasurements); Assert.Single(parametersMeasurements); Assert.Single(batchMeasurements); + Assert.Single(batchSizeMeasurements); // Check navigation Assert.Equal(1, navigationMeasurements[0].Value); @@ -380,7 +381,7 @@ await componentsMetrics.CaptureEventDuration(Task.CompletedTask, startTimestamp2 // Check batch duration Assert.True(batchMeasurements[0].Value > 0); - Assert.Equal(20, Assert.Contains("aspnetcore.components.diff.length", batchMeasurements[0].Tags)); + Assert.True(batchSizeMeasurements[0].Value > 0); } [Fact] diff --git a/src/Shared/Metrics/MetricsConstants.cs b/src/Shared/Metrics/MetricsConstants.cs index cebbaba0e6a9..c4716669458b 100644 --- a/src/Shared/Metrics/MetricsConstants.cs +++ b/src/Shared/Metrics/MetricsConstants.cs @@ -14,6 +14,9 @@ internal static class MetricsConstants // For blazor rendering, which should be very fast. public static readonly IReadOnlyList BlazorRenderingSecondsBucketBoundaries = [0.000001, 0.00001, 0.0001, 0.001, 0.005, 0.01, 0.025, 0.05, 0.075, 0.1, 0.25, 0.5, 0.75, 1, 2.5, 5, 7.5, 10]; + // For blazor rendering, which should be very fast. + public static readonly IReadOnlyList BlazorRenderingDiffLengthBucketBoundaries = [1, 2, 5, 10, 20, 50, 100, 500, 1000, 10000]; + // For blazor circuit sessions, which can last a long time. public static readonly IReadOnlyList BlazorCircuitSecondsBucketBoundaries = [1, 3, 10, 30, 1 * 60, 3 * 60, 10 * 60, 30 * 60, 1 * 60 * 60, 3 * 60 * 60, 10 * 60 * 60, 24 * 60 * 60]; } From 3a9725e1257636247ce1dbad470c103e7997fff9 Mon Sep 17 00:00:00 2001 From: Pavel Savara Date: Thu, 17 Jul 2025 09:41:24 +0200 Subject: [PATCH 2/5] Update src/Components/Components/src/ComponentsMetrics.cs Co-authored-by: James Newton-King --- src/Components/Components/src/ComponentsMetrics.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Components/Components/src/ComponentsMetrics.cs b/src/Components/Components/src/ComponentsMetrics.cs index 684776729ccd..063a559b5cd9 100644 --- a/src/Components/Components/src/ComponentsMetrics.cs +++ b/src/Components/Components/src/ComponentsMetrics.cs @@ -63,7 +63,7 @@ public ComponentsMetrics(IMeterFactory meterFactory) _batchSize = _lifeCycleMeter.CreateHistogram( "aspnetcore.components.render_diff.size", unit: "{elements}", - description: "Number of HTML elements modified during rendering of batch of changes.", + description: "Number of HTML elements modified during a rendering batch.", advice: new InstrumentAdvice { HistogramBucketBoundaries = MetricsConstants.BlazorRenderingDiffLengthBucketBoundaries }); } From 073cce320fc4495cedf17b4e3d4771a15fadc155 Mon Sep 17 00:00:00 2001 From: Pavel Savara Date: Thu, 17 Jul 2025 09:41:34 +0200 Subject: [PATCH 3/5] Update src/Shared/Metrics/MetricsConstants.cs Co-authored-by: James Newton-King --- src/Shared/Metrics/MetricsConstants.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/Shared/Metrics/MetricsConstants.cs b/src/Shared/Metrics/MetricsConstants.cs index c4716669458b..9af080724638 100644 --- a/src/Shared/Metrics/MetricsConstants.cs +++ b/src/Shared/Metrics/MetricsConstants.cs @@ -14,7 +14,6 @@ internal static class MetricsConstants // For blazor rendering, which should be very fast. public static readonly IReadOnlyList BlazorRenderingSecondsBucketBoundaries = [0.000001, 0.00001, 0.0001, 0.001, 0.005, 0.01, 0.025, 0.05, 0.075, 0.1, 0.25, 0.5, 0.75, 1, 2.5, 5, 7.5, 10]; - // For blazor rendering, which should be very fast. public static readonly IReadOnlyList BlazorRenderingDiffLengthBucketBoundaries = [1, 2, 5, 10, 20, 50, 100, 500, 1000, 10000]; // For blazor circuit sessions, which can last a long time. From 771329d99c80f020e2031bb2083b4de099228bdf Mon Sep 17 00:00:00 2001 From: Pavel Savara Date: Thu, 17 Jul 2025 09:42:20 +0200 Subject: [PATCH 4/5] Update src/Components/Components/src/ComponentsMetrics.cs Co-authored-by: James Newton-King --- src/Components/Components/src/ComponentsMetrics.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Components/Components/src/ComponentsMetrics.cs b/src/Components/Components/src/ComponentsMetrics.cs index 063a559b5cd9..089696e301ce 100644 --- a/src/Components/Components/src/ComponentsMetrics.cs +++ b/src/Components/Components/src/ComponentsMetrics.cs @@ -156,7 +156,7 @@ public async Task CaptureBatchDuration(Task task, long startTimestamp, int diffL } var duration = Stopwatch.GetElapsedTime(startTimestamp); _batchDuration.Record(duration.TotalSeconds, tags); - _batchSize.Record(diffLength); + _batchSize.Record(diffLength, tags); } public void FailBatchSync(Exception ex, long startTimestamp) From 83086d34c99192092e58d36ff12823919a233841 Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Thu, 17 Jul 2025 16:44:46 +0200 Subject: [PATCH 5/5] feedback --- src/Shared/Metrics/MetricsConstants.cs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/Shared/Metrics/MetricsConstants.cs b/src/Shared/Metrics/MetricsConstants.cs index 9af080724638..d62983f9bba4 100644 --- a/src/Shared/Metrics/MetricsConstants.cs +++ b/src/Shared/Metrics/MetricsConstants.cs @@ -11,11 +11,12 @@ internal static class MetricsConstants // Not based on a standard. Larger bucket sizes for longer lasting operations, e.g. HTTP connection duration. See https://github.com/open-telemetry/semantic-conventions/issues/336 public static readonly IReadOnlyList LongSecondsBucketBoundaries = [0.01, 0.02, 0.05, 0.1, 0.2, 0.5, 1, 2, 5, 10, 30, 60, 120, 300]; - // For blazor rendering, which should be very fast. + // For Blazor rendering, which should be very fast. public static readonly IReadOnlyList BlazorRenderingSecondsBucketBoundaries = [0.000001, 0.00001, 0.0001, 0.001, 0.005, 0.01, 0.025, 0.05, 0.075, 0.1, 0.25, 0.5, 0.75, 1, 2.5, 5, 7.5, 10]; - public static readonly IReadOnlyList BlazorRenderingDiffLengthBucketBoundaries = [1, 2, 5, 10, 20, 50, 100, 500, 1000, 10000]; + // For measuring the length of HTML diff in Blazor rendering. + public static readonly IReadOnlyList BlazorRenderingDiffLengthBucketBoundaries = [0, 1, 2, 4, 6, 8, 10, 20, 30, 40, 50, 100]; - // For blazor circuit sessions, which can last a long time. + // For Blazor circuit sessions, which can last a long time. public static readonly IReadOnlyList BlazorCircuitSecondsBucketBoundaries = [1, 3, 10, 30, 1 * 60, 3 * 60, 10 * 60, 30 * 60, 1 * 60 * 60, 3 * 60 * 60, 10 * 60 * 60, 24 * 60 * 60]; } pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy