Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add SocketsHttpHandler connection metrics #88893

Merged
merged 4 commits into from
Jul 14, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/libraries/System.Net.Http/src/System.Net.Http.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,8 @@
<Compile Include="System\Net\Http\SocketsHttpHandler\SystemProxyInfo.cs" />
<Compile Include="System\Net\Http\SocketsHttpHandler\SocksHelper.cs" />
<Compile Include="System\Net\Http\SocketsHttpHandler\SocksException.cs" />
<Compile Include="System\Net\Http\SocketsHttpHandler\Metrics\ConnectionMetricsInfo.cs" />
<Compile Include="System\Net\Http\SocketsHttpHandler\Metrics\SocketsHttpHandlerMetrics.cs" />
<Compile Include="$(CommonPath)System\Net\Security\SslClientAuthenticationOptionsExtensions.cs"
Link="Common\System\Net\Security\SslClientAuthenticationOptionsExtensions.cs" />
<Compile Include="$(CommonPath)System\Net\ExceptionCheck.cs"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -744,7 +744,7 @@ private MetricsHandler SetupHandlerChain()
{
handler = new DiagnosticsHandler(handler, DistributedContextPropagator.Current);
}
MetricsHandler metricsHandler = new MetricsHandler(handler, _meterFactory);
MetricsHandler metricsHandler = new MetricsHandler(handler, _meterFactory, out _);

// Ensure a single handler is used for all requests.
if (Interlocked.CompareExchange(ref _metricsHandler, metricsHandler, null) != null)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ private MetricsHandler Handler
{
handler = new DiagnosticsHandler(handler, DistributedContextPropagator.Current);
}
MetricsHandler metricsHandler = new MetricsHandler(handler, _meterFactory);
MetricsHandler metricsHandler = new MetricsHandler(handler, _meterFactory, out _);

// Ensure a single handler is used for all requests.
if (Interlocked.CompareExchange(ref _metricsHandler, metricsHandler, null) != null)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,11 @@ internal sealed class MetricsHandler : HttpMessageHandlerStage
private readonly Counter<long> _failedRequests;
private readonly Histogram<double> _requestsDuration;

public MetricsHandler(HttpMessageHandler innerHandler, IMeterFactory? meterFactory)
public MetricsHandler(HttpMessageHandler innerHandler, IMeterFactory? meterFactory, out Meter meter)
{
_innerHandler = innerHandler;

Meter meter = meterFactory?.Create("System.Net.Http") ?? SharedMeter.Instance;
meter = meterFactory?.Create("System.Net.Http") ?? SharedMeter.Instance;

// Meter has a cache for the instruments it owns
_currentRequests = meter.CreateUpDownCounter<long>(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,6 @@ internal sealed partial class Http2Connection : HttpConnectionBase
private bool _receivedSettingsAck;
private int _initialServerStreamWindowSize;
private int _pendingWindowUpdate;
private long _idleSinceTickCount;

private uint _maxConcurrentStreams;
private uint _streamsInUse;
Expand Down Expand Up @@ -77,10 +76,6 @@ internal sealed partial class Http2Connection : HttpConnectionBase
// When all requests have completed, the connection will be torn down.
private bool _disposed;

private const int TelemetryStatus_Opened = 1;
private const int TelemetryStatus_Closed = 2;
private int _markedByTelemetryStatus;

private const int MaxStreamId = int.MaxValue;

// Temporary workaround for request burst handling on connection start.
Expand Down Expand Up @@ -138,6 +133,7 @@ internal enum KeepAliveState
private volatile KeepAliveState _keepAliveState;

public Http2Connection(HttpConnectionPool pool, Stream stream)
: base(pool)
{
_pool = pool;
_stream = stream;
Expand All @@ -162,7 +158,6 @@ public Http2Connection(HttpConnectionPool pool, Stream stream)
_streamsInUse = 0;

_pendingWindowUpdate = 0;
_idleSinceTickCount = Environment.TickCount64;

_keepAlivePingDelay = TimeSpanToMs(_pool.Settings._keepAlivePingDelay);
_keepAlivePingTimeout = TimeSpanToMs(_pool.Settings._keepAlivePingTimeout);
Expand All @@ -177,12 +172,6 @@ public Http2Connection(HttpConnectionPool pool, Stream stream)
_maxHeaderListSize = maxHeaderListSize;
}

if (HttpTelemetry.Log.IsEnabled())
{
HttpTelemetry.Log.Http20ConnectionEstablished();
_markedByTelemetryStatus = TelemetryStatus_Opened;
}

if (NetEventSource.Log.IsEnabled()) TraceConnection(_stream);

static long TimeSpanToMs(TimeSpan value)
Expand Down Expand Up @@ -327,6 +316,11 @@ public bool TryReserveStream()

if (_streamsInUse < _maxConcurrentStreams)
{
if (_streamsInUse == 0)
{
MarkConnectionAsNotIdle();
}

_streamsInUse++;
return true;
}
Expand Down Expand Up @@ -356,7 +350,7 @@ public void ReleaseStream()

if (_streamsInUse == 0)
{
_idleSinceTickCount = Environment.TickCount64;
MarkConnectionAsIdle();

if (_disposed)
{
Expand Down Expand Up @@ -1836,7 +1830,7 @@ public override long GetIdleTicks(long nowTicks)
{
lock (SyncObject)
{
return _streamsInUse == 0 ? nowTicks - _idleSinceTickCount : 0;
return _streamsInUse == 0 ? base.GetIdleTicks(nowTicks) : 0;
}
}

Expand Down Expand Up @@ -1894,13 +1888,7 @@ private void FinalTeardown()
// ProcessIncomingFramesAsync and ProcessOutgoingFramesAsync respectively, and those methods are
// responsible for returning the buffers.

if (HttpTelemetry.Log.IsEnabled())
{
if (Interlocked.Exchange(ref _markedByTelemetryStatus, TelemetryStatus_Closed) == TelemetryStatus_Opened)
{
HttpTelemetry.Log.Http20ConnectionClosed();
}
}
MarkConnectionAsClosed();
}

public override void Dispose()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@
using System.Diagnostics;
using System.Globalization;
using System.Net.Http.Headers;
using System.Net.Security;

namespace System.Net.Http
{
Expand All @@ -21,7 +20,6 @@ namespace System.Net.Http
internal sealed class Http3Connection : HttpConnectionBase
{
private readonly HttpConnectionPool _pool;
private readonly HttpAuthority? _origin;
private readonly HttpAuthority _authority;
private readonly byte[]? _altUsedEncodedHeader;
private QuicConnection? _connection;
Expand All @@ -48,10 +46,6 @@ internal sealed class Http3Connection : HttpConnectionBase
// A connection-level error will abort any future operations.
private Exception? _abortException;

private const int TelemetryStatus_Opened = 1;
private const int TelemetryStatus_Closed = 2;
private int _markedByTelemetryStatus;

public HttpAuthority Authority => _authority;
public HttpConnectionPool Pool => _pool;
public uint MaxHeaderListSize => _maxHeaderListSize;
Expand All @@ -71,10 +65,10 @@ private bool ShuttingDown
}
}

public Http3Connection(HttpConnectionPool pool, HttpAuthority? origin, HttpAuthority authority, QuicConnection connection, bool includeAltUsedHeader)
public Http3Connection(HttpConnectionPool pool, HttpAuthority authority, QuicConnection connection, bool includeAltUsedHeader)
: base(pool)
{
_pool = pool;
_origin = origin;
_authority = authority;
_connection = connection;

Expand All @@ -93,12 +87,6 @@ public Http3Connection(HttpConnectionPool pool, HttpAuthority? origin, HttpAutho
_maxHeaderListSize = maxHeaderListSize;
}

if (HttpTelemetry.Log.IsEnabled())
{
HttpTelemetry.Log.Http30ConnectionEstablished();
_markedByTelemetryStatus = TelemetryStatus_Opened;
}

// Errors are observed via Abort().
_ = SendSettingsAsync();

Expand Down Expand Up @@ -168,13 +156,7 @@ private void CheckForShutdown()

}, CancellationToken.None, TaskContinuationOptions.ExecuteSynchronously, TaskScheduler.Default);

if (HttpTelemetry.Log.IsEnabled())
{
if (Interlocked.Exchange(ref _markedByTelemetryStatus, TelemetryStatus_Closed) == TelemetryStatus_Opened)
{
HttpTelemetry.Log.Http30ConnectionClosed();
}
}
MarkConnectionAsClosed();
antonfirsov marked this conversation as resolved.
Show resolved Hide resolved
}
}

Expand All @@ -201,6 +183,11 @@ public async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, lon
requestStream = new Http3RequestStream(request, this, quicStream);
lock (SyncObj)
{
if (_activeRequests.Count == 0)
{
MarkConnectionAsNotIdle();
}

_activeRequests.Add(quicStream, requestStream);
}
}
Expand Down Expand Up @@ -352,11 +339,17 @@ public void RemoveStream(QuicStream stream)
{
lock (SyncObj)
{
bool removed = _activeRequests.Remove(stream);

if (removed && ShuttingDown)
if (_activeRequests.Remove(stream))
{
CheckForShutdown();
if (ShuttingDown)
{
CheckForShutdown();
}

if (_activeRequests.Count == 0)
{
MarkConnectionAsIdle();
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,6 @@ internal sealed partial class HttpConnection : HttpConnectionBase
private ValueTask<int> _readAheadTask;
private ArrayBuffer _readBuffer;

private long _idleSinceTickCount;
private int _keepAliveTimeoutSeconds; // 0 == no timeout
private bool _inUse;
private bool _detachedFromPool;
Expand All @@ -70,13 +69,13 @@ internal sealed partial class HttpConnection : HttpConnectionBase
private bool _connectionClose; // Connection: close was seen on last response

private const int Status_Disposed = 1;
private const int Status_NotDisposedAndTrackedByTelemetry = 2;
private int _disposed;

public HttpConnection(
HttpConnectionPool pool,
Stream stream,
TransportContext? transportContext)
: base(pool)
{
Debug.Assert(pool != null);
Debug.Assert(stream != null);
Expand All @@ -89,14 +88,6 @@ public HttpConnection(
_writeBuffer = new ArrayBuffer(InitialWriteBufferSize, usePool: false);
_readBuffer = new ArrayBuffer(InitialReadBufferSize, usePool: false);

_idleSinceTickCount = Environment.TickCount64;

if (HttpTelemetry.Log.IsEnabled())
{
HttpTelemetry.Log.Http11ConnectionEstablished();
_disposed = Status_NotDisposedAndTrackedByTelemetry;
}

if (NetEventSource.Log.IsEnabled()) TraceConnection(_stream);
}

Expand All @@ -108,16 +99,11 @@ private void Dispose(bool disposing)
{
// Ensure we're only disposed once. Dispose could be called concurrently, for example,
// if the request and the response were running concurrently and both incurred an exception.
int previousValue = Interlocked.Exchange(ref _disposed, Status_Disposed);
if (previousValue != Status_Disposed)
if (Interlocked.Exchange(ref _disposed, Status_Disposed) != Status_Disposed)
{
if (NetEventSource.Log.IsEnabled()) Trace("Connection closing.");

// Only decrement the connection count if we counted this connection
if (HttpTelemetry.Log.IsEnabled() && previousValue == Status_NotDisposedAndTrackedByTelemetry)
{
HttpTelemetry.Log.Http11ConnectionClosed();
}
MarkConnectionAsClosed();

if (!_detachedFromPool)
{
Expand Down Expand Up @@ -270,8 +256,6 @@ private bool CheckKeepAliveTimeoutExceeded()
GetIdleTicks(Environment.TickCount64) >= _keepAliveTimeoutSeconds * 1000;
}

public override long GetIdleTicks(long nowTicks) => nowTicks - _idleSinceTickCount;

public TransportContext? TransportContext => _transportContext;

public HttpConnectionKind Kind => _pool.Kind;
Expand Down Expand Up @@ -517,6 +501,8 @@ public async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, boo
Debug.Assert(_readBuffer.ActiveLength == 0, "Unexpected data in read buffer");
Debug.Assert(_readAheadTaskStatus != ReadAheadTask_Started);

MarkConnectionAsNotIdle();

TaskCompletionSource<bool>? allowExpect100ToContinue = null;
Task? sendRequestContentTask = null;

Expand Down Expand Up @@ -2086,8 +2072,6 @@ private void ReturnConnectionToPool()
{
Debug.Assert(!_detachedFromPool, "Should not be detached from pool unless _connectionClose is true");

_idleSinceTickCount = Environment.TickCount64;

// Put connection back in the pool.
_pool.RecycleHttp11Connection(this);
}
Expand Down
Loading