The ObjectWeb Consortium

Interface Specification

MonoLog

-

Logging and Monitoring Specifications

Authors:

S. Chassande-Barrioz (INRIA)

Contributors:

JB. Stefani (INRIA)

B. Dumant (Kelua)

Released:June 22, 2001

Status:Final Draft

Version:0.1

Interface Specification

Table of contents

1Introduction

1.1Overview

1.2Target audience

1.3Goals

1.4Document Convention

2Logging API overview

2.1Architecture

2.1.1Overview of Control flow

2.1.2Granularity of logging

2.2Level interface & Levels class

2.3Monitor

2.4TopicalMonitor

2.4.1Definition

2.4.2Properties

2.4.3TopicalMonitor API

2.5MonitorFactory

2.5.1Goals

2.5.2Api

2.5.3How to find a MonitorFactory ?

3Instrumentation Convention

3.1Header & declaration

3.2Logging an event

4Implementations & Wrapper

4.1Log4j Wrapper

4.2JavaLog Wrapper

Annexe A.Level Interface

Annexe B.TopicalMonitor Interface

Annexe C.Monitor Interface

Annexe D.MonitorFactory Interface

Annexe E.Levels Class

Annexe F.DefaultMonitorFactoryManager Class

Annexe G.Change History

Table of figures

Figure 1 : Event logging on a Monitor

Figure 2 : Event Routing

Figure 3 : Logging chain

Figure 4 : Logger and its Monitors

Figure 5 : Hierarchical namespace

Figure 6 : Multiple names

1Introduction

A step of development is the product debugging. The source code is instrumented in order to detect or find problems. Java log and Log4j are two standard specifications of logging. Both products contain only class specifications without interfaces.

1.1Overview

The aim of this document is to describe a set of interfaces for the source code instrumentation independent from an implementation and a convention about the instrumentation code.

1.2Target audience

The target audience for this specification includes all Objectweb developers, but also all developers who don’t want to depend on a logging implementation.

1.3Goals

The MonoLog specification has been designed with the following goals :

  • It standardizes the instrumentation code.
  • It is structured to support a component architecture.
  • It allows an efficient implementation of logging.
  • It allows to abstract source code instrumentation to an implementation of logging.

1.4Document Convention

Font / Using
Times New Roman:12 / Description of MonoLog
Courier New:10 / Example or source code

2Logging API overview

The source code of all interfaces is in annexes A, B, C, D, E.

2.1Architecture

2.1.1Overview of Control flow

Applications make logging calls on object instances which implement the Monitor interface. A Monitor allows to publish events and is anonymous.

Figure 1 : Event logging on a Monitor

A TopicalMonitor is a named Monitor which can route events to other Monitors :

Figure 2 : Event Routing

Both interfaces allow to construct a chain :

Figure 3 : Logging chain

2.1.2Granularity of logging

It appears desirable to support granularity of logging in two different dimensions, first by sub-system and second by priority or level.

A field service engineer might be interested in tracing all events in AWT, but have no interest in socket events or memory management.

Logging is relatively expensive. We want to allow fine grain logging, but in order to preserve system performance we will normally want to disable most logging. It appears desirable to allow logging to be enabled based on a system levels, so that a program can be configured to output logging for some levels while ignoring output a other levels.

Therefore a TopicalMonitor has two properties, a level and a topic list.

2.2Level interface & BasicLevel class

An event must be registered with a level which represents its importance and also a quantity of log that must be treated. This specification provides a Level interface to represent this concept. Levels are ordered, and enabling logging at a given level also enables logging at all higher levels.

An object which implements Level interface, can be used in log methods to specify the event importance. This interface contains methods to compare Level instance. This specification proposes also to apply the flyweight pattern to this Level interface. A Level can be represents by a simple integer value. To apply this pattern, the specification proposes that all log methods know take in consideration an int parameter to represent a level. The Level interface is defined in org.objectweb.monolog.api package.

To be complete, this specification must predefine a set of level. Indeed during the instrumentation, developers must write commands to log an event with a specific level. Predefined variables or constants are needed, if we want that the instrumentation don’t depend on the logging implementation. This specification provides a org.objectweb.monolog.api.BasicLevel class which contains static but not final variables to represents the predefined levels. To respect the flyweight pattern chosen before, for each predefined level, a Level variable and a int variable are declared. Their values are not defined, in order to leave the implementation set its values. Below the array describes the mean of these five predefined levels:

Level / Details
FATAL / In general FAILURE messages should describe events that are of considerable importance and which will prevent normal program execution. They should be reasonably intelligible to end users and to system administrators.
ERROR / The ERROR level designates error events that might still allow the application to continue running.
WARN / In general WARNING messages should describe event that will be of interest to end users or system managers, or which indicate potential problems.
INFO / The INFO level designates informational messages that highlight the progress of the application at coarse-grained level.
DEBUG / DEBUG messages might include things like minor (recoverable) failures. Logging calls for entering, returning, or throwing an exception can be traced at this level.

The class Levels defined variables which will be set by the implementation:

package org.Objectweb.monolog.api;

public class BasicLevel {

public static Level LEVEL_FATAL ;

public static int FATAL ;

public static Level LEVEL_ERROR ;

public static int ERROR ;

………………

public static Level LEVEL_DEBUG ;

public static int DEBUG ;

}

2.3Monitor

A Monitor implementation receives event messages from an object and exports them. It might for example, write them to a console or write them to a file, or send them to a network logging service, or forward them to an OS log, or whatever. Each Monitor is associated with a log level and discards log requests that are below this level.

log methods

These methods are used to log an event for a specific level. The type of the event parameter is java.lang.Object, in order to not impose a specific type. When the log method is called, the monitor checks if the event parameter is loggable with the level parameter. This interface provides log methods with many parameters. It is possible to specify:

  • The level represented by a Level implementation or a integer value.
  • The event as object parameter.
  • A throwable.
  • An object instance.
  • An method.

getLevel / getIntLevel / setLevel / setIntLevel Methods

These methods are accessors of the current monitor level. These methods are doubled to apply the flyweight pattern and also to permit to use an integer value or a Level implementation.

turnOn / turnoff / isOn methods

A Monitor can be enabled or disabled by these methods.

isLoggable Method

This method allows to check if a level parameter is loggable by the current Monitor. The level parameter is compared to the current level.

2.4TopicalMonitor

2.4.1Definition

A TopicalMonitor is a monitor extension:

  • TopicalMonitor dispatches events to a set of monitor instead of a traditional output(file, screen). A TopicalMonitor is a sort of message router.

Figure 4 : Logger and its Monitors

  • With each TopicalMonitor a topic is associated. A topic is represented by a dotted string, and is a sort of name. This constraint defines a hierarchical namespace which should typically be aligned with the Java packaging namespace.

Figure 5 : Hierarchical namespace

2.4.2Properties

The name hierarchy of TopicalMonitor allows to add the inheritance property for monitors. For example, a TopicalMonitor with the “a.b.c” name can inherit monitors and level from the a.b parent.

The second property for a TopicalMonitor is the capacity to have many names. This is important when a component is shared by two other components. Indeed events logged by a shared component must appear for each user component of the shared component. A consequence of this property is that a TopicalMonitor may have many parents. Therefore a TopicalMonitor can inherit monitors from all its parents.

2.4.3TopicalMonitor API

addMonitor / removeMonitor Methods

A TopicalMonitor manages a list of Monitor. These methods allow to add or remove a monitor from this list.

addTopic / removeTopic / getTopics Methods

These methods allow to add or remove a topic to a TopicalMonitor. This actions change the hierarchical structure, but also the monitor list. The monitors list of a TopicalMonitor is composed of its monitors and all monitors inherited from its parents. Adding or removing a topic change only the inherited monitors list.

Example :

Figure 6 : Multiple names

This example presents a TopicalMonitor “o” with two topic: ‘a.b.o’ and ‘x.y.o’. Each TopicalMonitor parent has a monitor. The children inherits monitors from its parents. The children level is the lowest of its parents.

If the a.b.o topic is removed, then the TopicalMonitor children will not forward event to the M1 Monitor.

2.5MonitorFactory

2.5.1Goals

  • Not to impose an implementation at instrumentation time.
  • Have the same implementation of logging when many objectweb components are used in a application.

2.5.2Api

The org.objectweb.monolog.api.MonitorFactory interface provides a method to fetch a Monitor:

Monitor getMonitor(String key);

The key parameter is a monitor identifier. For example, if the Monitor is a TopicalMonitor, the key could be the class name of the user class.

2.5.3How to find a MonitorFactory ?

In a component architecture, a component must be initialised with a MonitorFactory. Classes use also this reference to obtain their Monitor. In other architecture type, this specification suggest to keep a static reference into an intermediate class. This is a sort of MonitorFactory manager.

This specification provides an example of MonitorFactory Manager (annexe F). The DefaultMonitorFactoryManager class, included in lib package, could be used to register a unique MonitorFactory. This manager provides static methods to set or get the MonitorFactory

public static void setMonitorFactory(MonitorFactory mf);

public static MonitorFactory getMonitorFactory();

3Instrumentation Convention

This part of the specification describes a convention to instrument the source code.

3.1Header & declaration

To log event is necessary to fetch a Monitor implementation from a MonitorFactory. As explained in section 2.5, a component must in a first time fetch a MonitorFactory. Below the example shows the DefaultMonitorFactoryManager using, and the necessaries imports.

import org.objectweb.monolog.api.Monitor;

import org.objectweb.monolog.api.MonitorFactory;

import org.objectweb.monolog.lib.DefaultMonitorFactoryManager;

static Monitor m =

DefaultMonitorFactoryManager.

getMonitorFactory().getMonitor(“org.ow.toto”);

A static final variable ‘trace’ can be also defined. This variable is not necessary but permits to delete the logging code at the compilation time.

static final boolean trace = true; //or false

3.2Logging an event

To log an event, there are many alternatives:

  • First the most simple is to call the log method with the level and the message:

m.log(Levels.DEBUG, ...);

  • Second, it is possible to prefix the call by a level test. This permits to not construct the message if it is not necessary. Indeed a message is often a complex argument built with many object.

if (m.isLoggable(Levels.DEBUG) )

m.log(Levels.DEBUG, ...);

  • A third possibility permits to delete code at compilation time. Just add the test of the static constant ‘trace’:

if ( trace & m.isLoggable(Levels.DEBUG) )

m.log(Levels.DEBUG, ...);

4Implementations & Wrapper

4.1Log4j Wrapper

This part describes the different tasks of the log4j wrapper :

  • The chosen levels by this specification are the same as the log4j Priorities.
  • The multiple topic property must be managed by the wrapper.
  • The log4j wrapper contains a MonitorFactory implementation.

4.2JavaLog Wrapper

This part describes the different tasks of the Java Log wrapper :

  • This next array presents the mapping of MonoLog level to Java Log Level

MonoLog levels / Java Log Priorities
FATAL / SEVERE
ERROR / SEVERE
WARN / WARN
INFO / INFO
DEBUG / FINE

For example, when you log an event with the ERROR Level, Java Log will receive a log call with SEVERE Level.

  • The multiple topic property must be managed by the wrapper.
  • The java log wrapper contains a MonitorFactory implementation.

Annexe A. Level Interface

package org.objectweb.monolog.api;

/**

* This class represents a logging level. A logging level allows to

* classify events by their importance. This interface provides

* methods to compare Level instances.

*/

public interface Level {

int compareTo(Object o);

boolean equals(Object o);

int hashCode();

int intValue();

}

Annexe B. TopicalMonitor Interface

package org.objectweb.monolog.api;

import java.util.Iterator;

/**

* A TopicalMonitor allows to log events. Events are filtered according to

* their level, then are send to a monitor. Each TopicalMonitor has one or

* more topics. After the level filter, an event is sent to all these

* monitor.

*/

public interface TopicalMonitor extends Monitor {

/**

* Add a monitor in the monitor list of the logger

*/

void addMonitor(Monitor h);

/**

* Add a topic to the logger

*/

void addTopic(String topic);

/**

* Returns the list of the different names of the logger

*/

Iterator getTopics();

/**

* Remove a monitor from the monitor list of the logger

*/

void removeMonitor(Monitor h);

/**

* Remove a topic from the logger

*/

void removeTopic(String topic);

}

Annexe C. Monitor Interface

package org.objectweb.monolog.api;

/**

* A Monitor receives event messages from an object and exports them. It

* might for example, write them to a console or write them to a file, or

* send them to a network logging service, or forward them to an OS log,

* or whatever. Each Monitor keeps track of a log level it is interested

* in and discards log requests that are below this level.

*/

public interface Monitor {

/**

* Set the current level of the logger

*/

void setIntLevel(int level);

void setLevel(Level l);

/**

* Return the current Level of the logger

*/

int getIntLevel();

Level getLevel();

/**

* Check if the level parameter are not filtered by the logger

*/

boolean isLoggable(int level);

boolean isLoggable(Level l);

/**

* Log an object with a specific level. If the level parameter is

* loggable the object is handled.

*/

void log(int level, Object o);

void log(Level l, Object o);

/**

* Log an object and a trowable with a specific level.

*/

void log(int level, Object o, Throwable t);

void log(Level l, Object o, Throwable t);

/**

* Log an object and a trowable with a specific level. This method

* permits to specify an object instance and a method.

*/

void log(int level, Object o, Throwable t, Object class,

Object method);

void log(Level l, Object o, Throwable t, Object class,

Object method);

}

Annexe D. MonitorFactory Interface

package org.objectweb.monolog.api;

/**

* A MonitorFactory is used to find Monitors.

*/

public interface MonitorFactory {

public Monitor getMonitor(String key);

}

Annexe E. BasicLevel Class

package org.objectweb.monolog.api;

public class BasicLevel {

public static Level LEVEL_FATAL ;

public static int FATAL ;

public static Level LEVEL_ERROR ;

public static int ERROR ;

public static Level LEVEL_WARN ;

public static int WARN ;

public static Level LEVEL_INFO ;

public static int INFO ;

public static Level LEVEL_DEBUG ;

public static int DEBUG ;

}

Annexe F. DefaultMonitorFactoryManager Class

package org.objectweb.monolog.api;

/* local package import

import org.objectweb.monolog.api.MonitorFactory

*/

/**

* This class defines a default manager for Monitor factory.

*/

public class DefaultMonitorFactoryManager {

private static MonitorFactory factory = null;

/**

* This method return the MonitorFactory. If any MonitorFactory has

* been registered previously, the method throws a

* NullPointerException. Any exception was defined to simplify the

* instrumentation code.

*/

public static MonitorFactory getMonitorFactory() {

return factory;

}

public static void setMonitorFactory(MonitorFactory mf) {

factory = mf;

}

}

Annexe G. Change History

This appendix outlines the significant changes during the evolution of these specifications.

The ObjectWeb Consortium1Final Draft0.1