Handling exceptions, is this a good way?

We're struggling with a policy to correctly handle exceptions in our application. Here's our goals for it (summarized):

  • Handle only specific exceptions.
  • Handle only exceptions that you can correct
  • Log only once.

We've come out with a solution that involves a generic Application Specific Exception and works like this in a piece of code:

try {
  // Do whatever
}
catch(ArgumentNullException ane)
{
  // Handle, optinally log and continue
}
catch(AppSpecificException)
{
  // Rethrow, don't log, don't do anything else
  throw;
}
catch(Exception e)
{
  // Log, encapsulate (so that it won't be logged again) and throw
  Logger.Log("Really bad thing", e.Message, e);
  throw new AppSpecificException(e)
}

All exception is logged and then turned to an AppSpecificException so that it won't be logged again. Eventually it will reach the last resort event handler that will deal with it if it has to.

I don't have so much experience with exception handling patterns... Is this a good way to solve our goals? Has it any major drawbacks or big red warnings?

Note: One of the drawbacks of this is that after the first catch you lose the ability to handle an specific exception (if you call a method that calls another method and the second one throws an exception you're not able to handle it) but I've found I've never done this any way ... I only handle exceptions with one level of depth ...


Solution 1:

If you log the exception too near the time it is first thrown, you won't be logging the full stack trace.

Handle exceptions (that is, fix them), as close as possible to when they were thrown. Gather information about the context as soon as possible to when they were thrown. But allow exceptions to propagate up to where they can actually be handled. Logging is a last-resort sort of handling, so it should occur in the outer layers of application subsystems.

This should eliminate the need for an application-specific exception used as a marker to not log an exception which shouldn't have been caught to begin with.

Solution 2:

Don't log an exception and then re-throw it - it is the callers responsibility to handle / log any exceptions that you generate.

Only catch an exception to handle it (for example to log it), or add context specific information.