This tutorial provides an introduction to the Java Util Logging framework to provide structured logging for your application. Remember that this is only the most basic usage of the logging framework, and much more complex capabilities exist, including file-based configuration, network logging, and event-based logging.
package edu.rutgers.sakai.java.util; import java.util.concurrent.atomic.AtomicInteger; import java.util.logging.ConsoleHandler; import java.util.logging.Handler; import java.util.logging.Level; import java.util.logging.Logger; /** * An example of using the java.util.logging package to provide useful logging * for applications. * * For more information about logging in Java, see the <a href= * "http://docs.oracle.com/javase/1.4.2/docs/guide/util/logging/overview.html" * >Java Logging Overview</a> or the <a href= * "http://docs.oracle.com/javase/1.4.2/docs/api/java/util/logging/package-summary.html" * >JavaDoc for java.util.logging</a>. * * @author Robert Moore * */ public class Logging { /** * A private, static logger for this class to use. We could also use the empty * string to log to the "root" logger. */ private static final Logger log = Logger.getLogger(Logging.class.getName()); /** * Main method, demonstrating the use of different logging levels and * configuration options. * * @param args * Ignored */ public static void main(String[] args) { // With the default configuration options, only config, severe, warning, and // info will output invokeLog(); /* * Let's use a ConsoleHandler that allows ALL output. We'll grab the root * logger and replace its ConsoleHandler. */ replaceConsoleHandler(Logger.getLogger(""), Level.ALL); // Now, let's set the level down to "FINER". All but FINEST will print log.setLevel(Level.FINER); invokeLog(); // Now let's see what happens in our subclasses /* * For InnerClass1, both objects will log to the same logger, since we use a * static (i.e., class-bound) variable. This is fairly common, and using * separate loggers for each object is uncommon. * * Instead, InnerClass1 overrides the toString() method (from Object) to make * its object-specific log messages easier to read. */ InnerClass1 ic1a = new InnerClass1(); InnerClass1 ic1b = new InnerClass1(); log.setLevel(Level.FINEST); // 5th Fibonacci number log.fine("Computing 5th Fibonacci number."); try { int fib5 = ic1a.computeFibonacci(5); log.info("Fib(5) = " + fib5); }catch(Exception e){ log.severe("Caught exception: " + e); } log.setLevel(Level.FINE); // 15th Fibonacci number log.fine("Computing 15th Fibonacci number."); try { int fib15 = ic1b.computeFibonacci(15); log.info("Fib(15) = " + fib15); }catch(Exception e){ log.severe("Caught exception: " + e); } // Invalid Fibonacci number (throws exception) log.fine("Computing 0th Fibonacci number."); try { int fib15 = ic1b.computeFibonacci(0); log.info("Fib(0) = " + fib15); }catch(Exception e){ log.severe("Caught exception: " + e); } log.info("The program has left the virtual machine."); } /** * Replaces the ConsoleHandler for a specific Logger with one that will log * all messages. This method could be adapted to replace other types of * loggers if desired. * * @param logger * the logger to update. * @param newLevel * the new level to log. */ public static void replaceConsoleHandler(Logger logger, Level newLevel) { // Handler for console (reuse it if it already exists) Handler consoleHandler = null; // see if there is already a console handler for (Handler handler : logger.getHandlers()) { if (handler instanceof ConsoleHandler) { // found the console handler consoleHandler = handler; break; } } if (consoleHandler == null) { // there was no console handler found, create a new one consoleHandler = new ConsoleHandler(); logger.addHandler(consoleHandler); } // set the console handler to fine: consoleHandler.setLevel(newLevel); } /** * Creates log messages at all possible levels. */ public static void invokeLog() { log.severe("This is a severe log message. It should be used to log severe or unexpected failures."); log.warning("This is a warning log message. It should be used to log non-severe failures or exceptional conditions that are expected."); log.info("This is an info log message. It should be used to log informative messages that are appropriate for production or customer use."); log.config("This is a config log message. It should be called to provide configuration-specific information about the application."); log.fine("This is a fine log message. It should be used to log course-grained debugging information."); log.finer("This is a finer log message. It should be used to log medium-grained debugging information."); log.finest("This is a finest log message. It should be used to log fine-grained debugging information. Basically, a trace of your program."); } /** * An inner class, used to represent how other classes would log within an * application. Notice how * * @author Robert Moore * */ public static class InnerClass1 { /** * A private, static logger for this class to use. */ @SuppressWarnings("hiding") private static final Logger log = Logger.getLogger(InnerClass1.class .getName()); // Configure the logger to log all messages static { log.setLevel(Level.ALL); } /** * Keeps track of the number of objects of this type that we've created. */ private static AtomicInteger instanceCount = new AtomicInteger(0); /** * The instance number of this object. Unique within this class. */ private final int instanceNumber; /** * Creates a new instance of this class with a unique instance number value. */ public InnerClass1() { this.instanceNumber = instanceCount.incrementAndGet(); } @Override public String toString() { return "InnerClass1 (" + this.instanceNumber + ")"; } /** * Computes the n<sup>th</sup> Fibonacci number. * @param n the n<sup>th</sup> number. * @return the n<sup>th</sup> Fibonacci number. */ public int computeFibonacci(final int n) { if(n <= 0){ log.severe(this +": There is no " + n + "th Fibonacci number."); throw new IllegalArgumentException("Input value must be >= 1."); } int a = 1; int b = 1; log.config(this + ": Computing the " + n + "th Fibonacci number."); if(n <= 2){ log.fine(this + ": Input was 1 or 2, returning 1."); return 1; } for(int i = 2; i < n; ++i){ log.finer(this + ": i = " + i + "/" + n); log.finest("a="+a+ ", b=" + b); int tmp = b; b = b + a; a = tmp; } // Overflow if(b < 0) { log.warning(this + ": Input was too big for a 32-bit value!"); throw new RuntimeException("Input value " + n + " is too large to compute in 32 bits."); } return b; } } }