Skip to content

Commit 1db1ba4

Browse files
authored
Extend SocketsHttpHandler Connection and Request telemetry (#88853)
Fixes #63159, fixes #85729.
1 parent 31ffdb7 commit 1db1ba4

File tree

10 files changed

+368
-69
lines changed

10 files changed

+368
-69
lines changed

src/libraries/System.Net.Http/src/System/Net/Http/HttpTelemetry.cs

Lines changed: 97 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -90,16 +90,23 @@ private void RequestFailed(string exceptionMessage)
9090
WriteEvent(eventId: 3, exceptionMessage);
9191
}
9292

93-
[Event(4, Level = EventLevel.Informational)]
94-
private void ConnectionEstablished(byte versionMajor, byte versionMinor)
93+
[NonEvent]
94+
private void ConnectionEstablished(byte versionMajor, byte versionMinor, long connectionId, string scheme, string host, int port, IPEndPoint? remoteEndPoint)
95+
{
96+
string? remoteAddress = remoteEndPoint?.Address?.ToString();
97+
ConnectionEstablished(versionMajor, versionMinor, connectionId, scheme, host, port, remoteAddress);
98+
}
99+
100+
[Event(4, Level = EventLevel.Informational, Version = 1)]
101+
private void ConnectionEstablished(byte versionMajor, byte versionMinor, long connectionId, string scheme, string host, int port, string? remoteAddress)
95102
{
96-
WriteEvent(eventId: 4, versionMajor, versionMinor);
103+
WriteEvent(eventId: 4, versionMajor, versionMinor, connectionId, scheme, host, port, remoteAddress);
97104
}
98105

99-
[Event(5, Level = EventLevel.Informational)]
100-
private void ConnectionClosed(byte versionMajor, byte versionMinor)
106+
[Event(5, Level = EventLevel.Informational, Version = 1)]
107+
private void ConnectionClosed(byte versionMajor, byte versionMinor, long connectionId)
101108
{
102-
WriteEvent(eventId: 5, versionMajor, versionMinor);
109+
WriteEvent(eventId: 5, versionMajor, versionMinor, connectionId);
103110
}
104111

105112
[Event(6, Level = EventLevel.Informational)]
@@ -108,10 +115,10 @@ private void RequestLeftQueue(double timeOnQueueMilliseconds, byte versionMajor,
108115
WriteEvent(eventId: 6, timeOnQueueMilliseconds, versionMajor, versionMinor);
109116
}
110117

111-
[Event(7, Level = EventLevel.Informational)]
112-
public void RequestHeadersStart()
118+
[Event(7, Level = EventLevel.Informational, Version = 1)]
119+
public void RequestHeadersStart(long connectionId)
113120
{
114-
WriteEvent(eventId: 7);
121+
WriteEvent(eventId: 7, connectionId);
115122
}
116123

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

172+
[Event(16, Level = EventLevel.Informational)]
173+
public void Redirect(string redirectUri)
174+
{
175+
WriteEvent(eventId: 16, redirectUri);
176+
}
177+
165178
[NonEvent]
166-
public void Http11ConnectionEstablished()
179+
public void Http11ConnectionEstablished(long connectionId, string scheme, string host, int port, IPEndPoint? remoteEndPoint)
167180
{
168181
Interlocked.Increment(ref _openedHttp11Connections);
169-
ConnectionEstablished(versionMajor: 1, versionMinor: 1);
182+
ConnectionEstablished(versionMajor: 1, versionMinor: 1, connectionId, scheme, host, port, remoteEndPoint);
170183
}
171184

172185
[NonEvent]
173-
public void Http11ConnectionClosed()
186+
public void Http11ConnectionClosed(long connectionId)
174187
{
175188
long count = Interlocked.Decrement(ref _openedHttp11Connections);
176189
Debug.Assert(count >= 0);
177-
ConnectionClosed(versionMajor: 1, versionMinor: 1);
190+
ConnectionClosed(versionMajor: 1, versionMinor: 1, connectionId);
178191
}
179192

180193
[NonEvent]
181-
public void Http20ConnectionEstablished()
194+
public void Http20ConnectionEstablished(long connectionId, string scheme, string host, int port, IPEndPoint? remoteEndPoint)
182195
{
183196
Interlocked.Increment(ref _openedHttp20Connections);
184-
ConnectionEstablished(versionMajor: 2, versionMinor: 0);
197+
ConnectionEstablished(versionMajor: 2, versionMinor: 0, connectionId, scheme, host, port, remoteEndPoint);
185198
}
186199

187200
[NonEvent]
188-
public void Http20ConnectionClosed()
201+
public void Http20ConnectionClosed(long connectionId)
189202
{
190203
long count = Interlocked.Decrement(ref _openedHttp20Connections);
191204
Debug.Assert(count >= 0);
192-
ConnectionClosed(versionMajor: 2, versionMinor: 0);
205+
ConnectionClosed(versionMajor: 2, versionMinor: 0, connectionId);
193206
}
194207

195208
[NonEvent]
196-
public void Http30ConnectionEstablished()
209+
public void Http30ConnectionEstablished(long connectionId, string scheme, string host, int port, IPEndPoint? remoteEndPoint)
197210
{
198211
Interlocked.Increment(ref _openedHttp30Connections);
199-
ConnectionEstablished(versionMajor: 3, versionMinor: 0);
212+
ConnectionEstablished(versionMajor: 3, versionMinor: 0, connectionId, scheme, host, port, remoteEndPoint);
200213
}
201214

202215
[NonEvent]
203-
public void Http30ConnectionClosed()
216+
public void Http30ConnectionClosed(long connectionId)
204217
{
205218
long count = Interlocked.Decrement(ref _openedHttp30Connections);
206219
Debug.Assert(count >= 0);
207-
ConnectionClosed(versionMajor: 3, versionMinor: 0);
220+
ConnectionClosed(versionMajor: 3, versionMinor: 0, connectionId);
208221
}
209222

210223
[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode",
@@ -293,9 +306,9 @@ private unsafe void WriteEvent(int eventId, double arg1, byte arg2, byte arg3)
293306
[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode",
294307
Justification = "Parameters to this method are primitive and are trimmer safe")]
295308
[NonEvent]
296-
private unsafe void WriteEvent(int eventId, byte arg1, byte arg2)
309+
private unsafe void WriteEvent(int eventId, byte arg1, byte arg2, long arg3)
297310
{
298-
const int NumEventDatas = 2;
311+
const int NumEventDatas = 3;
299312
EventData* descrs = stackalloc EventData[NumEventDatas];
300313

301314
descrs[0] = new EventData
@@ -308,6 +321,67 @@ private unsafe void WriteEvent(int eventId, byte arg1, byte arg2)
308321
DataPointer = (IntPtr)(&arg2),
309322
Size = sizeof(byte)
310323
};
324+
descrs[2] = new EventData
325+
{
326+
DataPointer = (IntPtr)(&arg3),
327+
Size = sizeof(long)
328+
};
329+
330+
WriteEventCore(eventId, NumEventDatas, descrs);
331+
}
332+
333+
[UnconditionalSuppressMessage("ReflectionAnalysis", "IL2026:RequiresUnreferencedCode",
334+
Justification = "Parameters to this method are primitive and are trimmer safe")]
335+
[NonEvent]
336+
private unsafe void WriteEvent(int eventId, byte arg1, byte arg2, long arg3, string? arg4, string arg5, int arg6, string? arg7)
337+
{
338+
arg4 ??= "";
339+
arg5 ??= "";
340+
arg7 ??= "";
341+
342+
const int NumEventDatas = 7;
343+
EventData* descrs = stackalloc EventData[NumEventDatas];
344+
345+
fixed (char* arg4Ptr = arg4)
346+
fixed (char* arg5Ptr = arg5)
347+
fixed (char* arg7Ptr = arg7)
348+
{
349+
descrs[0] = new EventData
350+
{
351+
DataPointer = (IntPtr)(&arg1),
352+
Size = sizeof(byte)
353+
};
354+
descrs[1] = new EventData
355+
{
356+
DataPointer = (IntPtr)(&arg2),
357+
Size = sizeof(byte)
358+
};
359+
descrs[2] = new EventData
360+
{
361+
DataPointer = (IntPtr)(&arg3),
362+
Size = sizeof(long)
363+
};
364+
descrs[3] = new EventData
365+
{
366+
DataPointer = (IntPtr)arg4Ptr,
367+
Size = (arg4.Length + 1) * sizeof(char)
368+
};
369+
descrs[4] = new EventData
370+
{
371+
DataPointer = (IntPtr)arg5Ptr,
372+
Size = (arg5.Length + 1) * sizeof(char)
373+
};
374+
descrs[5] = new EventData
375+
{
376+
DataPointer = (IntPtr)(&arg6),
377+
Size = sizeof(int)
378+
};
379+
descrs[6] = new EventData
380+
{
381+
DataPointer = (IntPtr)arg7Ptr,
382+
Size = (arg7.Length + 1) * sizeof(char)
383+
};
384+
}
311385

312386
WriteEventCore(eventId, NumEventDatas, descrs);
313387
}

src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http2Connection.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -132,8 +132,8 @@ internal enum KeepAliveState
132132
private long _keepAlivePingTimeoutTimestamp;
133133
private volatile KeepAliveState _keepAliveState;
134134

135-
public Http2Connection(HttpConnectionPool pool, Stream stream)
136-
: base(pool)
135+
public Http2Connection(HttpConnectionPool pool, Stream stream, IPEndPoint? remoteEndPoint)
136+
: base(pool, remoteEndPoint)
137137
{
138138
_pool = pool;
139139
_stream = stream;
@@ -1656,7 +1656,7 @@ private async ValueTask<Http2Stream> SendHeadersAsync(HttpRequestMessage request
16561656
ArrayBuffer headerBuffer = default;
16571657
try
16581658
{
1659-
if (HttpTelemetry.Log.IsEnabled()) HttpTelemetry.Log.RequestHeadersStart();
1659+
if (HttpTelemetry.Log.IsEnabled()) HttpTelemetry.Log.RequestHeadersStart(Id);
16601660

16611661
// Serialize headers to a temporary buffer, and do as much work to prepare to send the headers as we can
16621662
// before taking the write lock.

src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http3Connection.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ private bool ShuttingDown
6666
}
6767

6868
public Http3Connection(HttpConnectionPool pool, HttpAuthority authority, QuicConnection connection, bool includeAltUsedHeader)
69-
: base(pool)
69+
: base(pool, connection.RemoteEndPoint)
7070
{
7171
_pool = pool;
7272
_authority = authority;

src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/Http3RequestStream.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -552,7 +552,7 @@ private void CopyTrailersToResponseMessage(HttpResponseMessage responseMessage)
552552

553553
private void BufferHeaders(HttpRequestMessage request)
554554
{
555-
if (HttpTelemetry.Log.IsEnabled()) HttpTelemetry.Log.RequestHeadersStart();
555+
if (HttpTelemetry.Log.IsEnabled()) HttpTelemetry.Log.RequestHeadersStart(_connection.Id);
556556

557557
// Reserve space for the header frame envelope.
558558
// The envelope needs to be written after headers are serialized, as we need to know the payload length first.

src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnection.cs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ internal sealed partial class HttpConnection : HttpConnectionBase
4343
private static readonly ulong s_http11Bytes = BitConverter.ToUInt64("HTTP/1.1"u8);
4444

4545
private readonly HttpConnectionPool _pool;
46-
private readonly Stream _stream;
46+
internal readonly Stream _stream;
4747
private readonly TransportContext? _transportContext;
4848

4949
private HttpRequestMessage? _currentRequest;
@@ -73,8 +73,9 @@ internal sealed partial class HttpConnection : HttpConnectionBase
7373
public HttpConnection(
7474
HttpConnectionPool pool,
7575
Stream stream,
76-
TransportContext? transportContext)
77-
: base(pool)
76+
TransportContext? transportContext,
77+
IPEndPoint? remoteEndPoint)
78+
: base(pool, remoteEndPoint)
7879
{
7980
Debug.Assert(pool != null);
8081
Debug.Assert(stream != null);
@@ -515,7 +516,7 @@ public async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, boo
515516
CancellationTokenRegistration cancellationRegistration = RegisterCancellation(cancellationToken);
516517
try
517518
{
518-
if (HttpTelemetry.Log.IsEnabled()) HttpTelemetry.Log.RequestHeadersStart();
519+
if (HttpTelemetry.Log.IsEnabled()) HttpTelemetry.Log.RequestHeadersStart(Id);
519520

520521
WriteHeaders(request, normalizedMethod);
521522

src/libraries/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/HttpConnectionBase.cs

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ namespace System.Net.Http
1616
{
1717
internal abstract class HttpConnectionBase : IDisposable, IHttpTrace
1818
{
19+
private static long s_connectionCounter = -1;
20+
1921
// May be null if none of the counters were enabled when the connection was established.
2022
private readonly ConnectionMetrics? _connectionMetrics;
2123

@@ -31,7 +33,9 @@ internal abstract class HttpConnectionBase : IDisposable, IHttpTrace
3133
/// <summary>Cached string for the last Server header received on this connection.</summary>
3234
private string? _lastServerHeaderValue;
3335

34-
public HttpConnectionBase(HttpConnectionPool pool)
36+
public long Id { get; } = Interlocked.Increment(ref s_connectionCounter);
37+
38+
public HttpConnectionBase(HttpConnectionPool pool, IPEndPoint? remoteEndPoint)
3539
{
3640
Debug.Assert(this is HttpConnection or Http2Connection or Http3Connection);
3741
Debug.Assert(pool.Settings._metrics is not null);
@@ -64,9 +68,13 @@ public HttpConnectionBase(HttpConnectionPool pool)
6468
{
6569
_httpTelemetryMarkedConnectionAsOpened = true;
6670

67-
if (this is HttpConnection) HttpTelemetry.Log.Http11ConnectionEstablished();
68-
else if (this is Http2Connection) HttpTelemetry.Log.Http20ConnectionEstablished();
69-
else HttpTelemetry.Log.Http30ConnectionEstablished();
71+
string scheme = pool.IsSecure ? "https" : "http";
72+
string host = pool.OriginAuthority.HostValue;
73+
int port = pool.OriginAuthority.Port;
74+
75+
if (this is HttpConnection) HttpTelemetry.Log.Http11ConnectionEstablished(Id, scheme, host, port, remoteEndPoint);
76+
else if (this is Http2Connection) HttpTelemetry.Log.Http20ConnectionEstablished(Id, scheme, host, port, remoteEndPoint);
77+
else HttpTelemetry.Log.Http30ConnectionEstablished(Id, scheme, host, port, remoteEndPoint);
7078
}
7179
}
7280

@@ -79,9 +87,9 @@ public void MarkConnectionAsClosed()
7987
// Only decrement the connection count if we counted this connection
8088
if (_httpTelemetryMarkedConnectionAsOpened)
8189
{
82-
if (this is HttpConnection) HttpTelemetry.Log.Http11ConnectionClosed();
83-
else if (this is Http2Connection) HttpTelemetry.Log.Http20ConnectionClosed();
84-
else HttpTelemetry.Log.Http30ConnectionClosed();
90+
if (this is HttpConnection) HttpTelemetry.Log.Http11ConnectionClosed(Id);
91+
else if (this is Http2Connection) HttpTelemetry.Log.Http20ConnectionClosed(Id);
92+
else HttpTelemetry.Log.Http30ConnectionClosed(Id);
8593
}
8694
}
8795
}
@@ -125,7 +133,7 @@ protected void TraceConnection(Stream stream)
125133
if (stream is SslStream sslStream)
126134
{
127135
Trace(
128-
$"{this}. " +
136+
$"{this}. Id:{Id}, " +
129137
$"SslProtocol:{sslStream.SslProtocol}, NegotiatedApplicationProtocol:{sslStream.NegotiatedApplicationProtocol}, " +
130138
$"NegotiatedCipherSuite:{sslStream.NegotiatedCipherSuite}, CipherAlgorithm:{sslStream.CipherAlgorithm}, CipherStrength:{sslStream.CipherStrength}, " +
131139
$"HashAlgorithm:{sslStream.HashAlgorithm}, HashStrength:{sslStream.HashStrength}, " +
@@ -134,7 +142,7 @@ protected void TraceConnection(Stream stream)
134142
}
135143
else
136144
{
137-
Trace($"{this}");
145+
Trace($"{this}. Id:{Id}");
138146
}
139147
}
140148

0 commit comments

Comments
 (0)