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: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to