Skip to content

Instantly share code, notes, and snippets.

@antonfirsov
Last active April 19, 2023 22:05
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save antonfirsov/c565ede5947c5552193f5a80c9993560 to your computer and use it in GitHub Desktop.
Save antonfirsov/c565ede5947c5552193f5a80c9993560 to your computer and use it in GitHub Desktop.
[PROPOSAL] Logging IP information for HttpClient requests with successful connections using EventListener
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