Getting started

The heart of the logging API is a class called Logger. This is the class that is responsible for outputting log information. The following shows a simple example of a class declaring a Logger and outputting a message:

package logging;

import java.util.logging.Logger;

 

public class SimpleLogging {

    public static void main(String[] args) {

        Logger log = Logger.getLogger(SimpleLogging.class.getName());

        log.info("This is an information message");

    }

}

If I run this program in Eclipse it produces the following output:

Apr 25, 2014 2:39:02 PM logging.SimpleLogging main

INFO: This is an information message

In many ways this is similar to using System.out.println, but you can already see some advantages.

  • The output includes the current date and time that the message was logged

  • The output includes information about the class that produced the output

You will look at these features in more detail shortly, but for now, turn your attention to the line that creates the logger:

Logger log = Logger.getLogger(SimpleLogging.class.getName());

The getLogger static helper returns an object that can be used for logging messages. Because there will be many Loggers in a complex program it is important to associated a String with each Logger so that it is possible to differentiate the output of one Logger from another.

The most common String to associate with a Logger is the name of the class the Logger is declared in – and this is the reason that the previous example output the class name – in reality it was outputting the Logger name.

Notice that the method I have used in this example is info. When you log messages you assign an importance to them via a levelinfo indicates that the output is for informational purposes only. The level can also be assigned explicitly:

package logging;

import java.util.logging.Level;

import java.util.logging.Logger;

 

public class SimpleLogging {

    public static void main(String[] args) {

        Logger log = Logger.getLogger(SimpleLogging.class.getName());

        log.log(Level.FINEST, "This is a finest message");

        log.log(Level.FINER, "This is a finer message");

        log.log(Level.FINE, "This is a fine message");

        log.log(Level.INFO, "This is a info message");

        log.log(Level.WARNING, "This is a warning message");

        log.log(Level.SEVERE, "This is a severe message");

    }

}

This example shows the six most common levels, from the least important to the most important.

If you run this example you may be surprised by the results. I received the following output:

Apr 25, 2014 3:24:01 PM logging.SimpleLogging main

INFO: This is a info message

Apr 25, 2014 3:24:01 PM logging.SimpleLogging main

WARNING: This is a warning message

Apr 25, 2014 3:24:01 PM logging.SimpleLogging main

SEVERE: This is a severe message

The first three messages have not been printed. The reason for this is that each Logger has a default level set against it, and unless the logged message is at least as important as this level, the message will not be printed.

The reason for this becomes obvious when you reflect back on the reason you are logging information. Information is being logged typically to help understand what is happening with the program. In some situations, however, you may only want to know about severe messages (when the program is being run by end users), while other times you may want much more information (when the program is being run in development or by testers).

If you want the Logger to print all messages (or messages above a specified importance), you begin by specifying this on the Logger before logging any information:

log.setLevel(Level.ALL);

You may think this would be sufficient to print the extra messages. The beauty of levels, however, is that you may wish to log fine messages to the console, while you want to log severe messages to a file – therefore each output destination also has a default logging level.

In order to see this, create an executable JAR from this project using the techniques described in the previous chapter (I called mine simplelogging.jar). Place this somewhere on your file system, create a file called logging.properties in the same directory, and add the following to it:

handlers=java.util.logging.ConsoleHandler

java.util.logging.ConsoleHandler.level=FINE

This configuration file states that you want to perform logging to the console, and that you want to log all messages that are FINE or higher.

If you now execute this as follows:

java -Djava.util.logging.config.file=logging.properties -jar simplelogging.jar

(make sure you are in the directory with the JAR file and the logging.properties file).

It should print the following:

Apr 25, 2014 4:30:59 PM logging.SimpleLogging main

FINE: This is a fine message

Apr 25, 2014 4:30:59 PM logging.SimpleLogging main

INFO: This is a info message

Apr 25, 2014 4:30:59 PM logging.SimpleLogging main

WARNING: This is a warning message

Apr 25, 2014 4:30:59 PM logging.SimpleLogging main

SEVERE: This is a severe message

If you play around with the level you will see more or fewer lines logged.

The console is an example of a handler, but you can add others. Change the logging.properties file as follows:

handlers=java.util.logging.FileHandler, java.util.logging.ConsoleHandler

java.util.logging.ConsoleHandler.level=FINE

java.util.logging.FileHandler.level=INFO

java.util.logging.FileHandler.pattern=simple.log

java.util.logging.FileHandler.limit=10000

java.util.logging.FileHandler.formatter=java.util.logging.SimpleFormatter

This now states that the program should log messages to both a file and the console. The file logger will only log messages that are INFO or higher, and these will be logged to a file called simple.log. This can grow in size to a maximum of 10000 bytes, at which time it will be recycled.

The last line associates a formatter with the FileHandler. By default the FileHandler creates XML output, whereas I just want the simple output that is logged to the console.

If you run this now you should see a file called simple.log created with the following contents:

Apr 25, 2014 4:38:44 PM logging.SimpleLogging main

INFO: This is a info message

Apr 25, 2014 4:38:44 PM logging.SimpleLogging main

WARNING: This is a warning message

Apr 25, 2014 4:38:44 PM logging.SimpleLogging main

SEVERE: This is a severe message

Handlers do not need to be limited to consoles and files. There are many other potential destinations for log messages, such as emails, databases and phone alerts. The handler mechanism abstracts the manner in which messages are logged from the process of logging messages. This is a very flexible design, because it means any program with logging code can be extended to support different approaches to logging without changing the program itself.

So far I have focused on logging messages, but another important consideration is logging stack traces. The following program demonstrates the logging of an error. In this program the c method will generate an exception when it is invoked by main because it is being passed a null String:

package logging;

import java.util.logging.Level;

import java.util.logging.Logger;

 

public class SimpleLogging {

    public static void main(String[] args) {

        Logger log = Logger.getLogger(SimpleLogging.class.getName());

        log.setLevel(Level.ALL);

        try {

            a(null);

        } catch (Exception e) {

            log.log(Level.SEVERE, "An error occured in main", e);

        }

    }

    public static void a(String s) {

        b(s);

    }

    public static void b(String s) {

        c(s);

    }

    public static void c(String s) {

        s.substring(0, 10);

    }

}

When you run this it should produce the following output:

Apr 26, 2014 2:13:57 PM logging.SimpleLogging main

SEVERE: An error occured in main

java.lang.NullPointerException

      at logging.SimpleLogging.c(SimpleLogging.java:27)

      at logging.SimpleLogging.b(SimpleLogging.java:23)

      at logging.SimpleLogging.a(SimpleLogging.java:19)

      at logging.SimpleLogging.main(SimpleLogging.java:12)

Notice how simply passing the exception to the log method causes the entire stack trace to be printed, thereby allowing you to see the entire call stack of the program when the exception occurred.

A Software Engineer Learns Java and Object Orientated Programming
titlepage.xhtml
part0000_split_000.html
part0000_split_001.html
part0000_split_002.html
part0000_split_003.html
part0000_split_004.html
part0000_split_005.html
part0000_split_006.html
part0000_split_007.html
part0000_split_008.html
part0000_split_009.html
part0000_split_010.html
part0000_split_011.html
part0000_split_012.html
part0000_split_013.html
part0000_split_014.html
part0000_split_015.html
part0000_split_016.html
part0000_split_017.html
part0000_split_018.html
part0000_split_019.html
part0000_split_020.html
part0000_split_021.html
part0000_split_022.html
part0000_split_023.html
part0000_split_024.html
part0000_split_025.html
part0000_split_026.html
part0000_split_027.html
part0000_split_028.html
part0000_split_029.html
part0000_split_030.html
part0000_split_031.html
part0000_split_032.html
part0000_split_033.html
part0000_split_034.html
part0000_split_035.html
part0000_split_036.html
part0000_split_037.html
part0000_split_038.html
part0000_split_039.html
part0000_split_040.html
part0000_split_041.html
part0000_split_042.html
part0000_split_043.html
part0000_split_044.html
part0000_split_045.html
part0000_split_046.html
part0000_split_047.html
part0000_split_048.html
part0000_split_049.html
part0000_split_050.html
part0000_split_051.html
part0000_split_052.html
part0000_split_053.html
part0000_split_054.html
part0000_split_055.html
part0000_split_056.html
part0000_split_057.html
part0000_split_058.html
part0000_split_059.html
part0000_split_060.html
part0000_split_061.html
part0000_split_062.html
part0000_split_063.html
part0000_split_064.html
part0000_split_065.html
part0000_split_066.html
part0000_split_067.html
part0000_split_068.html
part0000_split_069.html
part0000_split_070.html
part0000_split_071.html
part0000_split_072.html
part0000_split_073.html
part0000_split_074.html
part0000_split_075.html
part0000_split_076.html
part0000_split_077.html
part0000_split_078.html
part0000_split_079.html
part0000_split_080.html
part0000_split_081.html
part0000_split_082.html
part0000_split_083.html
part0000_split_084.html
part0000_split_085.html
part0000_split_086.html
part0000_split_087.html
part0000_split_088.html
part0000_split_089.html
part0000_split_090.html
part0000_split_091.html
part0000_split_092.html
part0000_split_093.html
part0000_split_094.html
part0000_split_095.html
part0000_split_096.html
part0000_split_097.html
part0000_split_098.html
part0000_split_099.html
part0000_split_100.html
part0000_split_101.html
part0000_split_102.html
part0000_split_103.html
part0000_split_104.html
part0000_split_105.html
part0000_split_106.html
part0000_split_107.html
part0000_split_108.html
part0000_split_109.html
part0000_split_110.html
part0000_split_111.html
part0000_split_112.html
part0000_split_113.html
part0000_split_114.html
part0000_split_115.html
part0000_split_116.html
part0000_split_117.html
part0000_split_118.html
part0000_split_119.html
part0000_split_120.html
part0000_split_121.html
part0000_split_122.html
part0000_split_123.html
part0000_split_124.html
part0000_split_125.html
part0000_split_126.html
part0000_split_127.html
part0000_split_128.html
part0000_split_129.html
part0000_split_130.html
part0000_split_131.html
part0000_split_132.html
part0000_split_133.html
part0000_split_134.html
part0000_split_135.html
part0000_split_136.html
part0000_split_137.html
part0000_split_138.html
part0000_split_139.html