2
votes

Whenever an error occurs within our API, we end up getting multiple emails for a single error. Based on the log messages; we can see that these other emails seem to be getting generated because various Microsoft libraries are calling something like _logger.LogError as well as our own _logger.LogError that happens when we handle the error.

For example, when there is a database timeout, we see 4 emails from these different classes:

  • Microsoft.AspNetCore.Diagnostics.ExceptionHandlerMiddleware
  • Microsoft.EntityFrameworkCore.Database.Command
  • Microsoft.EntityFrameworkCore.Query
  • Web.Controllers.ErrorController (Our own exception handler; this is the only one we want to see)

The last one is the only one that has our own error formatting with helpful information in it such as current user, etc. The others just contain a stack trace, which is already within our own formatted email.

We can't figure out for sure where these other log messages are coming from; but the most likely thing I can think of is that within Microsoft's libraries, they are calling _logger.LogError(), and our own NLog configuration is handling all instances of LogError; instead of just handling our own.

How can we prevent these other log statements from being logged and especially emailed to us?

This is our setup in Program.cs:

public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
                    WebHost.CreateDefaultBuilder(args)
                        .UseStartup<Startup>()
                         .ConfigureLogging(logging =>
                         {
                             logging.ClearProviders();
                             logging.SetMinimumLevel(Microsoft.Extensions.Logging.LogLevel.Trace);
                         })
                    .UseNLog();
1

1 Answers

3
votes

You could filter this in .NET Core - because your using the Microsoft.Extensions.Logging integration and Microsoft send the messages to that - and in NLog.

Configure in .NET Core

Modify you config, e.g. appsettings.json. For example at least an error for all Microsoft.* and Warning for Microsoft.EntityFrameworkCore.*

{
  "Logging": {
    "IncludeScopes": false,
    "LogLevel": {
      "Default": "Trace",
      "Microsoft": "Error",
      "Microsoft.EntityFrameworkCore": "Warning"
    }
  }
}

Note, this isn't NLog specific so you can't use the NLog level names. possible level names

Read more about this approach here.

Configure NLog

Or you could configure in the NLog config.

In the NLog.config, edit the <rules> .Those rules are processed from top to bottom.

  • You could filter the namespace with the name attribute (* are allowed)
  • Without a writeTo attribute, the logs are discarded
  • If a rule has final="true" and matching the events, the next rule won't be processed.

For example:

<rules>
    <!--All logs, including from Microsoft-->
    <logger name="*" minlevel="Trace" writeTo="allfile" />

    <!--Skip non-critical Microsoft logs and so log only own logs-->
    <logger name="Microsoft.*" maxlevel="Info" final="true" /> <!-- BlackHole without writeTo -->
    <logger name="*" minlevel="Trace" writeTo="ownFile-web" />
  </rules>

You could read about the nlog.config rules here.

This is also possible with the same approach from code, see here.