Skip to content

[HTTP] High cardinality metrics to observable#131275

Open
ManickaP wants to merge 5 commits into
dotnet:mainfrom
ManickaP:http-metrics-observable
Open

[HTTP] High cardinality metrics to observable#131275
ManickaP wants to merge 5 commits into
dotnet:mainfrom
ManickaP:http-metrics-observable

Conversation

@ManickaP

@ManickaP ManickaP commented Jul 23, 2026

Copy link
Copy Markdown
Member

The open_connections and active_requests up down counters both use peer address in their tags and suffer from accumulation of data at the monitoring side. This PR changes them to their observable counterpart that counts the values and reports them only when asked.

This does not solve the underlying issue, this just somewhat mitigates the biggest pain points for customers. Eventually, this change should be reverted when the issue is solved on OpenTelemtry side, see open-telemetry/semantic-conventions#3279.

Unintentianal side effect is that if someone is directly using MeterListener this change will be breaking for them. They also need to start using RecordObservableInstruments to get the values now, see changes in our metrics tests.

Fixes #122752

@azure-pipelines

Copy link
Copy Markdown
Azure Pipelines:
Successfully started running 4 pipeline(s).
12 pipeline(s) were filtered out due to trigger conditions.
There may be pipelines that require an authorized user to comment /azp run to run.

@dotnet-policy-service

Copy link
Copy Markdown
Contributor

Tagging subscribers to this area: @karelz, @dotnet/ncl
See info in area-owners.md if you want to be subscribed.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates System.Net.Http client metrics to mitigate high-cardinality tag fallout by switching http.client.open_connections and http.client.active_requests from UpDownCounter<long> (event-based adds) to ObservableUpDownCounter<long> (snapshot reporting via callbacks).

Changes:

  • Introduces per-tag-combination trackers (ConcurrentDictionary<..., long>) to compute current counts and feed observable instruments.
  • Updates MetricsHandler and SocketsHttpHandler connection metrics to increment/decrement the trackers instead of calling Add(...).
  • Adjusts System.Net.Http metrics functional tests to explicitly call MeterListener.RecordObservableInstruments() and to validate snapshot-style observations.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 3 comments.

File Description
src/libraries/System.Net.Http/tests/FunctionalTests/MetricsTest.cs Updates tests to collect observable instrument values and adapts expectations to snapshot semantics.
src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Metrics/SocketsHttpHandlerMetrics.cs Converts open_connections to an observable counter and adds a tracker + tag key infrastructure.
src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Metrics/ConnectionMetrics.cs Routes connection open/close/idle transitions through the new open-connections tracker.
src/libraries/System.Net.Http/src/System/Net/Http/Metrics/MetricsHandler.cs Converts active_requests to an observable counter backed by an active-requests tracker keyed by request tags.

Port = port;
IsIdle = isIdle;
PeerAddress = peerAddress;
_hashCode = HashCode.Combine(protocolVersion, scheme, host, port, isIdle);
Comment on lines +4 to +8
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.Metrics;
using System.Threading;
Comment on lines +306 to +314
var requestTask = SendAsync(client, request);
await serverTcs.Task.WaitAsync(TestHelper.PassingTestTimeout);
recorder.RecordObservableInstruments();
clientTcs.SetResult();
var response = await requestTask;
response.Dispose(); // Make sure disposal doesn't interfere with recording by enforcing early disposal.

Assert.Collection(recorder.GetMeasurements(),
m => VerifyActiveRequests(m, 1, uri),
m => VerifyActiveRequests(m, -1, uri));
m => VerifyActiveRequests(m, 1, uri));
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Many dimensions with http.client.open_connections

2 participants