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…
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.
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.