Welcome to Marlon's place!


Message of the day


"There is a brave man waiting, who'll take me back to where I come from"


(The Black Heart Rebellion)

Logger - a simple way to log Java applications

posted: January 23, 2010

In this article I'd like to describe a small Java class that will enable you to log what your application is doing. Before I continue, I'd like to point out that this is a very simple, basic logger - if you need a serious logging framework for your application I suggest that you check out Log4J.

This logger class, however, is more than enough for most applications. As with most loggers, the messages are separated into different categories:

  • debug: messages used to help debug the software, not shown in production.
  • info: messages that allow users to get some basic information about what the software is doing.
  • warn: warning messages, stuff that users should be aware of. Things that are not really a problem at the moment, but one should keep an eye out for possible errors as a result.
  • error: errors which occured in the application, but from which the application was able to recover or continue.
  • fatal: errors from which there is no recovery possible, the application will probably exit at this time.

Now then, let's have a look at the code:

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;

import java.util.Calendar;

public class Logger
{

  public final static int LOG_DEBUG = 0;
  public final static int LOG_INFO = 1;
  public final static int LOG_WARN = 2;
  public final static int LOG_ERROR = 3;
  public final static int LOG_FATAL = 4;
  
  private static int level = LOG_DEBUG;
  private static File logFile = null;
  private static boolean logToFile = false;
  private static boolean display = true;   
  
  public static void debug(String message)
  {
    if (level <= LOG_DEBUG)
    {
      logMessage(message);
    }
  }
  
  public static void info(String message)
  {	
    if (level <= LOG_INFO)
    {
      logMessage(message);
    }
  }
  
  public static void warn(String message)
  {
    if (level <= LOG_WARN)
    {
      logMessage(message);
    }
  }
  
  public static void error(String message)
  {
    if (level <= LOG_ERROR)
    {
      logMessage(message);
    }
  }
  
  public static void fatal(String message)
  {
    if (level <= LOG_FATAL)
    {
      logMessage(message);
    }
  }
  
  public static void setDisplay(boolean display)
  {
    Logger.display = display;
  }
  
  public static void setLevel(int level)
  {
    Logger.level = level;	
  }
  
  public static void setLogFile(File logFile)
  {
    Logger.logFile = logFile;
  }
  
  public static void setLogToFile(boolean logToFile)
  {
    Logger.logToFile = logToFile;
  }
  
  public static synchronized void logMessage(String message)
  {
    Calendar c = Calendar.getInstance();
    String time = c.get(Calendar.YEAR) + "/" +
                  c.get(Calendar.MONTH) + "/" +
                  c.get(Calendar.DAY_OF_MONTH) + " " +
                  c.get(Calendar.HOUR_OF_DAY) + ":" + 
                  c.get(Calendar.MINUTE) + ":" + 
                  c.get(Calendar.SECOND) + "." + 
                  c.get(Calendar.MILLISECOND);		
    
    if (display)
    {
      System.out.println(time + " " + message);
    }
    
    if ((logToFile) && (logFile != null))
    {
      try
      {
        PrintWriter pw = new PrintWriter(
            new FileWriter(logFile, true)
        );
        pw.println(time + " " + message);
        pw.close();
      }
      catch (IOException ioe)
      {
        // be silent
      }
    }
  }

}

All methods are declared static - it's just another way to keep the class both easy to use and simple. The code can be easily rewritten to use a Singleton pattern if needed.

Only the method which performs the actual logging is synchronized - but that does not keep this class from being thread-safe, so you can safely use this logger class in a multi-threaded environment.

Perhaps a little word about configuration. There are a few options to configure this logger to your liking.

  • setDisplay: tells the logger whether or not to show the log statement in your console window (note: only if the log level permits this)
  • setLevel: set the level of log messages. Only messages of this level and higher will be logged. Levels can be set using the static level fields available in the class.
  • setLogFile: tells the logger which file should be used to store log messages in. Messages will be appended to the end of the file.
  • setLogToFile: tells the logger whether or not messages should be written to a log file

Please note that using setLogToFile without specifying a log file makes no sense - the logger needs to know where to store messages.

A typical usage of this logger class would look like the following snippet:

Logger.setDisplay(true);
Logger.setLogToFile(true);
Logger.setLogFile(new File("logfile.log"));
Logger.setLevel(Logger.LOG_DEBUG);

Logger.debug("This is a message of type 'debug'.");
Logger.info ("This is a message of type 'info'.");
Logger.warn ("This is a message of type 'warn'.");
Logger.error("This is a message of type 'error'.");
Logger.fatal("This is a message of type 'fatal'.");

So there you have it - a very simple logger class to use in your own applications. May it be as useful for you as it is for me.

Previous articles

Recent C++ stuff

Recent Delphi stuff

Recent Java stuff