Java Logger Utility

Here is a utility that will help you to better use java.util.logging.Logger class. In this Java logger utility, I have tried provide the most commonly used features in this utility. In this article, few important features of Java logger framework are also explained in brief while going through the code. I am not going into deep to explain all features of Java logger technology, instead focusing on what this utility will help you with. You can use it as is or customize it according to your advanced needs.

Let us start with the list of elements of this utility and what is responsibility of those elements.

1. LogWrapper.java: This is the heart of this utility. It wraps up the java.util.logging.Logger class.

2. CustomMessageFormatter.java: Used to format the message getting logged.

3. UseExample.java: An example showing how to use this utility.

4. logger.properties: Configuration properties of logger.

Features:

1.       Wrapper to standard Java logging framework to facilitate customizable message construction.

2.       Better exception logging.

3.       Easy to integrate and enhance.

4.       Using features of Java 5.

Integration:

1. Standalone Java Application: Directly copy the classes in appropriate package (may be util or common package, but no restriction). Second is the property file, it should be kept directly in classpath. If you are placing it in any other folder then ensure that there is correct path in LogWrapper.java. Change the log file path in properties to appropriate location. This can be absolute as well as relative path with respect to classpath root.

2. Java Web Application: The only change you would require to make is placing the property file in WEB-INF directory/folder. Change the log path as required (and explained above).

Elements in Detail:

LogWrapper.java: This class is the main class. Below are the silent features of the code in this class.

  • Instantiates custom logger and holds in static way.
  • Uses Varargs to allow variable input in methods.
  • Creates printable string from the exception stack trace.
  • Reads properties from property file and creates FileHandler and MessageFormatter accordingly.

Here is the code of this class.

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.text.MessageFormat;
import java.util.Properties;
import java.util.logging.FileHandler;
import java.util.logging.Level;
import java.util.logging.Logger;

public class LogWrapper{
    private static Logger logger = null;
    public static final String SPACE = " ";
    public static final String TAB = "t";
    private static final String END_OF_LINE = System.getProperty("line.separator");
    public static final String LOGGER_PROPERTY_FILE = "logger.properties";
    public static final String LOG_FILE_NAME = "log.file.name";
    public static final String LOG_LEVEL = "logger.level";
    public static final String LOG_FILE_SIZE = "logger.file.size";
    public static final String LOG_NUMBER_OF_FILES = "logger.numberof.files";
    public static final String LOGGER_NAME = "logger.name";
    public static final String MESSAGE_FORMAT = "logger.message.format";
    public String className = "";

    private void init(Class clazz, URL logPropertiesFile)
    {
    	InputStream is = null;
		try{
            is = new FileInputStream(logPropertiesFile.getFile());  
            Properties prop = new Properties();
            prop.load(is);
            if(logger == null){

                logger= Logger.getLogger(prop.getProperty(LOGGER_NAME));
    	        String fileName = prop.getProperty(LOG_FILE_NAME);
    	        FileHandler fh = new FileHandler(fileName.concat("%g.log"), 
    	        		Integer.parseInt(prop.getProperty(LOG_FILE_SIZE)), 
    	        		Integer.parseInt(prop.getProperty(LOG_NUMBER_OF_FILES)),true);
    	        fh.setFormatter(new CustomMessageFormatter(new MessageFormat(prop.getProperty(MESSAGE_FORMAT))));
    	        logger.setLevel(Level.parse(prop.getProperty(LOG_LEVEL)));
    	        logger.addHandler(fh);
            }
            this.className = clazz.getName();
        }catch(FileNotFoundException fnfe){
        	fnfe.printStackTrace();
        }catch(IOException ioe){
        	ioe.printStackTrace();
        }
    }

    public LogWrapper(Class clazz){
		URL logPropertiesFile = this.getClass().getClassLoader().getResource(LOGGER_PROPERTY_FILE);
		init(clazz, logPropertiesFile);
    }

    public LogWrapper(Class clazz, URL logPropertiesFile){
    	init(clazz, logPropertiesFile);
    }
    public LogWrapper(){

    }
    public void info(String...strings  ){
        logger.info(constructMessage(strings));
    }

    public void debug(String...strings  ){
        logger.fine(constructMessage(strings));
    }

    public void warn(String...strings  ){
        logger.warning(constructMessage(strings));

    }

    public void entering(String className, String methodName, Object[] data){

        logger.entering(className, methodName, data);

    }
    public void entering(String className, String methodName){

        logger.entering(className, methodName);

    }
    public void entering(String className, String methodName, Object data){

        logger.entering(className, methodName, data);

    }
    public void exiting(String className, String methodName, Object data){

        logger.exiting(className, methodName, data);

    }
    public void exiting(String className, String methodName){

        logger.exiting(className, methodName);

    }

    public void error(Exception trw, String...strings  ){
        logger.severe(constructMessage(strings)+ constructStackTrace(trw));
    }

    private String constructMessage(String[] strings){
        StringBuilder sbl = new StringBuilder();
        sbl.append(SPACE);
        sbl.append(className);
        if(strings != null || strings.length >0){
            for(int count=0; count< strings.length; count++){
                sbl.append(SPACE);
                sbl.append(strings[count]);
            }
        }

        return sbl.toString();
    }
    private String constructStackTrace(Exception exe){
        StringBuilder sbl = new StringBuilder();
    	sbl.append(END_OF_LINE);
        sbl.append(exe.toString());
        for(StackTraceElement ste:exe.getStackTrace()){
        	sbl.append(END_OF_LINE);
        	sbl.append(TAB);
        	sbl.append(ste.toString());
        }

        return sbl.toString();
    }

}

CustomMessageFormatter.java: This class is used to format a log message. LogWrapper reads the message formatter and uses this formatter instance to format the log message.

import java.text.MessageFormat;
import java.util.Date;
import java.util.logging.Formatter;
import java.util.logging.LogRecord;
public class CustomMessageFormatter extends Formatter {

	private MessageFormat messageFormat = new MessageFormat("{0}t{1}t{2,date,dd:MM:yy:h:mm:ss.SSS}:tt{3}n");

	@Override
	public String format(LogRecord record) {
		Object[] arguments = new Object[4];
		arguments[0] = record.getLevel();
		arguments[1] = Thread.currentThread().getName();
		arguments[2] = new Date(record.getMillis());
		arguments[3] = record.getMessage();
		return messageFormat.format(arguments);
	}

	public CustomMessageFormatter( MessageFormat mf) {
		super();
		messageFormat = mf;
	}

}

UseExample.java: In this class, this utility is used in standalone way. Entry, exit, info, error logging examples are explained here.

public class UseExample {
    private static LogWrapper logger = new LogWrapper(UseExample.class);

    public static void main (String[] strs){
    	logger.entering(UseExample.class.getName(), "main");
    	try{
        	logger.info("This","is", "sample", "logging." );
        	String str = null;
        	str.length();
    	}catch(Exception exc){
    		logger.error(exc, "Exception","occurred" ,"in" , "main" ,"method");
    	}
    	logger.exiting(UseExample.class.getName(), "main");
    }
}

logger.properties: Controls the logger behavior. Below are the property details.

  • log.file.name: Relative or absolute file location and name should be given here. Actual file name will be concatenated with a number and .log. e.g. Sample0.log
  • logger.name: This defines the name of logger.
  • logger.level: Values can be the constants from java.util.logging.Level class. “ALL” will log everything while “SEVERE” will log only errors.
  • logger.file.size: You can define the log file size in bytes.
  • logger.numberof.files: Defines how many number of files should be created before overwriting first file. In this example Sample0.log through Sample9.log will be created before overwriting Sample0.log.
  • logger.message.format: Defines message format.

References:

Java Logging Package

Be the first to comment

Leave a Reply

Your email address will not be published.


*