| File: Logging\LoggingHttpMessageHandlerBuilderFilter.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 System.Threading; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Http.Logging; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; namespace Microsoft.Extensions.Http { // Internal so we can change the requirements without breaking changes. internal sealed class LoggingHttpMessageHandlerBuilderFilter : IHttpMessageHandlerBuilderFilter { // we want to prevent a circular depencency between ILoggerFactory and IHttpMessageHandlerBuilderFilter, in case // any of ILoggerProvider instances use IHttpClientFactory to send logs to an external server private ILoggerFactory LoggerFactory => field ??= _serviceProvider.GetRequiredService<ILoggerFactory>(); private readonly IServiceProvider _serviceProvider; private readonly IOptionsMonitor<HttpClientFactoryOptions> _optionsMonitor; public LoggingHttpMessageHandlerBuilderFilter(IServiceProvider serviceProvider, IOptionsMonitor<HttpClientFactoryOptions> optionsMonitor) { ArgumentNullException.ThrowIfNull(serviceProvider); ArgumentNullException.ThrowIfNull(optionsMonitor); _serviceProvider = serviceProvider; _optionsMonitor = optionsMonitor; } public Action<HttpMessageHandlerBuilder> Configure(Action<HttpMessageHandlerBuilder> next) { ArgumentNullException.ThrowIfNull(next); return (builder) => { // Run other configuration first, we want to decorate. next(builder); HttpClientFactoryOptions options = _optionsMonitor.Get(builder.Name); if (options.SuppressDefaultLogging) { return; } string loggerName = !string.IsNullOrEmpty(builder.Name) ? builder.Name : "Default"; // We want all of our logging message to show up as-if they are coming from HttpClient, // but also to include the name of the client for more fine-grained control. ILogger outerLogger = LoggerFactory.CreateLogger($"System.Net.Http.HttpClient.{loggerName}.LogicalHandler"); ILogger innerLogger = LoggerFactory.CreateLogger($"System.Net.Http.HttpClient.{loggerName}.ClientHandler"); // The 'scope' handler goes first so it can surround everything. builder.AdditionalHandlers.Insert(0, new LoggingScopeHttpMessageHandler(outerLogger, options)); // We want this handler to be last so we can log details about the request after // service discovery and security happen. builder.AdditionalHandlers.Add(new LoggingHttpMessageHandler(innerLogger, options)); }; } } }