Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to exclude specific exception types from Serilog?

I am using Serilog to log information about an asp.net core 2.1 application hosted on IIS. When exceptions occur, I am informed by email. The thing is, some exceptions happen without hurting the application at all and I don't want to be noticed each time it happens.

Is there a way in Serilog to exclude a specific exception type from being logged?

EDIT :

Here is how I configured Serilog in my Program.cs :

using System;
using System.Data;
using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Serilog;
using Serilog.Sinks.MSSqlServer;

namespace Some_App
{
    public class Program
    {
        public static void Main(string[] args)
        {
            var configuration = new ConfigurationBuilder()
                .AddJsonFile(Environment.CurrentDirectory + "/appsettings.json")
                .Build();

            var columnOptions = new ColumnOptions {
                AdditionalDataColumns = new System.Collections.ObjectModel.Collection<DataColumn>
                {
                    new DataColumn {DataType = typeof (string), ColumnName = "email", DefaultValue = "[email protected]", MaxLength = 4000},
                    new DataColumn {DataType = typeof (string), ColumnName = "subject", DefaultValue = "Application error", MaxLength = 4000},
                }
            };
            columnOptions.Store.Remove(StandardColumn.Level);
            columnOptions.Store.Remove(StandardColumn.LogEvent);
            columnOptions.Store.Remove(StandardColumn.Message);
            columnOptions.Store.Remove(StandardColumn.MessageTemplate);
            columnOptions.Store.Remove(StandardColumn.Properties);
            columnOptions.Store.Remove(StandardColumn.TimeStamp);
            columnOptions.Exception.ColumnName = "message";
            columnOptions.Id.ColumnName = "id";
            columnOptions.DisableTriggers = true;

            Log.Logger = new LoggerConfiguration()
                .MinimumLevel.Debug()
                .MinimumLevel.Override("Microsoft", Serilog.Events.LogEventLevel.Information)
                .Enrich.FromLogContext()
                .Filter.ByExcluding(ObjectDisposedException) //What is the right way to tell Serilog to ignore this type of exception?
                .WriteTo.RollingFile("logs\\log-{Hour}.txt", retainedFileCountLimit: 168)
                .WriteTo.MSSqlServer(
                connectionString: configuration.GetConnectionString("DefaultConnection"),
                tableName: "emailtosend",
                columnOptions: columnOptions,
                restrictedToMinimumLevel: Serilog.Events.LogEventLevel.Error
                )
                .CreateLogger();

            CreateWebHostBuilder(args).Build().Run();
        }

        public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
            WebHost.CreateDefaultBuilder(args)
                .UseStartup<Startup>()
                .UseSerilog();
    }
}

EDIT 2:

@reza baiat, @GoldenAge & @Alessandro Di Cicco: Of course your answers would allow me to handle exceptions, but just the ones occurring outside Serilog's logger. Serilog is a logging library that replaces Microsoft's default one and enables me to omit all the Try/Catch inside the rest of my code as it will log them all in (in my case) a log file and an SQL table. The thing I'm trying to do is to tell Serilog to not log, for example, ObjectDisposedException exceptions that happens inside the critical code. I guess the Try/Catch was confusing in my code so I'll drop it from my example as it is not relevant. Serilog will catch any exception thrown once the application is built and run. What I was thinking was maybe an additional Serilog config line like this : .Filter.ByExcluding(ObjectDisposedException) or something like that. Is it possible?

Thank you

like image 539
Jimmy Jacques Avatar asked Aug 29 '18 19:08

Jimmy Jacques


2 Answers

Adding a filter when you declare your LoggerConfiguration should work just fine:

Log.Logger = new LoggerConfiguration()
    .MinimumLevel.Debug()
    ...
    .Filter
      .ByExcluding(logEvent => 
         logEvent.Exception != null && 
         logEvent.Exception.GetType() == typeof(OperationCanceledException))
    ...
    .CreateLogger();

like image 147
Grzegorz Smulko Avatar answered Oct 04 '22 22:10

Grzegorz Smulko


EDIT

Let me clarify that I was mostly thinking about the production code where I still stand on what I wrote before that every unhandled exception should be logged by the logger to be able to catch some edge cases that normally you would never predict. If you disagree please write down a comment so we can discuss it. For other environments e.g localhost you can use the Grzegorz Smulko answer

ANSWER:

Is there a way in Serilog to exclude a specific exception type from being logged?

I would just create an empty catch for that specific type of exception and do just nothing inside the body e.g.

try
{
    // invoke some function/s
}
catch (BlahException)
{
    // do nothing
}
catch (Exception e)
{
    Log.Fatal(ex, "Host terminated unexpectedly");
    // do something
}
finally
{
    Log.CloseAndFlush();
}

If you want to ignore more exceptions I would create some extra function which checks if you want to log this type of error or not.

// list of error codes:
// https://docs.microsoft.com/en-gb/windows/desktop/Debug/system-error-codes
public static bool IgnoreError(int errorCode)
{
    switch (errorCode)
    {
        case 16389:
            return true;
        case 16387:
            return true;
        default:
            return false;
    }
}

then inside the catch block, you can pass the exception code to this method. e.g.

try
{
    throw new ArgumentNullException("value");
}
catch (Exception e) 
{
    // Using an AND operation will retrieve the error code from the HRESULT:
    if (IgnoreError(e.HResult & 0xFFFF))
    {
        return;
    }
    Log.Fatal(e, "message");
}

I think every unhandled exception should be logged by logger because this is its main responsibility. I can't see any advantage to ignore logging unhandled exception and there shouldn't be such a setting, this is just too scary! If you know that exception can occur in a given place, then you should create the try and catch blocks to catch as many expected exceptions as possible. Then you can make a decision if you want to ignore some specific exception or no in the catch block.

like image 37
GoldenAge Avatar answered Oct 04 '22 22:10

GoldenAge