Dashboard > JJGuidelines > Home > Chapter 2 - Guidelines > 2. 4. Logging
JJGuidelines Log In | Sign Up   View a printable version of the current page.
2. 4. Logging
Added by Davy Vermeir, last edited by Stephan Janssen on Jan 11, 2007  (view change)

Logging

Introduction

The System.out.println method is often misused to display, in a quick and dirty way, logging or debugging information. The problem with this approach is that often these print methods remain in the source code even when the project is running in production!

Some developers centralize these print methods in a debug class and use a boolean flag to turn the debugging on or off. This approach is already a lot better than the first one. Often this approach is only applicable for straight forward debugging purposes and the debug information is displayed in a proprietary format and priority levels are frequently not used.

Different logging APIs have been created to solve the above problems, the best known ones are the Apache Jakarta Log4J and the IBM logging toolkit called JLog.

With the release of J2SE version 1.4 we finally have a consolidated logging API located in the java.util.logging package.

Why Use Logging?

The J2SE 1.4 logging API can be used to improve problem diagnosis during the life-cycle of a J2EE project by either developers, system administrators and even end users. With the logging API you can capture information such as security failures, configuration errors, bugs etc.

The core logging package includes formatted log records using either plain text or XML. Through the use of handlers we can send our log information to the console, streams, console, files, sockets or even implement our own.

Tip

In the SDK 1.4 documentation you can find an overview of the Logging API and more detailed information on the logging package.

Tip

Maybe you're still using J2SE version 1.2 or 1.3? No problem because there is an open source implementation of the Logging API called Lumberjack available on SourceForge (http://javalogging.sourceforge.net/). This implementation uses the same package structure and class names and can be easily replaced once you've migrated to J2SE 1.4.

Logging Example

Below you can find a shortened version of a Message Driven Bean using the logging API.

/*
 * Copyright notice
 *
 * File : $RCSfile: ch02s04.html,v $
 */
package be.vlaanderen.examples.messagebean;

import java.util.logging.Level;
import java.util.logging.Logger;

// Other imports

/**
 * A simple Message Driven Bean example
 *
 * @author Stephan Janssen - JCS Int.
 * @version $Revision: 1.2 $ $Date: 2004/04/02 08:14:03 $
 */
public class FooBean implements MessageDrivenBean, MessageListener {

    /** Initialize the logging API here and use it for any std. error output */
    private static final Logger logger =
            Logger.getLogger(FooBean.class.getName()); TODO_link_1

    // Bean methods

    /**
     * The onMessage method is called when a message
     * has been produced for
     *
     * @param msg The asynchronous received message.
     */
    public void onMessage(Message msg) {
        String txtMessage = null;
        try {
            txtMessage = ((TextMessage) msg).getText();
            helperMethod(txtMessage);
        } catch (JMSException e) {
            logger.log(Level.WARNING, "JMS Problem", e); TODO_link_2
        }
    }

    /**
     * An example of a helper method which
     * can be called by the onMessage method.
     *
     * @param text A String value from the onMessage method
     */
    public static void helperMethod(String text) {
        logger.info(text); TODO_link_3
    }
}

The above example is compliant to the following logging rules:
Rule LOG_001: Retrieve A Logger Based On The Fully Qualified Package And Class Name
Rule LOG_003: Log A Catched Exception
Rule JAC_065: Do Not Unnecessary Use The System.out.print or System.err.print Methods (High)

Tip

If you want to create your own a Log Handler using JDBC then have a look at http://www.developer.com/db/article.php/1468351.

Logging Levels

The Logging API supports 7 standard log levels through the java.util.logging.Level class.

Table 2.6. Logging Levels
Level Description
SEVERE Use this log level for non-recoverable or catched runtime (unchecked) exceptions. The severe level has the highest importance. See also rule LOG_005: Use The Log Level SEVERE Only For Non Recoverable Problems.
WARNING Use this log level for recoverable or checked exceptions. See also rule LOG_006: Use The Log Level WARNING Only For Recoverable Problems.
INFO Use this level for informational logs. See also rule LOG_007: Use The Log Level INFO Only For Information Logs.
CONFIG This log level should be used for configuration messages or related problems. See also rule LOG_008: Use The Log Level CONFIG Only For Configuration Problems.
FINE Can be used for temporary debug info.
FINER Can be used for temporary debug info.
FINEST The finest level is has the lowest importance and can be used for temporary debug info.

Each of the above log levels has a related convenience method named after the level. For example:

logger.severe("This is a severe problem");
logger.warning("A warning log message");
logger.info("An information log message");

When using the SEVERE or WARNING log levels you might also want to display the related exception, this can be done as follows:

try {
    txtMessage = ((TextMessage) msg).getText();

    helperMethod(txtMessage);
} catch (JMSException e) {
    logger.log(Level.WARNING, "JMS Problem", e);
}
Tip

If you need to collect a lot of information for your log message or create some specific handlers than use the isLoggable method within the Logger class. For example:

if (logger.isLoggable(Level.FINE)) {
    // prepare your log message here
}

Localized Messages

The text used for each log message can be localized through the use of a ResourceBundle. The example below shows a localized warning message using the Dutch ResourceBundle for Belgium.

private static final Logger logger =
        Logger.getLogger(Demo.class.getName(),
                "be.vlaanderen.examples.MyResources");
// ...

Locale currentLocale = new Locale("nl", "BE");

ResourceBundle myResources =
        ResourceBundle.getBundle(
                "be.vlaanderen.examples.MyResources",
                currentLocale);

logger.warning("WARNING1");

The supported resource bundle for this localized logging example needs to look as follows:

package be.vlaanderen.examples;

import java.util.ListResourceBundle;

public class MyResources_nl extends ListResourceBundle {

    static final Object[][] contents = {
        { "WARNING1", "Voorbeeld van een nederlandstalige boodschap." },
    };

    public Object[][] getContents() {
        return contents;
    }
}

This simple logging program generates the following output:

22-okt-2003 14:19:04 be.vlaanderen.examples.Foo main
INFO: Voorbeeld van een nederlandstalige boodschap

Configuration File

The project logging features can easily be maintained by using a centralized configuration file. In this file we can setup a default logging level or define a separate level per package or even just turn the logging off for a given package. The logging configuration file is based on the java.util.Properties format using key/value pairs. We'll name this configuration file {{logging.properties and store it in the conf directory.

Next to the log level we can also configure the different logging handlers which the project can use. The Logging API supports five handlers: StreamHandler, ConsoleHandler, FileHandler, SocketHandler and MemoryHandler. We simply add these handlers to the configuration file and the project will use the given handlers once it's restarted.

Tip

Use the readConfiguration method in the LogManager class when the logging configuration is changed and you do not want to restart your application. This method could also get triggered through the use of JMX. See the chapter about JMX.

The logging configuration example below sets the default log level to CONFIG, uses the File and Console handlers and will redirect all log records in the user home directory to the log file guidelines%u.log.

.level = CONFIG
handlers = java.util.logging.FileHandler, java.util.logging.ConsoleHandler
java.util.logging.FileHandler.pattern = %h\guidelines%u.log
be.vlaanderen.examples.level = WARNING

The application can only use the above configuration file when the JVM parameter java.util.logging.config.file is set correctly:

java -Djava.util.logging.config.file=..\..\conf\logging.properties
    be.vlaanderen.examples.Foo

Site powered by a free Open Source Project / Non-profit License (more) of Confluence - the Enterprise wiki.
Learn more or evaluate Confluence for your organisation.
Hosted by JavaLobby
Powered by Atlassian Confluence, the Enterprise Wiki. (Version: 2.2.5 Build:#520 Jun 27, 2006) - Bug/feature request - Contact Administrators