In the current log4j code, the Category
class is
polluted with static methods such as getInstance()
,
getRoot()
, exists
() etc. These methods
essentially wrap method invocations on the default hierarchy. Although
a single hierarchy may be suitable in stand alone applications, it is
inadequate when used within Servlet containers or Application
Servers. Moreover, a number of users have asked for the simplication
of the Category
class.
At this juncture it also seems beneficial to adopt some of the
component names as proposed in the upcoming JSR47 API, namely,
Level
instead of Priority
and
Logger
instead of Category
.
It is proposed to rename the Priority
class to
Level
. To preserve backward compatibility a Priority
class will be included which will extend Level
without
changing or adding any functionality. Classes that contain methods
involving priorities, say setPriority
, will contain a
method called setLevel
and also a method called
setPriority
(to preserve backward compatibility).
The user will only deal with a minimal Logger
class
offering few essential methods. More concretely:
public abstract class Logger { protected final String name; protected Logger(String name) { this.name = name; } public final String getName() { return name; } public abstract boolean isDebugEnabled(); public abstract void debug(Object message); public abstract void debug(Object message, Throwable t); public abstract boolean isInfoEnabled(); public abstract void info(Object message); public abstract void info(Object message, Throwable t); public abstract boolean isWarnEnabled(); public abstract void warn(Object message); public abstract void warn(Object message, Throwable t); public abstract boolean isErrorEnabled(); public abstract void error(Object message); public abstract void error(Object message, Throwable t); public abstract boolean isFatalEnabled(); public abstract void fatal(Object message); public abstract void fatal(Object message, Throwable t); public abstract boolean isEnabledFor(Level level); public abstract void log(Level level, Object message, Throwable t); public abstract void log(Level level, Object message); } |
Here are a few remarks on the Logger
class.
Logger
is an abstract
class and not an interface.
debug
, info
,
warn, error
, fatal
levels is hardcoded in
Logger
methods. This seems appropriate because, as far as
I am aware, these levels are not disputed.
Intent
The LogManager
provides a flexible method for
retrieving Logger
instances of varying types
held in context-dependent repositories.
Motivation
Log4j is a a low level API used in a variety of projects.
Consequently, it is hard to make a priori assumptions about the
environment where log4j will run. The problem is particularly acute in
embedded components (e.g. libraries) which rely on log4j for their
logging. The author of embedded component can rarely afford to make
restrictive assumptions about the surrounding environment, a fortiori
assumtions about logging. It might be the case that the end user is
not interested in logging at all. It would be a total waste to
generate logging output for a user who will never look at them. Under
such circumstances, the embedded component will want to use a
NullLogger
which would not genereate any log output at
all.
Logging in Application Servers and Servlet Containers also create unique problems. It is often desirable to separate logging output originating from different applications (or web-application in the case of Servlet Containers). In the current version of log4j it is possible to have different applications live in their own parallel universe by using a different hierarchy for each application. For more details, refer to my multiple hierarchy tutorial for Servlet Containers.
Using multiple hierarchies works well with code that is designed to use them. However, it does not entend to a library which uses log4j but is unaware of multiple hierarchies.
LogManager should allow us to vary Logger
implementation depending on the circumstances. Moreover, we would like
to be able to control the logging repository (or hierarchy) where
loggers are held depending on the application context.
Related Patterns
LogManager is related to the AbstractFactory
design pattern. It is largely based on the
PluggableFactory
pattern. Refer to John Vlissides' two
articles Pluggable
Factory, Part I and Pluggable
Factory, Part II to gain more insight on the problem.
Public interface
The public interface of the LogManager class consists of a few static methods.
public class LogManager {
public static Logger getRootLogger() {
// return the appropriate root Logger
}
public static Logger getLogger(String name) {
// return the appropriate Logger instance
}
// The actual task of manufacturing loggers is delegated to a
|
Note that altough the methods are static there is a lot of flexibility in the underlying implementation. See the implementation section below.
Typical usage:
import org.apache.log4j.LogManager; import org.apache.log4j.Logger; public class Foo { final static Logger logger = LogManager.getLogger(Foo.class.getName()); void bar() { logger.debug("hello world."); } } |
One of the advantages of the LogManager
approach is
that the getInstance
method can return totally different
Logger
implementations. For example, under JDK 1.2 we can
return a Logger implementation that is aware of the Java2 security
model whereas under JDK 1.1 the returned logger implementation may be
oblivious to Java2 security checks. In shipped code, LogManager may be
configured to return a NullLogger
which could implement
the Logger
(abstract) class with empty method bodies.
Impelementation
The behavior of LogManager
is mostly determined by the
LoggerRepository
it uses. However, it may also be influenced
by system properties or by parameters passed as a result of
LogManager
method invocations.
Here is a tentative implementation.
package org.apache.log4j; /** Use the |
public interface LoggerRepository { // return the appropriate root Logger public Logger getRootLogger(); // return an appropriate Logger instance public Logger getLogger(String name); // public void enable(Level level); } |
Existing users of log4j need not worry about the compatibility of their code with future versions of log4j. We will make sure that client code runs seamlessly with log4j versions based on the revised interfaces proposed in this document.