In this article, we will discuss about the logging functionality in Java. Logging in simple words refers to the recording of an application activity. Logging is used to store exceptions, information, and warnings as messages that occur during the execution of a program. Logging helps a programmer in the debugging process of a program.

Java provides logging facility in the java.util.logging package. The package consists of a set of classes and interfaces which are used in logging. The System uses a Logger object to log messages.

The Logger object is allocated with a LogRecord object which stores the message to be logged. This LogRecord object is forwarded to all the handlers assigned to the Logger object. Both loggers and handlers can optionally use a Filter that is associated with them, to filter the log messages. Then, the handlers published the logged messages to the external system.

Let’s start with some of the important classes of the package.



Do you want to know how to develop your skillset to become a Java Rockstar? Subscribe to our newsletter to start Rocking right now! To get you started we give you our best selling eBooks for FREE! 1. JPA Mini Book 2. JVM Troubleshooting Guide 3. JUnit Tutorial for Unit Testing 4. Java Annotations Tutorial3> 5. Java Interview Questions 6. Spring Interview Questions 7. Android UI Design and many more .... Email address: Leave this field empty if you're human:

1. Logger and Level

A Logger class is used to create a logger object which is used to log messages. A logger object is provided with a name and has a set of methods which are used to log messages at the different levels. Although you can provide any name to the logger, it is recommended to provide a name based on the package and the class name in which the logger is created.

There are seven logging levels provided by the Level class.

• SEVERE (highest level)

• WARNING

• INFO

• CONFIG

• FINE

• FINER

• FINEST (lowest level)

All these levels are present in the Level class, as a static final field. You can use any of these levels, according to the level of the message you log. Additionally, it also provides a level OFF that can be used to turn off the logging and a level ALL to turn on the logging for all the levels.

Let’s see an example about how to create and use a logger.

LoggerExample.java

package com.javacodegeeks.corejava.util.logging; import java.io.IOException; import java.util.logging.Level; import java.util.logging.Logger; public class LoggerExample { private static final Logger LOGGER = Logger.getLogger(LoggerExample.class.getName()); public static void main(String[] args) throws SecurityException, IOException { LOGGER.info("Logger Name: "+LOGGER.getName()); LOGGER.warning("Can cause ArrayIndexOutOfBoundsException"); //An array of size 3 int []a = {1,2,3}; int index = 4; LOGGER.config("index is set to "+index); try{ System.out.println(a[index]); }catch(ArrayIndexOutOfBoundsException ex){ LOGGER.log(Level.SEVERE, "Exception occur", ex); } } }

If we run the above code, we will have the following results:

Jun 08, 2014 1:19:30 PM com.javacodegeeks.corejava.util.logging.LoggerExample main INFO: Logger Name: com.javacodegeeks.corejava.util.logging.LoggerExample Jun 08, 2014 1:19:31 PM com.javacodegeeks.corejava.util.logging.LoggerExample main WARNING: Can cause ArrayIndexOutOfBoundsException Jun 08, 2014 1:19:31 PM com.javacodegeeks.corejava.util.logging.LoggerExample main SEVERE: Exception occur java.lang.ArrayIndexOutOfBoundsException: 4 at com.javacodegeeks.corejava.util.logging.LoggerExample.main(LoggerExample.java:22)

In the above example, we have created a logger object using the getLogger static method. Then we have logged messages at different levels. We also have thrown an ArrayIndexOutOfBoundsException to illustrate the use of the Logger .

Let’s have a look at some of the methods used in this example.

Logger.getLogger(String name) : This method is used to create or find a logger by the name passed as a parameter.

void info(String msg) : This instance method is used to log an INFO message, if the logger is currently enabled for the INFO message else the logged message is gets ignored.

void warning(String msg) : This instance method is used to log a WARNING message, if the logger is currently enabled for the WARNING message else the logged message is gets ignored.

void config(String msg) : This instance method is used to log a CONFIG message, if the logger is currently enabled for the CONFIG message else the logged message is gets ignored.

void log(Level level, String msg, Object param1) : This method is used to log a message with a given level, and with an Object as a parameter. You can use this method when you want to store an object in the log as done in the above example where we have logged an exception object at SEVERE level.

Please note that the INFO level is the default level set in the Logger . Any message logged with the level lower than the INFO gets ignored. As you can see, the message logged at the WARNING level gets ignored and it did not get published in the console.

2. Handler

A Handler is one of the components of the logging framework. It is responsible for printing the log message at a target destination. The destination can be a console or a file. The Handler is used to take a log message in the form of a LogRecord object and export it to the target destination.

A Logger can be associated with one or more handlers that eventually forward the logged message to all the handlers. A Handler is an abstract class in the java.util.logging package which is a base class for all types of handlers in Java. There are 4 types of built-in handlers in Java.

ConsoleHandler : A ConsoleHandler records all the log messages to System.err . By default, a Logger is associated with this handler.

FileHandler : A FileHandler is used to record all the log messages to a specific file or to a rotating set of files.

StreamHandler : A StreamHandler publishes all the log messages to an OutputStream .

SocketHandler : The SocketHandler publish the LogRecords to a network stream connection.

MemoryHandler : It is used to keep the LogRecords into a memory buffer. If the buffer gets full, the new LogRecords starts overwriting the old LogRecords .

HandlerExample.java

package com.javacodegeeks.corejava.util.logging; import java.io.IOException; import java.util.logging.ConsoleHandler; import java.util.logging.FileHandler; import java.util.logging.Handler; import java.util.logging.Level; import java.util.logging.Logger; public class HandlerExample { private static final Logger LOGGER = Logger.getLogger(LoggerExample.class.getName()); public static void main(String[] args) { Handler consoleHandler = null; Handler fileHandler = null; try{ //Creating consoleHandler and fileHandler consoleHandler = new ConsoleHandler(); fileHandler = new FileHandler("./javacodegeeks.log"); //Assigning handlers to LOGGER object LOGGER.addHandler(consoleHandler); LOGGER.addHandler(fileHandler); //Setting levels to handlers and LOGGER consoleHandler.setLevel(Level.ALL); fileHandler.setLevel(Level.ALL); LOGGER.setLevel(Level.ALL); LOGGER.config("Configuration done."); //Console handler removed LOGGER.removeHandler(consoleHandler); LOGGER.log(Level.FINE, "Finer logged"); }catch(IOException exception){ LOGGER.log(Level.SEVERE, "Error occur in FileHandler.", exception); } LOGGER.finer("Finest example on LOGGER handler completed."); } }

If we run the above code, we will have the following results:

Jun 08, 2014 1:43:19 PM com.javacodegeeks.corejava.util.logging.HandlerExample main CONFIG: Configuration done.

This example also generates a log file javacodegeeks.log at the root directory of this project.

The file contains the following log.

<?xml version="1.0" encoding="windows-1252" standalone="no"?> <!DOCTYPE log SYSTEM "logger.dtd"> <log> <record> <date>2014-06-08T13:43:19</date> <millis>1402215199326</millis> <sequence>0</sequence> <logger>com.javacodegeeks.corejava.util.logging.LoggerExample</logger> <level>CONFIG</level> <class>com.javacodegeeks.corejava.util.logging.HandlerExample</class> <method>main</method> <thread>1</thread> <message>Configuration done.</message> </record> <record> <date>2014-06-08T13:43:19</date> <millis>1402215199376</millis> <sequence>1</sequence> <logger>com.javacodegeeks.corejava.util.logging.LoggerExample</logger> <level>FINE</level> <class>com.javacodegeeks.corejava.util.logging.HandlerExample</class> <method>main</method> <thread>1</thread> <message>Finer logged</message> </record> <record> <date>2014-06-08T13:43:19</date> <millis>1402215199376</millis> <sequence>2</sequence> <logger>com.javacodegeeks.corejava.util.logging.LoggerExample</logger> <level>FINER</level> <class>com.javacodegeeks.corejava.util.logging.HandlerExample</class> <method>main</method> <thread>1</thread> <message>Finest example on LOGGER handler completed.</message> </record> </log>

In this example, we have logged messages to both the FileHandler and the ConsoleHandler . Let’s discuss the above example.

ConsoleHandler() : A constructor that creates a ConsoleHandler for System.err .

FileHandler(String pattern) : A constructor that creates a FileHandler to log messages in the given file name.

void addHandler(Handler handler) : It’s an instance method from the Logger class which is used to assign a handler to the logger object. You can assign multiple handlers to a single logger object. Like in this example, we have assigned both ConsoleHandler and FileHandler to a single logger object.

void setLevel(Level newLevel) : This method is from the Logger and the Handler class. It sets the log level specifying which message levels will be logged by this logger. Message levels lower than the level set will be ignored.

void removeHandler(Handler handler) : It is used to remove the associated handler from the logger object. Once the handler is removed, it will not be able to publish any further logs. In this example, we removed the ConsoleHandler and all messages following it did not get published in the console.

void finer(String msg) : This instance method is used to log a FINER message, if the logger is currently enabled for the FINER message else the logged message gets ignored.

The log messages published by the FileHandler in the above example are in the XML format. It’s the default format of the FileHandler . We can change the format of the handler using a Formatter . In the next section, we will discuss about the Formatter class and its uses.

3. Formatter

A Formatter is used to format a LogRecord . Each handler is associated with a formatter. Java provides the Formatter as a parent class of two in-built formatter’s i.e. SimpleFormatter and XMLFormatter . Let’s see some examples:

FormatterExample.java

package com.javacodegeeks.corejava.util.logging; import java.io.IOException; import java.util.logging.Formatter; import java.util.logging.FileHandler; import java.util.logging.Handler; import java.util.logging.Level; import java.util.logging.Logger; import java.util.logging.SimpleFormatter; public class FormatterExample { private static final Logger LOGGER = Logger.getLogger(LoggerExample.class.getName()); public static void main(String[] args) { Handler fileHandler = null; Formatter simpleFormatter = null; try{ // Creating FileHandler fileHandler = new FileHandler("./javacodegeeks.formatter.log"); // Creating SimpleFormatter simpleFormatter = new SimpleFormatter(); // Assigning handler to logger LOGGER.addHandler(fileHandler); // Logging message of Level info (this should be publish in the default format i.e. XMLFormat) LOGGER.info("Finnest message: Logger with DEFAULT FORMATTER"); // Setting formatter to the handler fileHandler.setFormatter(simpleFormatter); // Setting Level to ALL fileHandler.setLevel(Level.ALL); LOGGER.setLevel(Level.ALL); // Logging message of Level finest (this should be publish in the simple format) LOGGER.finest("Finnest message: Logger with SIMPLE FORMATTER"); }catch(IOException exception){ LOGGER.log(Level.SEVERE, "Error occur in FileHandler.", exception); } } }

If we run the above code, we will have the following results:

Jun 08, 2014 4:57:02 PM com.javacodegeeks.corejava.util.logging.FormatterExample main INFO: Finnest message: Logger with DEFAULT FORMATTER

This example also generates a log file javacodegeeks.formatter.log in the root directory of this project.

In the above example, we have used the SimpleFormatter in our example, which prints the LogRecord in a simple human readable format. Please note that before setting the SimpleFormatter to the handler, we have logged a message which is published in an XML format, this is because the XMLFormatter is the default formatter for the FileHandler . Also note that the LogRecord is also published in the console because the ConsoleHandler is by default associated with the Logger .

SimpleFormatter() : This constructor is used to create a SimpleFormatter object.

void setFormatter(Formatter newFormatter) : This method is from the Handler class and used to set the formatter to the handler.

4. Filter

A Filter is an interface in java.util.logging package. It is used to control the messages to be logged by the handler. Every Logger and Handler optionally can have a Filter . The Filter has a isLoggable method which returns a boolean . Before publishing the message the Logger or the Handler calls this method, if the method returns true the LogRecord gets publish else it gets ignored.

FilterExample.java

package com.javacodegeeks.corejava.util.logging; import java.util.logging.Filter; import java.util.logging.LogRecord; import java.util.logging.Logger; public class FilterExample implements Filter{ private static final Logger LOGGER = Logger.getLogger(LoggerExample.class.getName()); public static void main(String[] args) { //Setting filter FilterExample LOGGER.setFilter(new FilterExample()); //Since this message string does not contain the word important. Despite of being the Level SEVERE this will be ignored LOGGER.severe("This is SEVERE message"); //This will get published LOGGER.warning("This is important warning message"); } // This method will return true only if the LogRecord object contains the message which contains the word important @Override public boolean isLoggable(LogRecord record) { if(record == null) return false; String message = record.getMessage()==null?"":record.getMessage(); if(message.contains("important")) return true; return false; } }

If we run the above code, we will have the following results:

Jun 08, 2014 5:13:46 PM com.javacodegeeks.corejava.util.logging.FilterExample main WARNING: This is important warning message

void setFilter(Filter newFilter) : This method sets a Filter which controls the output on this Logger .

boolean isLoggable(LogRecord record) : This method is from the Filter interface which checks if a given LogRecord object should be published or not.

5. Configuration

You can provide configuration properties to a Logger using a configuration file. This helps you to remove the configuration from the code and provides an easy way to re-configure whenever it is required without changing the code again and again. This flexibility is provided by the LogManager class.

ConfigurationExample.java

package com.javacodegeeks.corejava.util.logging; import java.io.FileInputStream; import java.io.IOException; import java.util.logging.Level; import java.util.logging.LogManager; import java.util.logging.Logger; public class ConfigurationExample { private static final LogManager logManager = LogManager.getLogManager(); private static final Logger LOGGER = Logger.getLogger("confLogger"); static{ try { logManager.readConfiguration(new FileInputStream("./javacodegeeks.properties")); } catch (IOException exception) { LOGGER.log(Level.SEVERE, "Error in loading configuration",exception); } } public static void main(String[] args) { LOGGER.fine("Fine message logged"); } }

This example reads a property file which contains the following properties:

handlers=java.util.logging.ConsoleHandler .level=ALL java.util.logging.ConsoleHandler.level=ALL java.util.logging.ConsoleHandler.formatter=java.util.logging.SimpleFormatter confLogger.level=ALL

If we run the above code, we will have the following results:

Jun 08, 2014 5:23:25 PM com.javacodegeeks.corejava.util.logging.ConfigurationExample main FINE: Fine message logged

Let’s us discuss about the code and the configuration properties.

handlers: used to set the default handlers for all the loggers.

.level: sets the default Level for all the loggers to ALL.

java.util.logging.ConsoleHandler.level: sets the default Level for all the ConsoleHandler to ALL.

java.util.logging.ConsoleHandler.formatter: sets the default formatter for the ConsoleHandler to a SimpleFormatter .

confLogger.level: sets the default level of the Logger named confLogger to ALL.

Please note that you can override these properties in the code.

LogManager.getLogManager() : This is a static factory method used to get a LogManager object. There is a single global LogManager object that is used to maintain a set of shared state about the Loggers and the log services.

void readConfiguration(InputStream ins) : This method is used to reinitialize the logging properties and re-read the logging configuration from the given stream, which should be in java.util.Properties format.

6. Download the source code

You can download the source code of this example from here: LoggingExample.zip