Tutorials : Looking into the JDK 1.4 Logging API :

Formatters

Every handler must have a formatter defined, and the API has pre-defined a SimpleFormatter and an XMLFormatter which both extend the abstract class Formatter. You may define your own formatter if you like, and it's actually quite simple. You only have to implement the format method. This method receives an instance of the LogRecord class which contains several properties. format returns a string with the data that should be logged. In the next example I've made a formatter that returns the most important properties from the LogRecord:

package hansen.playground.logging;
    
    import java.util.*;
    import java.util.logging.*;
    
    public class MyFormatter extends Formatter {
      public String format(LogRecord record) {
        return
          "LogRecord info:\n" +
          "Level: " + record.getLevel() + '\n' +
          "LoggerName: " + record.getLoggerName() + '\n' +
          "Message: " + record.getMessage() + '\n' +
          " " + record.getMillis() + '\n' +
          "Sequence Number: " + record.getSequenceNumber() + '\n' +
          "SourceClassName: " + record.getSourceClassName() + '\n' +
          "SourceMethodName: " + record.getSourceMethodName() + '\n' +
          "ThreadID: " + record.getThreadID() + '\n';
      }
    }

The simplest way to try this formatter is to put its name in the logging.properties file. So we replace

java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter

with

java.util.logging.ConsoleHandler.formatter = hansen.playground.logging.MyFormatter

If we run program Log1 we get this written out to the console:

LogRecord info:
    Level: SEVERE
    LoggerName: hansen.playground.logging.Log1
    Message: severe message
    Millis: 1028657842830
    Sequence Number: 0
    SourceClassName: hansen.playground.logging.LoggerInformation
    SourceMethodName: tryLevels
    ThreadID: 10
    LogRecord info:
    Level: WARNING
    LoggerName: hansen.playground.logging.Log1
    Message: warning message
    Millis: 1028657842830
    Sequence Number: 1
    SourceClassName: hansen.playground.logging.LoggerInformation
    SourceMethodName: tryLevels
    ThreadID: 10
    LogRecord info:
    Level: INFO
    LoggerName: hansen.playground.logging.Log1
    Message: info message
    Millis: 1028657842830
    Sequence Number: 2
    SourceClassName: hansen.playground.logging.LoggerInformation
    SourceMethodName: tryLevels
    ThreadID: 10

If you compare it to the output from the SimpleFormatter:

11-08-2002 19:49:10 hansen.playground.logging.LoggerInformation tryLevels
    SEVERE: severe message

then you can see that this format contains: a timestamp, SourceClassName, SourceMethodName, Level, and Message. In most cases this format is sufficient.

Rotating files

A very nice feature in the FileHandler is the option to use a set of rotating files. If you define your FileHandler like this:

FileHandler filehandler =
      new FileHandler("%h/mylog%g.txt", 100000, 2);

then the file is placed in the "user.home" directory (the "%h"), it can hold 100000 bytes of data, and it'll switch between two files called mylog0.txt and mylog1.txt. The generation numbers comes from the "%g" notation. A small example will illustrate this. We'll write 10 lines to two very small log-files (300 bytes each):

package hansen.playground.logging;
    
    import java.util.*;
    import java.util.logging.*;
    
    public class CyclicFiles {
    
      private static Logger logger1 =
        Logger.getLogger("hansen.playground.logging.CyclicFiles");
    
      public static void main(String[] args)
        throws java.io.IOException {
        FileHandler filehandler =
          new FileHandler("%h/mylog%g.txt", 300, 2);
        logger1.addHandler(filehandler);
        filehandler.setFormatter(new SimpleFormatter());
        for (int i = 0; i < 10; i++) {
          logger1.info("Line " + i);
        }
      }
    }

When we run this program we'll first of all see 10 lines written to the console (System.err), but in the user.home directory--which is C:\WINDOWS on my Win98 computer--we find two files: mylog0.txt contains this:

11-08-2002 13:07:48 hansen.playground.logging.CyclicFiles main
    INFO: Line 8
    11-08-2002 13:07:48 hansen.playground.logging.CyclicFiles main
    INFO: Line 9

and mylog1.txt this:

11-08-2002 13:07:48 hansen.playground.logging.CyclicFiles main
    INFO: Line 4
    11-08-2002 13:07:48 hansen.playground.logging.CyclicFiles main
    INFO: Line 5
    11-08-2002 13:07:48 hansen.playground.logging.CyclicFiles main
    INFO: Line 6
    11-08-2002 13:07:48 hansen.playground.logging.CyclicFiles main
    INFO: Line 7

A total of 10 messages have been logged. The first 4 were logged to mylog0.txt, which then was full (as defined by the maximum allowable size of 300 bytes). The following 4 were logged to mylog1.txt which then was also full. Then the cyclic logging mechanism started over with the first file (mylog0.txt), which it completely overwrites and thereby only leaves the last 2 messages in the file.

If you have ever tried to empty a log file on a web server without success, because the file was being used by the server, then you'll appreciate this feature.

How to Add Java Applets to Your Site

New on the Java Boutique:

New Review:

Time Management Made Easy with the Quartz Enterprise Job Scheduler
Why not just use the Java timer API? This open source scheduling API boasts simplicity, ease-of-integration, a well-rounded feature set, and it's free!

New Applet:

Reverse Complement
Reverse Complement is a simple applet that converts DNA or RNA sequences into three useful formats.

Elsewhere on internet.com:

WebDeveloper Java
Lots of Java information on webdeveloper.com

WDVL Java
Thorough Java resource at the Web Developer's Virtual Library.

ScriptSearch Java
Hundreds of free Java code files to download.

jGuru: Your View of the Java Universe
Customizable portal with online training, FAQs, regular news updates, and tutorials.