Juan Camilo Sierra
Juan Camilo Sierra

Reputation: 13

Logging in the middleware exception handler

In a layered web application I want to move all error logging from the Domain and Data layers to the global exception handler, but I'm not sure what is the trade-off. I want to remove any logging call and replace it by a more specific Exception (custom if it's necessary) or remove the catching:

try{
   . . . 
}
catch
{
   Logger.Error('Info'); // <-- remove this for a: throw new CustomException('Info', ex);
   throw;                // <-- then, remove this line
}

There is a configured Global Exception Handler as middle-ware in the WebAPI, then as part of the handler method I'm going to log any exception occurred

// Startup.cs
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    app.UseExceptionHandler(
    error =>
    {
        GlobalExceptionHandler.ErrorHandling(error, env);
    });
}

// GlobalExceptionHandler.cs
public static class GlobalExceptionHandler
{
    public static void ErrorHandling(IApplicationBuilder errorApp, IHostingEnvironment env)
    {
        errorApp.Run(async context =>
        {
            .
            .
            .

            Log.Current.Error(exception.Message, () => exception);
        }
    }
}

Could be a better approach to avoid duplicated logging records?

Upvotes: 1

Views: 3970

Answers (1)

Francesco D.M.
Francesco D.M.

Reputation: 2227

In the applications I build I like to use the approach you are suggesting. I'll post the middleware that I use:

using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using MyProject.Interfaces;

namespace MyProject.Middlewares
{
    public class ErrorReporterMiddleware
    {
        private readonly RequestDelegate RequestDelegate;

        public ErrorReporterMiddleware(RequestDelegate requestDelegate)
        {
            RequestDelegate = requestDelegate ?? throw new ArgumentNullException(nameof(requestDelegate));
        }

        public async Task Invoke(HttpContext httpContext, IErrorReporter errorReporter)
        {
            try
            {
                await RequestDelegate(httpContext);
            }
            catch (Exception e)
            {
                await errorReporter?.CaptureAsync(e);
                throw;
            }
        }
    }
}

In this case IErrorReporter is an interface I have defined in the MyProject.Interfaces namespace. I use it to abstract the logging service:

using System;
using System.Threading.Tasks;

namespace MyProject.Interfaces
{
    public interface IErrorReporter
    {
        Task CaptureAsync(Exception exception);
        Task CaptureAsync(string message);
    }
}

Then in the Startup.cs I just add the following line to the Configure method:

app.UseMiddleware<ErrorReporterMiddleware>();

Nothing special but I think it's a clean approach.

Upvotes: 1

Related Questions