ASP.NET Core – Logging requests and responses

The simplest way to log requests/responses is to use the HTTP Logging middleware (added in v6). This is configurable, so you can make it suit your needs. If you need more control, you can add your own middleware instead.

To use the HTTP Logging middleware, call UseHttpLogging() in your initialization code:

var app = builder.Build(); app.UseHttpLogging(); //rest of code
Code language: C# (cs)

Then add Microsoft.AspNetCore.HttpLogging.HttpLoggingMiddleware to appsettings.json:

{ "Logging": { "LogLevel": { "Default": "Information", "Microsoft.AspNetCore": "Warning", "Microsoft.AspNetCore.HttpLogging.HttpLoggingMiddleware": "Information" } }, "AllowedHosts": "*" }
Code language: JSON / JSON with Comments (json)

Now send a request to see it work. Here’s an example of what it logs when I send a GET request with Postman:

info: Microsoft.AspNetCore.HttpLogging.HttpLoggingMiddleware[1] Request: Protocol: HTTP/1.1 Method: GET Scheme: https PathBase: Path: /weatherforecast Accept: */* Connection: keep-alive Host: localhost:7291 User-Agent: PostmanRuntime/7.29.2 Accept-Encoding: gzip, deflate, br Cache-Control: no-cache IsTest: [Redacted] SecretToken: [Redacted] Postman-Token: [Redacted] info: Microsoft.AspNetCore.HttpLogging.HttpLoggingMiddleware[2] Response: StatusCode: 200 Content-Type: application/json; charset=utf-8 Date: Wed, 31 Aug 2022 14:04:17 GMT Server: Kestrel Transfer-Encoding: chunked
Code language: plaintext (plaintext)

Note: If you’re using Swagger, you’ll see a bunch of info get logged when you first launch.

In the rest of this article, I’ll explain how to configure the HTTP Logger.

Configuring what gets logged

The HTTP Logging middleware logs the following info by default:

  • Request properties (path, protocol, method, and scheme) and headers.
  • Response properties (status code) and headers.

You can configure what gets logged by calling AddHttpLogging() in your initialization code and setting the HttpLoggingOptions properties to whatever you want.

For example, let’s say you only want to log the request path/method and response status code. Here’s how to do that:

using Microsoft.AspNetCore.HttpLogging; var builder = WebApplication.CreateBuilder(args); builder.Services.AddHttpLogging(httpLoggingOptions => { httpLoggingOptions.LoggingFields = HttpLoggingFields.RequestPath | HttpLoggingFields.RequestMethod | HttpLoggingFields.ResponseStatusCode; }); //rest of code
Code language: C# (cs)

Note: LoggingFields uses the [Flags] attribute, so you can assign it multiple enum options by bitwise ORing them together.

Here’s what it looks like when you send a request (GET /weatherforecast) with a 200 response:

info: Microsoft.AspNetCore.HttpLogging.HttpLoggingMiddleware[1] Request: Method: GET PathBase: Path: /weatherforecast info: Microsoft.AspNetCore.HttpLogging.HttpLoggingMiddleware[2] Response: StatusCode: 200
Code language: plaintext (plaintext)

I suggest taking a look at all the configuration settings and choosing whatever makes sense to log in your situation.

Request/response headers

When you’re logging request/response headers, you have to specify which headers you want fully logged. If you don’t specify a header, it’ll be logged with its name and [Redacted] (instead of the actual value). In other words, you can see that a header is present, but you have to opt-in to be able to see its actual value.

You specify headers by adding them to HttpLoggingOptions.RequestHeaders/ResponseHeaders in AddHttpLogging(). Here’s an example of configuring it to fully log a request header called IsTest:

builder.Services.AddHttpLogging(opts => { opts.RequestHeaders.Add("IsTest"); });
Code language: C# (cs)

Now when a request comes in with this header, it’ll show this header’s actual value. Here’s an example of what it logs:

info: Microsoft.AspNetCore.HttpLogging.HttpLoggingMiddleware[1] Request: Protocol: HTTP/1.1 Method: GET Scheme: https PathBase: Path: /weatherforecast IsTest: true ...other headers...
Code language: plaintext (plaintext)

If you hadn’t added “IsTest” to RequestHeaders, it’d log it like this:

IsTest: [Redacted]
Code language: plaintext (plaintext)

They did a good job designing this feature. It prevents you from accidently showing sensitive info in the logs. You have to make the choice about what header values to actually show.

Headers logged by default

There are several request/response headers that are fully logged by default. They are already added to RequestHeaders/ResponseHeaders, so you don’t need to explicitly add these yourself.

These default headers are listed below.

Request headers:

  • Accept
  • Accept-Charset
  • Accept-Encoding
  • Accept-Language
  • Allow
  • Cache-Control
  • Connection
  • Content-Encoding
  • Content-Length
  • Content-Type
  • Date
  • DNT
  • Expect
  • Host
  • Max-Forwards
  • Range
  • Sec-WebSocket-Extensions
  • Sec-WebSocket-Version
  • TE
  • Trailer
  • Transfer-Encoding
  • Upgrade
  • User-Agent
  • Warning
  • X-Requested-With
  • X-UA-Compatible

Response headers:

  • Accept-Ranges
  • Age
  • Allow
  • Alt-Svc
  • Connection
  • Content-Disposition
  • Content-Language
  • Content-Length
  • Content-Location
  • Content-Range
  • Content-Type
  • Date
  • Expires
  • Last-Modified
  • Location
  • Server
  • :status
  • Transfer-Encoding
  • Upgrade
  • X-Powered-By

If you don’t want one of these default headers to be fully logged, you can remove it from the configuration. Here’s an example of removing the User-Agent request header:

builder.Services.AddHttpLogging(httpLoggingOptions => { httpLoggingOptions.RequestHeaders.Remove("User-Agent"); });
Code language: C# (cs)

Note: You can remove all of the defaults by clearing the collection – httpLoggingOptions.RequestHeaders.Clear().

Like any other header that’s not part of the RequestHeaders collection, this header will be logged without its actual value:

User-Agent: [Redacted]
Code language: plaintext (plaintext)

Leave a Comment