Naming logger instances

I would like to create individual logger instances for each of my subclasses, so I can turn logging on/off class-by-class. I could do it like this:

However, after someone does some cut-and-paste, it'll wind up looking like this:

(note how Child2 accidently uses Child1's logger). To protect against this, I would like the "boilerplate" needed to be as small as possible, and as static as possible. My ideal scenario would be to have code in Parent which ensured that all Child classes would have a logger based on their class name... with NO code required in the child class. I can come CLOSE with this design:

Using that design, no boilerplate is needed in the Child classes. Unfortunately, now "log" is an instance variable instead of a static variable, and can't be used within static functions. That's unacceptable, so I conclude that I'm forced to have at least a declaration in the child class. So I'm hoping for something like this:

...except that I'm not sure how to write setUpLogger(). Is there any (portable) way to find out what my parent class is? I was thinking of some trick with throwing an exception and examining it's stack trace, but it seems like there must be a better way. Any suggestions? -- Michael Chermside

Not really answering your question, but I've often set up loggers with a conditional switch.

The logger checks a static (choke, global) set of switches to see if the switch is set. If not, no logging. Risk: If it is expensive to build the message, we have to build it before deciding not to log. I heard of a system that was using 90% CPU formatting dates for messages that were never written. Bad. Forces developer to sometimes write

Feature: All classes write to same logger, logfile. Is this good or bad for you? Donno if that helped ...

A good question is never answered. It is not a bolt to be tightened into place but a seed to be planted and to bear more seed toward the hope of greening the landscape of the idea. John Ciardi

Michael Chermside
Greenhorn

Joined: Jul 22, 2003
Posts: 11

posted Jul 22, 2003 12:55:00

0

I'm using Java's logging (java.util.logging.*, java 1.3+). It all gets fed to a single file if you want, a "Logger" object is really a particular log identifier, for which the log level and log distribution can be controlled independently. The issue of building the string is, indeed, a very real one. I've measured x5 slowdowns in code due to logging in real code... within a factor of 2 of your 90% figure. The standard solution in java's logging framework is for all log lines lines to look like this:

Frankly, I think that's a BIG PAIN... before java's system existed I built my own and had it down to a managable:

which is enough shorter to be significantly more usable. But Sun didn't consult me.

This is a little bit better, since a cut-and-paste of the if(log == null){...} section would throw a compile time error if the Test class cannot be found--of course, if you are in the same package or in a subclass, then you still have the problem. I would therefore have the boilerplate in a separate text file and have a holder inplace of the new Test() command -- possibly: new _some_class_(). That way, it would garunteedly not compile. Unfortunately (or fortunately?) the developers of Java did not see the need for a way to access the class name inside of a static context. As only cut-and-paste coding would require this, perhaps its a good thing. But it assuredly makes things more difficult. Note that this can also get expensive if the constructor takes a lot of resources--you are essentially creating a "throw-away" object here. I suggest having a separate init() method if you do do this, so that your calls to the constructor are not so expensive. [ July 22, 2003: Message edited by: Joel McNary ]

The problem with this suggestion is that I now need to do something special every time I call the logger (or at least at the top of every method that uses it). This is completely unacceptable... far worse than a one-line not-quite-boilerplate in each class. I did a little research on my own and found that as of java 1.4, Throwable has grown a getStackTrace() method which allows access to the stack trace in a "safe" manner (parsing the string from printStackTrace() is NOT portable and was NOT safe). So I could write setUpLogger() to throw an exception, catch it, then examine the stack trace to pull out the value. Something like this: