I am a green developer trying to get a handle (har-har) on error handling in a large multi-layer java application. There are many situations where I believe that chaining exceptions through several layers is a good idea; e.g. when a failure in calling out to some external service at the lowest layer causes problems all the way up in the view:
The most important exception, the one whose stacktrace I really want to examine, is the last in the chain; that I made a bad request and I need to fix foo's formatting. But when I let this exception bubble up through the layers, nicely chained in exceptions that are meaningful to each layer... when I eventually catch and log the thing, the default logging behavior always shows me gobs of detail about the outermost exception, and maybe 5 lines of stacktrace of the root cause.
This makes me want to log exceptions as they happen, AND let them bubble up, but then you end up logging most things twice; when they happen and when they are eventually caught.
What is the best practice here?
I would recommend a different approach of exception management. At the top most layer of the application (like request entry point) create a try catch block to call any runtime exception. It's preferable that you have 2 catch blocks: - for your application specific (business) exceptions - for the rest (exception)
As you can see youl'l need to introduce you own exception type that you'll extend to create different exceptions for different purposes. For example you can create a custom exception for every layer of the application, for each integrarion etc. Use unchecked exeptions as they all will be handled on the top level. When any exceptional situation ocures (catch of low level exception) you should: - Put a description associated with the business context (for example "failed to load account data from DB" - Add description of the original exception (for example "Original error: Connection to DB failed") - Pass original exception to your exception in order to not loose the trace - Throw and forget. In other words top level catch block is responsible to handle it appropriatelly (rollback a transaction, show error message or anything else you may need
Great question, I'm curious about other answers you will get.
I tend to take a "more is better" approach, and log at each step of the way. Does this make large logs? Yes, but when you're debugging an issue in a large Java application, you will be thankful for every log line you have. There are also tools (at the very least the grep
, awk
, sed
trio) to help you filter through large files.
Another technique is to write this logging code, but turn it down (if you're using something like log4j, to the TRACE
level). This way, should you run into an issue, you may not have the logs available, but it's a one line change (to lower the logging threshold) and you start generating a wealth of data for debugging.
In tandem with the previous technique, most logging libraries (again I'm falling back on my knowledge of log4j here) allow you to tune the log levels of different java packages. This means that you can write all of these "catch and rethrow" log lines as trace, and turn down the logging on lower level packages to WARN
while you keep upper level packages at DEBUG
or TRACE
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With