How to exclude specific exception types from Serilog?
Asked Answered
C

4

16

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

Cartercarteret answered 29/8, 2018 at 19:17 Comment(3)
Can you describe your Serilog configuration in details (e.g. sinks, global filters for asp.net core)Pani
The answer should not have been accepted. It still does not answer your question that you clarified in Edit2Beveridge
Your .Filter.ByExcluding(ObjectDisposedException) approach works for me. In fact it solves a problem I've been having. I have exception-handling middleware that logs some types of exceptions in a certain format, but when I re-throw the exceptions Serilog logs them again in its standard format. I need to re-throw them to preserve the application's proper behaviour on exception, but it's been annoying to have these exceptions logged twice. So thank you. Your question actually answers itself ... and you've solved my problem!Ubiety
H
1

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://learn.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.

Hierophant answered 29/8, 2018 at 19:38 Comment(1)
I think I will just do this. Thank you.Cartercarteret
J
27

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

Log.Logger = new LoggerConfiguration()
    .MinimumLevel.Debug()
    ...
    .Filter
      .ByExcluding(logEvent => logEvent.Exception is OperationCanceledException)
    ...
    .CreateLogger();

Jemappes answered 13/10, 2019 at 22:45 Comment(2)
what's the appsettings version of this - trying to get the syntax down for the Filter.ByExcluding appsettingsRubin
logEvent.Exception is OperationCanceledException is more concise and will also cover inherited types. No null check is needed.Reticule
H
1

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://learn.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.

Hierophant answered 29/8, 2018 at 19:38 Comment(1)
I think I will just do this. Thank you.Cartercarteret
C
0

below code may help you

catch (Exception ex)
{
    if (ex.GetType() != typeof(ExceptionTypeToExclude) ) {
         Log.Fatal(ex, "Host terminated unexpectedly");
    }
    return;
}
Cuman answered 29/8, 2018 at 19:36 Comment(0)
U
0

If you are configuring your Serilog from appsetting.json using configuration.ReadFrom you can use Serilog.Expressions.

{
  "Serilog": {
    "Using": ["Serilog.Expressions"],
    "Filter": [
      {
        "Name": "ByExcluding",
        "Args": {
          "expression": "Exception is ExceptionTypeToExclude1 or ExceptionTypeToExclude2"
        }
      }
    ]
  }
}
Unemployable answered 13/8, 2024 at 6:42 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.