Thursday, January 19, 2006

Please log

I respectfully take exception to Benjamin Booth's Pragmatic Exceptions tip #6 as published in the February 2006 DDJ (page 24).

He there recommends that you not both log and throw an exception.

Bad. This will most likely result in seeeing the same exception message at very different points in your program's execution. The problem is, it's the same error!


No, it's not. It's the same exception. It's not necessarily the same error. At least, not in the ways that matter. Context matters.

Ideally, your code will log its progress and the problems it encounters. Ideally, it will do so providing locally appropriate context. "Here's the exception I encountered, here's what I was doing when I encountered it, and here's what it means to me."

Remember your purpose in programming your module and in adding logging statements in the first place. The logging statements are to make the code more literate and to support current and future development and debugging. Logging the exceptions encountered, especially with appropriate context, is in keeping with this purpose.

When I encounter your code's exception, will it log the error before allowing it to escape the module, or will it just throw it up hoping that the outside module will log it appropriately?

I'm much happier to see an error logged twice with appropriate context, than not logged at all.

Benjamin wrote:
"[both logging and throwing an exception] sends an ambivalent message to callers of your function. The pitcher is saying to the catcher, "I'll log this now but, well, I'm not sure, it could be fatal, perhaps you should deal with it too?" This isn't only weak minded, it's also lazy and pathetic."


Wow. I think that's too harsh. I also think it's just wrong.

What my code does with an exception before it throws it is none of your code, the calling code's, business. The method signature and logging behavior are only loosely related at best. Certainly someone should be sure to log the exception, and I might provide a guarantee about whether my method will log it before it throws it to ease your handling burden. But exceptions are about much more than logging the exceptional condition. When my method throws an exception, it does so to communicate a result, and you, the caller, are advised of this result by receiving the exception, and have an opportunity to truly handle it, rather than just log it.

I wrote a letter to DDJ in response to this tip.

1 Comments:

Blogger Andrew Petro said...

I wrote a letter to DDJ on this topic and will mail it tomorrow. It reads:

Dr. Dobb’s Journal
2800 Campus Drive
San Mateo, CA 94403
Date 1/22/06

Dear DDJ,
I take exception to Pragmatic Exceptions Tip #6 (DDJ, February 2006).

The presentation is needlessly harsh (“this isn’t only weak minded; it’s also lazy and pathetic”) and the advice presented is poor.

Components logging exceptions prior to throwing them is an opportunity to record the functioning of the module, preferably in context. “This is what I was doing, this is the exception I encountered, this is the relevant context, and this is what I’m doing about it.”
Tip #6 confuses the internal behavior and best-practices implementation of a module (log exceptions encountered) with the exernal-facing API exposed by that module. When a module declares to throw and actually throws an exception, it is communicating with its caller and providing an opportunity for that caller to truly handle, rather than merely log, the exceptional condition. Often a component’s local perspective on and recovery from an exceptional condition is only part of the story, with the calling code also needing to respond to the exceptional condition. Whether I log an exception is an internal consideration of what will make my component reasonably literate and will ease in its development and troubleshooting. Whether I throw an exception is a consideration of what API I am exposing and what capabilities I expect my caller to require. The concerns are orthogonal and it is often the best solution to both log an exception and to throw it.

As a concrete example: database access code on encountering an exception might justifiably locally catch and handle the exception, closing allocated resources and logging the exception in the local context (what SQL were we executing? Exactly what data access module encountered the failure, doing what?) and might justifiably also throw the exception, allowing the calling code to consider it in perspective of the larger task under way and even report the failure to the end user (“Your account is not available at this time. Please try again later.”).

With the advent of powerful, configurable logging systems and a growing professional expertise in using these tools, the pragmatic programmer should include appropriate logging in all the code she writes, confident that programmers will be able to understand and filter the logging appropriately to generally monitor the system or to focus on the behavior of particular modules.

If a component does not log the exceptions it throws (in context) then a logging environment focusing on that component will fail to report the exceptions it threw and thereby miss an important part of the behavior of the component under scrutiny. While this can be rectified by carefully applied Aspects, this increases the burden on the troubleshooting programmer and still misses the opportunity to log the exceptions with the local context provided by the forward-looking programmer.

Taking care not to log, removing logging statements and fine-tuning logging to ensure that particular exceptions are logged once and only once, is a poor use of programmer time that will often reduce, rather than improve, the value of a body of code. Logging an exception in context before throwing it is literate, forward-looking, and a reasonable investment in the quality of a module implementation. This sort of logging is neither “lazy” nor “pathetic”.

Modern logging APIs and tools afford the luxury of a component developer adding as much logging as necessary at very low marginal cost. I don’t know about “weak-minded”, but I would suggest that the tools have advanced to the point where a programmer need not think very hard about whether to add a particular piece of logging and can instead focus on adding the logging and using the log tools. Very pragmatic.

Sincerely yours,


Andrew Petro

1:44 PM  

Post a Comment

<< Home