-
-
Save antonfirsov/c565ede5947c5552193f5a80c9993560 to your computer and use it in GitHub Desktop.
[PROPOSAL] Logging IP information for HttpClient requests with successful connections using EventListener
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System.Collections.Concurrent; | |
using System.Collections.ObjectModel; | |
using System.Diagnostics.Tracing; | |
using System.Net; | |
_ = new IPLoggingListener(); | |
using HttpClient client = new(); | |
await SendRequestAsync("http://httpbin.org/get"); | |
async Task SendRequestAsync(string uri) | |
{ | |
RequestInfo info = RequestInfo.Current; | |
try | |
{ | |
using var response = await client.GetAsync(uri); | |
// process response | |
} | |
finally | |
{ | |
if (RequestInfo.Current != null) | |
{ | |
// ONLY HIT WHEN THE CONNECTION WAS SUCCESFUL | |
// Log RequestInfo.RemoteEndPoint | |
} | |
} | |
} | |
internal sealed class RequestInfo | |
{ | |
private static readonly AsyncLocal<RequestInfo> _asyncLocal = new(); | |
public static RequestInfo Current => _asyncLocal.Value ??= new(); | |
public string? RemoteEndPoint; | |
} | |
internal sealed class IPLoggingListener : EventListener | |
{ | |
private static readonly ConcurrentDictionary<long, string> s_connection2Endpoint = new ConcurrentDictionary<long, string>(); | |
private const int ConnectionEstablished_ConnectionIdIndex = 2; | |
private const int ConnectionEstablished_EndPointIndex = 6; | |
private const int ConnectionClosed_ConnectionIdIndex = 2; | |
private const int RequestHeadersStart_ConnectionIdIndex = 0; | |
protected override void OnEventSourceCreated(EventSource eventSource) | |
{ | |
if (eventSource.Name == "System.Net.Http") | |
{ | |
EnableEvents(eventSource, EventLevel.LogAlways); | |
} | |
} | |
protected override void OnEventWritten(EventWrittenEventArgs eventData) | |
{ | |
ReadOnlyCollection<object?>? payload = eventData.Payload; | |
if (payload == null) return; | |
if (eventData.EventName == "ConnectionEstablished") | |
{ | |
long connectionId = (long)payload[ConnectionEstablished_ConnectionIdIndex]!; | |
string? endPoint = (string?)payload[ConnectionEstablished_EndPointIndex]; | |
if (endPoint != null) | |
{ | |
s_connection2Endpoint.TryAdd(connectionId, endPoint); | |
} | |
} | |
else if (eventData.EventName == "ConnectionClosed") | |
{ | |
long connectionId = (long)payload[ConnectionClosed_ConnectionIdIndex]!; | |
s_connection2Endpoint.TryRemove(connectionId, out _); | |
} | |
else if (eventData.EventName == "RequestAssignedConnection") | |
{ | |
long connectionId = (long)payload[RequestHeadersStart_ConnectionIdIndex]!; | |
if (s_connection2Endpoint.TryGetValue(connectionId, out string? remoteEp)) | |
{ | |
RequestInfo.Current.RemoteEndPoint = remoteEp; | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment