Skip to content

Instantly share code, notes, and snippets.

@jasmin-mistry
Created November 29, 2020 20:40
Show Gist options
  • Save jasmin-mistry/7d33bb08c44393444e2434575624fb86 to your computer and use it in GitHub Desktop.
Save jasmin-mistry/7d33bb08c44393444e2434575624fb86 to your computer and use it in GitHub Desktop.
A New Pattern for Exception Logging

True or False?

I’ve defined two helper methods - True and False - to apply side effects and then return a boolean. I recommend using False if the body of your catch is nothing more than throw;. When an exception is thrown, the exception filter is run and the exception is logged, and then the false result means that the exception filter does not match the exception, and the runtime continues searching for a matching handler.

Another scenario is if the catch block actually handles the exception. Say, if we know there is an exception that is safe to ignore. In that case, use the True helper method so that the exception matches the catch block and the stack is unwound and the exception is handled there.

Both helpers are useful in different scenarios.

Caveat

The solution here unfortunately does not work well with async code. This is because async will cause exceptions to be caught and then re-thrown at the point of the await. So, the exception filter runs at the point of the await instead of where the exception was originally thrown.

Tip: The Console logger ignores logging scopes by default; they have to be manually enabled.

public static class ExceptionFilterUtility
{
public static bool True(Action action)
{
action();
return true;
}
public static bool False(Action action)
{
action();
return false;
}
}
public class Program
{
public void Main()
{
try
{
Divide(13, 0);
}
catch (Exception e)
{
_logger.LogError(e, "Unexpected error."); // would NOT print the BeginScope message...
throw;
}
try
{
Divide(13, 0);
}
catch (Exception e) when (False(() => _logger.LogError(e, "Unexpected error."))) // would print the BeginScope message if fa
{
throw;
}
}
private int Divide(int numerator, int denominator)
{
using var _ = _logger.BeginScope("Dividing {numerator} by {denominator}", numerator, denominator);
var result = numerator / denominator;
_logger.LogInformation("Result: {result}", result);
return result;
}
}
public class Startup
{
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
// (begin code changes)
.ConfigureLogging(logging =>
{
logging.ClearProviders();
logging.AddConsole(console =>
{
console.IncludeScopes = true;
});
})
// (end code changes)
.ConfigureServices((hostContext, services) =>
{
services.AddHostedService<Worker>();
});
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment