Skip to content

Commit

Permalink
Add flag on metrics feature to disable metrics per request
Browse files Browse the repository at this point in the history
  • Loading branch information
JamesNK committed Jun 27, 2024
1 parent 8a6e8d7 commit 40dabd3
Show file tree
Hide file tree
Showing 8 changed files with 76 additions and 5 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -154,12 +154,12 @@ public void RequestEnd(HttpContext httpContext, Exception? exception, HostingApp

if (context.MetricsEnabled)
{
Debug.Assert(context.MetricsTagsFeature != null, "MetricsTagsFeature should be set if MetricsEnabled is true.");

var endpoint = HttpExtensions.GetOriginalEndpoint(httpContext);
var disableHttpRequestDurationMetric = endpoint?.Metadata.GetMetadata<IDisableHttpMetricsMetadata>() != null;
var disableHttpRequestDurationMetric = endpoint?.Metadata.GetMetadata<IDisableHttpMetricsMetadata>() != null || context.MetricsTagsFeature.MetricsDisabled;
var route = endpoint?.Metadata.GetMetadata<IRouteDiagnosticsMetadata>()?.Route;

Debug.Assert(context.MetricsTagsFeature != null, "MetricsTagsFeature should be set if MetricsEnabled is true.");

_metrics.RequestEnd(
context.MetricsTagsFeature.Protocol!,
context.MetricsTagsFeature.Scheme!,
Expand Down
2 changes: 2 additions & 0 deletions src/Hosting/Hosting/src/Internal/HttpMetricsTagsFeature.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ namespace Microsoft.AspNetCore.Hosting;
internal sealed class HttpMetricsTagsFeature : IHttpMetricsTagsFeature
{
ICollection<KeyValuePair<string, object?>> IHttpMetricsTagsFeature.Tags => TagsList;
public bool MetricsDisabled { get; set; }

public List<KeyValuePair<string, object?>> TagsList { get; } = new List<KeyValuePair<string, object?>>();

Expand All @@ -20,6 +21,7 @@ internal sealed class HttpMetricsTagsFeature : IHttpMetricsTagsFeature
public void Reset()
{
TagsList.Clear();
MetricsDisabled = false;

Method = null;
Scheme = null;
Expand Down
58 changes: 57 additions & 1 deletion src/Hosting/Hosting/test/HostingApplicationDiagnosticsTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -295,7 +295,7 @@ public void Metrics_Route_RouteTagReported()
}

[Fact]
public void Metrics_DisableHttpMetrics_NoMetrics()
public void Metrics_DisableHttpMetricsWithMetadata_NoMetrics()
{
// Arrange
var hostingEventSource = new HostingEventSource(Guid.NewGuid().ToString());
Expand Down Expand Up @@ -349,6 +349,62 @@ public void Metrics_DisableHttpMetrics_NoMetrics()
Assert.Empty(requestDurationCollector.GetMeasurementSnapshot());
}

[Fact]
public void Metrics_DisableHttpMetricsWithFeature_NoMetrics()
{
// Arrange
var hostingEventSource = new HostingEventSource(Guid.NewGuid().ToString());

var testMeterFactory = new TestMeterFactory();
using var activeRequestsCollector = new MetricCollector<long>(testMeterFactory, HostingMetrics.MeterName, "http.server.active_requests");
using var requestDurationCollector = new MetricCollector<double>(testMeterFactory, HostingMetrics.MeterName, "http.server.request.duration");

// Act
var hostingApplication = CreateApplication(out var features, eventSource: hostingEventSource, meterFactory: testMeterFactory, configure: c =>
{
c.Request.Protocol = "1.1";
c.Request.Scheme = "http";
c.Request.Method = "POST";
c.Request.Host = new HostString("localhost");
c.Request.Path = "/hello";
c.Request.ContentType = "text/plain";
c.Request.ContentLength = 1024;
});
var context = hostingApplication.CreateContext(features);

Assert.Collection(activeRequestsCollector.GetMeasurementSnapshot(),
m =>
{
Assert.Equal(1, m.Value);
Assert.Equal("http", m.Tags["url.scheme"]);
Assert.Equal("POST", m.Tags["http.request.method"]);
});

context.HttpContext.Features.Get<IHttpMetricsTagsFeature>().MetricsDisabled = true;

// Assert 1
Assert.True(context.MetricsTagsFeature.MetricsDisabled);

hostingApplication.DisposeContext(context, null);

// Assert 2
Assert.Collection(activeRequestsCollector.GetMeasurementSnapshot(),
m =>
{
Assert.Equal(1, m.Value);
Assert.Equal("http", m.Tags["url.scheme"]);
Assert.Equal("POST", m.Tags["http.request.method"]);
},
m =>
{
Assert.Equal(-1, m.Value);
Assert.Equal("http", m.Tags["url.scheme"]);
Assert.Equal("POST", m.Tags["http.request.method"]);
});
Assert.Empty(requestDurationCollector.GetMeasurementSnapshot());
Assert.False(context.MetricsTagsFeature.MetricsDisabled);
}

private sealed class TestRouteDiagnosticsMetadata : IRouteDiagnosticsMetadata
{
public string Route { get; } = "hello/{name}";
Expand Down
1 change: 1 addition & 0 deletions src/Hosting/Hosting/test/HostingMetricsTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,7 @@ public void IHttpMetricsTagsFeatureNotUsedFromFeatureCollection()
private sealed class TestHttpMetricsTagsFeature : IHttpMetricsTagsFeature
{
public ICollection<KeyValuePair<string, object>> Tags { get; } = new Collection<KeyValuePair<string, object>>();
public bool MetricsDisabled { get; set; }
}

private static HostingApplication CreateApplication(IHttpContextFactory httpContextFactory = null, bool useHttpContextAccessor = false,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@

namespace Microsoft.AspNetCore.Http.Metadata;

/// <summary>
/// A marker interface which can be used to identify metadata that disables HTTP request duration metrics.
/// </summary>
public interface IDisableHttpMetricsMetadata
{
}
1 change: 1 addition & 0 deletions src/Http/Http.Abstractions/src/PublicAPI.Unshipped.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@
Microsoft.AspNetCore.Http.HostString.HostString(string? value) -> void
*REMOVED*Microsoft.AspNetCore.Http.HostString.Value.get -> string!
Microsoft.AspNetCore.Http.HostString.Value.get -> string?
Microsoft.AspNetCore.Http.Metadata.IDisableHttpMetricsMetadata
8 changes: 7 additions & 1 deletion src/Http/Http.Features/src/IHttpMetricsTagsFeature.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,18 @@
namespace Microsoft.AspNetCore.Http.Features;

/// <summary>
/// Provides access to tags added to the metrics HTTP request counter. This feature isn't set if the counter isn't enabled.
/// Provides access to tags added to the metrics HTTP request duration counter. This feature isn't set if the counter isn't enabled.
/// </summary>
public interface IHttpMetricsTagsFeature
{
/// <summary>
/// Gets the tag collection.
/// </summary>
ICollection<KeyValuePair<string, object?>> Tags { get; }

// MetricsDisabled was added after the initial release of this interface and is intentionally a DIM property.
/// <summary>
/// Gets or sets a flag that disables recording HTTP request duration counter for the current HTTP request.
/// </summary>
public bool MetricsDisabled { get; set; }
}
2 changes: 2 additions & 0 deletions src/Http/Http.Features/src/PublicAPI.Unshipped.txt
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
#nullable enable
Microsoft.AspNetCore.Http.Features.IHttpMetricsTagsFeature.MetricsDisabled.get -> bool
Microsoft.AspNetCore.Http.Features.IHttpMetricsTagsFeature.MetricsDisabled.set -> void

0 comments on commit 40dabd3

Please sign in to comment.