Fork me on GitHub

Logging

History

Up until and including Oracle Coherence Incubator 8, all logging occurred through the use of the CacheFactory.log method. While this was somewhat consistent with the internal implementation of Oracle Coherence, it prevented certain flexibility provided by standard java.util.logging framework.

Post Oracle Coherence Incubator 8 we changed our strategy and refactored almost all of the logging to use the standard java.util.logging framework, thus allowing fine-grain control, filtering and ultimately replacement using commonly requested and community-driven logging frameworks.

While Java logging gives a lot of flexibility, we additionally want to ensure that logging via the Coherence provided framework is still possible. To achieve this we have provided a java.util.logging.Handler implementation that redirects standard java.util.logging messages to the Coherence log facility.

One of the core reasons for keeping the Coherence Logging facility is that the Coherence Logging is asynchronous internally. It uses a separate thread for actual logging, thus preventing logging-based latency to accidentally impact performance (unlike the java.util.logging framework prior to Java SE 7).

Additional Information

The following links further information about logging frameworks and Java.

http://www.crazysquirrel.com/computing/java/logging.jspx http://www.vogella.de/articles/Logging/article.html

How to log messages

Logging is quite easy. Simply acquire a Logger for your class and log use it as follows:

package com.wombat;

import java.util.logging.*;

public class Nose
{
    // obtain a suitable logger.
    private static Logger logger = Logger.getLogger(Nose.class.getName());

    public static void main(String args[])
    {
        // Log a FINE tracing message
        if (logger.isLoggable(Level.FINE))
        {
            logger.log(Level.FINE, "doing stuff");
        }

        try 
        {
            Wombat.sneeze();
        }
        catch (Exception e)
        {
            if (logger.isLoggable(Level.SEVERE)) 
            {
                logger.log(Level.SEVERE, "trouble sneezing", e);
            }

            if (logger.isLoggable(Level.FINE)) 
            {
                logger.log(Level.FINE, "doing stuff");
            }
        }
    }
}

Setting a Class Logger logging level

The logging level for an individual class logger can be configured by adding an entry in the JRE/lib/logging.properties file:

 com.oracle.coherence.patterns.pushreplication.CachePublisher.level=FINE  An Incubator class logger logging level is independent of the Coherence Logging Level (i.e. tangosol.coherence.log.level). This allows for detailed class logging without impacting the entire Coherence/Incubator stack's logging.

An Incubator class logger LogRecord's logging level is set to the lower of: the Coherence Logging Level and the Incubator Class Logger Logging Level. This allows the LogRecord into the Coherence log stream.

When to use guards around logging?

As the construction of the strings and getting values for log messages can be expensive, we recommend that you always guard the generation of log messages like this:

if (logger.isLoggable(INFO))
{
    logger.info(getExpensiveString());
}

What levels should I use?

One of the most important decisions to be made when logging is to choose the correct logging level. The following section outlines our recommendations for choosing the correct logging level when developing for the Oracle Coherence Incubator.

The Severe Level:

The Level.SEVERE level should be used for logging errors, exceptions and messages prior to a process terminating. The method logger.severe(...) should be used for logging at the severe level.

In general, there's never a requirement to use a guard when using this level, simply because you want the end-user to see as much logging as possible prior to process termination.

The Warning Level:

The Level.WARNING level should be used for logging unhandled exceptions and messages:

  1. prior to a part of a system/service/feature going unexpectedly going offline, deteriorating or becoming unavailable (without a process terminating).

  2. when using a deprecated feature.

  3. for recommending a better use of a feature.

  4. when experiencing unexpected unhandled / unknown exception conditions (that won't lead to system instability). This does not include exceptions due to user error. ie: file not found, but does include exceptions due to configuration/developer error.

The method logger.warning(...) should be used for logging warnings.

The Information Level:

The Level.INFO level should be used for logging:

  1. High-level feature functional activity in a system. eg: life-cycles

  2. Information about the dynamic configuration of a sub-system/component/service/feature

  3. Dynamic information/dependencies/configuration changes that have a material effect on a sub-system/component/feature's future behaviour.

    For example when a feature becomes available/starting/stopping with a certain configuration.

The method logger.info(...) should be used for logging at the info level

The Configuration Level:

The Level.CONFIG level should be used for logging static configuration information.

The method logger.config(...) should be used for logging at the config level.

The Fine Level:

The Level.FINE level should be used for logging top-level implementation details, but not lifecycles or entry-exit. Examples include:

  1. The successful (or unsuccessful) creation of a messaging session.

  2. A request for some action to be performed.

  3. An exception has occurred (like file not found).

  4. A message that has been published / consumed.

  5. A task that has been created/submitted

  6. A namespace handler that has been created  In most cases, Level.FINE will be the most common level of logging seen.

The method logger.fine(...) should be used for logging at the fine level

The Finer Level

The Level.FINER level should be used for logging method/feature implementation entry-exit and exceptions.

The methods logger.entering(...)/exiting(...) and throwing(...) should be used for logging entry, exit and exceptions at the finer level.

The Finest Level

The Level.FINEST should be used for logging the internal execution of algorithms. This is by far the noisiest level of logging. You'd typically see this logging within a loop or method showing the progress of execution.

Use this level for where you'd be tempted to uses a System.out.print to debug/trace an implementation.

The method logger.finest(...) should be used for logging at this level.