Despite of being named blah-blah, log2 somehow determined the caller class name.

How does it work?

JVM keeps track of calls that have been performed in every thread. In brief it is required for JVM to know, where to return after method execution. This information is usually seen if form of stacktrace.

So, the general idea is to get stacktrace and find a StackTraceElement in it, that corresponds to the caller.

Note, that you don't even have to throw a newly created Throwable. Stacktrace gets filled in when you create a Throwable instance. Moreover, you can reuse same Throwable instance calling its fillInStacktrace() to refresh stacktrace when needed (of course, keeping in mind possible race conditions when shared across threads).

Under the hood, native method Throwable.fillInStackTrace(int dummy) gets called eventually.

Thread.getStackTrace()

Usage is

Thread.currentThread().getStackTrace();

Under the hood, though, this code will create new Exception and obtain stacktrace from it.

Flow is a bit different and more complicated, if method is invoked on a Thread object that doesn't represent current thread. Though, this is not a topic of this post.

So, obviously, the first way is preferable just because the latter one doesn't provide any benefits and does exactly the same thing eventually. Also, Thread.getStackTrace() additionally checks, whether the Thread instance represents current thread, and this is not free (I measured Thread.getStackTrace() method to be approximately 10% slower than Throwable.getStackTrace() on stacktraces of <10 elements).

Parsing stacktrace

As I said, it's a trivial task. StackTraceElement has declaringClass and methodName properties. If we have, say, my.company.CallerUtil, that creates new Throwable for us in its method m(), then we should traverse through stacktrace and find the StackTraceElement that is below the one with