| File: System\Net\Http\Metrics\HttpMetricsEnrichmentContext.cs | Web Access |
| Project: src\runtime\src\libraries\System.Net.Http\src\System.Net.Http.csproj (System.Net.Http) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System.Collections.Generic; using System.Diagnostics; using System.Diagnostics.Metrics; namespace System.Net.Http.Metrics { /// <summary> /// Provides functionality for enriching request metrics `http-client-request-duration` and `http-client-failed-requests`. /// </summary> /// <remarks> /// Enrichment is done on per-request basis by callbacks registered with <see cref="AddCallback(HttpRequestMessage, Action{HttpMetricsEnrichmentContext})"/>. /// The callbacks are responsible for adding custom tags via <see cref="AddCustomTag(string, object?)"/> for which they can use the request, response and error /// information exposed on the <see cref="HttpMetricsEnrichmentContext"/> instance. /// /// > [!IMPORTANT] /// > The <see cref="HttpMetricsEnrichmentContext"/> instance must not be used from outside of the enrichment callbacks. /// </remarks> public sealed class HttpMetricsEnrichmentContext { private static readonly HttpRequestOptionsKey<List<Action<HttpMetricsEnrichmentContext>>> s_optionsKeyForCallbacks = new(nameof(HttpMetricsEnrichmentContext)); private HttpRequestMessage? _request; private HttpResponseMessage? _response; private Exception? _exception; private TagList _tags; private HttpMetricsEnrichmentContext() { } // Hide the default parameterless constructor. /// <summary> /// Gets the <see cref="HttpRequestMessage"/> that has been sent. /// </summary> /// <remarks> /// This property must not be used from outside of the enrichment callbacks. /// </remarks> public HttpRequestMessage Request => _request!; /// <summary> /// Gets the <see cref="HttpRequestMessage"/> received from the server or <see langword="null"/> if the request failed. /// </summary> /// <remarks> /// This property must not be used from outside of the enrichment callbacks. /// </remarks> public HttpResponseMessage? Response => _response; /// <summary> /// Gets the exception that occurred or <see langword="null"/> if there was no error. /// </summary> /// <remarks> /// This property must not be used from outside of the enrichment callbacks. /// </remarks> public Exception? Exception => _exception; /// <summary> /// Appends a custom tag to the list of tags to be recorded with the request metrics `http-client-request-duration` and `http-client-failed-requests`. /// </summary> /// <param name="name">The name of the tag.</param> /// <param name="value">The value of the tag.</param> /// <remarks> /// This method must not be used from outside of the enrichment callbacks. /// </remarks> public void AddCustomTag(string name, object? value) => _tags.Add(name, value); /// <summary> /// Adds a callback to register custom tags for request metrics `http-client-request-duration` and `http-client-failed-requests`. /// </summary> /// <param name="request">The <see cref="HttpRequestMessage"/> to apply enrichment to.</param> /// <param name="callback">The callback responsible to add custom tags via <see cref="AddCustomTag(string, object?)"/>.</param> public static void AddCallback(HttpRequestMessage request, Action<HttpMetricsEnrichmentContext> callback) { ArgumentNullException.ThrowIfNull(request); ArgumentNullException.ThrowIfNull(callback); HttpRequestOptions options = request.Options; if (options.TryGetValue(s_optionsKeyForCallbacks, out List<Action<HttpMetricsEnrichmentContext>>? callbacks)) { callbacks.Add(callback); } else { options.Set(s_optionsKeyForCallbacks, [callback]); } } internal static List<Action<HttpMetricsEnrichmentContext>>? GetEnrichmentCallbacksForRequest(HttpRequestMessage request) { if (request._options is HttpRequestOptions options && options.Remove(s_optionsKeyForCallbacks.Key, out object? callbacks)) { return (List<Action<HttpMetricsEnrichmentContext>>)callbacks!; } return null; } internal static void RecordDurationWithEnrichment( List<Action<HttpMetricsEnrichmentContext>> callbacks, HttpRequestMessage request, HttpResponseMessage? response, Exception? exception, TimeSpan durationTime, in TagList commonTags, Histogram<double> requestDuration) { var context = new HttpMetricsEnrichmentContext { _request = request, _response = response, _exception = exception, _tags = commonTags, }; foreach (Action<HttpMetricsEnrichmentContext> callback in callbacks) { callback(context); } requestDuration.Record(durationTime.TotalSeconds, context._tags); } } }