Stan,

I like your solution quite a lot. I'd thought about how to accomplish
this, but couldn't come up with something so elegant.

My solution is woefully low-tech, but does avoid the wrong
class/category name problem. I have the following lines of code I use
to insert into each class:
-----------------------------------------------------------------------------------
import org.apache.log4j.Category;
    static Category logger = Category.getInstance
({thisclassname}.class.getName());
        if (logger.isDebugEnabled()) logger.debug("...");
-----------------------------------------------------------------------------------
Insertion can occur via cut & paste or keyboard macro, depending upon
one's preference.

The "solution" is that the "{thisclassname}" in the second line won't
compile, so it needs to be replaced with the class name, a really
simple sharp short shot of clicks & ctrl-c/v.

I like yours, though, and am interested in the answer to your stack
frame question.

I'm curious, though, have you noticed any effect from what seems to be
a fair bit of indirection involved with resolving the logging class'
name for each log statement? My primary interest is in addressing the
objections I see coming from the managers who think the logging
overhead is already nearly too big a performance hit.

Regards,

  Chris Gerrard





                                                                                       
                            
                    "Silvert,                                                          
                            
                    Stan"                To:     [EMAIL PROTECTED]         
                            
                    <Stan@mediaoc        cc:                                           
                            
                    ean.com>             Subject:     Clever Logging?                  
                            
                                                                                       
                            
                    01/14/2002                                                         
                            
                    03:39 PM                                                           
                            
                    Please                                                             
                            
                    respond to                                                         
                            
                    "Log4J Users                                                       
                            
                    List"                                                              
                            
                                                                                       
                            
                                                                                       
                            



I am responsible for defining standards around how our developers use
Log4J.
When our company started using Log4J a couple of months ago, I told
developers to use this technique in their code:

public class MyClass {
    private static final Category LOG =
Category.getInstance(MyClass.class.getName());
    private static boolean DEBUG() { return LOG.isDebugEnabled(); }
}

So, for all debug statements, write something like this:
  if (DEBUG()) LOG.debug("The value of my vars are: " + v1 + " and " +
v2);

If not a debug statement, just do something like this:
    LOG.info("My info message");

That all worked fine, except that developers would make the mistake of
putting the wrong class name inside the getInstance() method.  This
would
usually happen when they would cut and paste code.

So, one of our developers came up with a clever solution to cut down
on the
mistakes.  He created a logging utility that could automatically read
the
stack frames, discover which class logged the message, and invoke
logging
from the proper Category.

Here is how he did it:

public class LogUtil {
    /**
     * Extends <code>java.lang.SecurityManager</code> to provide the
<code>getClassName()</code>
     * method.
     */
    private static class ClassGetter extends SecurityManager {
        // Inner class necessary because getClassContext() is
protected

        /**
         * Returns the name of the calling class.
         * @return  the name of the calling class
         */
        public String getClassName() {
            // getClassContext() returns the current execution stack
trace
            // as an array of classes -- the element at index 0 is the
class
            // of the currently executing method, the element at index
1 is
            // the class of that method's caller, and so on. So, 0 is
going
            // to be this class (ClassGetter), 1 will be LogUtil, and
2 will
            // be the magic number we are after.
            return getClassContext()[2].getName();
        }
    }
    private static ClassGetter classGetter = new ClassGetter();

    /**
     * Returns the name of the calling class.
     * Intended to be used from static methods or initializers to
automagically
     * determine the calling class's name.
     * @return  the name of the calling class
     */
    public static String getClassName() {
        return classGetter.getClassName();
    }


///////////////////////////////////////////////////////////////////

    /**
     * Returns <code>true</code> if debugging is enabled for a given
category
     *
     * @return  <code>true</code> if debugging is enabled,
     *          <code>false</code> if not
     */
    public static boolean DEBUG() {
        Category cat = Category.getInstance(classGetter.getClassName
());
        return cat.isDebugEnabled();
    }


///////////////////////////////////////////////////////////////////

    /**
     * Logs the given message with <code>DEBUG</code> priority, to the
category
     * automagically derived from the calling class name.
     *
     * @param  msg  the message to log
     */
    public static void debug(String msg) {
        Category cat = Category.getInstance(classGetter.getClassName
());
        cat.debug(msg);
    }
}

This looks very nice and seems to solve all the problems quite well -
except
for one thing.  I have been reading about how some JIT's can remove
stack
frames during optimization.  This would cause messages to once again
be
logged under the wrong Category.

My questions to the folks on this list are,
What is your opinion of both techniques?
Do you know other developers who have tried the "clever" approach and
run
into the "disappearing stack frame" problem?
Is there another solution we are overlooking?  (short of disabling cut
and
paste from everyone's IDE)

Thanks in advance for your input.

Stan Silvert


--
To unsubscribe, e-mail:   <
mailto:[EMAIL PROTECTED]>
For additional commands, e-mail: <
mailto:[EMAIL PROTECTED]>






--
To unsubscribe, e-mail:   <mailto:[EMAIL PROTECTED]>
For additional commands, e-mail: <mailto:[EMAIL PROTECTED]>

Reply via email to