P.S. As log4j 1.3 now stands, I'd think it would be tempting to
repackage all of log4j 1.3 in org.apache.log4j2.* and call it
log4j 2.0. That way you could have log4j 1.2 and 1.3/2.0 in the same
classloader at the same time without having to worry about some legacy
library that requires 1.2.x and some other than requires 1.3.x. As it
stands now I worry about such issues cropping up more often than not.
That's ugly, yes, but 1.3 seems to go out of its way to break both
binary and source compatibility -- in which case using the same fully
qualified package names is a bad thing!
Jess Holle wrote:
I just about a day and a half trying to get my code to be log4j 1.3
compatible while still being log4j 1.2.12+ compatible. Note this was
despite the fact that I reviewed the 1.3 compatibility guidelines prior
to writing any of this code. I clearly stepped over the lines in
various areas, but there were non-trivial reasons for this.
I have to say I am shocked by the lack of compatibility between the
two. I understand the need to clean things up, but there were a lot of
gratuitous incompatibilities.
Worst of all, despite all my efforts and the fact that my code now
compiles just fine against 1.2.12+ and 1.3 alpha 7, I cannot compile
against 1.2 and run with 1.3 (or presumably vice versa). This turns
out to be due to the fact that Logger has the following methods in
log4j 1.2:
- isEnabledFor(Priority)
- log(Priority,Object)
- log(Priority,Object,Throwable)
whereas in log4j 1.3 there are only equivalents of this that take
"Level" instead of Priority. The only alternative here appears to be
to introduce some reflection-based utility, but that would defeat the
speed and efficiency of these calls whose performance is absolutely
critical!
For this issue I would really like to see log4j 1.2.13 introduce:
- isEnabledFor(Level)
- log(Level,Object)
- log(Level,Object,Throwable)
Compilation against 1.2.13 would then automatically bind against these
methods in preference to those above when passed Level objects, which
should always be the case if one is following the 1.3 compatibility
guidelines. This would then produce binaries that are compatible with
1.2.13 and 1.3 -- assuming various source-level compatibility
guidelines are followed.
I suspect there may be other such issues lingering elsewhere in the API
but these methods are so widely used and so critical that they should
be addressed immediately and that may solve the problem for many.
Other compatibility issues (source-level, in these cases) beyond this
that I encountered included:
- I had to use java.lang.reflect.Proxy to create code that would
compile against log4j 1.2 or 1.3 unchanged but yet could listen for the
addition of an appender to a logger repository (i.e. I conditionally
create either a LoggerEventListener proxy or a HierarchyEventListener
proxy depending on what I can load).
- Was it really necessary to maroon all
HierarchyEventListener's
and break all code that adds them?
- By the way, neither log4j 1.2 nor 1.3 fire any event upon
removing an appender from a logger, despite the API's implication that
this will be done. Also log4j 1.3 does not fire a level changed event
despite implying that it does! This issue should be addressed
irrespective of compatibility-level decisions!
- In case my code ever gets a Category object in 1.2 I had to
create a reflection-based wrapper to get the name of a Logger/Category
object that will compile against both 1.2 and 1.3.
- The RepositorySelector interface now has 2 more methods. This
breaks all existing implementations of this interface! Introducing
these methods via a sub-interface and/or checking for them via
reflection upon initial selector registration would have been
preferable.
- org.apache.log4j.RollingFileAppender and
org.apache.log4j.DailyRollingFileAppender are no longer subclasses of
FileAppender and no longer provide get/setEncoding() methods.
- I understand that these classes are retained purely for
compatibility, but:
- These changes unnecessarily break existing code.
- The replacement class is rather generic and is
substantially
harder to configure (neither the log4j MBeans nor my own enhanced
replacements thereof handle this class yet -- nor does the properties
configurator), so I see these classes as living a *lot* longer in
practice -- at least DailyRollingFileAppender.
- In trying to produce truly generic MBean wrappers for 1.2 I had
to special case Priority objects to convert to/from Strings and had to
add reflection based logic to decide whether to use Priority or Level
in such cases.
- Layout's setIgnoresThrowable() has no corresponding
isIgnoresThrowable()
or getIgnoresThrowable() so anything based on bean patterns (e.g. the
log4j MBeans last I looked and mine as well) will not pick up on the
fact that the 'ignoresThrowable' property is readable. An
isIgnoresThrowable() or getIgnoresThrowable() method should be
introduced (it can simply call ignoresThrowable(), of course).
Such issues -- both binary and source compatibility, but especially the
binary compatibility issues -- would seem to:
- limit log4j 1.3 migration,
- fragment the log4j community, and
- push log4j users towards any available alternative.
All of which are the last thing any of us want.
Is there any chance such issues can be addressed? Is there any notion
as to when log4j 1.3 might realistically be released? I fear for the
deadlocking issues in 1.2 and want to see a move to 1.3, but the number
of hurdles above beyond simple "don't use Priority or Category in your
source code" mantra would seem to hurt the log4j community if the 1.3
release was to occur today. On the other hand assuming nothing else
broke that I use that in turn uses log4j, I'd personally just recompile
against 1.3 at that point. I'm a bit doubtful that nothing else would
break, however!
--
Jess Holle
|