Logger replaces CategoryAround the time JDK 1.4 was released, it was decided that
log4j would rename its Category class as
Logger. We of course wanted to preserve
compatibility with existing client code, so several migration
strategies were studied.
The obvious strategy of Category extending
Logger was not an option because it could not
guarantee compatibility with existing code invoking log4j methods
returning a Category instance. For example,
Category cat = Category.getInstance();
would either not compile or throw a
ClassCastException because if Category
extends Logger, then an instance of Logger
is not an instance of Category.
Nicholas Wolff suggested a less intuitive alternative whereby
Logger would extend Category and we
would make sure that log4j only produced Logger
instances. This is the alternative we adopted.
There are two inconveniences with Nicholas' method. First,
since Logger extends Category,
Category could not be marked as @deprecated because
that would cause derived classes, in particular the
Logger class to also generate deprecation warnings
rendering the whole exercise rather pointless and
even counterproductive. Second, although Nicholas' strategy solves
compile time issues, it still leaves room for binary (or
runtime) compatibility problems. These problems are fortunately
rare and are being addressed on a case by case basis..
Category class directly, but use the
Logger class instead.
In log4j 1.2, released on May 2002, that is almost 3 years
ago, the Category class has been
advertised as being deprecated. It has been replaced
by the Logger class. As of log4j version 1.2, users
should never refer to the Category class directly,
but use the Logger class instead as advertised
in the Category class javadocs.
For the reasons mentioned previously, in log4j version 1.2.x,
the Category class was not tagged with the
@deprecated javadoc tag in the source code. This voluntary
omission led to a situation where users could still refer to the
Category class without deprecation warnings being
generated by the java compiler. Consequently, some users
unfortunately still continue to refer to the
Category class.
We have marked in red and in bold that users should drop
references to the Category class and use
Logger instead. However, us shouting about this
important point does not tell the java compiler to enforce
it. Since we cannot mark the Category class as
@deprecated in the javadocs, the only compiler-enforced way of
pushing users to migrate to the Logger class is to
tag those methods in the Category class that have
Category as their return value in their
signature. These methods are:
static public Category getRoot();static public Category getInstance(String name);static public Category getInstance(Class clazz);Unfortunately, log4j versions up to and including 1.2.8 did not mark these methods as deprecated. However, log4j 1.2.9 will mark them as deprecated. Note that the release of log4j 1.2.9 has not been yet been approved by the PMC of the Logging Services project.
Assuming log4j version 1.2.9 is approved, then we can assume
that users of 1.2.9 will only refer to the Logger
class. If that is the case, their code will compile and run
without change with log4j 1.3 even when the
Category class is removed.
Level replaces PriorityPriority class directly, but use the
Level class instead.
In log4j 1.2, the Level class replaced the
Priority class. We adopted the same migration
strategy as for the Category/Logger case. In other words, the
Level class extends the Priority
class. The client code should not use or refer to the
Priority class but use Level class
instead.
Since the Priority class could not be tagged as
deprecated, we deprecated all the methods returning a
Priority instance. These are:
static public Priority toPriority(int);static public Priority toPriority(int, Priority);static public Priority toPriority(String);static public Priority toPriority(String, Priority);Moreover, all the static member fields of type
Priority in the Priority class have
been deprecated. They have been replaced by equivalent fields of
the same name in the Logger class. These deprecated
fields in the Priority class are listed below:
static public Priority FATAL;static public Priority ERROR;static public Priority WARN;static public Priority INFO;static public Priority DEBUG;For all appenders except trivial ones, the
activateOptions() method must be called before an
appender can be used. This is true for both log4j versions 1.2
as well 1.3.
However, in log4j 1.3, this contract is enforced by run-time
checks. Thus, if you forget to call
activateOptions() method,
AppenderSkeleton will refuse to invoke the
append() method of its derived classes.
Users who programmatically instantiate appenders, even
appenders maintained outside the log4j project, need to call the
activateOptions() method after they instantiate and
set its options. This will ensures run-time compatibility for
log4j 1.2 as well as 1.3.
Even if you are still using log4j version 1.2.x, we highly recommend that you follow the following recipe to prepare your code for 1.3, the next version of log4j.
Category class directly,
refer to Logger instead.
Do not invoke the deprecated Category.getRoot
method. Invoke Logger.getRootLogger
method instead.
Do not invoke the deprecated Category.getInstance(String)
method. Invoke Logger.getLogger(String)
method instead.
Category.getInstance(Class)
method. Invoke Logger.getLogger(Class)
method instead.
Never refer to the Priority class, refer to
Level class instead.
Do not invoke the deprecated Category.setPriority(Priority)
method. Invoke Logger.setLevel(Level) method instead.
Do not invoke the deprecated Priority.toPriority(int)
method. Invoke Level.toLevel(int)
method instead. The same holds true for the other variants of the Priority.toPriority method.
Never refer to the deprecated Priority.FATAL,
Priority.ERROR, Priority.WARN,
Priority.INFO, Priority.DEBUG
fields. Refer to the Level.FATAL,
Level.ERROR, Level.WARN,
Level.INFO, Level.DEBUG fields
instead.
If you confiugure appenders programmatically, do not
forget to invoke the activateOptions method of an
appender after you have instantiated it and set its options.
Thus, instead of writing:
Category root = Category.getRoot();
root.debug("hello");
Category cat = Category.getInstance(Some.class);
cat.debug("hello");
cat.setPriority(Priority.INFO);
Logger root = Logger.getRootLogger();
root.debug("hello");
Logger logger = Logger.getLogger(Some.class);
logger.debug("hello");
logger.setLevel(LEVEL.INFO);
For 99.99% of users, this translates to the following string find-and-replace operations: