// Need to support adding multiple callbacks to support adding metrics from multiple places:
// 1. Creating HttpRequestMessage
// 2. During HTTP request pipeline in delegating handlers
// 3. In diaganostic event callbacks
public static class HttpOptionsExtensions
{
public static void AddCustomMetricsTagsCallback(
this HttpOptions options, Action<HttpCustomMetricsContext> callback);
// GetCustomMetricsTags method is removed.
}
// A context type allows new arguments to be added in the future if required.
// There is an extra allocation, but it's small, once per-request, and only required if metrics are enabled.
public sealed class HttpCustomMetricsTagsContext
{
public HttpRequestMessage Request { get; init; }
public HttpResponseMessage Response { get; init; }
// The tags collection could be TagList or ICollection<KeyValuePair<string, object?>
public TagList Tags { get; init; }
}
// Internally the client factory will just register an internal delegating handler.
// The delegating handler adds the registered callbacks to the HttpRequestMessage.
public static class HttpClientBuilderExtensions
{
public static void AddCustomMetricsTagsCallback(
this IHttpClientBuilder builder, Action<HttpCustomMetricsContext> context);
public static void AddCustomMetricsTagsCallback(
this IHttpClientBuilder builder, Action<IServiceProvider, HttpCustomMetricsContext> context);
}
HttpRequestMessage message = new HttpRequestMessage(HttpMethod.Get, "https://www.google.com");
message.Options.AddCustomMetricsTagsCallback(c =>
{
var value = c.Response.Headers.GetValue("x-contoso-header");
c.Tags.Add("contoso-header", value);
});
And internal custom handlers can add a callback like this:
public class DelegatingHandler(HttpMessageHandler inner) : base(inner)
{
public Task<HttpResponseMessage> SendAsync(HttpRequestMessage message)
{
message.Options.AddCustomMetricsTagsCallback(c =>
{
var value = c.Request.Headers.GetValue("x-retry-count");
c.Tags.Add("retry-count", value);
});
return base.SendAsync(message);
}
}
And HttpClientFactory users can add callbacks like this:
services
.AddHttpClient("GitHubClient")
.ConfigureHttpClient(httpClient =>
{
httpClient.BaseAddress = new Uri("https://api.github.com");
})
.AddCustomMetricsTagsCallback(c =>
{
message.Options.AddCustomMetricsTagsCallback(c =>
{
var value = c.Request.Headers.GetValue("authorize");
c.Tags.Add("request-authorized", value != null);
});
});