HTTP: HttpClient instances created by IHttpClientFactory log integer status codes

HttpClient instances created by IHttpClientFactory log HTTP status codes as integers instead of with status code names.

Version introduced

5.0 Preview 1

Old behavior

Logging uses the textual descriptions of HTTP status codes. Consider the following log messages:

Received HTTP response after 56.0044ms - OK
End processing HTTP request after 70.0862ms - OK

New behavior

Logging uses the integer values of HTTP status codes. Consider the following log messages:

Received HTTP response after 56.0044ms - 200
End processing HTTP request after 70.0862ms - 200

Reason for change

The original behavior of this logging is inconsistent with other parts of ASP.NET Core that have always used integer values. The inconsistency makes logs difficult to query via structured logging systems such as Elasticsearch. For more context, see dotnet/extensions#1549.

Using integer values is more flexible than text because it allows queries on ranges of values.

Adding another log value to capture the integer status code was considered. Unfortunately, doing so would introduce another inconsistency with the rest of ASP.NET Core. HttpClient logging and HTTP server/hosting logging use the same StatusCode key name already.

The best option is to update logging queries to use the integer values of status codes. This option may cause some difficulty writing queries across multiple ASP.NET Core versions. However, using integers for this purpose is much more flexible for querying logs.

If you need to force compatibility with the old behavior and use textual status codes, replace the IHttpClientFactory logging with your own:

  1. Copy the .NET Core 3.1 versions of the following classes into your project:

  2. Rename the classes to avoid conflicts with public types in the Microsoft.Extensions.Http NuGet package.

  3. Replace the built-in implementation of LoggingHttpMessageHandlerBuilderFilter with your own in the project's Startup.ConfigureServices method. For example:

    public void ConfigureServices(IServiceCollection services)
    {
        // Other service registrations go first. Code omitted for brevity.
    
        // Place the following after all AddHttpClient registrations.
        services.RemoveAll<IHttpMessageHandlerBuilderFilter>();
    
        services.AddSingleton<IHttpMessageHandlerBuilderFilter,
                              MyLoggingHttpMessageHandlerBuilderFilter>();
    }
    

Affected APIs

System.Net.Http.HttpClient