So what do you do when you catch an exception? Do you log (or trace) some additional information before either re-throwing the original exception or throwing a new one? If you answer yes to that I think you make a mistake. Or let me rephrase that - you are likely making a mistake.
The rule of thumb for catching exceptions is that you either catch it because you can handle it or because you can add more information. So if you can handle the exception logging/tracing information about the event might be a good idea because there is no more throwing.
But if you catch it because you want to add information, logging is not the right thing to do I think. You should add information by throwing a new exception with the additional information and use the original exception as an inner exception.
Why? Well if you log before throwing what do you think the catcher of your exception will do? Probably log right? So now you have the same error logged twice but in the form of different (or even the same if you re-threw) exceptions.
But you might argue that it would make sense to trace debugging information before (re-)throwing. Well why not keep that information in the exception? Adding information about an error as a trace before throwing is only making it harder to correlate what trace belongs to what error. much easier if you keep it all together.
So there is really two simple rules to follow when it comes to exception catching. If you catch an exception you should either;
- handle the exception, meaning you log/trace as needed and then continue execution without throwing any exception
- or you throw a new type of exception where additional information about the state causing the exception is added.
The bonus rule is that you should never re-throw the original exception. But that is actually not true. no good rule without an exception (no pun intended). Remember how I said in the beginning that logging and throwing likely is a mistake? For certain types of components that wrap other functionality it might be appropriate.
For example if you were to implement a HttpRequestWithRetries, that is a HttpRequest implementation that also does retries. In this case what do you want to do if the request fails? Well before you retry you probably want to update some counter to track retries or failures. You might even want to log the actual error you get so you know why you retry. But the user of this class probably doesn't care. If the final attempt fails the user of this class is likely to just want the same type of error as if the simpler HttpRequest was used. Hence after you logging (or just updating a performance counter) you need to re-throw.
While this is an example of where re-throwing actually might make sense it is still possible to have a nice HttpRequestWithRetries without any re-throwing. You can still throw a RetriesFailedException and stick with following my two rules above. That is why I said breaking my two rules likely means you are making a mistake.
What examples do you have where you log and (re-)throw?
I couldn't agree more, and I wrote as such here https://richiban.wordpress.com/2014/06/06/exceptions-and-error-logging/ back in June.ReplyDelete
In my opinion logging should be done at the application level, and you shouldn't pollute your business logic with logging code. The only exception (pardon the pun) to this rule is when you're swallowing the exception you caught, in which case it *is* your responsibility to log it.