Java Logging
Facilities
The monitorization of the behavior complex
applications, during development and execution phase proves to be necessary
in order to assert their correctness. For runtime advanced monitoring and
management, specific frameworks exit, such as JMX. But development and error
tracking require more leightweight, static solutions. Logging libraries
provide tools that enable a posteriori analysis of the behavior of considered
systems.
Logging means classifying
alerts according to severity level and making them available for the users,
administrators, or developpers. In order to provide a comprehensive view of
the system, a dedicated Logger is often bounded to each class.
This document propose an overview of the main logging
facilities for Java, along with links to reference documents that give more
details about their use. Some comparison elements between J2SE Logging API
and Log4J framework are given.
Logging Libraries for Java
Main logging libraries for
Java are :
- Sun J2SE Logging API
- Apache Log4J framework
- Simple Log library
- Jakarta Common Logging API
- Simple Logging Facade for Java
- X4juli
Sun J2SE Logging
API
Main objective :
configurable logging API for Java
For further informations
:
Apache Log4J
framework
Main Objective : Prevent
performance cost that frequently occur in logging API (even when turned
off).
For further informations
:
Simple Log
library
Main Objective : Zero learning curve for
simpliest logging.
For further informations
:
Jakarta Common Logging API
Main Objective : Thin, modular bridging API with
out-of-the-box support for most well known logging systems.
For further informations :
Simple
Logging Facade for Java (SL4J)
Main Objective : Providing a facade for various
logging APIs
For further informations :
X4juli
Main Objective : Extension to J2SE Logging API
that provide main parts of log4J, as well as an implementation of Jakarta
Commons Logging (JCL) API and Simple Logging Facade for Java (SLF4J)
API
For further information :
The
Logging Process
The overall logging process is the following
:
- An application sends
logs to a given Logger Object,
- The Logger can filter
the informations it receives (for instance according to the severity of
the alert),
- The Logger forwards
logging data to the handler,
- The Handler can filter
the informations it receives (for instance according to the Logger Type,
of to the severity of the alert),
- The Handler them writes the filtered information
to a specific Output Format.
Comparison
: Sun J2SE Logging API vs. Apache Log4J
You will find in
this section some technical comparison between Sun J2SE Logging API and
Log4J. They are meant as technical reference for helping you chose between
both libraries, not as a tutorial.
Severity
of the Alerts - Warning levels
Warning levels are defined in the Level class in both
libraries. They make it possible to indicate the severity of the alert, and
thus to filter these alerts.
Warning levels are the
following (in growing order of severity) :
- Sun J2SE Loggin API :
All, Finest, Finer, Fine, Config, Info, Warning, Severe, Off.
- Apache Log4J : All, Debug, Info, Warn, Error,
Fatal, Off.
Handlers
Various Handler are defined, that enable to
forward loggin information to various output facilities :
- Sun J2SE Loggin API :
StreamHandler (to data stream), ConsoleHandler (to System.err),
FileHandler (to a specified file), SocketHandler (to the network),
MemoryHandler (to a shared memory).
- Apache Log4J : console,
files, GUI components, remote socket servers, JMS, NT Event Loggers, and
remote UNIX Syslog daemons (+ asynchronous logging).
Output
Layout
Several Output
Layout can be used, according to output type (graphical, text, automated
analysis):
- Sun J2SE Loggin API :
SimpleFormatter, XMLFormatter
- Apache Log4J :
SimpleLayout (log type - log message), DateLayout, TTCC (log type, logger
name, log message), HTML Layout, PatternLayout (enables fine
configurations), XMLLayout.
Security
- Sun J2SE Loggin API :
LoggingPermission Permission for checking if logging is authorized;
method getAnonimousLogger for untrusted code and applets; beware of lack
of protection against spoofing (log forging), and DoS attacks (excessive
log load).
- Apache Log4J : not
specified.
Code Examples
Here are some code example that provide first
examples for using several logging libraries : Simple Log, Sun J2SE Logging
API, Log4J.
Simple Log
A piece of code
fromSimple Log web site.
public class
HelloWorld
{
// Create a
SimpleLogger:
private static final
SimpleLogger log = new SimpleLogger(HelloWorld.class);
public static
void
main(String[]
argv)
{
try
{
// Use it!
log.entry("main()");
log.debug("About to
print 'Hello World!'");
String
helloWorldString = "'Hello World!'";
log.dbo(DebugLevel.L6_VERBOSE,
"helloWorldString", helloWorldString);
log.db(DebugLevel.L7_LUDICROUS,
"I can't believe
this library has a level called 'Ludicrous'!");
System.out.println(helloWorldString);
log.debug("Printed
'Hello World!'");
log.info("Did you
get that?");
log.warn("This
example is very contrived.");
}
catch (Throwable
t)
{
// Just in
case...
log.fatal("Something
really unexpected dropped by.");
log.dbe(DebugLevel.L1_FATAL,
t);
}
log.exit("main()");
}
|
Matching output is
:
Fri 2004/11/26
21:10:32.618|>>>|main|HelloWorld|main()
Fri 2004/11/26
21:10:32.618| |main|HelloWorld|About to print 'Hello World!'
Fri 2004/11/26
21:10:32.618|---|main|HelloWorld|helloWorldString|'Hello World!'
Fri 2004/11/26
21:10:32.618| |main|HelloWorld|I can't believe this library has a
level called 'Ludicrous'!
'Hello World!'
Fri 2004/11/26
21:10:32.618| |main|HelloWorld|Printed 'Hello World!'
Fri 2004/11/26
21:10:32.618| |main|HelloWorld|Did you get that?
Fri 2004/11/26
21:10:32.618| |main|HelloWorld|This example is very contrived.
Fri 2004/11/26
21:10:32.618|<<<|main|HelloWorld|main()
|
Sun
J2SE Logging API
Example of a method
doSomething() that creates a Logger, and launches a class MyFunnyClass using
this logger.
public void doSomething()
throws
IOException
{
//create a logger
logger =
Logger.getLogger("logging.sun");
fh = new
FileHandler("mylog.txt");
logger.addHandler(fh);
// Request that
every detail gets logged.
logger.setLevel(Level.ALL);
// Log a simple INFO
message.
logger.info("doing
stuff");
//lauches a class
that use this logger
MyFunnyClass fun =
new MyFunnyClass(logger);
fun.execute();
}
|
doSomething()
method.
import java.util.logging.Level;
import
java.util.logging.Logger;
public class
MyFunnyClass {
Logger log =
null;
public
MyFunnyClass(Logger log)
{
this.log = log;
}
public void
execute()
{
System.out.println("I
am funny");
log.log(Level.WARNING,"Funny
is Warning U");
}
}
|
MyFunnyClass
class.
Log4J
Two option s exist for configuration : programmatic
configuration, or config file based configuration. Config file based
configuration enables centralized control of logging, and thus easier control
of the logging process. Both are presented here.
This code is
partially driven fromLog4J tutorial.
- Programmatic configuration
As in Sun Logging example
API, a method (testWithManualConfiguration) (often not found in monitorized
class, MyFunnyClass) contains the configuration of the logger.
public void
testWithManualConfiguration()
{
Layout layout =
null;
//layout = new
TTCCLayout();
layout = new
XMLLayout();
//layout = new
HTMLLayout();
AppenderSkeleton
appender = null;
appender = new
ConsoleAppender(layout);
MyFunnyClass fun =
new MyFunnyClass(appender);
fun.execute();
}
|
testWithManualConfiguration
method
package logging.log4J;
import
org.apache.log4j.AppenderSkeleton;
import
org.apache.log4j.Level;
import
org.apache.log4j.Logger;
import
org.apache.log4j.PropertyConfigurator;
public class
MyFunnyClass {
Logger logger =
null;
AppenderSkeleton
appender = null;
public
MyFunnyClass(AppenderSkeleton as)
{
appender = as;
logger =
Logger.getLogger("logging.log4J.LoggingTest");
logger.addAppender(appender);
logger.setLevel(Level.INFO);
}
public void execute()
{
System.out.println("I am funny");
logger.log(Level.WARN,"Funny is
Warning U");
// This request is enabled, because
WARN >= INFO.
logger.warn("Low fuel level.");
// This request is disabled, because
DEBUG < INFO.
logger.debug("Starting search for
nearest gas station.");
// The logger instance barlogger,
named "com.foo.Bar",
// will inherit its level from the
logger named
// "com.foo" Thus, the following
request is enabled
// because INFO >= INFO.
logger.log(Level.INFO,"Located
nearest gas station.");
// This request is disabled, because
DEBUG < INFO.
logger.debug("Exiting gas station
search");
}
}
|
MyFunnyClass class.
- Config File Based
configuration
No code in necessary
outside of the monitorized class. The configuration file is defined in a
centralized place, and can be common to all loggers.
# Set root logger level to DEBUG and its
only appender to A1.
log4j.rootLogger=INFO,
A1
# A1 is set to be a
ConsoleAppender.
log4j.appender.A1=org.apache.log4j.ConsoleAppender
# A1 uses
TTCCLayout.
log4j.appender.A1.layout=org.apache.log4j.TTCCLayout
#log4j.appender.A1.layout=org.apache.log4j.xml.XMLLayout
#log4j.appender.A1.layout.ConversionPattern=%-4r
[%t] %-5p %c %x - %m%n
|
log4j.properties file.
package logging.log4J;
import
org.apache.log4j.AppenderSkeleton;
import
org.apache.log4j.Level;
import
org.apache.log4j.Logger;
import
org.apache.log4j.PropertyConfigurator;
public class
MyFunnyClass {
Logger logger =
null;
AppenderSkeleton
appender = null;
public
MyFunnyClass()
{
logger =
Logger.getLogger("logging.log4J.LoggingTest");
PropertyConfigurator.configure("log4J.properties");
}
public void
execute()
{
System.out.println("I
am funny");
logger.log(Level.WARN,"Funny is Warning
U");
// This request is enabled, because WARN >= INFO.
logger.warn("Low fuel level.");
// This request is disabled, because DEBUG < INFO.
logger.debug("Starting search for nearest gas station.");
// The logger instance barlogger, named "com.foo.Bar",
// will inherit its level from the logger named
// "com.foo" Thus, the following request is enabled
// because INFO >= INFO.
logger.log(Level.INFO,"Located nearest gas station.");
// This request is disabled, because DEBUG < INFO.
logger.debug("Exiting gas station search");
}
}
|
MyFunnyClass class.
|