You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@commons.apache.org by Simon Kitching <si...@ecnetwork.co.nz> on 2004/05/10 07:37:01 UTC

Re: [logging] eliminate dependencies on commons-logging [was [beanutils] PROPOSAL: eliminate core dependency on collections

On Sun, 2004-05-09 at 06:16, matthew.hawthorne wrote:
> robert burrell donkin wrote:
> > funnily enough, if commons logging was to be created again, i'd (with 
> > hindsight) consider something along those lines. the bridging 
> > implementations would be in a separate, optional jar and the two classes 
> > required in the public logging API would be copied over into each 
> > component (as part of the build). if the implementation jar is not 
> > present, error and fatal levels (only) would log to system.err. those 
> > users wanting logging would have to grab and drop in the implementation 
> > jar.

Doh! Can I vote +2 on this :-)

In fact I liked the idea so much, that attached is a proposed
implementation.

I suggest that the attached LogSource class, together with o.a.c.l.Log, 
be copied into every project. Of course all the LogFactory.getLog calls
would need to be changed to LogSource.getLog calls too.

The effect would be that users do not need to download commons-logging
in order to use the libraries. If they want to enable logging, they just
place commons-logging.jar in the classpath and then configure it as
normal. Price: disk space for 1 interface and 1 trivial class, plus a
trivial performance hit in the getLog method if they do enable logging.

As BeanUtils and Digester are winding up for releases, I would love to
get this in if people are happy with the idea. And the nice thing is, we
wouldn't need to wait for a logging release to do this!

The code deliberately discards all logging rather than writing to
stderr; if output is being generated then there must be a configuration
system to enable/disable it, which leads back towards commons-logging
functionality. The point here is to provide something *so* simple that
it *never* needs to change, and hence it is safe to copy the code into
multiple places. By discarding log output, we behave exactly as if
logging had never been used in the first place which I think is
appropriate for an *optional logging* library.

Note that this code doesn't try to do anything clever with classloaders.
Any mucking about with context class loader, etc. is handled by
LogFactory, *not* this class whose responsibility is only to hand off to
commons-logging or do nothing.

The mechanism Robert suggests for the build (auto copy from the logging
jar or dir as part of the build) is nice, but the point is that Log and
LogSource should never need updating, so just committing copies of them
into the CVS repo for each project should also work, and be simpler.

Does copying of classes sound scary? The comments in the LogSource.java
file describe why I think this is not a problem. But here's another
angle on it. If you compile an app with version 1.0.0 of a lib, then try
to run with a version that has a different binary API, what happens?
Boom - and you expect it. And if you run with multiple copies of a class
and they are identical, what happens? Nothing - because they are all the
same. So a problem only occurs when the ABI is the same, but the
implementation is different (eg one lib has a bugfixed version, the
other doesn't). And because LogSource is trivial this shouldn't occur. I
certainly wouldn't recommend copying the complete commons-logging into
each project because that code is not trivial.

Question: what about situations where multiple libraries are running
with different security policies? Might this cause problems when each
lib contains its own copy of o.a.c.l.Log ? Would this be worse than if
they didn't have their own copy?

> 
> Here's my opinion on the best approach to logging for each component:
> 
> Each component creates a simple interface for logging (which could just 
> be a
> copy of o.a.c.l.Log copied into the components namespace, becoming, for 
> example,
> o.a.c.beanutils.Log)
> 
> The component also creates a LogFactory, which checks if commons logging 
> is in
> the classpath.  If it is, it returns an implementation which delegates 
> to commons-logging.
> If it isn't, it just sends messages of the appropriate level to 
> system.err (just like robert suggests).
> 
> This may sound a bit complicated, but it's really not.  To me, this is a 
> good example of how to
> deal with optional dependencies.  In this example, [beanutils] functions 
> fine without
> commons-logging, but adding commons-logging to the classpath enhances 
> the logging capabilities.
> 
> The only problem would be that beanutils would have to invoke the 
> commons-logging methods
> through reflection, since making the calls directly would result in a 
> compile-time dependency
> on commons-logging.  This would slow things down a bit.
> 
> Is this reasonable, or too much work?

Unfortunately, I think the delegation step is just too much overhead.
The log4j docs describe how much effort they went to to make calls fast
in the case where the message is not logged. But commons-logging adds
overhead to every call, and as far as I can see this approach would add
another level of calls, including **reflection** which has significant
overheads. 

The approach I suggest only uses Method.invoke within the getLog method.

This solution is definitely "cleaner", as it avoids having multiple
copies of the Log and LogSource class in multiple libraries. However by
hiding the o.a.c.l.Log interface behing a {component}.Log interface I
believe this forces indirect invocation (Method.invoke) on every
debug/info/warn/error call (filtered or not) which seems unacceptable to
me. If I've misunderstood you, please set me straight..

Maybe a bytecode generation implementation of this idea would work, ie
have a factory that generates custom classes to bridge between the local
component's Log interface and the commons-logging Log interface. But
that's a serious project!

I seem to remember sun introducing a class recently into the std
libraries which uses bytecode generation to create classes on the fly; I
think it was intended for use in swing apps to avoid too many anonymous
inner class declarations. Anyone remember what it was? [I'm not thinking
of java.lang.reflect.Proxy].





I look forward to comments....

Cheers,

Simon

Re: [logging] eliminate dependencies on commons-logging [was [beanutils] PROPOSAL: eliminate core dependency on collections

Posted by Simon Kitching <si...@ecnetwork.co.nz>.
On Mon, 2004-05-10 at 17:37, Simon Kitching wrote:
> On Sun, 2004-05-09 at 06:16, matthew.hawthorne wrote:
> > robert burrell donkin wrote:
> > > funnily enough, if commons logging was to be created again, i'd (with 
> > > hindsight) consider something along those lines. the bridging 
> > > implementations would be in a separate, optional jar and the two classes 
> > > required in the public logging API would be copied over into each 
> > > component (as part of the build). if the implementation jar is not 
> > > present, error and fatal levels (only) would log to system.err. those 
> > > users wanting logging would have to grab and drop in the implementation 
> > > jar.
> 
> Doh! Can I vote +2 on this :-)

Doh! I forgot something very important...

> 
> In fact I liked the idea so much, that attached is a proposed
> implementation.
> 
> I suggest that the attached LogSource class, together with o.a.c.l.Log, 
> be copied into every project. Of course all the LogFactory.getLog calls
> would need to be changed to LogSource.getLog calls too.

Of course the proposed LogSource class can be renamed in the "importing"
project. And probably should be.

Only the o.a.c.l.Log interface needs to be distributed "un-renamed", and
therefore potentially duplicated when multiple libraries are then used
together. And as it's an interface which will only change in major
library upgrades, I don't see that the duplication causes any problems
except *possibly* this security policy issue:

> Question: what about situations where multiple libraries are running
> with different security policies? Might this cause problems when each
> lib contains its own copy of o.a.c.l.Log ? Would this be worse than if
> they didn't have their own copy?

Cheers,

Simon


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


Re: [logging] eliminate dependencies on commons-logging [was[beanutils] PROPOSAL: eliminate core dependency on collections

Posted by "matthew.hawthorne" <ma...@apache.org>.
Tomasz Pik wrote:
> Also, o.a.c.l is probably the biggest success of Jakarta Commons team
> and I don't think that such solution is the best in the 'marketing'
> terms ('whole world using it so we're going not to use it...').

The fact that many servers already include commons-logging isn't the point.
I typically have at least 10 commons jars in my classpath at all times, but
it isn't fair to assume that everyone else does the same.

Also, I don't think any decision has been made to stop using 
commons-logging.

All that is occurring is a conversion of the commons-logging dependency
from mandatory to optional.

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


Re: [logging] eliminate dependencies on commons-logging [was[beanutils] PROPOSAL: eliminate core dependency on collections

Posted by robert burrell donkin <ro...@blueyonder.co.uk>.
On 11 May 2004, at 21:57, Tomasz Pik wrote:

> robert burrell donkin wrote:
>
>> On 10 May 2004, at 21:26, Stephen Colebourne wrote:
>>> This looks like a very neat solution to the problem to me. The 
>>> Class.forName
>>> worries me a little though, as I believe that its not too happy in 
>>> class
>>> loaders.
>> it should probably try the context classloader first.
>> note: it is *very* important to remember that beanutils is used 
>> indirectly by a *very* large user base. (think about the user base 
>> for strut and tomcat at the very least.) i'd be *very* likely to veto 
>> any changes that risk breaking a release without adequate time for 
>> testing.
>
> Hmm, Struts is bad example here because it's already using
> commons-logging ;)

the point i was trying (but failed) to make was that both tomcat and 
struts use beanutils. that's a lot of users.

>> (it took a lot of work to make commons-logging work anywhere near 
>> reasonably in complex container environments.)
>
> And I'm worry that this will be the same process but code will be split
> across different modules.

i'd definitely agree with that.

that's why the key is keeping the bootstrap code very, very simple. all 
the sophistication needs to be in the LogFactory implementation. this 
may mean generating the bootstrap source from a common template.

> One more note - I don't know how many 'server applications' are not
> using commons-logging, directly or not. Please, take a look at Gump
> email and a list of projects depending on o.a.c.l. All of the projects
> depending on those projects depends on o.a.c.l.
> Also, some recent RIs from Sun using o.a.c.l.
> And for them running 'wrapper' around o.a.c.l will be a waste of
> force.

true.

hopefully it wouldn't be a wrapper, just a bit of dependency magic...

> Also, o.a.c.l is probably the biggest success of Jakarta Commons team
> and I don't think that such solution is the best in the 'marketing'
> terms ('whole world using it so we're going not to use it...').

i'm glad someone appreciates it. we went through (political) hell 
creating it :)

- robert


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


Re: [logging] eliminate dependencies on commons-logging [was[beanutils] PROPOSAL: eliminate core dependency on collections

Posted by Tomasz Pik <pi...@ais.pl>.
robert burrell donkin wrote:

> On 10 May 2004, at 21:26, Stephen Colebourne wrote:
> 
>> This looks like a very neat solution to the problem to me. The 
>> Class.forName
>> worries me a little though, as I believe that its not too happy in class
>> loaders.
> 
> 
> it should probably try the context classloader first.
> 
> note: it is *very* important to remember that beanutils is used 
> indirectly by a *very* large user base. (think about the user base for 
> strut and tomcat at the very least.) i'd be *very* likely to veto any 
> changes that risk breaking a release without adequate time for testing.

Hmm, Struts is bad example here because it's already using
commons-logging ;)

> (it took a lot of work to make commons-logging work anywhere near 
> reasonably in complex container environments.)

And I'm worry that this will be the same process but code will be split
across different modules.
One more note - I don't know how many 'server applications' are not
using commons-logging, directly or not. Please, take a look at Gump
email and a list of projects depending on o.a.c.l. All of the projects
depending on those projects depends on o.a.c.l.
Also, some recent RIs from Sun using o.a.c.l.
And for them running 'wrapper' around o.a.c.l will be a waste of
force.

Also, o.a.c.l is probably the biggest success of Jakarta Commons team
and I don't think that such solution is the best in the 'marketing'
terms ('whole world using it so we're going not to use it...').

Just my 2cents,
Tomek


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


Re: [logging] eliminate dependencies on commons-logging [was[beanutils] PROPOSAL: eliminate core dependency on collections

Posted by robert burrell donkin <ro...@blueyonder.co.uk>.
On 10 May 2004, at 21:26, Stephen Colebourne wrote:

> This looks like a very neat solution to the problem to me. The 
> Class.forName
> worries me a little though, as I believe that its not too happy in 
> class
> loaders.

it should probably try the context classloader first.

note: it is *very* important to remember that beanutils is used 
indirectly by a *very* large user base. (think about the user base for 
strut and tomcat at the very least.) i'd be *very* likely to veto any 
changes that risk breaking a release without adequate time for testing. 
(it took a lot of work to make commons-logging work anywhere near 
reasonably in complex container environments.)

i would definitely prefer a service release which would allow 
downstream developers to resolve any possible issues with collections 
3.0 before moving on to looking at commons-logging. so, i'd strong 
suggest that any ideas for altering the way that logging works are 
committed into a branch.

- robert


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


Re: [logging] eliminate dependencies on commons-logging [was[beanutils] PROPOSAL: eliminate core dependency on collections

Posted by Stephen Colebourne <sc...@btopenworld.com>.
This looks like a very neat solution to the problem to me. The Class.forName
worries me a little though, as I believe that its not too happy in class
loaders.

Stephen

----- Original Message -----
From: "Simon Kitching" <si...@ecnetwork.co.nz>
To: "Jakarta Commons Developers List" <co...@jakarta.apache.org>
Sent: Monday, May 10, 2004 6:37 AM
Subject: Re: [logging] eliminate dependencies on commons-logging
[was[beanutils] PROPOSAL: eliminate core dependency on collections


> On Sun, 2004-05-09 at 06:16, matthew.hawthorne wrote:
> > robert burrell donkin wrote:
> > > funnily enough, if commons logging was to be created again, i'd (with
> > > hindsight) consider something along those lines. the bridging
> > > implementations would be in a separate, optional jar and the two
classes
> > > required in the public logging API would be copied over into each
> > > component (as part of the build). if the implementation jar is not
> > > present, error and fatal levels (only) would log to system.err. those
> > > users wanting logging would have to grab and drop in the
implementation
> > > jar.
>
> Doh! Can I vote +2 on this :-)
>
> In fact I liked the idea so much, that attached is a proposed
> implementation.
>
> I suggest that the attached LogSource class, together with o.a.c.l.Log,
> be copied into every project. Of course all the LogFactory.getLog calls
> would need to be changed to LogSource.getLog calls too.
>
> The effect would be that users do not need to download commons-logging
> in order to use the libraries. If they want to enable logging, they just
> place commons-logging.jar in the classpath and then configure it as
> normal. Price: disk space for 1 interface and 1 trivial class, plus a
> trivial performance hit in the getLog method if they do enable logging.
>
> As BeanUtils and Digester are winding up for releases, I would love to
> get this in if people are happy with the idea. And the nice thing is, we
> wouldn't need to wait for a logging release to do this!
>
> The code deliberately discards all logging rather than writing to
> stderr; if output is being generated then there must be a configuration
> system to enable/disable it, which leads back towards commons-logging
> functionality. The point here is to provide something *so* simple that
> it *never* needs to change, and hence it is safe to copy the code into
> multiple places. By discarding log output, we behave exactly as if
> logging had never been used in the first place which I think is
> appropriate for an *optional logging* library.
>
> Note that this code doesn't try to do anything clever with classloaders.
> Any mucking about with context class loader, etc. is handled by
> LogFactory, *not* this class whose responsibility is only to hand off to
> commons-logging or do nothing.
>
> The mechanism Robert suggests for the build (auto copy from the logging
> jar or dir as part of the build) is nice, but the point is that Log and
> LogSource should never need updating, so just committing copies of them
> into the CVS repo for each project should also work, and be simpler.
>
> Does copying of classes sound scary? The comments in the LogSource.java
> file describe why I think this is not a problem. But here's another
> angle on it. If you compile an app with version 1.0.0 of a lib, then try
> to run with a version that has a different binary API, what happens?
> Boom - and you expect it. And if you run with multiple copies of a class
> and they are identical, what happens? Nothing - because they are all the
> same. So a problem only occurs when the ABI is the same, but the
> implementation is different (eg one lib has a bugfixed version, the
> other doesn't). And because LogSource is trivial this shouldn't occur. I
> certainly wouldn't recommend copying the complete commons-logging into
> each project because that code is not trivial.
>
> Question: what about situations where multiple libraries are running
> with different security policies? Might this cause problems when each
> lib contains its own copy of o.a.c.l.Log ? Would this be worse than if
> they didn't have their own copy?
>
> >
> > Here's my opinion on the best approach to logging for each component:
> >
> > Each component creates a simple interface for logging (which could just
> > be a
> > copy of o.a.c.l.Log copied into the components namespace, becoming, for
> > example,
> > o.a.c.beanutils.Log)
> >
> > The component also creates a LogFactory, which checks if commons logging
> > is in
> > the classpath.  If it is, it returns an implementation which delegates
> > to commons-logging.
> > If it isn't, it just sends messages of the appropriate level to
> > system.err (just like robert suggests).
> >
> > This may sound a bit complicated, but it's really not.  To me, this is a
> > good example of how to
> > deal with optional dependencies.  In this example, [beanutils] functions
> > fine without
> > commons-logging, but adding commons-logging to the classpath enhances
> > the logging capabilities.
> >
> > The only problem would be that beanutils would have to invoke the
> > commons-logging methods
> > through reflection, since making the calls directly would result in a
> > compile-time dependency
> > on commons-logging.  This would slow things down a bit.
> >
> > Is this reasonable, or too much work?
>
> Unfortunately, I think the delegation step is just too much overhead.
> The log4j docs describe how much effort they went to to make calls fast
> in the case where the message is not logged. But commons-logging adds
> overhead to every call, and as far as I can see this approach would add
> another level of calls, including **reflection** which has significant
> overheads.
>
> The approach I suggest only uses Method.invoke within the getLog method.
>
> This solution is definitely "cleaner", as it avoids having multiple
> copies of the Log and LogSource class in multiple libraries. However by
> hiding the o.a.c.l.Log interface behing a {component}.Log interface I
> believe this forces indirect invocation (Method.invoke) on every
> debug/info/warn/error call (filtered or not) which seems unacceptable to
> me. If I've misunderstood you, please set me straight..
>
> Maybe a bytecode generation implementation of this idea would work, ie
> have a factory that generates custom classes to bridge between the local
> component's Log interface and the commons-logging Log interface. But
> that's a serious project!
>
> I seem to remember sun introducing a class recently into the std
> libraries which uses bytecode generation to create classes on the fly; I
> think it was intended for use in swing apps to avoid too many anonymous
> inner class declarations. Anyone remember what it was? [I'm not thinking
> of java.lang.reflect.Proxy].
>
>
>
>
>
> I look forward to comments....
>
> Cheers,
>
> Simon
>


----------------------------------------------------------------------------
----


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


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


Re: [logging] eliminate dependencies on commons-logging [was [beanutils] PROPOSAL: eliminate core dependency on collections

Posted by Simon Kitching <si...@ecnetwork.co.nz>.
On Mon, 2004-05-10 at 17:37, Simon Kitching wrote:
> On Sun, 2004-05-09 at 06:16, matthew.hawthorne wrote:

[logging suggestion involving reflection]

> > 
> > Is this reasonable, or too much work?
> 
> Unfortunately, I think the delegation step is just too much overhead.
> The log4j docs describe how much effort they went to to make calls fast
> in the case where the message is not logged. But commons-logging adds
> overhead to every call, and as far as I can see this approach would add
> another level of calls, including **reflection** which has significant
> overheads. 
> 
> The approach I suggest only uses Method.invoke within the getLog method.
> 
> This solution is definitely "cleaner", as it avoids having multiple
> copies of the Log and LogSource class in multiple libraries. However by
> hiding the o.a.c.l.Log interface behing a {component}.Log interface I
> believe this forces indirect invocation (Method.invoke) on every
> debug/info/warn/error call (filtered or not) which seems unacceptable to
> me. If I've misunderstood you, please set me straight..
> 
> Maybe a bytecode generation implementation of this idea would work, ie
> have a factory that generates custom classes to bridge between the local
> component's Log interface and the commons-logging Log interface. But
> that's a serious project!
> 
> I seem to remember sun introducing a class recently into the std
> libraries which uses bytecode generation to create classes on the fly; I
> think it was intended for use in swing apps to avoid too many anonymous
> inner class declarations. Anyone remember what it was? [I'm not thinking
> of java.lang.reflect.Proxy].


I've found the class I was trying to remember about. I was thinking of
java.beans.EventHandler, which was added in java 1.4 as part of the
"long term persistence" project. Unfortunately, it's just a wrapper
around java.lang.reflect.Proxy, so still uses reflection on one side
even though it generates bytecode to implement the appropriate
interface. Quite appropriate performance for GUI tasks, I think, but not
what I would look for in a logging library (see below).


On re-reading my earlier email, I thought I really should justify my
assumption that Method.invoke is too slow. So I created a test which
disables logging at info level, then logs 1,000,000 info messages
directly and via a wrapper that uses Method.invoke (note that
Class.findMethod is only used once, and the Method object cached).

Result: direct 80 msecs, indirect: 440 msecs.

So the Method.invoke wrapper makes the call around 5 times slower. I'm
not generally an optimise-at-all-costs guy, but this does sound a hefty
price to pay for breaking the explicit lib dependency.


Regards,

Simon


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