You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
There is a growing number of asks to make HttpClientFactory's logging opt out and/or configurable (see original issue description). Given the enrichable logging designed in dotnet/extensions, we want to have a flexible and extensible logging infrastructure and give users an API experience that feels consistent even if it spans more than one package.
API Proposal
// newinterfaceIHttpClientLogger{// returns context object (e.g. LogRecord)ValueTask<object?>LogRequestStartAsync(HttpRequestMessagerequest,CancellationTokencancellationToken=default);ValueTaskLogRequestStopAsync(object?context,HttpRequestMessagerequest,HttpResponseMessageresponse,TimeSpanelapsed,CancellationTokencancellationToken=default);ValueTaskLogRequestFailedAsync(object?context,HttpRequestMessagerequest,HttpResponseMessage?response,Exceptionexception,TimeSpanelapsed,CancellationTokencancellationToken=default);}// newinterfaceIHttpClientLoggingBuilder{stringName{get;}IServiceCollectionServices{get;}// adds custom implementation// wrapHandlersPipeline -- whether a logging handler should be added to the top or to the bottom// of the handlers chainIHttpClientLoggingBuilderAddLogger(Func<IServiceProvider,IHttpClientLogger>httpClientLoggerFactory,boolwrapHandlersPipeline=false);// removes all loggers incl. default onesIHttpClientLoggingBuilderRemoveAllLoggers();}// newstaticclassHttpClientLoggingBuilderExtensions{// adds (back) the default logging (LoggingHttpMessageHandler + LoggingScopeHttpMessageHandler)// useful if the logging was removed by RemoveAll before e.g. by ConfigureHttpClientDefaultspublicstaticIHttpClientLoggingBuilderAddDefaultLogger(thisIHttpClientLoggingBuilderbuilder);// convenience method -- adds custom implementation from containerpublicstaticIHttpClientLoggingBuilderAddLogger<TLogger>(thisIHttpClientLoggingBuilderbuilder,boolwrapHandlersPipeline=false)whereTLogger:IHttpClientLogger;}// existingstaticclassHttpClientBuilderExtensions{// newpublicstaticIHttpClientBuilderConfigureLogging(thisIHttpClientBuilderbuilder,Action<IHttpClientLoggingBuilder>configure){}}
services.AddHttpClient("foo").ConfigureLogging(b =>b.RemoveAllLoggers());// -OR-// remove for all clientsservices.ConfigureHttpCientDefaults(defaults =>defaults.ConfigureLogging(b =>b.RemoveAllLoggers());
GET https://httpbin.dmuth.org/get - 200 OK in 393.2039ms
POST https://httpbin.dmuth.org/post - 200 OK in 95.524ms
GET https://httpbin.dmuth.org/status/500 - 500 InternalServerError in 99.5025ms
GET http://localhost:1234/ - FAILED System.Net.Http.HttpRequestException: No connection could be made because the target machine actively refused it. (localhost:1234)
3. Same but for ILogger
Bonus: add client name to ILogger category name
Bonus 2: custom extension method
info: MyMinimalLogger.baz[0]
GET https://httpbin.dmuth.org/get - 200 OK in 393.2039ms
info: MyMinimalLogger.baz[0]
POST https://httpbin.dmuth.org/post - 200 OK in 95.524ms
info: MyMinimalLogger.baz[0]
GET https://httpbin.dmuth.org/status/500 - 500 InternalServerError in 99.5025ms
warn: MyMinimalLogger.baz[0]
GET http://localhost:1234/ - FAILED System.Net.Http.HttpRequestException: No connection could be made because the target machine actively refused it. (localhost:1234)
4. Adding (back) the default HttpClientFactory logging
After removal, or after the logging would be potentially turned off by default in a future release
// remove for all clientsservices.ConfigureHttpCientDefaults(defaults =>defaults.ConfigureLogging(b =>b.RemoveAllLoggers());// add back for a single clientservices.AddHttpClient("qux").ConfigureLogging(b =>b.AddDefaultLogger());
I believe we can expect most of the custom user logging to be sync rather than async. Having async-only interface would force the users to always do return ValueTask.CompletedTask; in the end of an inherently sync implementation, which might be a bit inconvenient. We might consider having sync methods on the interface as well, and default-implement async ones. We cannot drop async, as there's already a precedent for async logging in dotnet/extensions.
Original issue by @CarnaViire
Tracking all the community asks regarding HttpClientFactory logging in one place.
Make logging opt-in. Opt-out currently is possible only using a workaround to remove all IHttpMessageHandlerBuilderFilter registrations from the DI container. Related: Make it possible to disable the built-in HTTP client logging #81540, Microsoft.Extensions.Http is too heavy-weight for mobile usages #66863, Ability to disable default http request logging #85840
Make logging configurable. Related: Modify HttpClientFactory based HttpClient request logging #44411 -- 7 upvotes
Background and motivation
There is a growing number of asks to make HttpClientFactory's logging opt out and/or configurable (see original issue description). Given the enrichable logging designed in dotnet/extensions, we want to have a flexible and extensible logging infrastructure and give users an API experience that feels consistent even if it spans more than one package.
API Proposal
API Usage
1. Removing the logging
Related: #81540, #85840
2. Implementing custom one-line console logging
Related: #44411, #76998, #68675, #86095
example output
client code:
console output:
3. Same but for
ILoggerBonus: add client name to ILogger category name
Bonus 2: custom extension method
example output
client code:
console output:
4. Adding (back) the default HttpClientFactory logging
After removal, or after the logging would be potentially turned off by default in a future release
5. Implementing Microsoft.Extensions.Http.Telemetry logging
Related: #87247
Based on
HttpLoggingHandlerfunctionality from Extensions.The logger itself in the gist https://gist.github.com/CarnaViire/08346da1634d357f6bcb8adefa01da67#file-httpclientlogger-cs
6. Going forward
We can consider adding convenience methods for a configurable minimal logging in the future (with implementation based on the Example 3):
Logger implementation
Alternative Design
I believe we can expect most of the custom user logging to be sync rather than async. Having async-only interface would force the users to always do
return ValueTask.CompletedTask;in the end of an inherently sync implementation, which might be a bit inconvenient. We might consider having sync methods on the interface as well, and default-implement async ones. We cannot drop async, as there's already a precedent for async logging in dotnet/extensions.