Java Logger API

Posted by Koppar on Oracle Blogs See other posts from Oracle Blogs or by Koppar
Published on Wed, 30 May 2012 17:58:52 +0000 Indexed on 2012/05/30 22:47 UTC
Read the original article Hit count: 900

Filed under:

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/


© Oracle Blogs or respective owner

Related posts about /Sun