ASP.NET Core request logging middleware
Tags: dotnet, csharp, aspnetcore
Published: 2021-06-02 10:38:47

---
title: ASP.NET Core request logging middleware
published: true
description: Simple example of how to implement request logging using Microsoft.Extensions.Logging and ASP.NET Core middleware. Plus things to be aware of during config.
tags: dotnet, csharp, aspnetcore
cover_image: https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5t7a7vlgwdjwird7jqtp.png
canonical_url: https://blog.elmah.io/asp-net-core-request-logging-middleware/
---

I needed to debug an error logged through Microsoft.Extensions.Logging (MEL) on one of our ASP.NET Core-based services today. Usually, when getting errors logged through MEL, all of the HTTP context data is logged as part of the error, making it easy to spot why an error happened or at least making it a lot easier recreating the error. Today's error didn't include much more information than an error message and a request-id.

To help debug what is turning sideways, I created a quick request logging feature in ASP.NET Core. There are multiple posts on the subject already, but while most of them are really good posts, they often cover too much for my simple use case or leave out essential information about how to create the configuration. I simply want a log message for each request, with as little information as possible, but enough for me to be able to correlate the generated error with an HTTP request.

To log a message on every web request, start by creating a new class named `RequestLoggingMiddleware`:

```csharp
public class RequestLoggingMiddleware
{
}
```

Add the following locals:

```csharp
private readonly RequestDelegate _next;
private readonly ILogger _logger;
```

I'll explain what these are and what they are used for in a bit. Create a constructor on the class:

```csharp
public RequestLoggingMiddleware(RequestDelegate next, ILoggerFactory loggerFactory)
{
    _next = next;
    _logger = loggerFactory.CreateLogger<RequestLoggingMiddleware>();
}
```

I set the `RequestDelegate` local added in the previous step and create a new MEL `ILogger` for my middleware class.

Finally, add a new `Invoke` method:

```csharp
public async Task Invoke(HttpContext context)
{
    try
    {
        await _next(context);
    }
    finally
    {
        _logger.LogInformation(
            "Request {method} {url} => {statusCode}",
            context.Request?.Method,
            context.Request?.Path.Value,
            context.Response?.StatusCode);
    }
}
```

This is where the magic happens. The method invokes the next piece of ASP.NET Core middleware and logs an information message with the HTTP method, URL and status code. To avoid repeating myself, check out [Error Logging Middleware](https://blog.elmah.io/error-logging-middleware-in-aspnetcore/) for a detailed explanation of how ASP.NET Core middleware works.

Here's the source for the entire class:

```csharp
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using System.Threading.Tasks;

namespace My.Service.Logging
{
    public class RequestLoggingMiddleware
    {
        private readonly RequestDelegate _next;
        private readonly ILogger _logger;

        public RequestLoggingMiddleware(RequestDelegate next, ILoggerFactory loggerFactory)
        {
            _next = next;
            _logger = loggerFactory.CreateLogger<RequestLoggingMiddleware>();
        }

        public async Task Invoke(HttpContext context)
        {
            try
            {
                await _next(context);
            }
            finally
            {
                _logger.LogInformation(
                    "Request {method} {url} => {statusCode}",
                    context.Request?.Method,
                    context.Request?.Path.Value,
                    context.Response?.StatusCode);
            }
        }
    }
}
```

The only missing part now is configuring the middleware. You'd normally create an extension method to help, but in this case I'm taking the easy path and call the `UseMiddleware` method directly in my `Startup.cs` class:

```csharp
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    ...
    app.UseMiddleware<RequestLoggingMiddleware>();
    ...
}
```

That's it. Every request now generates a log message in the configured log. In my case, I'm logging to elmah.io. I'm using the [Elmah.Io.Extensions.Logging](https://www.nuget.org/packages/Elmah.Io.Extensions.Logging/) NuGet package to do the actual logging and the [Elmah.Io.AspNetCore.ExtensionsLogging](https://www.nuget.org/packages/Elmah.Io.AspNetCore.ExtensionsLogging/) package to decorate all log messages with HTTP contextual information.

I normally don't log information messages from production, since ASP.NET Core generates a lot of info messages out of the box. In this example, I want to log all `Warning`, `Error`, and `Fatal` messages, but also the new `Information` messages generated from the new middleware class. This can be set up by including the following config in `appsettings.json`:

```json
{
  "Logging": {
    "ElmahIo": {
      "LogLevel": {
        "Default": "Warning",
        "My.Service.Logging": "Information"
      }
    }
  },
  ...
}
```

Inside the `Logging` section, I've included an `ElmahIo` section. If you are using `Console` or another logger, you will need to replace the section name with the correct one. By including a `Default` log level and setting the value to `Warning`, I make sure that only `Warning` messages and up are logged. For the specific namespace `My.Service.Logging` I also allow `Information` messages.

To use the configuration from the `Logging` section, call the `AddConfiguration` method as part of your logging initialization in the `Program.cs` file:

```csharp
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
    WebHost.CreateDefaultBuilder(args)
        .UseStartup<Startup>()
        .ConfigureLogging((ctx, logging) =>
        {
            logging.AddConfiguration(ctx.Configuration.GetSection("Logging"));
            ...
        });
```

Everything is done in less than 30 minutes and ready to go to production. Here's an example of a log message stored in [elmah.io](https://elmah.io):

![](https://blog.elmah.io/content/images/2020/01/request-logging.png)

If you are using another logger, the view will be different but you will be able to see all of the same information.

## Would your users appreciate fewer errors?

elmah.io is the easy error logging and uptime monitoring service for .NET. Take back control of your errors with support for all .NET web and logging frameworks.

➡️ [Error Monitoring for .NET Web Applications](https://elmah.io/?utm_source=devto&utm_medium=social&utm_campaign=devtoposts) ⬅️

This article first appeared on the elmah.io blog at https://blog.elmah.io/asp-net-core-request-logging-middleware/