dev@glassfish.java.net

Re: a more efficient way to initialize Loggers?

From: Ken Cavanaugh <Ken.Cavanaugh_at_Sun.COM>
Date: Thu, 07 Dec 2006 13:19:37 -0800

On Thu, 2006-12-07 at 10:50 -0800, Lloyd L Chambers wrote:

> Please see:
>
> https://glassfish.dev.java.net/issues/post_bug.cgi
>
> ------------
> Initializing all the Loggers at startup
> [ServerLogManager.reInitializeServerLoggers] takes about half a
> second even on a very fast machine.
>
> But observe that many Loggers are never used unless an exception
> needs to be reported. The typical
> idiom is: try { ... } catch( ... ) { _logger.log(...); }.
>
> Thus, a cost is paid even if the logger is never used. Additionally,
> Loggers cannot be initialized at
> startup because the ServerContext is not yet available. This causes
> wasted cycles and leads to a
> transient half-initialized state which much be protected against
> internally.
>
> We might be see some performance improvements by deferring the
> initialization of Loggers. This would
> need to be done in a thread-safe manner. I think the following code
> snippet is thread-safe and would
> remain efficient, especially if applied only to cases where the
> Logger is needed only for exceptions:
>
>
> private static Logger
> getLogger() {
> // if it's non-null, then it's safe to return it
> if ( _logger != null ) {
> return _logger;
> }
>
> // null, synchronize before getting the logger
> synchronized( StringManagerBase.class ) {
> if ( _logger == null ) {
> _logger=LogDomains.getLogger(LogDomains.UTIL_LOGGER)
> }
> }
> return _logger;
> }
>
> This could be captured in a class for convenience:
>
>
> static private final class LoggerGetter {
> private final String mLoggerName;
> private volatile Logger mLogger;
>
> public LoggerGetter( final String loggerName ) {
> mLoggerName = loggerName;
> mLogger = null;
> }
> public Logger
> getLogger() {
> // if it's non-null, then it's safe to return it
> if ( mLogger != null ) {
> return mLogger;
> }
> else synchronized( this ) {
> if ( mLogger == null ) {
> mLogger=LogDomains.getLogger
> (LogDomains.UTIL_LOGGER)
> }
> }
> return mLogger;
> }
> }
>
> and used like this:
> static private final LoggerGetter _loggerGetter = new LoggerGetter
> ( "MyLogger" );
> static private Logger _getLogger() { return _loggerGetter.getLogger(); }
>

We are doing something very similar to this in CORBA, which also has a
lot of logger instances.
The biggest difference for us is that all of the above boilerplate code
is generated from the
ORB log domain descriptions that are stored in a data file. Our latest
round of optimization on
this eliminated a complex hash map lookup, and improved ORB performance
by something like
2-4% on Scott's stateless session bean ping benchmark.

Ken.