3. How does the CLF work?
Applications make logging calls on commonLogger objects. These commonLogger
objects pass log messages to Handler for publication. Both commonLoggers
and Handlers may use logging Levels to decide if they are interested in
a particular log message. Since a commonLogger object is tied with an underlying
logger tool, such a category or a channel according to the underlying logging
service, the Handler responsible to manage the output is also tied with
the respective mechanism managing the output as defined by the same underlying
logging service such an Appender or a LogWriter. That is a Handler can
use appropriate mechanism to format and localize a log message before publishing
it to the output.
3.1 commonLogger,
LoggerFactory and LogManager
commonLogger
objects are provided by a LoggerFactory
object, which hides the type of the underlying logging implementation.
The
LogManager
is responsible to create a LoggerFactory appropriate to an underlying
logging implementation. For this aim, the LogManager uses the property
named "com.hp.mw.common.utils.logging.factory", to
determine the underlying class that shall be loaded to create commonLogger
objects. The classes provided by this distribution are:
-
com.hp.mwlabs.common.util.logging.log4j.ArjLoggerFactory (Default
class). This class allows to build log4j logger objects.
-
com.hp.mwlabs.common.util.logging.csf.ArjChannelFactory. This class
allows to build logger objects specific to the HP logging API mainly used
by the HP CSF framework.
-
com.hp.mwlabs.common.util.logging.simpleLog.ArjSimpleLoggerFactory
. This class allows to build simple commonLogger objects if an underlying
logging tool is not provided.
The way to provide the classname, identifying the LoggerFactory to use,
allows defining new logging services without rebuilding the Common Logging
Framework. The following example illustrates how a LoggerFactory object
and a commonLogger object are created:
import com.hp.mw.common.util.logging.LogManager;
import com.hp.mw.common.util.logging.LoggerFactory;
import com.hp.mw.common.util.logging.commonLogger;
..
static LoggerFactory
log_fac = LogManager.getLogFactory();
static commonLogger
mylogger = (commonLogger)log_fac.getLogger("TestLogLevels"); |
An application can be executed as follows where the property specifying
the underlying logging service is provided:
java –Dcom.hp.mw.common.utils.logging.factory
=<log_classname> MyApplication
Where <log_classname> may have one of the values described above or
any class that implements the LoggerFactory interface.
Rather that using the Java -D flag, all all properties may be defined
in a configuration file used by the CLF.
3.2 Logs Levels
Each log message has an associated log Level. The Level gives the importance
and urgency of a log message. Log level objects encapsulate an integer
value, with higher values indicating higher priorities.
Similarly commonLogger may be assigned log Levels. The set of
possible Log Levels are DEBUG, INFO, WARN,
ERROR and FATAL defined
in the com.hp.mw.common.util.logging.CommonLevel
class. Since Log Levels are assumed to be associated to the underlying
levels or priorities defined by the underlying logging service, they are
defined as static but no final variables in such way that their final values
will be assigned at initialisation by the appropriate LoggerFactory.
The table below describes how is mapped the concept of the Level interface
and the CommonLevel values to the underlying logging service.
Common Logging Framework
|
Log4j
|
HP Logging
|
JDK1.4 Logging API*
|
Level
|
Priority
|
LogLevel
|
Level
|
FATAL
|
FATAL
|
CRITICAL
|
SEVERE
|
ERROR
|
ERROR
|
ERROR
|
SEVERE
|
WARN
|
WARN
|
WARNING
|
WARNING
|
INFO
|
INFO
|
INFO
|
INFO
|
DEBUG
|
DEBUG
|
DEBUG
|
FINEST
|
*Not Implemented yet
Clients should normally use the predefined Common Level such as CommonLevel.FATAL
or CommonLevel.INFO.
As stated earlier, client code sends log requests to commonLogger
objects. Each commonLogger keeps track of a log level that it is
interested in, and discards log requests that are below this level. In
other words, a logging request is said to be enabled if its log Level is
higher than or equal to the Log Level of its commonLogger. Otherwise, the
request is said to be disabled. By default, a commonLogger is assigned
with the CommonLevel.DEBUG, the
lowest value allowing the commonLogger to accept any log request.
The Level associated with the commonLogger can be changed with the
setLogLevel method defined in the commonLogger interface.
In addition to specify its Level, a commonLogger may be disabled and
enabled. Disabling a CommonLogger, with the DisableLog
method on the commonLogger
interface, means that it any log message is discarded whatever its Level.
Enabling a commonLogger, the EnableLog
method on the commonLogger interface, means that log messages with same
or higher priority are enabled. The method IsEnabled on the commonLogger
interface allows determining if the commonLogger is enabled or not.
Defined Levels are ordered according to their integer values as follows:
DEBUG
< INFO < WARN < ERROR < FATAL. The following example
illustrates how logging request are enabled or disabled:
. . .
static LoggerFactory
log_fac = LogManager.getLogFactory();
// get a commonLogger
instance named "TestLogLevels"
static commonLogger
mylogger = (commonLogger)log_fac.getLogger("TestLogLevels");
// Set the commonLogger
Level to INFO
mylogger.setLogLevel(CommonLevel.INFO);
// This request
is enabled, because FATAL > INFO
mylogger.log(CommonLevel.FATAL,
"This is the first FATAL Message");
// This request
is disabled, because DEBUG < INFO
mylog.log(CommonLevel.DEBUG,
"This is the first DEBUG Message");
// This CommonLogger
is disabled the two next request are disabled
mylogger.DisableLog();
mylogger.log(CommonLevel.INFO,
"This is the first Info Message");
mylogger.log(CommonLevel.FATAL,
"This is the second FATAL Message");
/* This CommonLogger
is enabled the two next request are enabled since their values >= INFO
*/
mylogger.EnableLog();
mylogger.log(CommonLevel.INFO,
"This is the second INFO Message");
mylogger.log(CommonLevel.FATAL,
"This is the third FATAL Message");
. . . |
3.3 Logging Requests
The commonLogger interface provides the log method with a variety of arguments
as described hereafter:
/** Log a message, with
no arguments if the the commonLogger is enabled for
* the given
message level */
void log(Level
level, Object message);
/** Log a throwable arguments
message */
void log(Level
level, Throwable throwable);
/** Log a message, with
a throwable arguments */
void log(Level
level, Object message, Throwable throwable);
/** Log a message, with
arguments */
void log(Level
level, Object message, Object[] params);
/** Log a message, with
arguments and with a throwable arguments */
void log(Level
level, Object message, Object[] params, Throwable throwable); |
Rather than calling the log method on the commonLogger interface, for
convenience the Common Logging Framework provides methods associated with
Level. That is rather than to invoke “commonLogger.log(CommonLevel.FATAL,
…” a programmer will invoke “commonLogger.fatal(…”.
3.4 Debugging Granularity
Extension
The Common Logging Framework provides an extension to filter logging messages
according to finer granularity an application may define. That is, when
a log message is provided to the commonLogger with the DEBUG level, additional
conditions can be specified to determine if the log message is enabled
or not. Note that these conditions are applied if and only the DEBUG level
is enabled and the log request performed by the application specifies debugging
granularity.
When enabled, Debugging is filtered conditionally on three variables:
-
Debugging level: this is where the log request with the DEBUG Level is
generated from, e.g., constructors or basic methods.
-
Visibility level: the visibility of the constructor, method, etc. that
generates the debugging.
-
Facility code: for instance the package or sub-module within which debugging
is generated, e.g., the object store.
According to these variables the Common Logging Framework defines three
interfaces. A particular product may implement its own classes according
to its own finer granularity.
public interface DebugLevel
{
/**
return the value of the Debug level. */
long
getLevel (String level);
/**
return the string representation of the Debug level.
*/
String
printString (long level);
} |
public interface FacilityCode
{
/**
return the value of the facility level. */
long
getLevel (String level);
/**return
the string representation of the facility level. */
String
printString (long level);
} |
public interface VisibilityLevel{
/**
return the value of the visibility level. */
long
getLevel (String level);
/**
return the string representation of the visibility level. */
String
printString (long level);
} |
To permit the possibility to associate finer granularity values for
a debug messages, the commonLogger interface provide the following operation:
void
debug(Object message, long dl, long vl, long fl);
The debug message is sent to the output only if the specified debug level
(dl), visibility
level (vl),
and facility code (fl)
match those allowed by the commonLogger. Finer levels assigned to the commonLogger
are initialised at its creation or can be defined dynamically via a set
of operations provided by the commonLogger interface. An application can
specify its own values, however the Common Logging Framework provides default
level values, per finer class, to indicate that no possible debug message
is permitted or all debug messages are permitted.
3.4.1 Common Values
1. The CommonDebugLevel
class provides the following enumerated types
public class CommonDebugLevel
{
public
static final long NO_DEBUGGING = 0;
public
static final long CONSTRUCTORS = 0x00000001;
public
static final long DESTRUCTORS = 0x00000002;
public
static final long CONSTRUCT_AND_DESTRUCT = CONSTRUCTORS |
DESTRUCTORS;
public
static final long FUNCTIONS = 0x00000010;
public
static final long OPERATORS = 0x00000020;
public
static final long FUNCS_AND_OPS = FUNCTIONS | OPERATORS;
public
static final long ALL_NON_TRIVIAL = CONSTRUCT_AND_DESTRUCT | FUNCTIONS
| OPERATORS;
public
static final long TRIVIAL_FUNCS = 0x00000100;
public
static final long TRIVIAL_OPERATORS = 0x00000200;
public
static final long ALL_TRIVIAL = TRIVIAL_FUNCS |
TRIVIAL_OPERATORS;
public
static final long FULL_DEBUGGING = 0xffffffff;
} |
-
NO_DEBUGGING: No diagnostics.
A commonLogger object assigned with this values discard all debug requests
-
FULL_DEBUGGING: Full diagnostics.
A CommonLogger object assigned with this value allows all debug requests
if the facility code and the visibility level match those allowed by the
commonLogger.
Additional Debugging Values are:
-
CONSTRUCTORS: Diagnostics from
constructors.
-
DESTRUCTORS: Diagnostics
from finalizers.
-
CONSTRUCT_AND_DESTRUCT: Diagnostics
from constructors and finalizers.
-
FUNCTIONS: Diagnostics from
functions.
-
OPERATORS: Diagnostics from
operators, such as equals.
-
FUNCS_AND_OPS: Diagnostics from
functions and operations.
-
ALL_NON_TRIVIAL: Diagnostics from
all non-trivial operations.
-
TRIVIAL_FUNCS: Diagnostics
from trivial functions.
-
TRIVIAL_OPERATORS: Diagnostics
from trivial operations, and operators.
-
ALL_TRIVIAL: Diagnostics
from all trivial operations.
2. The CommonFacilityCode
class provides two enumerated types as described below:
public class CommonFacilityCode
{
public
static final long FAC_NONE = 0x00000000;
public
static final long FAC_ALL = 0xfffffff;
} |
-
FAC_NONE: No Diagnostic
A commonLogger object assigned with this values discard all debug requests
-
FAC_ALL: Full Diagnostic
A commonLogger object assigned with this value allows all debug requests
if the debug level and the visibility level match those allowed by the
commonLogger.
3. The CommonVisibilityCode
class provides two enumerated types as described below:
public class CommonVisibilityLevel
{
public
static final long VIS_NONE = 0x00000000;
public
static final long VIS_PRIVATE = 0x00000001;
public
static final long VIS_PROTECTED = 0x00000002;
public
static final long VIS_PUBLIC = 0x00000004;
public
static final long VIS_PACKAGE = 0x00000008;
public
static final long VIS_ALL = 0xffffffff;
} |
-
VIS_NONE: No Diagnostic
-
VIS_PRIVATE : only from private methods.
-
VIS_PROTECTED only from protected methods.
-
VIS_PUBLIC only from public methods.
-
VIS_PACKAGE only from package methods.
-
VIS_ALL: Full Diagnostic
A commonLogger object assigned with this value allows all debug requests
if the debug level and the facility code match those allowed by the commonLogger.
Once enabled, logging requests with DEBUG Level can be controller by
setting the property variables DEBUG_LEVEL, VIS_LEVEL and FAC_LEVEL appropriately.
3.4.2 Defining its own finer debugging classes
For each type of variable an application may define its own class providing
its own enumerated values, which shall differ those described above - In
other words different from 0x00000000 or 0xffffffff. However, to avoid
any confusion between finer values, the application should take benefit
from the bit representation by defining its values as follow.
Level_1 = 0x00000001
Level_2 = 0x00000002
. . .
public class MyDebugValues
public static final
long
Since each debugging level is represented by a single bit in the controller,
debugging of multiple levels can be produced by OR-ing together the fields.
For instance a new value can be defined as follow:
Level_3 = Level_1
| Level_2
If for instance, a CommonLogger object is assigned the Level_3, it enables
a debug message only if the debug request is provided either with Level_3
or with Level_1 | Level_2.
As a template the following example illustrates how to build its own
debugging classes providing a finer granularity.
import com.hp.mw.common.util.logging.DebugLevel;
import com.hp.mw.common.util.logging.CommonDebugLevel;
public class MyDebugLevel
implements DebugLevel
{
public static
final long DEBUG_LEVEL_1 = 0x00000001;
public static
final long DEBUG_LEVEL_2 = 0x00000002;
public static
final long DEBUG_LEVEL_3 = 0x00000004
. . .
public final
long getLevel (String level)
{
if (level.equals("N0_DEBUGGING"))
return CommonDebugLevel.NO_DEBUGGING;
if (level.equals("DEBUG_LEVEL_1"))
return DEBUG_LEVEL_1;
if (level.equals("DEBUG_LEVEL_2"))
return DEBUG_LEVEL_2;
. . .
if (level.equals("FULL_DEBUGGING"))
return CommonDebugLevel.FULL_DEBUGGING;
return CommonDebugLevel.NO_DEBUGGING;
//Default
}
public final String
printString (long level)
{
if (level == CommonDebugLevel.NO_DEBUGGING)
return "NO_DEBUGGING";
if (level == CommonDebugLevel.FULL_DEBUGGING)
return "FULL_DEBUGGING";
String sLevel =
null;
if ((level &
DEBUG_LEVEL_1) != 0)
sLevel = ((sLevel == null) ? "DEBUG_LEVEL_1" : " & DEBUG_LEVEL_1");
if ((level &
DEBUG_LEVEL_2) != 0)
sLevel = ((sLevel == null) ? "DEBUG_LEVEL_2" : " & DEBUG_LEVEL_2");
. . .
return ((sLevel
== null) ? "NO_DEBUGGING" : sLevel);
}
} |
In a similar way the application may define its own classes implementing
the classes FacilityCode and VisibilityLevel.
3.4.3 commonLogger Debugging Values
Finer debugging values are assigned to a commonLogger object dynamically
through the following methods on the commonLogger interface:
public interface CommonLogger
extends Handler {
.
. .
//
All Level
void
setLevels (long dl, long vl, long fl);
//
Debug Level
long
getDebugLevel ();
void
setDebugLevel (long level);
void
mergeDebugLevel (long level);
//
Visibility Level
long
getVisibilityLevel ();
void
setVisibilityLevel (long level);
void
mergeVisibilityLevel (long level);
//
FacilityCode Levels
long
getFacilityCode ();
void
setFacilityCode (long level);
void
mergeFacilityCode (long level);
....
} |
-
getXXX methods
are used to obtain the current level assigned to a CommonLogger object.
-
setXXX methods
are used to set the level of a CommonLogger object
-
mergeXXX methods
are used to add a level value to CommonLogger.
3.4.4 A simple scenario
The following example illustrates how finer granularity extension is used
when the DEBUG is enabled by the commonLogger. The application provides
its own finer classes. We assume that the default finer values used to
initialize the commonLogger are defined a configuration file.
import com.hp.mw.common.util.logging.CommonLevel;
import com.hp.mw.common.util.logging.commonLogger;
import com.hp.mw.common.util.logging.LoggerFactory;
import com.hp.mw.common.util.logging.LogManager;
import com.hp.mw.common.util.logging.Level;
import com.hp.mw.common.util.logging.CommonDebugLevel;
public class DebugExt{
static LoggerFactory
log_fac = LogManager.getLogFactory();
static commonLogger
mylog = (commonLogger)log_fac.getLogger("TestLogLevels");
public static
void main(String[] args) {
mylog.debug("This
is a DEBUG Message");
mylog.debug("This
debug message is enabled since it matches default
Finer Values", MyDebugLevel.DEBUG_LEVEL_1,
MyVisibilityLevel.VIS_LEVEL_1, MyFacilityCode.LEVEL_1);
mylog.debug("This
debug message is discarded since it does'nt match
default Finer Values", MyDebugLevel.DEBUG_LEVEL_2,
MyVisibilityLevel.VIS_LEVEL_1, MyFacilityCode.FAC_LEVEL_1);
mylog.mergeDebugLevel(CommonDebugLevel.FULL_DEBUGGING);
mylog.debug("This
debug message is enabled since it the CommonLogger allows
full debugging", MyDebugLevel.DEBUG_LEVEL_3,
MyVisibilityLevel.VIS_LEVEL_1, MyFacilityCode.FAC_LEVEL_1);
}
} |
Main
Previous
Next