Hello, Friends!

Have just re-configured my laptop to be a
contributor's box, ready to get to work :-)

What would you say to the following changes to
*LoggerManager:

1) The creator of LoggerManager passes an initial
   logger to it.

   This is the logger that LoggerManager outputs
   messages to while it's
       contextualize()
       configure()
   stages. This is all what normal components do:
   get a logger and log to it.

   In practice, with Fortress for instance, at
   Fortress creation stage user will create
   a ConsoleLogger or a ServletLogger or
   something alike - bulletproof that will
   log the early stages of the startup.

   Then he the user would pass this
   ConsoleLogger or ServletLogger to
   DefaultContainerManager for instance.

   This, the "initialization" logger will
   be passed to LoggerManager to log its
   contextualize() and configure()

2) After the logger manager has passed all
   its initialization steps successfully
   
   (currenlty our *LoggerManager have only
   two such steps: contextualize() and
   configure())

   we shall have an option of the LoggerManager
   to switch its own logging to a Logger
   extracted from itself

   To implement this I propose a new
   3-argument constructor

       XXXLoggerManager(
               String prefix,
               Logger initialLogger,
               String switchToCategory )

   The last argument will be the name
   of the category to do

       this.getLoggerForCategory( m_switchToCategory )

   This will be the logger to log messages from
   LoggerManager to after the switch.

   Passing null as the last argument to this
   constructor will disable this feature - the
   logging will still happen to initialLogger.

   If the initalLogger will be set to null
   no logging will happen until end of configuration
   when the switch is done to m_switchToCategory().

   If both initialLogger and switchToCategory will
   be null, no logging will happen at all.
   
   I intend to create the AbstractLoggerManager
   class that will implement this logger switching
   functionality.

   It is going to supply via getLogger()
   a special Logger that will
   wrap two underlying loggers:
   
   * m_fallback

     this will be the initialLogger passed to
     XXXLoggerManager on creation or via enableLogging()
     
   * m_preferred

     the logger extracted via this.getLoggerForCategory(
     m_switchToCategory )

   So I'm going to implement getLogger() method in
   AbstractLoggerManager that will return a special

   o.a.a.e.logger.util.LoggerSwitch.SwitchingLogger

   logger that will internally log to either
   m_fallback or to m_preferred

3) One more thing I'm going to do [LogKitLoggerManager]

   LogKit logging system has an ErrorHandler, a "logger"
   that is used to "log" logging errors.

   There is one such thing per the whole hierarchy.

   The default implementation just writes to System.err

   Here is what I'm going to do about this:

   _if_ a LogKitLoggerManager is created with a constructor
   that does not accept a Hierarchy as its argument and
   we create the Hierarchy ourselves as

       new Hierarchy()

   then we shall set our own ErrorHandler for it.

   This ErrorHandler will do the following:
   it will try to log errors via getLogger()

   This means that errors in logging with LogKit
   will be attempted to be logged via LogKit itself!

   But, recursive invocation will be tracked with
   a couple of ThreadLocal variables and in case of
   recursion the error will be logged via the
   
   initialLogger

   originally supplied to LogKitLoggerManager.

   This is done for the following situation:

   imagine we configure

   <targets>
       <... id='unreliable' .../>
       <... id='reliable' .../>
   </targets>

   <categories>
       <category name='1' ..>
           <log-target id-ref='unreliable' />
       </category>

       <category name='system.logkit' ..>
           <log-target id-ref='reliable' />
       </category>
   </categories>

   imagine the LogKitLoggerManager has been created as

       new LogKitLoggerManager( "fortress", consoleLogger, "system.logkit" );
   
   and imagine target 'unreliable' fails and invokes
   ErrorHandler. Then we shall first try to log
   the error via the "fortress.system.logkit" category, that
   is via the 'reliable' log target. If it successeds it's all.

   If that fails, an error will be attempted to be recursively
   logged via the same logger, but this time the recursion will
   be detected by
   
       LoggerSwitch.SwitchingLogger

   and it will fallback to logging error together with the initial
   error via the its m_fallback, that is the initial ConsoleLogger
   passed to LogKitLoggerManager.

   This scheme seems to be close to optimal to me.
   We use the initialLogger as a fallback logger.

4)

   I'm also going to do a
   
       m_hierarchy.getRootLogger().unsetLogTargets()

   in case we create the hierarchy ourselves. This will
   remove the default System.out log target initially
   configured by new Hierarchy() constructor.

   And _if_ we detect that user has supplied no log targets
   for the "" caterogy we will complain loudly via an exception.

5)
   What a little worries me is what to do if we have been
   given a Hierarchy from outside, like via the

       LogKitLoggerManager( String prefix, Hierarchy hierarchy )

   constructor. If we're not given it and we are creating the
   Hierarchy ouselves we'll do

       m_hierarchy.getRootLogger().unsetLogTargets()
       m_hierarchy.setErrorHandler( m_errorHandler );

   But if the hierarchy has been passed to us already created,
   should we do _any_ of this? I'm currently inclined to
   thing that we should do _none_, but I would like
   an advice.

6)
   There's an option to test if our logging is alive
   in the end of configure() method by doing

       getLoggerForCategory("").info("Logging started");

   if this yields an error we can record it in our
   custom error handler, in a boolean variable. Then we
   can examine it right away and if there was an error
   we can blow up with an exception.

   However I have certain reservations on this:

   a) this won't work if the log-level is above "info"
   b) this won't work if the Hierarchy() has been passed
      ready-made to use (we won't have our custom error
      handler installed into it in this case)
   c) this will produce an extra line in the logs in this
      case (is this a plus or a minus?)

   Please, give me an advice on this feature.

7)

   The current implementation of LogKitLoggerManager
   does the following: if it is given a Logger it uses
   this logger as its defaultLogger. That is it has
   (I have changed the names of arguments a bit, but still
   I hope this all understandable)

   LogKitLoggerManager(
           String prefix,
           Logger defaultLogger,
           Logger interanlLogger )
   {
       m_defaultLogger = defaultLogger;
       ...
   }

   Logger getDefaultLogger()
   {
       return m_defaultLogger;
   }

   I must confess I sort of dislike this. I beleive that
   we should do instead an equivalent of

   Logger getDefaultLogger()
   {
       return getLoggerForCategory("");
   }

   to be true to the LoggerManager contract.

   With regards to this issue I would consider the following
   options:

   a) remove this constructor completely
   b) deprecate this constructor but retain functionality
   c) leave the constructor undeprecated

   I would like an advice on this, I just do not dare to
   do a) and b) without a permit, although I feel very much
   inclined to do one of this.

8)

   There is also one more constructor of LogKitLoggerManager
   that I would like to touch

   LogKitLoggerManager(
           String prefix,
           Logger defaultLogger)

   This currently has the following contract:

       defaultLogger

   becomes _both_ the internal logger (the logger to log
   LogKitLoggerManager's own messages to and
   
       m_defaultLogger

   used in

       getDefaultLogger(){ return m_defaultLogger; }

   in line with changes discussed in section 7) I would
   like to change the contract of this constructor and
   make it be
   
   LogKitLoggerManager(
           String prefix,
           Logger internalLogger )

   makeing the Logger argument be just the logger used
   for logging our own messages and instead have

       getDefaultLogger(){ return getLoggerForCategory(""); }

   As I have said I just do not see much point in
   initializing m_defaultLogger with an externally supplied
   logger since we can very well initialize if from the
   config file. (Reference: 6.a) in this mail )

----

Conclusion:

I would certainly not like to make drastic changes untill
allowed to. On the other hand maybe it's better to just
go ahead and implement it and _then_ have a discussion
on why I did that and probably revert some of the changes?

Anyway, I have implemented all the mentioned changes in
my local copy and works fine for me, so I almost have
all the code ready for this.

WBR, Anton :-)


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

Reply via email to