Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Log caught exceptions from outside the method in which they were caught

I have a method like:

public TResult DoSomethingWithLogging<TResult>(Func<TResult> someAction)
{
    try
    {
        return someAction.Invoke();
    }
    catch (Exception ex)
    {
        LogException(ex)
        throw;
    }

This method is used as follows:

var result = DoSomethingWithLogging(() => Foo());

I also want to log exceptions that were caught inside Foo(). I cannot use throw in catch inside of Foo.

How can I catch such exceptions?

Example:

public static string Foo()
{
    try
    {
        return "Foo";
    }
    catch (Exception)
    {
        // I have to log this exception too without adding anything to Foo
        return "Exception caught";            
    }       
}
like image 705
Vladislav Kurkotov Avatar asked Nov 24 '15 12:11

Vladislav Kurkotov


2 Answers

You can bind to the FirstChanceException event. Here's your code modified to demonstrate this:

using System;
using System.Runtime.ExceptionServices;

public class Program
{
  public static void Main()
  {
      AppDomain.CurrentDomain.FirstChanceException += 
      (object source, FirstChanceExceptionEventArgs e) =>
      {
        Console.WriteLine("FirstChanceException event raised in {0}: {1}",
          AppDomain.CurrentDomain.FriendlyName, e.Exception.Message);
      };
    Console.WriteLine("Hello World");
    Console.WriteLine(DoSomethingWithLogging(() => Foo()));
  }

  public static TResult DoSomethingWithLogging<TResult>(Func<TResult> someAction)
  {
    try
    {
      return someAction.Invoke();
    }
    catch (Exception ex)
    {
      Console.WriteLine(ex.Message);
      throw;
    }
  }

  public static string Foo()
  {
    try
    {
      throw new Exception("This will be caught");
      return"Foo";
    }
    catch (Exception) //I have to log this exception too without adding anything too Foo
    {
      return "Exception caught";      
    }    
  }
}

As a rule, I'd be very cautious of this in anything other than debugging scenarios. Once it's caught it shouldn't be considered an exception by code higher up. (Of course, catching it in the first place could have been a logical error, hence this indeed having some value in debugging scenarios).

There are also complications in multi-threaded cases. The code above demonstrates how FirstChanceException works, but if you attached before the call and then detached after it would still be triggered by any exceptions on other threads. Filtering those out could be tricky. I'd probably start by considering looking at the call-stack, but I'm not sure that's the best way.

like image 168
Jon Hanna Avatar answered Sep 28 '22 01:09

Jon Hanna


You can do so by handling the AppDomain.FirstChanceException event:

Occurs when an exception is thrown in managed code, before the runtime searches the call stack for an exception handler in the application domain.

See Catching First Chance Exceptions in Managed Code without being debugged.

like image 43
CodeCaster Avatar answered Sep 28 '22 00:09

CodeCaster