We have a method in some widely-used infrastructure code that requires a "name" to be passed in, for use in tracing and logging. Nine times out of ten, the "name" is actually the class and method of the caller, as a static String literal.
I am wondering whether I should auto-generate the name instead. One can get the current call stack and determine the caller's class and method. I am using Java 1.4, so I can't use the new methods on Thread, but I can make a Throwable and do fillInStackTrace(). I can get the StackTraceElements, then.
This will make the many call-sites more concise (good) and save a whole load of static strings (good). But getting the call stack takes the JVM a while, doesn't it?
Does anyone have well-founded views on how slow it is to construct a Throwable and fill in its stack trace? How much does this depend on the depth of the stack?
(Yes, I know I could write some tests, but it is difficult to do accurate performance tests in Java. I thought I'd see if anyone had already done that work.)
Betty Rubble? Well, I would go with Betty... but I'd be thinking of Wilma.
I don't have any hard numbers already available, so I'll let you do the testing part if no one else does. But from my experience, (a) getting class/method/line no. from the call stack is considerably slower than passing it in as a constant, but (b) in the vast majority of cases, this slowness is still negligible to your application, because something else ends up being slower. However there are probably one or two critical bottlenecks in your code where the difference in performance between these approaches becomes significant.
In general I would prefer to know that the call info was generated automatically, correctly, rather than relying on humans to get it right each time.
What I would do is create two versions of the method: a slow but easy-to-use version where you don't need to pass in the extra data (it's obtained from the stack trace), and a fast version where you do pass that data in. For most of your application, you use the slow version. But when you identify that a particular part of your code is presenting performance problems, and they come from the slow method call in that section, then you can replace it with the faster call.
Additionally, in the fast version, you can put in an assert to check that the data being passed in correctly matches the data that would be generated from a stack trace. That way you can enable asserts during testing, and sure it runs a little slower, but you check that the info being passed in is correct. In production of course, you leave asserts disabled as usual.
Does that help? [ August 16, 2006: Message edited by: Jim Yingst ]
I know they show how to do this in page 112 of 'Java Reflection in Action' (a very good book). They even have sample code.
You could also consider using proxy classes (which are also discussed in this book). This is great for getting class information and much more. I use this in my recent release of jamon, to grab method names on the fly to monitor method calls on interfaces. For example method calls on Connections/Statements/PreparedStatements/ResultSets.
You could use a similar approach for logging. Also, I would check out jamon as it isn't quite logging, but if you are logging to find out performance issues then jamon is a better approach.
If you look at the live demo (see the link below) you will see methond signatures. They are all determined on the fly without looking at the call stack. If an exception is thrown I do save the call stack in that case. jamon will also display performance stats for all sql issued by using the jamon jdbc driver.
Here is an example of how easily an interface can be monitored (assume Zip is an interface).