Should I catch exceptions for logging purposes?
public foo(..) { try { ... } catch (Exception ex) { Logger.Error(ex); throw; } }
If I have this in place in each of my layers (DataAccess, Business and WebService) it means the exception is logged several times.
Does it make sense to do so if my layers are in separate projects and only the public interfaces have try/catch in them? Why? Why not? Is there a different approach I could use?
This Software Engineering Radio podcast is a very good reference for best practices in error handling. There are actually 2 lectures.
My method is to log the exceptions only in the handler. The 'real' handler so to speak. Otherwise the log will be very hard to read and the code less structured.
Unless you are going to change the exception, you should only log at the level where you are going to handle the error and not rethrow it. Otherwise your log just has a bunch of "noise", 3 or more of the same message logged, once at each layer.
My best practice is:
You will want to log at a tier boundary. For example, if your business tier can be deployed on a physically separate machine in an n-tier application, then it makes sense to log and throw the error in this way.
In this way you have a log of exceptions on the server and don't need to go poking around client machines to find out what happened.
I use this pattern in business tiers of applications that use Remoting or ASMX web services. With WCF you can intercept and log an exception using an IErrorHandler attached to your ChannelDispatcher (another subject entirely) - so you don't need the try/catch/throw pattern.
You may want to log at the highest level, which is usually your UI or web service code. Logging multiple times is sort of a waste. Also, you want to know the whole story when you are looking at the log.
In one of our applications, all of our pages are derived from a BasePage object, and this object handles the exception handling and error logging.
It's good practice is to translate the exceptions. Don't just log them. If you want to know the specific reason an exception was thrown, throw specific exceptions: