I'm sorry if I gave you the wrong impression, but I already fully understand the consequences and tradeoffs of this way to obtain a logger.  Since there is *NO* consequence to 2 simultaneous calls (all logging implementations do not init another logger, including commons-logging LogFactory), why bother?

-Kevin Ross

Kevin Smith wrote:
Here's the threading issue I see:

public class DatabaseManager
{
   private transient Logger logger;
   
   public Database getDatabase() {
      Logger logger = getLogger();
      logger.debug("Getting database");
      // do something here and return database
   }
   protected Logger getLogger() {
      if(logger == null)
         logger = LogFactory.getLogger(getClass());

   }
}

If two threads call getDatabase() at the same time, there is a chance that you 
could wind up allocating two loggers when only one is needed. Since the 
logger is thread-safe, we need to make getting a reference to a logger 
thread-safe, too.

There are three ways of doing it:

1) Synchronize getLogger() - This introduces synchronization overhead every 
time you need a logger.

2) Synchronize all methods that call getLogger() - Ugly.

3) Make the logger a static variable - This moves the initialization of the 
logger to when the class is loaded and thus, removes any threading issues. 
The penalty for such a refactoring is having one line of duplicate code in 
each class:

private static Logger logger = LogFactory.getLogger(Database.class.getName());

That's why I was suggesting using #3.

--Kevin
On Tuesday 19 November 2002 07:52 pm, Kevin Ross wrote:
  
Obtaining loggers might be a bad example. All I'm saying that in my
      
experience, this kind of resource initialization scheme is better off
being thread safe from >the start. It eliminates a whole family of bugs
that you need to worry about down the road.

Agreed, but in the case of logging, I believe you should err on the side
of performance for the greater good, the 80%+ case.  Bothering with
paranoid initialization (synchronization) makes everyone instance pay
the price.

Just got your next message.  I'll say it one more time, WHAT thread
safety issues????  The logger is responsible for thread safety.  I don't
implement synchronization when initializing or using a Logger, because
it is unnecessary for the client to do so.  I haven't for years now, and
I haven't had one problem in organizations with traffic from a few
thousand hits a day, to a few million.

Duplication of code is one of the fundamentally wrong things to do in OO
programming, and I agree, therefore I stay away from it.

-Kevin Ross

Kevin A. Smith wrote:
    
I just thought I'd bring it up. Personally, I err on the side of
paranoia when I can. I don't enjoy debugging threading issues.

If the LogFactory is recycling logger instances, then at most you pay
the price of one extra method call. BUT, if the LogFactory is creating
a new logger per call, then you're (potentially) paying the price of
creating an object that won't be used and an extra method call.

Obtaining loggers might be a bad example. All I'm saying that in my
experience, this kind of resource initialization scheme is better off
being thread safe from the start. It eliminates a whole family of bugs
that you need to worry about down the road.

--Kevin

 -----Original Message-----
From: Kevin Ross [mailto:[EMAIL PROTECTED]]
Sent: Tuesday, November 19, 2002 2:30 PM
To: [EMAIL PROTECTED]
Subject: Re: LogFactory.getLogger()

    Threading issues?? I knew someone would bring that up.  Thread
    safetyness is the responsibility, gladly accepted by a logger
    instance, not on the classes using it.  There is NO reason why we
    need paranoid checking here to only get one instance, since it is
    the responsibility of the logging implementation to even provide
    the instance in the first place.  Do you really think you'll get
    different instances?  Probably not, worst case scenario, you call
    Logger.getLogger() twice and initialize your instance twice in a
    race condition.  Since it is of zero consequence either way, there
    is no reason to do it differently.  If you are particularly
    worried, just do:

    private transient Logger logger = LogFactory.getLogger(getClass());

    You CANNOT use MyClass.class and have MySubClass.class show up in
    the log statements, since this is static.  You must use dynamic
    initialization.

    -Kevin

    Kevin A. Smith wrote:
      
    That doesn't look thread-safe to me. You'd need to somehow
    synchronize access to getLogger() to eliminate a race-condition
    on the if(logger == null) test.

    While its a bit more typing, I prefer:

    private static Logger logger = LogFactory.getLogger(MyClass.class);

    or

    private static Logger logger =
    LogFactory.getLogger(MyClass.class.getName());

    No threading issues and is pretty easy to read and understand.

    --Kevin

        -----Original Message-----
        From: Kevin Ross [mailto:[EMAIL PROTECTED]]
        Sent: Tuesday, November 19, 2002 2:18 PM
        To: Vladimir R. Bossicard; [EMAIL PROTECTED]
        Subject: Re: LogFactory.getLogger()

        As I mentioned in my previous message, this is a poor way to
        obtain a logger, especially if you have deep inheritance
        heirarchies.  Since I'm a big fan of OO programming, and my
        heirarchies are especially deep, I find the static way of
        obtaining a logger invalid.

        Try this:

        public class AbstractLoggable{

            private static transient Logger logger;

            protected Logger getLogger(){

                if( logger == null ){

                    logger = Logger.getLogger(getClass());
                }

                return logger;
            }
        }

        whallah! efficient OO programming with an accessor for
        subclasses and the proper class name to go with it!

        -Kevin Ross

        Vladimir R. Bossicard wrote:
        
Logger.getLogger(getClass()) at least, whether or not you use the
string name is of no consequence.
            
have you ever tried to call a non-static method within a static
reference?

if you get this working:

  private static Log log = LogFactory.getLog(getClass());

I give you a high-five.

-Vladimir

--
Vladimir R. Bossicard
www.bossicard.com
          

  

Reply via email to