Sun Java Solaris Communities My SDN Account Join SDN
 
Article

Using the J2SE 1.4 Logging API in Systems Management

 
 

Articles Index

Logging Classes and Interfaces

New in Java 2, Standard Edition (J2SE) version 1.4, the package java.util.logging provides the classes and interfaces of a core logging facility for the Java platform. The central goal of the logging API is to support the maintenance and servicing of Java software in a production environment. There are four main target uses of the logging package:

  1. Problem diagnosis by end users and system administrators. This consists of simple logging of common problems that can be fixed or tracked locally, such as running out of resources, security failures, and simple configuration errors.
  2. Problem diagnosis by field service engineers. The logging information used by field service engineers may be considerably more complex and verbose than that required by system administrators. Typically such information will require extra logging within particular subsystems.
  3. Problem diagnosis by the development organization. When a problem occurs in the field, it may be necessary to return the captured logging information to the original development team for diagnosis. This logging information may be extremely detailed. Such information might include detailed tracing on the internal execution of particular subsystems.
  4. Problem diagnosis during development. The Logging APIs may also be used to help debug an application under development. This may include logging information generated by the target application as well as logging information generated by lower level libraries. Note however that the logging APIs are not intended to replace the normal debugging and profiling tools that may already exist in the development environment. Developers should be careful about using the logging API for debugging as it can lead to real code bloat if overdone. This could be especially bad practice for things like applets that travel over a network.

The key classes in the package include:

  • Logger:  The main entity on which applications make logging calls. A Logger object is used to log messages for a specific system or application component.
  • LogRecord:  Used to pass logging requests between the logging framework and individual log handlers.
  • Handler:  Exports LogRecord objects to a variety of destinations including memory, output streams, consoles, files, and sockets. A variety of Handler subclasses exist for this purpose. Additional Handlers may be developed by third parties and delivered on top of the core platform.

  • Level:  Defines a set of standard logging levels that can be used to control logging output. Programs can be configured to output logging for some levels while ignoring output for others.
  • Filter:  Provides fine-grained control over what gets logged, beyond the control provided by log levels. The logging APIs support a general-purpose filter mechanism that allows application code to attach arbitrary filters to control logging output.
  • Formatter:  Provides support for formatting LogRecord objects. This package includes two formatters, SimpleFormatter and XMLFormatter, for formatting log records in plain text or XML respectively. As with Handlers, additional Formatters may be developed by third parties.

The Logging APIs offer both static and dynamic configuration control. Static control enables field service staff to set up a particular configuration and then relaunch the application with the new logging settings. Dynamic control allows for updates to the logging configuration within a currently running program. The APIs also allow for logging to be enabled or disabled for different functional areas of the system. For example, a field service engineer might be interested in tracing all AWT events, but might have no interest in socket events or memory management.

Logging Class Interactions

Applications make logging calls on Logger objects. These Logger objects allocate LogRecord objects which are passed to Handler objects for publication. Both Loggers and Handlers may use logging Levels and (optionally) Filters to decide if they are interested in a particular LogRecord. When it is necessary to publish a LogRecord externally, a Handler can (optionally) use a Formatter to localize and format the message before publishing it to an I/O stream.

There is a single global LogManager object that is used to maintain a set of shared state about Loggers and log services. The LogManager class keeps track of a set of global Handlers. By default all Loggers send their output to this standard set of global Handlers. However, Loggers may also be configured to ignore the global Handler list and/or to send output to specific target Handlers. Some Handlers may direct output to other Handlers. For example, the MemoryHandler maintains an internal ring buffer of LogRecords and on trigger events it publishes its LogRecords through a target Handler. In such cases, any formatting is done by the last Handler in the chain.

The APIs are structured so that calls on the Logger APIs can be cheap when logging is disabled. If logging is disabled for a given log level, then the Logger can make a cheap comparison test and return. If logging is enabled for a given log level, the Logger is still careful to minimize costs before passing the LogRecord into the Handlers. In particular, localization and formatting (which are relatively expensive) are deferred until the Handler requests them. For example, a MemoryHandler can maintain a circular buffer of LogRecords without having to pay formatting costs.

The java.util.logging package provides the following Handlers,

  • StreamHandler: A simple handler for writing formatted records to an OutputStream.
  • ConsoleHandler: A simple handler for writing formatted records to System.err
  • FileHandler: A handler that writes formatted log records either to a single file, or to a set of rotating log files.
  • SocketHandler: A handler that writes formatted log records to remote TCP ports.
  • MemoryHandler: A handler that buffers log records in memory.

...and two standard Formatters:

  • SimpleFormatter: Writes brief "human-readable" summaries of log records.
  • XMLFormatter: Writes detailed XML-structured information.

Logging Configuration

The APIs are structured so that an initial set of configuration information is read as properties from a configuration file. The configuration information may then be changed programatically by calls on the various logging classes and objects. In addition, there are methods on LogManager that allow the configuration file to be re-read. When this happens, the configuration file values will override any changes that have been made programatically. The default logging configuration that ships with the JRE makes only limited use of disk space. It does not flood the user with information, but does make sure to capture key failure information. The default configuration establishes two global Handlers, one for a file in the system temporary directory and one for the console. Only high priority messages are recorded.

Programmers can update the logging configuration at runtime in a variety of ways:

  • FileHandlers, MemoryHandlers, and PrintHandlers can all be created with various attributes.
  • The LogManager allows new global Handlers to be added and old ones removed.
  • New Loggers can be created and can be supplied with specific Handlers.
  • The LogManager.setLevel method allows new logging levels to be specified for trees within the Logger namespace.

Remote Access and Serialization

As with most Java platform APIs, the logging APIs are designed for use inside a single address space. All calls are intended to be local. However, it is expected that some Handlers will want to forward their output to other systems. There are a variety of ways of doing this:

  • Some Handlers (such as the SocketHandler) may write data to other systems using the XMLFormatter. This provides a simple, standard, interchange format that can be parsed and processed on a variety of systems.
  • Some Handlers may wish to pass LogRecord objects over RMI. The LogRecord class is therefore serializable. However there is a problem in how to deal with the LogRecord parameters. Some parameters may not be serializable and other parameters may have been designed to serialize much more state than is required for logging. To avoid these problems the LogRecord class has a custom writeObject method that converts the parameters to strings (using Object.toString) before writing them out. See the LogRecord API Specification for details.
  • Most of the logging classes are not intended to be serializable. Both Loggers and Handlers are stateful classes that are tied into a specific virtual machine. In this respect they are analogous to the java.io classes, which are also not serializable.

Log Monitoring for Systems Management

Systems management products, such as BMC PATROL, can be configured to monitor system or application logfiles. Typically, a template is associated with each file to be monitored. If a string specified in the template matches a string found in the logfile, an alarm or other event is triggered. Depending on the configuration, the event may cause an update to appear on the management console, an email or page to be sent to a system administrator, or an SNMP trap to be generated. This mechanism can be used in combination with the J2SE Logging API to accomplish the monitoring of a set of Java programs. Events worth monitoring might include loss of a network connection, loss of a database connection, overflow of a JMS message queue, or exceeding some preset threshold in the application.

Perform the following steps to create a PATROL template file to apply to your J2SE logfile:

  • Make sure that a PATROL Agent is running on the host where the logfile will be written.
  • Start the PATROL Console and connect to the Agent on the target host.
  • Double click on the icon which represents the target host to expose the icons for that host.
  • Right click on the Log icon and choose Edit Templates from the popup menu to open the Log Search Templates dialog.
  • Choose the Add radio button and click on Apply to open the Log Template (New) dialog.
  • Enter the name of the new template file and the string or regular expression to match on and click Apply.
  • In this dialog, you can also choose an alarm level (OK, Warn, Alarm) to associate with the specified string.

Then configure PATROL to monitor your J2SE logfile, using the template you have just created:

  • Go back to the icon window for the target host.
  • Right click on the Log icon and choose Edit List of Monitored Files from the popup menu to open the Log Files dialog.
  • Choose the Add radio button and click on Apply to open the Log File (New) dialog.
  • Enter the file name and path of the log file you want to monitor in the File Name field.
  • From the Select/Deselect Templates list, select the template you have previously created for this log file.
  • After you click on Accept, the Log Files dialog box appears with the new log file name in the List of Monitored Files.
  • Click Close to close the Log Files dialog box and a LOGMON instance icon for this log file appears in the LOGS container window.
  • PATROL begins to monitor the log file. File size and growth rate will be monitored as well as occurrences of any search strings specified in the associated template(s).

Depending on the alarm severity associated with a search string (OK, Warn, or Alarm), an occurrence of that string in the monitored logfile will cause the LOGS icon in the PATROL Console to turn or flash red. If you also have a PATROL Event Manager window open, you will see green, yellow or red messages appear.

Conclusion

Although other means exist to monitor Java applications, the logging API provides a simple, straightforward mechanism to convey status information about a running Java application. Multiple severity levels are supported as well as multiple output handlers. This, combined with circular buffering and rotating logfiles, makes the mechanism suitable for production environments. The use of sequential, ASCII files provides for easy integration with third party systems' management products.

For More Information

Java Logging APIs

About the Author

Tom Harpin works in Market Development Engineering at Sun's Burlington, MA campus. He works primarily on Distributed System Management vendor integration efforts with WBEM, and JMX. Prior to working with Sun, Tom helped design and implement several client-server systems for Delta Airlines.

Have a question about programming? Use Java Online Support.