commons-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Leo Simons <leosim...@apache.org>
Subject Re: [logging] To depend or not to depend?
Date Sat, 08 Feb 2003 01:21:40 GMT
Hi peeps,

jumping in a little late here I guess....I'm going to mostly rant about 
how avalon relates to (and could in the future) commons-logging and 
logging in general, and not about the general case, as I feel I don't 
have enough knowledge to talk about the general case.

			Summary
			=======
warning: terribly long-winded! :D

We are also looking at how to integrate logkit & log4j; good hopes too 
but (personal estimate) it will take lots of time and effort.

We are looking at how to integrate commons-logging into avalon; it looks 
promising. We cannot drop stuff like the Logger interface in 
avalon-framework because we need backwards compatibility.

It seems like a commons-logging-noop.jar would make the difficulty of 
integrating a commons-logging-using-library into an avalon container and 
similar projects mostly dissapear.

(I also take too much time to explain the current logging setup in the 
various parts of avalon)

			Logging in Avalon
			=================
Introduction
------------
There's three main logging-related packages over @ avalon. There's 
avalon-logkit, which is a seperate downloadable binary that has got no 
dependency on any other part of avalon, and vice versa other parts of 
avalon have mostly been modified to have no more than soft dependencies 
on avalon-logkit.
The avalon-logkit feature set and use case is about the same as for 
log4j (differences are becoming less and less with each release).

There's excalibur-logger, which is mostly utility code for use by avalon 
containers to handle their logging setup. It is distributed as part of 
phoenix, ECM, and also included in the old big releases of excalibur. 
This is sort-of avalon-internal utility code.

Then there's avalon-framework, the client API which avalon components 
talk to in order to handle their logging. There's a package 
org.apache.avalon.framework.logger, with the avalon lifecycle interface 
LogEnabled, into which is passed an implementation of Logger. There's 
implementations of that Logger interface using the console, logkit, 
log4j and jdk14 logging.
This package is very similar to commons-logging in that it provides a 
sort-of facade to an underlying logging implementation.

Logkit & Log4J
--------------
There's been talks for ages about increased synergy between these 
projects, and recently people have been getting more enthousiastic 
again. It's doable. Hopefully we'll get there sometime. Lack of time and 
the need to support an existing userbase will mean this kind of process 
will probably take lots of time. And, I personally find this kind of 
stuff a terribly unsexy task ;)

(sidenote: I think it makes as little sense to integrate logkit into 
commons-logging as it makes sense to integrate log4j into 
commons-logging, ie very little. Commons-logging should not provide a 
logging implementation IMHO.)

Avalon-Framework & Commons-Logging
----------------------------------
We used to have (still have, deprecated) a Loggable interface which was 
coupled to Logkit, ie:

public interface Loggable {
	void setLogger( org.apache.log.Logger logger ); }

this was cumbersome as lots of people wanted to use log4j with avalon 
for obvious reasons, hence we now have LogEnabled and a simple facade.

Looking at the similarity between the Logger interface in 
avalon-framework and the Logger interface in commons-logging it is 
obvious that it makes sense to remove one in place of the other. It does 
not make sense to have a dependency on avalon-framework for commons-logging.

While it can make sense to have a dependency on commons-logging for 
avalon-framework, we are not going to change the LogEnabled interface 
(in avalon-framework 4.x) because we need total binary compatibility. As 
such, we also need to keep supporting the Logger interface in 
avalon-framework.

What is probably perfectly doable is providing:
--------------------------------
package org.apache.avalon.framework;

public class CommonsLoggingLogger implements Logger
{
     private Log m_log;

     public CommonsLoggingLogger(
         org.apache.commons.loggging.Log log )
     { m_log = log; }

     void debug( String message ) { m_log.debug( message ); }

     // simply redirect all methods defined in Logger to Log
}
--------------------------------

this is on the TODO. Not for an upcoming avalon-framework 4.1.4, but it 
might very well be in 4.1.5.

Excalibur-Logger & Commons-Logging
----------------------------------
Avalon containers like Avalon-Phoenix provide a very rigid black-box to 
hosted components, and provide support for complex multi-classloader 
setups. Very similar tech and associated problems as in EJB and servlet 
containers.

Within such a setup, the static factory pattern can often lead to nasty 
problems most of y'all probably have more experience with than me. We're 
very cautious with promoting use of libraries in avalon client code 
which enable use of static factories (the use of static factories within 
an avalon-container itself is less of an issue, as using IoC means the 
container behaviour in such a situation can be deterministic, but as a 
matter of habit, preference, and example, avalon containers are pretty 
non-static as well).

These containers defer to excalibur-logger for handling most of their 
logging needs. Excalibur-logger contains an interface LoggerManager, 
which does mostly the same as commons-logging its LogFactory, with the 
main difference it is completely non-static in nature. LoggerManager 
also needs to stay around for ages in order to preserve backwards 
compatibility.

Again, it should be possible to write a CommonsLoggerManager which 
defers to a LogFactory:

--------------------------------
package org.apache.avalon.excalibur.logger;
public class CommonsLoggerManager implements LoggerManager
{
     private org.apache.commons.LogFactory m_factory;

     public CommonsLoggingLogger(
         org.apache.commons.loggging.LogFactory factory )
     { m_factory = factory; }

     Logger getLoggerForCategory( String name )
     {
         return new CommonsLoggingLogger( m_factory.getInstance(name) );
     }

     // simply redirect all methods defined in LoggerManager
     // to LogFactory
}
--------------------------------

investigating this and how well it works is also on the TODO. I believe 
Jason's already done a lot of work in this direction with plexus, but I 
haven't actually looked at it yet.

		Logging in libraries used by Avalon
		===================================

The dillema/problem
-------------------
Stuff like commons-collections, commons-cli and commons-lang and all 
those other libraries I don't know much about just yet can definately be 
put to use in avalon all over the place. Our goal is indeed to get the 
'utility code' in avalon 'out' (and donate it to another project or 
deprecate it if a better alternative supporting the full usecase already 
exists, like with cli), and use the common code as much as possible.

In avalon containers like Avalon-Phoenix, we need to provide the end 
user with control over how to do logging. If a library does something like

class MyToolLikeCLI
{
     private static Log log = LogFactoryImpl.getInstance("");

     doStuff()
     {
         try { /* ... */ } catch( Throwable t )
         { log.error( "no good" ); }
     }
}

that makes our job a lot harder. Hence

     <dependency><id>commons-logging</id></dependency>

triggers a warning sign when evaluating how easy it is to integrate a 
library, as 'LogFactoryImpl.getInstance("")' looks like a lot of work to 
circumvent cleanly, and it is I believe commonly used.

Note that I totally agree the code in avalon creates a lot of the same 
problem with possibility for stuff like

     private static Logger log = new ConsoleLogger()

The only difference is that such a setup is discouraged in avalon and 
not in commons-logging. It'd be nice if the commons-logging docs would 
as well or at least point out potential problems (says nosy me, not 
actually knowing whether they do).

Personal preferences 'n stuff
-----------------------------
I like a library that doesn't use anything with a 'static' keyword 
attached to any of its methods that actually do much. It just makes life 
easier in the classloader-hell world we have in java. I would like the 
commons libraries to use a similar setup to Digester's setLogger() as 
much as possible.

Possible solution/workaround
----------------------------
Now, I saw someone suggest this problem is avoidable, ie by putting in 
place an alternative implementation for commons-logging which intercepts 
stuff like getInstance(), perhaps always providing a NoOpLog. This 
sounds like a workable, easily implementable idea, even if it feels 
'hacky'. IIUC what would happen is we put in place

commons-logging-noop.jar (commons-stub.jar)
commons-cli.jar
commons-lang.jar
commons-(...).jar

and never again get anxious about

     <dependency><id>commons-logging</id></dependency>

Sounds like a plan, and probably a rather common need for many projects, 
not just avalon. Maybe some smart classloader hacker/proxy wizard can 
even create something that properly routes LogFactory calls back into an 
excalibur LoggerManager...but I see a bigger amount of work and 
complexity involved there.

hope this all made some kind of sense to someone somewhere.

cheers & g'night,

- Leo



---------------------------------------------------------------------
To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: commons-dev-help@jakarta.apache.org


Mime
View raw message