Logger
replaces Category
Around 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 Priority
Priority
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: