Java Tricks: Find out who invoked you

There is a setting in the log4j framework that allows you to log the exact location of where the logger was invoked (I’d provide a link to the related documentation, but I can’t find it; the lo4j site is a horrible mess). I always wondered how that works, here’s how:

public class Invoker {

        public static void main(String[] args) {
                System.out.println("Invoked from: " + invoker());
                System.out.println("A bit more indirect: " + test());
        }
       
        private static String test() {
                return invoker();
        }

        public static String invoker() {
                try {
                        throw new RuntimeException();
                } catch(RuntimeException e) {
                        return e.getStackTrace()[1].toString();
                }
        }
}

The output format matches the Exception#printStackTrace format, so that you can click on the result in the Eclipse console and it opens the file at the correct line:

Invoked from: Invoker.main(Invoker.java:4)
A bit more indirect: Invoker.test(Invoker.java:9) 

Based on the comment attached to the code where I found this, there is an easier way to obtain the stack in Java 1.5. And with a bit of searching, I found the getStackTrace method, added to Thread in 1.5. With that, the code becomes even simpler:

public class Invoker {

        public static void main(String[] args) {
                System.out.println("Invoked from: " + invoker());
                System.out.println("A bit more indirect: " + test());
        }
       
        private static String test() {
                return invoker();
        }

        public static String invoker() {
                return Thread.currentThread().getStackTrace()[2].toString();
        }

} 

Note that the call to Thread#getStackTrace ends up on the stack, too, so the interesting StackTraceElement is at index 2, not 1 as before.

A final warning: While this is immensly helpful for log-based debugging, the performance hit should be kept in mind. The log4j documentation warns about that as well, though I suspect that the Java 1.5 methods will have less impact than the try-catch approach. And some very primitive benchmarking proved me wrong…

-Jörn

No more comments.
  1. 12. February 2010 |21:25

    Be warned that the result of getStackTrace() is not specified and behaves differently on other JVMs, e.g. sometimes the invoker is at index[2] and sometimes at index[1]. Also, from my findings the performance impact is severe, esp. in logging. You should therefore always use s.th. like log.isDebugEnabled() around such calls.

  2. 13. February 2010 |00:10

    Thanks for the info Mike. So the behaviour is at least consistent on Sun JVMs? Thats usually good enough, at least for the stuff I’m working on.