Last active
August 7, 2024 01:57
-
-
Save davidfowl/54a9e8b98de8a50eb017b64dd70b379a to your computer and use it in GitHub Desktop.
Using Yarp.Telemetry.Consumption to track outbound network events (this package isn't tied to YARP)
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
<Project Sdk="Microsoft.NET.Sdk.Web"> | |
<PropertyGroup> | |
<TargetFramework>net7.0</TargetFramework> | |
<Nullable>enable</Nullable> | |
<ImplicitUsings>enable</ImplicitUsings> | |
</PropertyGroup> | |
<ItemGroup> | |
<PackageReference Include="Yarp.Telemetry.Consumption" Version="2.0.1" /> | |
</ItemGroup> | |
</Project> |
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.Diagnostics; | |
using System.Net.Sockets; | |
using System.Security.Authentication; | |
using Yarp.Telemetry.Consumption; | |
var builder = WebApplication.CreateBuilder(args); | |
builder.Services.AddTelemetryConsumer<TelemetryConsumer>(); | |
var app = builder.Build(); | |
app.MapGet("/", async () => | |
{ | |
var events = new EventList(); | |
TelemetryConsumer.Events = events; | |
var client = new HttpClient(); | |
try | |
{ | |
await client.GetAsync("https://www.microsoft.com"); | |
} | |
finally | |
{ | |
foreach (var (Timestamp, Event) in events.GetRelativeEvents()) | |
{ | |
Console.WriteLine($"{Timestamp} - {Event}"); | |
} | |
} | |
}); | |
app.Run(); | |
public class EventList | |
{ | |
private readonly List<(long Timestamp, string Event)> _events = new(); | |
public void Add(string name) | |
{ | |
_events.Add((Stopwatch.GetTimestamp(), name)); | |
} | |
public IEnumerable<(double Timestamp, string Event)> GetRelativeEvents() | |
{ | |
foreach (var (timestamp, name) in _events) | |
{ | |
yield return (Stopwatch.GetElapsedTime(_events[0].Timestamp, timestamp).TotalMilliseconds, name); | |
} | |
} | |
} | |
public sealed class TelemetryConsumer : IHttpTelemetryConsumer, INameResolutionTelemetryConsumer, INetSecurityTelemetryConsumer, ISocketsTelemetryConsumer | |
{ | |
private static AsyncLocal<EventList> _events = new(); | |
public static EventList Events | |
{ | |
set => _events.Value = value; | |
} | |
private static void AddEvent(string name) | |
{ | |
_events.Value?.Add(name); | |
} | |
public void OnConnectStart(DateTime timestamp, string address) | |
{ | |
AddEvent($"OnConnectStart(address={address})"); | |
} | |
public void OnConnectStop(DateTime timestamp) | |
{ | |
AddEvent("OnConnectStop"); | |
} | |
public void OnConnectFailed(DateTime timestamp, SocketError error, string exceptionMessage) | |
{ | |
AddEvent($"OnConnectFailed(error={error}, exceptionMessage={exceptionMessage})"); | |
} | |
public void OnResolutionStart(DateTime timestamp, string hostNameOrAddress) | |
{ | |
AddEvent($"OnResolutionStart(hostNameOrAddress={hostNameOrAddress})"); | |
} | |
public void OnResolutionStop(DateTime timestamp) | |
{ | |
AddEvent("OnResolutionStop"); | |
} | |
public void OnResolutionFailed(DateTime timestamp) | |
{ | |
AddEvent("OnResolutionFailed"); | |
} | |
public void OnHandshakeStart(DateTime timestamp, bool isServer, string targetHost) | |
{ | |
AddEvent($"OnHandshakeStart(isServer={isServer}, targetHost={targetHost})"); | |
} | |
public void OnHandshakeStop(DateTime timestamp, SslProtocols protocol) | |
{ | |
AddEvent($"OnHandshakeStop(protocol={protocol})"); | |
} | |
public void OnHandshakeFailed(DateTime timestamp, bool isServer, string targetHost, string exceptionMessage) | |
{ | |
AddEvent($"OnHandshakeFailed(isServer={isServer}, targetHost={targetHost}, exceptionMessage={exceptionMessage})"); | |
} | |
public void OnRequestStart(DateTime timestamp, string scheme, string host, int port, string pathAndQuery, int versionMajor, int versionMinor, HttpVersionPolicy versionPolicy) | |
{ | |
AddEvent($"OnRequestStart(scheme={scheme}, host={host}, port={port}, pathAndQuery={pathAndQuery}, versionMajor={versionMajor}, versionMinor={versionMinor}, {versionPolicy})"); | |
} | |
public void OnRequestStop(DateTime timestamp) | |
{ | |
AddEvent("OnRequestStop"); | |
} | |
public void OnConnectionEstablished(DateTime timestamp, int versionMajor, int versionMinor) | |
{ | |
AddEvent($"OnConnectionEstablished(versionMajor={versionMajor}, versionMinor={versionMinor})"); | |
} | |
public void OnRequestLeftQueue(DateTime timestamp, TimeSpan timeOnQueue, int versionMajor, int versionMinor) | |
{ | |
AddEvent($"OnRequestLeftQueue(timeOnQueue={timeOnQueue.TotalMilliseconds}ms, versionMajor={versionMinor}, versionMinor={versionMinor})"); | |
} | |
public void OnRequestHeadersStart(DateTime timestamp) | |
{ | |
AddEvent("OnRequestHeadersStart"); | |
} | |
public void OnRequestHeadersStop(DateTime timestamp) | |
{ | |
AddEvent("OnRequestHeadersStop"); | |
} | |
public void OnRequestContentStart(DateTime timestamp) | |
{ | |
AddEvent("OnRequestContentStart"); | |
} | |
public void OnRequestContentStop(DateTime timestamp, long contentLength) | |
{ | |
AddEvent($"OnRequestContentStart(contentLength={contentLength})"); | |
} | |
public void OnResponseHeadersStart(DateTime timestamp) | |
{ | |
AddEvent("OnResponseHeadersStart"); | |
} | |
public void OnResponseHeadersStop(DateTime timestamp) | |
{ | |
AddEvent("OnResponseHeadersStop"); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Here's the full example on the YARP repo https://github.com/microsoft/reverse-proxy/tree/main/samples/ReverseProxy.Metrics.Sample