Welcome to the Java Programming Forums


The professional, friendly Java community. 21,500 members and growing!


The Java Programming Forums are a community of Java programmers from all around the World. Our members have a wide range of skills and they all have one thing in common: A passion to learn and code Java. We invite beginner Java programmers right through to Java professionals to post here and share your knowledge. Become a part of the community, help others, expand your knowledge of Java and enjoy talking with like minded people. Registration is quick and best of all free. We look forward to meeting you.


>> REGISTER NOW TO START POSTING


Members have full access to the forums. Advertisements are removed for registered users.

View RSS Feed

copeg

Logging

Rate this Entry
Logging is a great method to monitor the progress of a program while at the same time maintaining flexibility to control the output. Simply put, logging is just printing out statements during the runtime of an application. In another blog I described a simplistic method for logging - using System.out.println. More advanced logging libraries however go beyond just printing to the console - their flexibility allows control of when, how, and where to log.

Many logging libraries exist, including one within the java API (java.util.logging package) and Apache's open source log4j (Apache Logging Services ). A good logging library should provide the following major elements:

1) Levels - controls when logging should take place. One can place logging statements within code, defining a certain level for each statement, then define a runtime level, resulting in statements only of that level or higher being logged. This is very useful to differentiate between development and deployment.

2) Formats - controls the format of the logged statement - for instance one can format a logging statement to print out the level, time, class, and in some circumstances even the line number in the code.

3) Output (eg log4j Appender, java.util.logging.Handler) - where the logging statements will be printed. For instance one can specify the standard console IO or err stream, a file stream, a socket, etc…

4) Lastly, one should be able to specify the above three simply via properties or configuration file. Thus, one can change any one or all of these values simply by modifying an external file - without modifying any code or redeploying an application.

In the following example, I'll demonstrate the use of the java API logging. Below is a simple code snippet showing some very simple logging statements.

 
import java.util.logging.*;
 
public class Test{
	private static final Logger logger = Logger.getLogger(Test.class.toString());
 
	public static void main(String[] args){
		logger.setLevel(Level.INFO);
		printLogging();
		logger.setLevel(Level.WARNING);
		printLogging();
		logger.setLevel(Level.SEVERE);
		printLogging();
 
 
	}
	/**
	* Prints 3 standard logging messages at different levels.
	*/
	private static void printLogging(){
		logger.info("Info");
		logger.warning("Warning");
		logger.severe("Severe");
	}
}

The above code demonstrates the java API and how LEVEL's can be changed. In this simple example, the level for the logger is changed from INFO, to WARNING, to SEVERE - while logging messages are printed after each modification. Running this code, one can see that the for each level set, logging statements get printed for that level and those above, whereas those below the level do not. This can be extremely handy in large applications, where one can print debugging statements while writing and debugging an application, after which one can change to a higher level to omit those statements without removing any code.

While this is a simple example, there are other ways in which to change the output, for example the following code adds a new Handler to the Logger which outputs the logging statements to a file
 
import java.util.logging.*;
 
public class Test{
	private static final Logger logger = Logger.getLogger(Test.class.toString());
 
	private static final String PATH = "myfilepath";
	public static void main(String[] args) throws Exception{
		logger.addHandler(new FileHandler(PATH));
		printLogging();
	}
	private static void printLogging(){
		logger.info("Info");
		logger.warning("Warning");
		logger.severe("Severe");
	}
}
(Note the this code still prints the logging to the console as well as the file, see below)

The following is a more complex example
import java.util.logging.*;
public class Test{
	private static final Logger logger = Logger.getLogger(Test.class.toString());
 
	public static void main(String[] args) throws Exception{		
		logger.setUseParentHandlers(false);//prevent parent handlers from logging
		logger.addHandler(new ConsoleHandler());
		for ( Handler h : logger.getHandlers() ){
			h.setFormatter(new MyFormatter());
		}
		logger.setLevel(Level.INFO);
		printLogging();
	}
	private static void printLogging(){
		logger.info("Info");
		logger.warning("Warning");
		logger.severe("Severe");
	}
 
	private static class MyFormatter extends Formatter{
 
		@Override
		public String format(LogRecord arg0) {
			StringBuilder sb = new StringBuilder();
			sb.append(arg0.getLoggerName());
			sb.append(" ");
			sb.append(arg0.getLevel());
			sb.append(" ");
			sb.append(arg0.getMessage());
			sb.append("\n");
			return sb.toString();
		}
 
	}
}

In the above example several things were done. First, logging statements may get passed up to parent handlers (the reason why our file output example still prints to the console), thus setting the logger to not use any parent handlers allows our one handler to be the sole handler for this logger. Next, we created a ConsoleHandler and added this Handler to our Logger - this essentially logs messages to the System.err stream (note that one can readily configure this to the System.out stream). Lastly, we created a Formatter which customizes the output of the logging statements based upon a LogRecord.

These are just a few very simple examples to demonstrate the simplicity of logging. The flexibility of a logging system within an application takes the System.out.println to a whole new level, providing detailed information for the inner workings of an application in all phases of development and deployment. Of course, logging is useless unless one prints out details which are informative enough to understand and useful enough to help further develop the application.

Links:
Apache log4j 1.2 - log4j 1.2
Java TM Logging Overview

Updated May 31st, 2011 at 08:32 PM by copeg

Categories
Debugging

Comments

  1. Json's Avatar
    permalink
    Nice post. I tend to use logback for any logging implementation at the moment and if I'm just creating an artifact (jar) which is not supposed to create any log files etc I use SLF4J as the logging interface. Many of the bigger logging frameworks implement SLF4J so it gives the developer using my library the chance to pick his own implementation.

    Another think I came across the other week was Loggly|Logging as a Service which is a cloud based logging solution. It lets you log straight onto their machines and they index the logs for you and provide you with a nice interface for searching through them.

    I also think it's important to understand the impact of logging in a modern (possibly clustered/distributed) application. Logging can happen fast and with a lot of users using your application the disk space disappears quickly. You should also understand what you are logging and for who you are logging. This is where the levels can be really important and especially the difference between INFO and DEBUG. System administrators will most likely have access to INFO, WARN and ERROR when running in a live environment so take care with what you print out.

    Another thing to be careful about is logging sensitive information such as passwords and credit card details. If you REALLY need to log these things, you should consider blanking some of it out, such as only showing the last 4 digits of card numbers etc.

    Good article, I hope anyone reading this takes a moment to think about logging. It can be a really nice relief when debugging but it can also be the cause of major headaches.

    Keep up the nice blogs copeg.
  2. copeg's Avatar
    permalink
    Thanks for this informative comment Json. You raise some great points that my post above doesn't address. Never used SLF4J but it looks very interesting.