July 22, 2014
Hot Topics:
RSS RSS feed Download our iPhone app

Creating a JDBC Log Handler for JDK 1.4

  • September 23, 2002
  • By Jeff Heaton
  • Send Email »
  • More Articles »

One of the features that JDK 1.4 introduced is the Logging API. This is a set of objects that allows applications to create consistent, expandable logs. One important feature of the Logging API is the ability to create your own handler classes. A handler class gives you the ability to abstract where the logged data will go.

There are many eventual destinations for logged data. Programs commonly write the contents of an application log to files, the system console, or even to memory. If you want to log to one of these mediums, the Logging API provides several handler classes to allow it. If you want to log to an alternate medium, you must write your own handler class.

Writing a handler class is the subject of this article. This article shows you how to write a handler class that allows the logged information to be written to a database. The reusable class presented in this article will allow a standard JDK 1.4 log to be written to any JDBC-compatible database.

The Structure of the Logging API

It is important to review the basic structure of the Logging API before you are shown how to create your own handler class. First, you will be shown a simple Java program that uses the Logging API. Any class in your program that is going to make use of the Logging API must import it. This is done with the following line.

import java.util.logging.*;

This import gives you access to all of the classes in the Logging API. To begin using the Logging API, your program first must create a new Logger object. The Logger class is provided to you by the Logging API. This is done by the following lines of code.

// Create a new logger object
Logger logger = Logger.getLogger(
  "com.heaton.articles.logger");
logger.setLevel(Level.ALL);

This creates a new logger object that will log under the name of "com.heaton.articles.logger". This is just a hierarchical name that specifies the log's name. Every log will have a name similar to this. The hierarchical nature allows applications to see the logs from several different applications. For example, the log name "com.heaton" would specify every log that began with the levels "com" and "heaton". The setLevel command specifies that we want to record all levels of severity.

Now that the Logger object has been created, you should write some data to it. The following lines of code show you how a typical log is written to. As you can see, the Logging API can accept logged data in a variety of formats.

// try some logging

logger.info("Sample log entry");
logger.warning("Sample warning");

try {
  int i=0/0;
  } catch ( Exception e ) {
  logger.log(Level.WARNING, "This is what an exception looks
                             like", e);
}

This code does not specify a handler to use. By default, the Logging API will write the logged information to the console if no additional handlers are specified. Later in this article, we will see how to add the JDBC Logging handler to the Logger.

Creating a Handler Class

Now you will be shown how to create a handler class. Any handler class must subclass the Handler class provided by the Logging API. The class Handler is declared abstract. To create a functional handler class, you must override the following three abstract methods: close, flush, and publish. By implementing these three methods, you will be passed all of the logging information that your handler is expected to log.

In addition to these three required methods, you can implement any methods of your own that are needed to log incoming information. One such method is almost always a constructor. Your constructor allows you to prepare whatever storage medium you are using. This article creates a handler that can log data to a JDBC database. The constructor for this handler accepts information necessary to open the database, and then opens the database connection.

To properly implement a handler, you must implement the close method. The close method should close whatever medium was opened in the constructor. This is important so that system resources are properly closed. This is particularly important when files are used, so that the files are properly closed and do not lose any data.

In addition to the close method, you must implement a flush method. The flush method is called to ensure that all data, up to this point, has been written to whatever medium the handler is storing it to. For example, if you were logging to a file, you would simply call the flush method of the output stream that you were logging to. The flush method does not always make sense to implement. The JDBC logging handler that you will be shown in the next section has no need of a flush method. However, because the flush method is declared abstract, you must implement a flush method. If you have no use for the flush method, just implement an empty method.

The last required method is the one that does most of the work. The publish method is called for each logging event. The publish method accepts a single parameter, of type LogRecord. The LogRecord object contains all of the information that is to be logged for this event. A publish method will generally call all of the "get" methods contained in the LogRecord and write the data to whatever medium this log handler is using.

The LogRecord object passed to a publish method contains a variety of information. A level is used to indicate how severe the log event was. This level allows certain parts of the program to filter out unimportant log events. The LogRecord also contains the source class and method to allow you to trace what part of the program generated the log event. The log event also contains the actual text of the log entry. There are also other, less frequently used pieces of information that are also passed with the LogRecord.

Creating a JDBC Handler

Now you have seen what is necessary to create a log handler class. This section will show you how to create a log handler, named JDBCLogHandler, that will log information to a JDBC data source. The complete listing for the JDBCLogHandler class is shown in Listing 1. Before you are shown how this class was constructed the database connection must be explained. This class uses a JDBC database connection. Any JDBC-compatible database should work. For the purposes of this article, I will assume you are using the MySQL database. The MySQL database is a freely available, open source database that can be downloaded from http://www.mysql.org. All log information is written to a single table. This table, which is named log, can be created using the following SQL command.

CREATE TABLE log (
  level integer NOT NULL,
  logger varchar(64) NOT NULL,
  message varchar(255) NOT NULL,
  sequence integer NOT NULL,
  sourceClass varchar(64) NOT NULL,
  sourceMethod varchar(32) NOT NULL,
  threadID integer NOT NULL,
  timeEntered datetime NOT NULL)

As to the name of the database and how to access it, the JDBCLogHandler class remains oblivious to this information so that it can be used with any sort of database. This connection information is passed into the JDBCLogHandler class through the constructor.

For the sake of efficiency, this class uses prepared SQL. Prepared SQL, stored in PreparedStatement objects, compiles a SQL command so that it can be executed repeatedly as fast as possible. The JDBCLogHandler class uses two such SQL commands. The first, stored in the prepInsert variable, is used to insert a single row into the log table. The second, stored in the prepClear variable, is used to clear all rows from the log table. When the constructor is called, these two prepared statements are allocated.

The constructor handles opening the database. The constructor is passed the name of the JDBC driver, and a connection string that is used to define what database is to be used. The following lines of code are used, inside the constructor, to open the database connection and create the two prepared SQL commands.

Class.forName(driverString);
Connection=
  DriverManager.getConnection(
    connectionString);
prepInsert=
  connection.prepareStatement(
    insertSQL);
prepClear =
  connection.prepareStatement(
    clearSQL);

As you can see, the actual text of the SQL commands is stored in the insertSQL and clearSQL Strings. These values can also be found in Listing 1. The connection that is opened, by the above lines, is used through the lifetime of this handler object. The connection is ultimately closed when the user calls the handler's close method. The flush method is implemented only because it is required. As you can see in Listing 1, nothing is done by the flush method. The flush method normally forces any recent log entries to be stored to the underlying medium. This handler stores the rows as soon as they are received, so nothing is gained by calling flush.

The publish method is the heart of the handler. It is the publish method that writes each of the log entries to the database. When you instruct a Logger to use this handler, each entry will be sent to the handler. The next section will show you how to actually instruct the Logger to use this handler.

The handler itself is a very simple method. All that it does is copies each of the entries in the LogRecord to a parameter for the SQL INSERT statement. After all of the values are copied, the insert is executed. This command completes the process of inserting the row, and there is no reason to flush. Of course, close should be called when you are finished with the handler.

Using the JDBC Handler

Now that you have created a handler class that will store information to a database, you will be shown how to use it. Listing 2 shows a very simple Java application that makes use of the JDBC Log handler class. First, you must construct the JDBCLogHandler class, as seen here.

// set up the JDBCLogger handler
JDBCLogHandler jdbcHandler
  = new JDBCLogHandler(driver,connection);
jdbcHandler.clear();

As you can see, a driver name and connection are passed to the JDBCLogHandler class's constructor. This will be dependant upon what database your using. Here I am using a MySQL database named "logging", with a user name of "logger" and a password of "logpass". Consult your database's documentation for more information on what you should put here. After the JDBCLogHandler class has been instantiated, you must add a handler to the logger. This is done with the following command.

logger.addHandler(jdbcHandler);

Of course, you can have multiple handlers on one Logger. If you add additional handlers, the logging information will be sent to all of your handlers.





Page 1 of 2



Comment and Contribute

 


(Maximum characters: 1200). You have characters left.

 

 


Sitemap | Contact Us

Rocket Fuel