As of version 0.8 of the JSR47 specification the
java.util.logging
API resembles log4j even more
than was the case previously. The way the two APIs name their
components may differ but otherwise their degree of
resemblance is quite striking.
Changes introduced in the latest 0.8 draft include configuration order independence, appender inheritance, resource bundle inheritance, error handlers and lazy inference of caller information. In other words, even if the priority levels remain unchanged and somewhat bogus, the majority of the points raised in my critique of JSR47 are now obsolete.
Consequently, it is fair to say that our campaign to influence the JSR47 API handsomely bore fruit. I wish to thank the hundreds of concerned users who have expressed their support for log4j. My gratitude goes to Jason Hunter for arranging the appropriate communication channel to Sun. Graham Hamilton, the JSR47 specification lead, was very open and receptive during our exchanges.
From the user standpoint, there remain two critical differences. First, JSR47 requires JDK 1.4 whereas log4j is compatible with JDK 1.1 and later. Second, log4j offers much more functionality. It supports a rich configuration language, at least a dozen appenders and layouts as well as many other useful features.
Efforts to backport JSR47 to earlier JDKs are doomed to fail
because the java.util.logging
package is located under
the java
namespace. This will cause backported code to
systematically throw a SecurityException
under JDK
1.3. Moreover, Java is a trademark owned by Sun Microsystems. As such,
the backported code will be under the threat of litigation as long as
Sun can be expected to defend its trademark.
If you look at the terms of the final draft of the JSR47 specification, you will discover a copyright notice containing the following text.
Sun hereby grants you a fully-paid, non-exclusive, non-transferable, worldwide, limited license (without the right to sublicense), under Sun's intellectual property rights that are essential to practice the Specification, to internally practice the Specification solely for the purpose of creating a clean room implementation of the Specification that: (i) includes a complete implementation of the current version of the Specification, without subsetting or superset-ting; (ii) implements all of the interfaces and functionality of the Specification, as defined by Sun, without sub-setting or supersetting; (iii) includes a complete implementation of any optional components (as defined by Sun in the Specification) which you choose to implement, without subsetting or supersetting; (iv) implements all of the interfaces and functionality of such optional components, without subsetting or supersetting; (v) does not add any additional packages, classes or interfaces to the "java.*" or "javax.*" packages or subpackages (or other pack-ages defined by Sun); (vi) satisfies all testing requirements available from Sun relating to the most recently pub-lished version of the Specification six (6) months prior to any release of the clean room implementation or upgrade thereto; (vii) does not derive from any Sun source code or binary code materials; and (viii) does not include any Sun source code or binary code materials without an appropriate and separate license from Sun. The Specification contains the proprietary information of Sun and may only be used in accordance with the license terms set forth herein. This license will terminate immediately without notice from Sun if you fail to comply with any provision of this license. Upon termination or expiration of this license, you must cease use of or destroy the Specification.
Given these business terms it is not possible for log4j or other independent parties to implement the JSR47 specification. Here is how the Apache Software foundation, a member of the JCP Executive Committee, voted on this JSR.
The Apache Software Foundation is grateful for the significant efforts of the JSR 47 spec lead, Graham Hamilton, toward addressing the technical concerns raised by the members and lead of Apache's log4j project. Regretfully, under the Merlin business terms, log4j (or any other potential independent implementation of this specification) cannot make use of the Specification, not can anyone implement this specification for earlier J2SE platforms (J2SE 1.2, 1.3), and it is on this basis that Apache cannot support this JSR.
Even without the SecurityException
and the
licensing issue, you would need an additional logging library to fill
in the functionality gap, the JDK compatibility gap, or both. If you
are going to install one or more logging APIs, then why not install
log4j which offers a lot more than JSR47 and is backward compatible
with JDK 1.1?
Log4j is the de facto standard logging API in Java. It has been ported to Python, C, C++, Eiffel and the much maligned C#. By adopting log4j, you simultaneously benefit from much richer functionality and wider JDK compatibility. In any case, with the support of the log4j community, the log4j project will continue to innovate and lead the way. As such, many of the features that you need or will need in the future will be first available in log4j.
As in Linux ipchains, log4j filters use ternary logic. In JSR47, filter logic is binary. Mathematically the two logics are equivalent except that it is much easier to combine generic filters in log4j's ternary logic than in JSR47's binary logic
.For example, if you would like to reject a log message if it contains the string "Microsoft" or the string "proprietary code", accept messages having the info priority and only the info priority and reject everything else, you would write:
<filter class="org.apache.log4j.varia.StringMatchFilter"> <param name="StringToMatch" value="Microsoft" /> <param name="AcceptOnMatch" value="false" /> </filter> <filter class="org.apache.log4j.varia.StringMatchFilter"> <param name="StringToMatch" value="proprietary code" /> <param name="AcceptOnMatch" value="false" /> </filter> <filter class="org.apache.log4j.varia.PriorityMatchFilter"> <param name="PriorityToMatch" value="INFO" /> <param name="AcceptOnMatch" value="true" /> </filter> <filter class="org.apache.log4j.varia.DenyAllFilter"/>
You cannot express this policy with JSR47 filters without writing a filter for exactly this policy.
Filters in loggers (categories)
JSR47 allows filters to be attached to loggers (categories in log4j speak) and also to handlers (appenders in in log4j speak). Log4j allows filters to be attached to appenders but not to categories.
In short, attaching filters to loggers is a feature that JSR47 offers but log4j does not. However, because arbitrary logic cannot be meaningfully composed, filters cannot be inherited. Thus, you would need to attach a filter to every single logger where you would like it to apply.
Bogus levels
JSR 47 defines the levels ALL
,
SEVERE
, WARNING
,
INFO
, CONFIG
, FINE
,
FINER
, FINEST
and
OFF
.
Having three debugging levels FINE
,
FINER
, FINEST
could seem like a
good idea. However, you will soon discover that even when by
yourself, it is hard to decide when to use which level. It
is plain impossible in groups.
Arguing about priority levels is a bit like arguing about your favorite color. I will thus stop here.
Plethora of printing methods
The set of printing methods in the Logger
class is confusing. It is all there -- just not where you
would expect them to be. For example, you cannot log an
exception with the warning
or
severe
methods. You will need to use the
log
method instead.
JSR47 emits sequence numbers in each log record it
creates. The sequence number is synchronized using the
LogRecord
class itself at the cost of a small
but measurable performance penalty. This variable is not
likely to be very meaningful if the logging output is split
between different handlers as the output of each handler
will contain holes in the sequence numbers.
There are many other details in which log4j differs from JSR47. Even if the log4j core is small, the project contains a total of over 30'000 lines of well-tested code. JSR47 contains about 5'000 lines of code.
Log4j has been around for a number of years, enjoys the support of an active community and is being used in thousands of projects. Our site gets over 600 downloads each and every day, and the numbers are on the rise. Companies are also offering commercial products extending log4j.
Here is a short list of open source projects or sites that are known to use log4j.
Sun might be setting a dangerous precedent by ignoring a rather successful open source project. If it happens to log4j, can it happen to your project?
If you feel that Sun is reinventing the wheel and setting a dangerous precedent, then this the time to lobby Sun to adopt log4j as the official logging API for the Java language.
Please direct your polite and personalized request to jsr-47-comments@jcp.org with Bcc: to ceki@qos.ch.
Many individuals have written to Sun to express their concern, in their vast majority pushing for the adoption of log4j. Their names and the content of their request are listed below. I am very grateful for their support. Some of these requests are quite detailed and insightful.
Jon Stevens
Court Demas and his follow up
Henrik Fredholm and his follow up to Graham.
Andy DePue and his follow up
Emily Bache and her follow up
Nate Sammons author of Protomatter Syslog
Balaji Kithiganahalli and his follow up
Most of the e-mail notes are reproduced with permission. However, do not hesitate to contact ceki@qos.ch in case you are uncomfortable seeing your name or the contents of your request reproduced publicly.