Follow Techotopia on Twitter

On-line Guides
All Guides
eBook Store
iOS / Android
Linux for Beginners
Office Productivity
Linux Installation
Linux Security
Linux Utilities
Linux Virtualization
Linux Kernel
System/Network Admin
Programming
Scripting Languages
Development Tools
Web Development
GUI Toolkits/Desktop
Databases
Mail Systems
openSolaris
Eclipse Documentation
Techotopia.com
Virtuatopia.com

How To Guides
Virtualization
General System Admin
Linux Security
Linux Filesystems
Web Servers
Graphics & Desktop
PC Hardware
Windows
Problem Solutions

  




 

 

Thinking in Java
Prev Contents / Index Next

Handlers

As noted previously, you can easily create your own handler by inheriting from Handler and defining publish( ) to perform your desired operations. However, there are predefined handlers that will probably satisfy your needs without doing any extra work:

StreamHandler

Writes formatted records to an OutputStream

ConsoleHandler

Writes formatted records to System.err

FileHandler

Writes formatted log records either to a single file, or to a set of rotating log files

SocketHandler

Writes formatted log records to remote TCP ports

MemoryHandler

Buffers log records in memory

For example, you often want to store logging output to a file. The FileHandler makes this easy:

//: c15:LogToFile.java
// {Clean: LogToFile.xml,LogToFile.xml.lck}
import com.bruceeckel.simpletest.*;
import java.util.logging.*;

public class LogToFile {
  private static Test monitor = new Test();
  private static Logger logger =
    Logger.getLogger("LogToFile");
  public static void main(String[] args) throws Exception {
    logger.addHandler(new FileHandler("LogToFile.xml"));
    logger.info("A message logged to the file");
    monitor.expect(new String[] {
      "%% .* LogToFile main",
      "INFO: A message logged to the file"
    });
  }
} ///:~


When you run this program, you’ll notice two things. First, even though we’re sending output to a file, you’ll still see console output. That’s because each message is converted to a LogRecord, which is first used by the local logger object, which passes it to its own handlers. At this point the LogRecord is passed to the parent object, which has its own handlers. This process continues until the root logger is reached. The root logger comes with a default ConsoleHandler, so the message appears on the screen as well as appearing in the log file (you can turn off this behavior by calling setUseParentHandlers(false)).

The second thing you’ll notice is that the contents of the log file is in XML format, which will look something like this:

<?xml version="1.0" standalone="no"?>
<!DOCTYPE log SYSTEM "logger.dtd">
<log>
<record>
  <date>2002-07-08T12:18:17</date>
  <millis>1026152297750</millis>
  <sequence>0</sequence>
  <logger>LogToFile</logger>
  <level>INFO</level>
  <class>LogToFile</class>
  <method>main</method>
  <thread>10</thread>
  <message>A message logged to the file</message>
</record>
</log>


The default output format for a FileHandler is XML. If you want to change the format, you must attach a different Formatter object to the handler. Here, a SimpleFormatter is used for the file in order to output as plain text format:

//: c15:LogToFile2.java
// {Clean: LogToFile2.txt,LogToFile2.txt.lck}
import com.bruceeckel.simpletest.*;
import java.util.logging.*;

public class LogToFile2 {
  private static Test monitor = new Test();
  private static Logger logger =
    Logger.getLogger("LogToFile2");
  public static void main(String[] args) throws Exception {
    FileHandler logFile= new FileHandler("LogToFile2.txt");
    logFile.setFormatter(new SimpleFormatter());
    logger.addHandler(logFile);
    logger.info("A message logged to the file");
    monitor.expect(new String[] {
      "%% .* LogToFile2 main",
      "INFO: A message logged to the file"
    });
  }
} ///:~


The LogToFile2.txt file will look like this:

Jul 8, 2002 12:35:17 PM LogToFile2 main
INFO: A message logged to the file


Multiple Handlers

You can register multiple handlers with each Logger object. When a logging request comes to the Logger, it notifies all the handlers that have been registered with it,[100] as long as the logging level for the Logger is greater than or equal to that of the logging request. Each handler, in turn, has its own logging level; if the level of the LogRecord is greater than or equal to the level of the handler, then that handler publishes the record.

Here’s an example that adds a FileHandler and a ConsoleHandler to the Logger object:

//: c15:MultipleHandlers.java
// {Clean: MultipleHandlers.xml,MultipleHandlers.xml.lck}
import com.bruceeckel.simpletest.*;
import java.util.logging.*;

public class MultipleHandlers {
  private static Test monitor = new Test();
  private static Logger logger =
    Logger.getLogger("MultipleHandlers");
  public static void main(String[] args) throws Exception {
    FileHandler logFile =
      new FileHandler("MultipleHandlers.xml");
    logger.addHandler(logFile);
    logger.addHandler(new ConsoleHandler());
    logger.warning("Output to multiple handlers");
    monitor.expect(new String[] {
      "%% .* MultipleHandlers main",
      "WARNING: Output to multiple handlers",
      "%% .* MultipleHandlers main",
      "WARNING: Output to multiple handlers"
    });
  }
} ///:~


When you run the program, you’ll notice that the console output occurs twice; that’s because the root logger’s default behavior is still enabled. If you want to turn this off, make a call to setUseParentHandlers(false):

//: c15:MultipleHandlers2.java
// {Clean: MultipleHandlers2.xml,MultipleHandlers2.xml.lck}
import com.bruceeckel.simpletest.*;
import java.util.logging.*;

public class MultipleHandlers2 {
  private static Test monitor = new Test();
  private static Logger logger =
    Logger.getLogger("MultipleHandlers2");
  public static void main(String[] args) throws Exception {
    FileHandler logFile =
      new FileHandler("MultipleHandlers2.xml");
    logger.addHandler(logFile);
    logger.addHandler(new ConsoleHandler());
    logger.setUseParentHandlers(false);
    logger.warning("Output to multiple handlers");
    monitor.expect(new String[] {
      "%% .* MultipleHandlers2 main",
      "WARNING: Output to multiple handlers"
    });
  }
} ///:~


Now you’ll see only one console message.

Writing your own Handlers

You can easily write custom handlers by inheriting from the Handler class. To do this, you must not only implement the publish( ) method (which performs the actual reporting), but also flush( ) and close( ), which ensure that the stream used for reporting is properly cleaned up. Here’s an example that stores information from the LogRecord into another object (a List of String). At the end of the program, the object is printed to the console:

//: c15:CustomHandler.java
// How to write custom handler
import com.bruceeckel.simpletest.*;
import java.util.logging.*;
import java.util.*;

public class CustomHandler {
  private static Test monitor = new Test();
  private static Logger logger =
    Logger.getLogger("CustomHandler");
  private static List strHolder = new ArrayList();
  public static void main(String[] args) {
    logger.addHandler(new Handler() {
      public void publish(LogRecord logRecord) {
        strHolder.add(logRecord.getLevel() + ":");
        strHolder.add(logRecord.getSourceClassName()+":");
        strHolder.add(logRecord.getSourceMethodName()+":");
        strHolder.add("<" + logRecord.getMessage() + ">");
        strHolder.add("\n");
      }
      public void flush() {}
      public void close() {}
    });
    logger.warning("Logging Warning");
    logger.info("Logging Info");
    System.out.print(strHolder);
    monitor.expect(new String[] {
      "%% .* CustomHandler main",
      "WARNING: Logging Warning",
      "%% .* CustomHandler main",
      "INFO: Logging Info",
      "[WARNING:, CustomHandler:, main:, " +
      "<Logging Warning>, ",
      ", INFO:, CustomHandler:, main:, <Logging Info>, ",
      "]"
    });
  }
} ///:~


The console output comes from the root logger. When the ArrayList is printed, you can see that only selected information has been captured into the object.
Thinking in Java
Prev Contents / Index Next


 
 
   Reproduced courtesy of Bruce Eckel, MindView, Inc. Design by Interspire