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

Extend SocketsHttpHandler Connection and Request telemetry #88853

Merged
merged 17 commits into from
Jul 18, 2023
Merged
Show file tree
Hide file tree
Changes from 7 commits
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
114 changes: 94 additions & 20 deletions src/libraries/System.Net.Http/src/System/Net/Http/HttpTelemetry.cs
Original file line number Diff line number Diff line change
Expand Up @@ -90,16 +90,23 @@ private void RequestFailed(string exceptionMessage)
WriteEvent(eventId: 3, exceptionMessage);
}

[NonEvent]
private void ConnectionEstablished(byte versionMajor, byte versionMinor, long connectionId, Uri uri, IPEndPoint? remoteEndPoint)
{
string? remoteAddress = remoteEndPoint?.Address?.ToString();
ConnectionEstablished(versionMajor, versionMinor, connectionId, uri.Scheme, uri.Host, uri.Port, remoteAddress);
}

[Event(4, Level = EventLevel.Informational)]
private void ConnectionEstablished(byte versionMajor, byte versionMinor)
private void ConnectionEstablished(byte versionMajor, byte versionMinor, long connectionId, string scheme, string host, int port, string? remoteAddress)
{
WriteEvent(eventId: 4, versionMajor, versionMinor);
WriteEvent(eventId: 4, versionMajor, versionMinor, connectionId, scheme, host, port, remoteAddress);
}

[Event(5, Level = EventLevel.Informational)]
private void ConnectionClosed(byte versionMajor, byte versionMinor)
private void ConnectionClosed(byte versionMajor, byte versionMinor, long connectionId)
{
WriteEvent(eventId: 5, versionMajor, versionMinor);
WriteEvent(eventId: 5, versionMajor, versionMinor, connectionId);
}

[Event(6, Level = EventLevel.Informational)]
Expand All @@ -109,9 +116,9 @@ private void RequestLeftQueue(double timeOnQueueMilliseconds, byte versionMajor,
}

[Event(7, Level = EventLevel.Informational)]
public void RequestHeadersStart()
public void RequestHeadersStart(long connectionId)
{
WriteEvent(eventId: 7);
WriteEvent(eventId: 7, connectionId);
}

[Event(8, Level = EventLevel.Informational)]
Expand Down Expand Up @@ -162,49 +169,55 @@ private void RequestFailedDetailed(string exception)
WriteEvent(eventId: 15, exception);
}

[Event(16, Level = EventLevel.Informational)]
public void Redirect(string redirectUri)
{
WriteEvent(eventId: 16, redirectUri);
}

[NonEvent]
public void Http11ConnectionEstablished()
public void Http11ConnectionEstablished(long connectionId, Uri uri, IPEndPoint? remoteEndPoint)
{
Interlocked.Increment(ref _openedHttp11Connections);
ConnectionEstablished(versionMajor: 1, versionMinor: 1);
ConnectionEstablished(versionMajor: 1, versionMinor: 1, connectionId, uri, remoteEndPoint);
}

[NonEvent]
public void Http11ConnectionClosed()
public void Http11ConnectionClosed(long connectionId)
{
long count = Interlocked.Decrement(ref _openedHttp11Connections);
Debug.Assert(count >= 0);
ConnectionClosed(versionMajor: 1, versionMinor: 1);
ConnectionClosed(versionMajor: 1, versionMinor: 1, connectionId);
}

[NonEvent]
public void Http20ConnectionEstablished()
public void Http20ConnectionEstablished(long connectionId, Uri uri, IPEndPoint? remoteEndPoint)
{
Interlocked.Increment(ref _openedHttp20Connections);
ConnectionEstablished(versionMajor: 2, versionMinor: 0);
ConnectionEstablished(versionMajor: 2, versionMinor: 0, connectionId, uri, remoteEndPoint);
}

[NonEvent]
public void Http20ConnectionClosed()
public void Http20ConnectionClosed(long connectionId)
{
long count = Interlocked.Decrement(ref _openedHttp20Connections);
Debug.Assert(count >= 0);
ConnectionClosed(versionMajor: 2, versionMinor: 0);
ConnectionClosed(versionMajor: 2, versionMinor: 0, connectionId);
}

[NonEvent]
public void Http30ConnectionEstablished()
public void Http30ConnectionEstablished(long connectionId, Uri uri, IPEndPoint? remoteEndPoint)
{
Interlocked.Increment(ref _openedHttp30Connections);
ConnectionEstablished(versionMajor: 3, versionMinor: 0);
ConnectionEstablished(versionMajor: 3, versionMinor: 0, connectionId, uri, remoteEndPoint);
}

[NonEvent]
public void Http30ConnectionClosed()
public void Http30ConnectionClosed(long connectionId)
{
long count = Interlocked.Decrement(ref _openedHttp30Connections);
Debug.Assert(count >= 0);
ConnectionClosed(versionMajor: 3, versionMinor: 0);
ConnectionClosed(versionMajor: 3, versionMinor: 0, connectionId);
}

[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode",
Expand Down Expand Up @@ -293,9 +306,9 @@ private unsafe void WriteEvent(int eventId, double arg1, byte arg2, byte arg3)
[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode",
Justification = "Parameters to this method are primitive and are trimmer safe")]
[NonEvent]
private unsafe void WriteEvent(int eventId, byte arg1, byte arg2)
private unsafe void WriteEvent(int eventId, byte arg1, byte arg2, long arg3)
{
const int NumEventDatas = 2;
const int NumEventDatas = 3;
EventData* descrs = stackalloc EventData[NumEventDatas];

descrs[0] = new EventData
Expand All @@ -308,6 +321,67 @@ private unsafe void WriteEvent(int eventId, byte arg1, byte arg2)
DataPointer = (IntPtr)(&arg2),
Size = sizeof(byte)
};
descrs[2] = new EventData
{
DataPointer = (IntPtr)(&arg3),
Size = sizeof(long)
};

WriteEventCore(eventId, NumEventDatas, descrs);
}

[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode",
Justification = "Parameters to this method are primitive and are trimmer safe")]
[NonEvent]
private unsafe void WriteEvent(int eventId, byte arg1, byte arg2, long arg3, string? arg4, string arg5, int arg6, string? arg7)
{
arg4 ??= "";
arg5 ??= "";
arg7 ??= "";

const int NumEventDatas = 7;
EventData* descrs = stackalloc EventData[NumEventDatas];

fixed (char* arg4Ptr = arg4)
fixed (char* arg5Ptr = arg5)
fixed (char* arg7Ptr = arg7)
{
descrs[0] = new EventData
{
DataPointer = (IntPtr)(&arg1),
Size = sizeof(byte)
};
descrs[1] = new EventData
{
DataPointer = (IntPtr)(&arg2),
Size = sizeof(byte)
};
descrs[2] = new EventData
{
DataPointer = (IntPtr)(&arg3),
Size = sizeof(long)
};
descrs[3] = new EventData
{
DataPointer = (IntPtr)arg4Ptr,
Size = (arg4.Length + 1) * sizeof(char)
};
descrs[4] = new EventData
{
DataPointer = (IntPtr)arg5Ptr,
Size = (arg5.Length + 1) * sizeof(char)
};
descrs[5] = new EventData
{
DataPointer = (IntPtr)(&arg6),
Size = sizeof(int)
};
descrs[6] = new EventData
{
DataPointer = (IntPtr)arg7Ptr,
Size = (arg7.Length + 1) * sizeof(char)
};
}

WriteEventCore(eventId, NumEventDatas, descrs);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ internal enum KeepAliveState
private long _keepAlivePingTimeoutTimestamp;
private volatile KeepAliveState _keepAliveState;

public Http2Connection(HttpConnectionPool pool, Stream stream)
public Http2Connection(HttpConnectionPool pool, Stream stream, Uri requestUri, IPEndPoint? remoteEndPoint)
{
_pool = pool;
_stream = stream;
Expand Down Expand Up @@ -179,7 +179,7 @@ public Http2Connection(HttpConnectionPool pool, Stream stream)

if (HttpTelemetry.Log.IsEnabled())
{
HttpTelemetry.Log.Http20ConnectionEstablished();
HttpTelemetry.Log.Http20ConnectionEstablished(Id, requestUri, remoteEndPoint);
_markedByTelemetryStatus = TelemetryStatus_Opened;
}

Expand Down Expand Up @@ -1662,7 +1662,7 @@ private async ValueTask<Http2Stream> SendHeadersAsync(HttpRequestMessage request
ArrayBuffer headerBuffer = default;
try
{
if (HttpTelemetry.Log.IsEnabled()) HttpTelemetry.Log.RequestHeadersStart();
if (HttpTelemetry.Log.IsEnabled()) HttpTelemetry.Log.RequestHeadersStart(Id);

// Serialize headers to a temporary buffer, and do as much work to prepare to send the headers as we can
// before taking the write lock.
Expand Down Expand Up @@ -1898,7 +1898,7 @@ private void FinalTeardown()
{
if (Interlocked.Exchange(ref _markedByTelemetryStatus, TelemetryStatus_Closed) == TelemetryStatus_Opened)
{
HttpTelemetry.Log.Http20ConnectionClosed();
HttpTelemetry.Log.Http20ConnectionClosed(Id);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ private bool ShuttingDown
}
}

public Http3Connection(HttpConnectionPool pool, HttpAuthority? origin, HttpAuthority authority, QuicConnection connection, bool includeAltUsedHeader)
public Http3Connection(HttpConnectionPool pool, HttpAuthority? origin, HttpAuthority authority, QuicConnection connection, Uri requestUri, bool includeAltUsedHeader)
{
_pool = pool;
_origin = origin;
Expand All @@ -95,7 +95,7 @@ public Http3Connection(HttpConnectionPool pool, HttpAuthority? origin, HttpAutho

if (HttpTelemetry.Log.IsEnabled())
{
HttpTelemetry.Log.Http30ConnectionEstablished();
HttpTelemetry.Log.Http30ConnectionEstablished(Id, requestUri, connection.RemoteEndPoint);
_markedByTelemetryStatus = TelemetryStatus_Opened;
}

Expand Down Expand Up @@ -172,7 +172,7 @@ private void CheckForShutdown()
{
if (Interlocked.Exchange(ref _markedByTelemetryStatus, TelemetryStatus_Closed) == TelemetryStatus_Opened)
{
HttpTelemetry.Log.Http30ConnectionClosed();
HttpTelemetry.Log.Http30ConnectionClosed(Id);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -552,7 +552,7 @@ private void CopyTrailersToResponseMessage(HttpResponseMessage responseMessage)

private void BufferHeaders(HttpRequestMessage request)
{
if (HttpTelemetry.Log.IsEnabled()) HttpTelemetry.Log.RequestHeadersStart();
if (HttpTelemetry.Log.IsEnabled()) HttpTelemetry.Log.RequestHeadersStart(_connection.Id);

// Reserve space for the header frame envelope.
// The envelope needs to be written after headers are serialized, as we need to know the payload length first.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,9 @@ internal sealed partial class HttpConnection : HttpConnectionBase
public HttpConnection(
HttpConnectionPool pool,
Stream stream,
TransportContext? transportContext)
TransportContext? transportContext,
Uri requestUri,
IPEndPoint? remoteEndPoint)
{
Debug.Assert(pool != null);
Debug.Assert(stream != null);
Expand All @@ -93,7 +95,7 @@ public HttpConnection(

if (HttpTelemetry.Log.IsEnabled())
{
HttpTelemetry.Log.Http11ConnectionEstablished();
HttpTelemetry.Log.Http11ConnectionEstablished(Id, requestUri, remoteEndPoint);
_disposed = Status_NotDisposedAndTrackedByTelemetry;
}

Expand All @@ -116,7 +118,7 @@ private void Dispose(bool disposing)
// Only decrement the connection count if we counted this connection
if (HttpTelemetry.Log.IsEnabled() && previousValue == Status_NotDisposedAndTrackedByTelemetry)
{
HttpTelemetry.Log.Http11ConnectionClosed();
HttpTelemetry.Log.Http11ConnectionClosed(Id);
}

if (!_detachedFromPool)
Expand Down Expand Up @@ -531,7 +533,7 @@ public async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, boo
CancellationTokenRegistration cancellationRegistration = RegisterCancellation(cancellationToken);
try
{
if (HttpTelemetry.Log.IsEnabled()) HttpTelemetry.Log.RequestHeadersStart();
if (HttpTelemetry.Log.IsEnabled()) HttpTelemetry.Log.RequestHeadersStart(Id);

WriteHeaders(request, normalizedMethod);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,15 @@ namespace System.Net.Http
{
internal abstract class HttpConnectionBase : IDisposable, IHttpTrace
{
private static long s_connectionCounter = -1;

/// <summary>Cached string for the last Date header received on this connection.</summary>
private string? _lastDateHeaderValue;
/// <summary>Cached string for the last Server header received on this connection.</summary>
private string? _lastServerHeaderValue;

internal long Id { get; } = Interlocked.Increment(ref s_connectionCounter);

/// <summary>Uses <see cref="HeaderDescriptor.GetHeaderValue"/>, but first special-cases several known headers for which we can use caching.</summary>
public string GetResponseHeaderValueWithCaching(HeaderDescriptor descriptor, ReadOnlySpan<byte> value, Encoding? valueEncoding)
{
Expand Down Expand Up @@ -47,7 +51,7 @@ protected void TraceConnection(Stream stream)
if (stream is SslStream sslStream)
{
Trace(
$"{this}. " +
$"{this}. Id:{Id}, " +
$"SslProtocol:{sslStream.SslProtocol}, NegotiatedApplicationProtocol:{sslStream.NegotiatedApplicationProtocol}, " +
$"NegotiatedCipherSuite:{sslStream.NegotiatedCipherSuite}, CipherAlgorithm:{sslStream.CipherAlgorithm}, CipherStrength:{sslStream.CipherStrength}, " +
$"HashAlgorithm:{sslStream.HashAlgorithm}, HashStrength:{sslStream.HashStrength}, " +
Expand All @@ -56,7 +60,7 @@ protected void TraceConnection(Stream stream)
}
else
{
Trace($"{this}");
Trace($"{this}. Id:{Id}");
}
}

Expand Down
Loading