This is a more like a tip rather than
technical write up and serves as a quick intro for newbies.
The logger API helps to diagnose
application level or JDK level issues at runtime. There are 7 levels
which decide the detailing in logging (SEVERE, WARNING, INFO, CONFIG,
FINE, FINER, FINEST). Its best to start with highest level and as we
narrow down, use more detailed logging for a specific area. SEVERE is
the highest and FINEST is the lowest.
This may not make sense until we
understand some jargon.
The Logger class provides the ability
to stream messages to an output stream in a format that can be
controlled by the user. What this translates to is, I can create a
logger with this simple invocation and use it add debug messages in
my class:
import java.util.logging.*;
private static final Logger focusLog = Logger.getLogger("java.awt.focus.KeyboardFocusManager");
if (focusLog.isLoggable(Level.FINEST)) {
focusLog.log(Level.FINEST, "Calling peer setCurrentFocusOwner});
LogManager acts like a book keeper and
all the getLogger calls are forwarded to LogManager. The LogManager
itself is a singleton class object which gets statically initialized
on JVM start up. More on this later. If there is no existing logger
with the given name, a new one is created. If there is one (and not
yet GC’ed), then the existing Logger object is returned. By
default, a root logger is created on JVM start up. All anonymous
loggers are made as the children of the root logger. Named loggers
have the hierarchy as per their name resolutions. Eg: java.awt.focus
is the parent logger for java.awt.focus.KeyboardFocusManager etc.
Before logging any message, the logger checks for the log level
specified. If null is specified, the log level of the parent logger
will be set. However, if the log level is off, no log messages would
be written, irrespective of the parent’s log level.
All the messages that are posted to the
Logger are handled as a LogRecord object.i.e. FocusLog.log would
create a new LogRecord object with the log level and message as its
data members). The level of logging and thread number are also
tracked. LogRecord is passed on to all the registered Handlers.
Handler is basically a means to output the messages. The output may
be redirected to either a log file or console or a network logging
service. The Handler classes use the LogManager properties to set
filters and formatters.
During initialization or JVM start up,
LogManager looks for logging.properties file in jre/lib and sets the
properties if the file is provided. An alternate location for
properties file can also be specified by setting
java.util.logging.config.file system property. This can be set in
Java Control Panel ? Java ? Runtime parameters as
-Djava.util.logging.config.file = <mylogfile> or passed as a
command line parameter
java -Djava.util.logging.config.file =
C:/Sunita/myLog
The redirection of logging depends on
what is specified rather registered as a handler with JVM in the
properties file. java.util.logging.ConsoleHandler sends the output
to system.err and java.util.logging.FileHandler sends the output to
file. File name of the log file can also be specified.
If you prefer XML format output, in the
configuration file, set java.util.logging.FileHandler.formatter =
java.util.logging.XMLFormatter and if you prefer simple text, set set
java.util.logging.FileHandler.formatter
=java.util.logging.SimpleFormatter
Below is the default logging Configuration file:
############################################################
# Default Logging Configuration File
# You can use a different file by
specifying a filename
# with the
java.util.logging.config.file system property.
# For example java
-Djava.util.logging.config.file=myfile
############################################################
############################################################
# Global properties
############################################################
# "handlers" specifies a
comma separated list of log Handler
# classes. These handlers will be
installed during VM startup.
# Note that these classes must be
on the system classpath.
# By default we only configure a
ConsoleHandler, which will only
# show messages at the INFO and
above levels.
handlers=
java.util.logging.ConsoleHandler
# To also add the FileHandler, use
the following line instead.
#handlers=
java.util.logging.FileHandler, java.util.logging.ConsoleHandler
# Default global logging level.
# This specifies which kinds of
events are logged across
# all loggers. For any given
facility this global level
# can be overriden by a facility
specific level
# Note that the ConsoleHandler also
has a separate level
# setting to limit messages printed
to the console.
.level= INFO
############################################################
# Handler specific properties.
# Describes specific configuration
info for Handlers.
############################################################
# default file output is in user's
home directory.
java.util.logging.FileHandler.pattern = %h/java%u.log
java.util.logging.FileHandler.limit
= 50000
java.util.logging.FileHandler.count
= 1
java.util.logging.FileHandler.formatter =
java.util.logging.XMLFormatter
# Limit the message that are
printed on the console to INFO and above.
java.util.logging.ConsoleHandler.level = INFO
java.util.logging.ConsoleHandler.formatter =
java.util.logging.SimpleFormatter
############################################################
# Facility specific properties.
# Provides extra control for each
logger.
############################################################
# For example, set the com.xyz.foo
logger to only log SEVERE
# messages:
com.xyz.foo.level = SEVERE
Since I primarily use this method to
track focus issues, here is how I get detailed awt focus related
logging. Just set the logger name to java.awt.focus.level=FINEST and
change the default log level to FINEST.
Below is a basic sample program. The
sample programs are from http://www2.cs.uic.edu/~sloan/CLASSES/java/
and have been modified to illustrate the logging API. By changing
the .level property in the logging.properties file, one can control
the output written to the logs. To play around with the example, try
changing the levels in the logging.properties file and notice the
difference in messages going to the log file.
Example
--------KeyboardReader.java-------------------------------------------------------------------------------------
import java.io.*;
import java.util.*;
import java.util.logging.*;
public class KeyboardReader
{
private static final Logger mylog =
Logger.getLogger("samples.input");
public static void main (String[]
args) throws java.io.IOException
{
String s1;
String s2;
double num1, num2, product;
// set up the buffered reader to read
from the keyboard
BufferedReader br = new
BufferedReader (new InputStreamReader (System.in));
System.out.println ("Enter a
line of input");
s1 = br.readLine();
if (mylog.isLoggable(Level.SEVERE))
{
mylog.log (Level.SEVERE,"The
line entered is " + s1);
}
if (mylog.isLoggable(Level.INFO))
{
mylog.log (Level.INFO,"The line
has " + s1.length() + " characters");
}
if (mylog.isLoggable(Level.FINE))
{
mylog.log (Level.FINE,"Breaking
the line into tokens we get:");
}
int numTokens = 0;
StringTokenizer st = new
StringTokenizer (s1);
while (st.hasMoreTokens())
{
s2 = st.nextToken();
numTokens++;
if (mylog.isLoggable(Level.FINEST))
{
mylog.log (Level.FINEST, "
Token " + numTokens + " is: " + s2);
}
}
}
}
----------MyFileReader.java----------------------------------------------------------------------------------------
import java.io.*;
import java.util.*;
import java.util.logging.*;
public class MyFileReader extends
KeyboardReader
{
private static final Logger mylog =
Logger.getLogger("samples.input.file");
public static void main (String[]
args) throws java.io.IOException
{
String s1;
String s2;
// set up the buffered reader to read
from the keyboard
BufferedReader br = new
BufferedReader (new FileReader ("MyFileReader.txt"));
s1 = br.readLine();
if (mylog.isLoggable(Level.SEVERE))
{
mylog.log (Level.SEVERE,"ATTN
The line is " + s1);
}
if (mylog.isLoggable(Level.INFO))
{
mylog.log (Level.INFO, "The
line has " + s1.length() + " characters");
}
if (mylog.isLoggable(Level.FINE))
{
mylog.log (Level.FINE,"Breaking
the line into tokens we get:");
}
int numTokens = 0;
StringTokenizer st = new
StringTokenizer (s1);
while (st.hasMoreTokens())
{
s2 = st.nextToken();
numTokens++;
if
(mylog.isLoggable(Level.FINEST))
{
mylog.log
(Level.FINEST,"Breaking the line into tokens we get:");
mylog.log (Level.FINEST,"
Token " + numTokens + " is: " + s2);
}
} //end of while
} // end of main
} // end of class
----------MyFileReader.txt------------------------------------------------------------------------------------------
My first logging example
-------logging.properties-------------------------------------------------------------------------------------------
handlers=
java.util.logging.ConsoleHandler, java.util.logging.FileHandler
.level= FINEST
java.util.logging.FileHandler.pattern =
java%u.log
java.util.logging.FileHandler.limit =
50000
java.util.logging.FileHandler.count = 1
java.util.logging.FileHandler.formatter
= java.util.logging.SimpleFormatter
java.util.logging.ConsoleHandler.level
= FINEST
java.util.logging.ConsoleHandler.formatter
= java.util.logging.SimpleFormatter
java.awt.focus.level=ALL
------Output
log-------------------------------------------------------------------------------------------
May 21, 2012 11:44:55 AM MyFileReader
main
SEVERE: ATTN The line is My first
logging example
May 21, 2012 11:44:55 AM MyFileReader
main
INFO: The line has 24 characters
May 21, 2012 11:44:55 AM MyFileReader
main
FINE: Breaking the line into tokens we
get:
May 21, 2012 11:44:55 AM MyFileReader
main
FINEST: Breaking the line into tokens
we get:
May 21, 2012 11:44:55 AM MyFileReader
main
FINEST: Token 1 is: My
May 21, 2012 11:44:55 AM MyFileReader
main
FINEST: Breaking the line into tokens
we get:
May 21, 2012 11:44:55 AM MyFileReader
main
FINEST: Token 2 is: first
May 21, 2012 11:44:55 AM MyFileReader
main
FINEST: Breaking the line into tokens
we get:
May 21, 2012 11:44:55 AM MyFileReader
main
FINEST: Token 3 is: logging
May 21, 2012 11:44:55 AM MyFileReader
main
FINEST: Breaking the line into tokens
we get:
May 21, 2012 11:44:55 AM MyFileReader
main
FINEST: Token 4 is: example
Invocation command:
"C:\Program Files
(x86)\Java\jdk1.6.0_29\bin\java.exe"
-Djava.util.logging.config.file=logging.properties MyFileReader
References
Further technical details are available
here:
http://docs.oracle.com/javase/1.4.2/docs/guide/util/logging/overview.html#1.0
http://docs.oracle.com/javase/1.4.2/docs/api/java/util/logging/package-summary.html
http://www2.cs.uic.edu/~sloan/CLASSES/java/