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


Reply via email to