| File: DependencyInjection\HttpClientBuilderExtensions.Logging.cs | Web Access |
| Project: src\runtime\src\libraries\Microsoft.Extensions.Http\src\Microsoft.Extensions.Http.csproj (Microsoft.Extensions.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; using Microsoft.Extensions.Http; using Microsoft.Extensions.Http.Logging; namespace Microsoft.Extensions.DependencyInjection { public static partial class HttpClientBuilderExtensions { /// <summary> /// Adds a delegate that will be used to create an additional logger for a named <see cref="System.Net.Http.HttpClient"/>. The custom logger would be invoked /// from a dedicated logging DelegatingHandler on every request of the corresponding named <see cref="System.Net.Http.HttpClient"/>. /// </summary> /// <param name="builder">The <see cref="IHttpClientBuilder"/>.</param> /// <param name="httpClientLoggerFactory">A delegate that is used to create a custom logger. The logger should implement /// <see cref="IHttpClientLogger"/> or <see cref="IHttpClientAsyncLogger"/>.</param> /// <param name="wrapHandlersPipeline">Whether the logging handler with the custom logger would be added to the top /// or to the bottom of the additional handlers chains.</param> /// <returns>An <see cref="IHttpClientBuilder"/> that can be used to configure the client.</returns> /// <remarks> /// <para> /// If the <paramref name="wrapHandlersPipeline"/> is `true`, <see cref="IHttpClientLogger.LogRequestStart"/> and /// <see cref="IHttpClientAsyncLogger.LogRequestStartAsync"/> would be executed before all /// other additional handlers in the chain. <see cref="IHttpClientLogger.LogRequestStop"/> and /// <see cref="IHttpClientAsyncLogger.LogRequestStopAsync"/> would be executed after all /// other additional handlers, essentially wrapping the whole pipeline. /// </para> /// <para> /// If the <paramref name="wrapHandlersPipeline"/> is `false`, <see cref="IHttpClientLogger.LogRequestStart"/> and /// <see cref="IHttpClientAsyncLogger.LogRequestStartAsync"/> would be executed after all /// other additional handlers in the chain, right before the primary handler. <see cref="IHttpClientLogger.LogRequestStop"/> and /// <see cref="IHttpClientAsyncLogger.LogRequestStopAsync"/> would be executed before all /// other additional handlers, right after the primary handler. /// </para> /// <para> /// The <see cref="IServiceProvider"/> argument provided to <paramref name="httpClientLoggerFactory"/> will be /// a reference to a scoped service provider that shares the lifetime of the handler chain being constructed. /// </para> /// <para> /// If <see cref="AddLogger"/> is called multiple times, multiple loggers would be added. If <see cref="RemoveAllLoggers"/> was /// not called before calling <see cref="AddLogger"/>, then new logger would be added in addition to the default ones. /// </para> /// </remarks> public static IHttpClientBuilder AddLogger(this IHttpClientBuilder builder, Func<IServiceProvider, IHttpClientLogger> httpClientLoggerFactory, bool wrapHandlersPipeline = false) { ArgumentNullException.ThrowIfNull(builder); ArgumentNullException.ThrowIfNull(httpClientLoggerFactory); builder.Services.Configure<HttpClientFactoryOptions>(builder.Name, options => { options.LoggingBuilderActions.Add(b => { IHttpClientLogger httpClientLogger = httpClientLoggerFactory(b.Services); HttpClientLoggerHandler handler = new HttpClientLoggerHandler(httpClientLogger); if (wrapHandlersPipeline) { b.AdditionalHandlers.Insert(0, handler); } else { b.AdditionalHandlers.Add(handler); } }); }); return builder; } /// <summary> /// Adds a delegate that will be used to create an additional logger for a named <see cref="System.Net.Http.HttpClient"/>. The custom logger would be invoked /// from a dedicated logging DelegatingHandler on every request of the corresponding named <see cref="System.Net.Http.HttpClient"/>. /// </summary> /// <param name="builder">The <see cref="IHttpClientBuilder"/>.</param> /// <param name="wrapHandlersPipeline">Whether the logging handler with the custom logger would be added to the top /// or to the bottom of the additional handlers chains.</param> /// <returns>An <see cref="IHttpClientBuilder"/> that can be used to configure the client.</returns> /// <typeparam name="TLogger"> /// The service type of the custom logger as it was registered in DI. The logger should implement <see cref="IHttpClientLogger"/> /// or <see cref="IHttpClientAsyncLogger"/>. /// </typeparam> /// <remarks> /// <para> /// If the <paramref name="wrapHandlersPipeline"/> is `true`, <see cref="IHttpClientLogger.LogRequestStart"/> and /// <see cref="IHttpClientAsyncLogger.LogRequestStartAsync"/> would be executed before all /// other additional handlers in the chain. <see cref="IHttpClientLogger.LogRequestStop"/> and /// <see cref="IHttpClientAsyncLogger.LogRequestStopAsync"/> would be executed after all /// other additional handlers, essentially wrapping the whole pipeline. /// </para> /// <para> /// If the <paramref name="wrapHandlersPipeline"/> is `false`, <see cref="IHttpClientLogger.LogRequestStart"/> and /// <see cref="IHttpClientAsyncLogger.LogRequestStartAsync"/> would be executed after all /// other additional handlers in the chain, right before the primary handler. <see cref="IHttpClientLogger.LogRequestStop"/> and /// <see cref="IHttpClientAsyncLogger.LogRequestStopAsync"/> would be executed before all /// other additional handlers, right after the primary handler. /// </para> /// <para> /// The <typeparamref name="TLogger"/> will be resolved from a scoped service provider that shares /// the lifetime of the handler chain being constructed. /// </para> /// <para> /// If <see cref="AddLogger{TLogger}"/> is called multiple times, multiple loggers would be added. If <see cref="RemoveAllLoggers"/> was /// not called before calling <see cref="AddLogger{TLogger}"/>, then new logger would be added in addition to the default ones. /// </para> /// </remarks> public static IHttpClientBuilder AddLogger<TLogger>(this IHttpClientBuilder builder, bool wrapHandlersPipeline = false) where TLogger : IHttpClientLogger { ArgumentNullException.ThrowIfNull(builder); return AddLogger(builder, services => services.GetRequiredService<TLogger>(), wrapHandlersPipeline); } /// <summary> /// Removes all previously added loggers for a named <see cref="System.Net.Http.HttpClient"/>, including default ones. /// </summary> /// <param name="builder">The <see cref="IHttpClientBuilder"/>.</param> /// <returns>An <see cref="IHttpClientBuilder"/> that can be used to configure the client.</returns> public static IHttpClientBuilder RemoveAllLoggers(this IHttpClientBuilder builder) { ArgumentNullException.ThrowIfNull(builder); builder.Services.Configure<HttpClientFactoryOptions>(builder.Name, options => { options.LoggingBuilderActions.Clear(); options.SuppressDefaultLogging = true; }); return builder; } /// <summary> /// Adds back the default logging for a named <see cref="System.Net.Http.HttpClient"/>, if it was removed previously by calling <see cref="RemoveAllLoggers"/>. /// </summary> /// <param name="builder">The <see cref="IHttpClientBuilder"/>.</param> /// <returns>An <see cref="IHttpClientBuilder"/> that can be used to configure the client.</returns> public static IHttpClientBuilder AddDefaultLogger(this IHttpClientBuilder builder) { ArgumentNullException.ThrowIfNull(builder); builder.Services.Configure<HttpClientFactoryOptions>(builder.Name, options => options.SuppressDefaultLogging = false); return builder; } } }