Monday, September 24, 2012

SLF4J doesn't log Exception stackTrace! Why?

A lot of people knowing slf4j do logging with string formatting for several reasons: mainly readability and performance. Using slf4j (and many other logging frameworks, too) we can transform this log statement:
public class LogTest {
    private static final Logger log = LoggerFactory.getLogger()
    public static void main(String[] args) {
        log.info("Main is started with " + args.length + " arguments");
    }
}
into this:
public class LogTest {
    private static final Logger log = LoggerFactory.getLogger()
    public static void main(String[] args) {
        log.info("Main is started with {} arguments", args.length);
    }
}

The log of an exception should always contain the stack trace, so we can write the following code:
public class LogTest {
    private static final Logger log = LoggerFactory.getLogger()
    public static void main(String[] args) {
        log.info("Main is started with {} arguments", args.length);
        try {
            throw new RuntimeException("Do you now to log my stackTrace?");
        } catch (Exception e) {
            log.error("{} No, I don't!", e.getMessage(), e);
        }
    }
}
Are there any errors? No!? Yes, it compiles and runs as you wish... but?! Where is the stackTrace for the RuntimeException raised? The answer is simple: unfortunately slf4j does not provide methods with signatures like these:
  • [logLevel](String format, Object object, Throwable t)
  • [logLevel](String format, Object[] object, Throwable t)
So one solution is to write code this way:
public class LogTest {
    private static final Logger log = LoggerFactory.getLogger()
    public static void main(String[] args) {
        log.info("Main is started with {} arguments", args.length);
        try {
            throw new RuntimeException("Do you now to log my stackTrace?");
        } catch (Exception e) {
            log.error(e.getMessage() + " Yes, I do!", e);
        }
    }
}

Don't you like it? Below the elegant solution:
public class LogTest {
    private static final Logger log = LoggerFactory.getLogger()
    public static void main(String[] args) {
        log.info("Main is started with {} arguments", args.length);
        try {
            throw new RuntimeException("Do you now to log my stackTrace?");
        } catch (Exception e) {
            log.error("{} Yes, I do!", new Object[] {e.getMessage(), e});
        }
    }
}

The moral of the story is: always be careful about methods' signature.

Related posts:

No comments:

Post a Comment