Logging exceptions without crufty code: a comparison of strategies

January 7th, 2009 Brian Gray, Consultant

You get in to work, grab a cup of coffee, and start your day with a nice, simple, easy-to-read method.  Like this one:

public Long createUser(String username) {
    User user = new User(username);
    return userDao.create(user);
}

Then you think about debugging during development, production support, etc., and decide it would be best to get a stack trace on failure.  So you refactor:

public Long createUser(String username) {
    User user = new User(username);

    try {
        return userDao.create(user);
    } catch (DatabaseException e) {
        LOG.error("Error saving user with username " + username, e);
        throw e;
    }
}

The Problem

To start, your nice, easy-to-read method has become cruftier.  More importantly, you now have more lines devoted to logging exceptions than you have for creating a user. And what if after you write the above method, Bob in the next cube writes another method in which he doesn’t remember to log the error, and Becky uses info level logging instead of debug?

The Solutions

In this post, I will describe four solutions that I have seen for solving this problem and describe some pros and cons for each. The four solutions are, in no particular order:

  • Aspect-Oriented Programming (AOP): define an advice class that gets executed whenever any method throws an exception.  Log the exception in the advice.
  • The catch-all method (i.e. highest interface/tier logging):  Log no exceptions at lower levels and allow all runtime exceptions to bubble up.  At the highest tier (such as a web UI, main executable, Web Service, etc.), catch all exceptions and log them.
  • Self-logging exceptions:  Define a base exception class that logs itself in the constructor (takes a message and possibly a Class as parameters).  All exceptions in the application must extend from this base class (3rd party or library exceptions must be caught and re-thrown), but no application code should ever log an exception.
  • Developer logging: As above, each developer logs exceptions as they see fit.

How Do They Stack Up?

Here are what I (and a few other Summa consultants) consider the strengths and weaknesses of each approach:

Pros Cons
AOP
  • Non-invasive (code does not change)
  • Can log specific info about throwing method (including parameters) if desired
  • Could catch any exception (even from JDK or 3rd parties), as long as it’s from a proxied method (see cons)
  • Could log intelligently (e.g. log NullPointerExceptions but ignore DataIntegrityViolation)
  • Each exception logged only once (unless the exception is caught and rethrown in a method up the stack, but why?)
  • Will only work on classes that can be proxied (my familiarity here is with Spring AOP — let me know if this is easier with AspectJ or another solution).
  • Proxied classes make debugging much more difficult. Troubleshooting problems (an exception was thrown but I don’t see a stacktrace!) also becomes more complicated.
  • Difficult for the next developer to pickup and understand if he or she has not used AOP previously.
The catch-all method
  • Non-invasive
  • Guaranteed to catch every exception
  • Regular Java exceptions can be used (e.g. java.lang.IllegalArgumentException)
  • Easy to see where the exception handling is taking place
  • If there are multiple interfaces, then similar code is required in many places (web, batch, web services, unit tests, etc.)
  • No info about the throwing method (it will be in the stack trace, but it won’t be logged as coming from that class, no info about the parameters).
Self-logging exceptions
  • Every exception will be logged exactly once
  • Easy to customize - each new exception can have its own message and extra fields, or just call super
  • No higher level setup, works the same on all tiers
  • Provides method-level info if the class and any relevant parameters are passed into the exception constructor
  • Requires every exception to be wrapped
  • If a JDK or 3rd party exception gets through unwrapped (such as an NPE), it may not be logged
Developer logging
  • Any info can be logged about the method, class, parameters, etc.
  • Easy to understand and see where logging is occurring
  • No higher level setup, works the same on all tiers
  • Can use JDK or custom exceptions
  • Very invasive - logging statements all throughout the code
  • Very inconsistent on large development teams as each developer has their own ideas about logging
  • Exceptions may not be logged

So who wins?  It depends.  How large is the team?  How much time do you have to set up a solution?  How much experience do you have with similar approaches?

The real answer is that whatever you choose, some thought needs to go into your exception handling, and it should happen early.  Otherwise, you default to the wild west, and changes to this approach halfway through your development cycle are not only expensive, but also lower the value of your final choice.

Share and Enjoy:
  • Digg
  • Reddit
  • del.icio.us
  • Google
  • description
  • LinkedIn

Entry Filed under: Software Development

2 Comments Add your own

  • 1. Ben Northrop  |  January 7th, 2009 at 1:21 pm

    Great post.

    One additional disadvantage with AOP exception logging is the ability to add context to the logs. For example, if you wanted to log the state of some class data member when an exception occurred:


    public class A {
    public int x;


    public void createUser(String username) {
    try {
    doSomething();
    } catch(SomeException e) {
    LOG.error("some exception when x = " + x, e);
    }
    }
    }

    AOP logging is sometimes “one size fits none”.

  • 2. Brian Gray  |  January 7th, 2009 at 4:47 pm

    That’s true. Catch all doesn’t really help with that (in fact, it’s the least informative of the methods), but the self-logging exceptions would allow you to pass in any info you’d like.

Leave a Comment

Required

Required, hidden

Some HTML allowed:
<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Trackback this post  |  Subscribe to the comments via RSS Feed


Pages

Categories

Most Recent Posts

Feeds

  Subscribe in a reader

Calendar

January 2009
M T W T F S S
« Dec   Feb »
 1234
567891011
12131415161718
19202122232425
262728293031  

Tags