Consortium    Solutions    Middleware    Forge    MyObjectWeb 
ObjectWeb Consortium
Print

Advanced - Powered by Google






Monolog

Project Links
· Home
· Download
· Distribution
· Documentation
· Mailing List
· License

Developers' Corner
· Workplan
· CVS Repository
· ObjectWeb Forge Site

About
· Team
· Contacts

Monolog Documentation

  1. Instrumentation
  2. Initialisation
  3. Configuration
  4. Levels
  5. Topics
  6. Patterns / Formatting
  7. Remote administration JMX or RMI

1. Instrumentation

Declaration

In your source class you need to declare the following imports:

import org.objectweb.util.monolog.api.Logger;
import org.objectweb.util.monolog.api.BasicLevel;


Somewhere you must declare LoggerFactory fields which must be reachable by the classes allocating Logger:

LoggerFactory loggerFactory = Monolog.initialize();


Somewhere you must declare Logger fields which must be reachable by the classes which want to log event:

Logger logger = null;


Somewhere you must initialize these Logger fields. To do this you need to have a LoggerFactory instance. With this factory you can ask a Logger by the getLogger(String) method. The parameter is the topic of the logger:

logger = loggerFactory.getLogger("com.foo.MyClass");

For more details see the topics section

The Use

There are three way to instrument your source code:

  • Simple: You use directly the log method on the logger
    logger.log(BasicLevel.ERROR, "my message");

  • With level test: You prefix the use of the log method by a test on the level:
    if (logger.isLoggable(BasicLevel.DEBUG) {
      logger.log(BasicLevel.DEBUG, "my message" + value);
    }
    We advice to use this solution when the message is composed by several elements. Indeed a string concatenation for example is expensive and if the level is not enabled then the message will not build with a prefixed test.

  • With level test and static constant: You prefix the use of the log method by a test on a static constant and the level:
    public final static DEBUG_ON = true;
    ...
    if (DEBUG_ON && logger.isLoggable(BasicLevel.DEBUG) {
      logger.log(BasicLevel.DEBUG, "my message" + value);
    }
    We advice to use this solution when the message concerns a debug event which is not important in standard compilaed verstion. This is a way to have additionnal debug trace which are removable at compilation time. Indeed as DEBUG_ON is a final field, compiler can decide to not generate byte when the field has the false value.

Example

The Simple class:

/**
 * Copyright (C) 2001-2003 France Telecom R&D
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */
	
import org.objectweb.util.monolog.Monolog;
import org.objectweb.util.monolog.api.BasicLevel;
import org.objectweb.util.monolog.api.Logger;
import org.objectweb.util.monolog.api.LoggerFactory;


/**
 * This example showing how to use monolog (initialisation and instrumentation).
 *
 * @author Sebastien Chassande-Barrioz
 */
public class Simple {
	public static void main(String[] args) {
		LoggerFactory lf;
		switch(args.length) {
		case 0:
			//Let monolog find the monolog.properties in the classpath or use
			// the default configuration
			lf = Monolog.initialize();
			break;
		case 1:
			// A monolog configuration file has been specified, then use it
			lf = Monolog.getMonologFactory(args[0]);
			break;
		default:
			System.out.println("Syntax error!\nUsage: java Simple [<monolog file name>]");
			return;
		}
		Simple s = new Simple(lf);
		s.foo();
		s.bar();
	}

	private static final boolean DEBUG = false;

	protected Logger logger = null;

	public Simple(LoggerFactory lf) {
		logger = lf.getLogger("monolog.examples.Simple");
	}

	public void foo() {
		if (logger.isLoggable(BasicLevel.DEBUG)) {
			logger.log(BasicLevel.DEBUG,
			    "my logger has been configured in order to log debug message");
		}
		logger.log(BasicLevel.INFO, "foo : hello my favourite logger in info");

		if (DEBUG && logger.isLoggable(BasicLevel.DEBUG)) {
			//This code is removed at compilation time because the DEBUG final
			// static field is equal to false.
			logger.log(BasicLevel.DEBUG, "This message should not appears");
		}
	}

	public void bar() {
        logger.log(BasicLevel.WARN, "bar : warning !");
		logger.log(BasicLevel.ERROR, "This is a throwed exception",
			new Throwable().fillInStackTrace());
	}
}



2. Initialisation

There are several ways to initialize monolog.

  • The simplest:
    LoggerFactory loggerFactory = Monolog.initialize();
    This solution permits to let done automatically the Monolog configuration. The default configuration file ('monolog.properties') is search into the current classloader and/or in the current directory. If no configuration file is found, Monolog tries automatically to initialize them self by trying different wrappers (log4j, JDK1.4, log4jMini). If any of them is availlable, then the default wrapper is choosen.
    Note: It is possible to change the name of the default configuration, in assigning the system property 'monolog.filename' with your value.

  • With a Properties file:
    LoggerFactory loggerFactory = Monolog.getMonologFactory("myfile.properties);
    The properties file can contain the class name of the wrapper to use. This value has to be assigned to the 'monolog.classname' property. The current possible values are the following:
    • 'org.objectweb.util.monolog.wrapper.log4j.MonologLoggerFactory': the log4j wrapper
    • 'org.objectweb.util.monolog.wrapper.javaLog.LoggerFactory': the JDK 1.4 wrapper
    • 'org.objectweb.util.monolog.wrapper.log4jMini.MonologLoggerFactory': the log4jMini wrapper
    • 'org.objectweb.util.monolog.wrapper.printwriter.LoggerImpl': the PrintWriter wrapper
    The properties file can contain the monolog configuration (levels, handlers, loggers).

  • With a wrapper class name:
    LoggerFactory loggerFactory = Monolog.getLoggerFactory("org.objectweb.util.monolog.wrapper.log4j.MonologLoggerFactory");
    You specify a MonologFactory implementation to instanciate.



3. Configuration

The current wrappers support several ways to configure the log system:

The content of a monolog properties file

Thanks to the monolog API, tools are provided to load an initial configuration. Currently there is a one tool based on properties files. The configuration is described by several properties. It therefore possible to define:

  • Levels: you can define intermediate levels which you can use to initialize logger level. The syntax is the following:
      level.<level name> <value>
    The level value can be an integer value or a simple expression. The allowed values are the following:
    • <integer value>
    • <level name> + <integer value>
    • <level name> - <integer value>
    • <level name>
    Here few examples of level definition:
    level.my_level1 20002
    level.my_level2 DEBUG
    level.my_level3 ERROR + 1
    level.my_level4 my_level1 + 1
    level.my_level5 INFO - 15
    As you see in the examples the 5 predefined levels are usable in the value expression. The 5 level names are: FATAL, ERROR, WARN, INFO, DEBUG.

  • Handlers: An handler represents an output. Monolog provides three standard handlers(console, file and RollingFile) and a generic handler which permits to configure any handler.
    An Handler is identified by its name. It has a type and few others properties. To define an handler is needed to give its name and its type. The handler definition is composed by several lines where each line matches to a property. The general expression is the following:
    handler.<handler name>.<property name> <property value>
    Here is an example of handler definition:
    handler.my_console_output.type Console
    handler.my_console_output.output System.out
    handler.my_console_output.pattern %m%n
    This code defines an handler which prints the messages to the console. The output is the standard output (not the error stream). Finaly the pattern (the format of the messages) is very simple: one message by line. For more details about pattern see the pattern section
    The handler properties are the following:
    • type: is the type of the handler(Console, File or Rollingfile)
    • pattern: is the message format (pattern section)
    • output: is the name of the output. For a console handler the value can be 'System.out' or 'System.err' whereas for a file output the value is the file pattern name.
      The output value may use a java environment variable like MY_LOG_PATH
      handler.my_file_output.output ${MY_LOG_PATH}/my_log_file.txt
      where the variable is setted in the java command line argument -DMY_LOG_PATH=/home/my/logs.
    • level: is the level of the handler.
    • appendMode: indicates if the logs must be added at the end of the file or not.
    • fileNumber: is the number of file to use.
    • maxSize: is the maximal size of the file.

  • Loggers: A Logger is identified by names. However we consider that each logger has a main name. This name is used to identify it in the property file. There are several configurable things on a Logger instance.
    1. The first configurable element is its level:
      logger.<dotted logger name>.level <level value>
      The <dotted logger name> part represents the main name of the logger. This string can be composed of dot since the names can describe a hierarchy. The <level value> part represents the value of the level logger. This value MUST be a level name. The level name can represent a predefined level of an intermediate level already defined in the LevelFactory. Here are some examples of logger level definition:
      logger.org.objecweb.foo.level DEBUG
      logger.org.objecweb.foo.level my_level4
      logger.root.level WARN
      IMPORTANT: The last example shows the way to configure the root logger instance. "root" is the particular name which designs this logger.
    2. The second configurable element is the list of additional topics. The general expression is the following:
      logger.<dotted logger name>.topic.<topic id< <additional topic>
      The <topic id< is a simple integer value which permits to make the difference between each property. Here are some examples of logger topic definition:
      logger.org.objecweb.foo.topic.0 com.bar
      logger.org.objecweb.foo.topic.1 fr.bar
      logger.a.b.topic.0 e
    3. The firth configurable element is the handler list.The general expression is the following:
      logger.<dotted logger name>.handler.<handler id> <handler name>
      The <handler id> is a simple integer value which permits to make the difference between each property. Here are some examples of logger handler definition:
      logger.org.objecweb.foo.handler.0 my_console_output
      logger.org.objecweb.foo.handler.1 my_file_Log.txt
      logger.a.b.handler.0 my_console_output

      It is also possible to clean all previous handlers assigned to a logger with the extension 'cleanHandlers' like this example

      logger.org.objecweb.foo.handler.0 my_console_output
      logger.org.objecweb.foo.cleanHandlers true
      logger.org.objecweb.foo.handler.1 my_file_Log.txt
      logger.a.b.handler.0 my_console_output
    4. The fourth configurable element is the handler inheritance. It is possible to indicate if a logger inherits handlers of its ancestor. The property is named additivity and the possible values are true or false. The default value is true, ie by default the logger inherits handlers of their ancestors.
      logger.org.objecweb.foo.additivity false

Example of monolog properties file

  • Simple: simple configuration using the JDK 1.4 wrapper
    monolog.classname org.objectweb.util.monolog.wrapper.javaLog.LoggerFactory
    
    # define a simple console handler
    handler.consoleHandler.type Console
    handler.consoleHandler.output System.out
    #handler.consoleHandler.pattern %l %m%n
    handler.consoleHandler.pattern %l %d thread=%h topic=%t class=%O{1} method=%M line=%L %m%n
    
    # define a handler for the JMX notification BUS
    handler.jmxHandler.type jmx
    handler.jmxHandler.output System.out
    handler.jmxHandler.pattern %m%n
    
    logger.root.level WARN
    logger.root.handler.0 consoleHandler
    logger.root.handler.1 jmxHandler
    
    logger.monolog.examples.Simple.level DEBUG
    
  • Simple: simple configuration for log4j wrapper
    monolog.classname org.objectweb.util.monolog.wrapper.log4j.MonologLoggerFactory
    
    # define a simple console handler
    handler.consoleHandler.type Console
    handler.consoleHandler.output System.out
    handler.consoleHandler.pattern %-5l %d thread=%h topic=%t class=%O method=%M line=%L %m%n
    
    # define a handler for the JMX notification BUS
    handler.jmxHandler.type jmx
    handler.jmxHandler.output System.out
    handler.jmxHandler.pattern %m%n
    
    logger.root.level WARN
    logger.root.handler.0 consoleHandler
    logger.root.handler.1 jmxHandler
    
    logger.monolog.examples.Simple.level DEBUG
    
  • RollingFile: Logging over 4 files with a limited size (2ko)
    # define a rolling file handler
    handler.rfh.type RollingFile
    handler.rfh.maxSize 2000
    handler.rfh.fileNumber 3
    handler.rfh.output logs/rollingfile.log
    handler.rfh.pattern %-5l thread=%h topic=%t %m%n
    
    logger.root.level WARN
    logger.root.handler.0 rfh
    logger.monolog.examples.RollingFile.level DEBUG
  • additivity: Show of handler inheritance break.
    # define a simple console handler
    handler.A.type Console
    handler.A.output System.out
    handler.A.pattern A %m%n
    handler.B.type Console
    handler.B.output System.out
    handler.B.pattern B %m%n
    
    logger.root.level DEBUG
    logger.root.handler.0 A
    logger.monolog.examples.additivity.level DEBUG
    logger.monolog.examples.additivity.additivity true
    logger.monolog.examples.additivity.handler.0 B

To use a specific file

Monolog provides a way to configure the log system whith a file specific to the log system. The supported format file are XML or properties. Here is an example for the log4j wrapper:

Properties p = new Properties;
p.put(Configurable.LOG_CONFIGURATION_TYPE, Configurable.PROPERTY);
p.put(Configurable.LOG_CONFIGURATION_FILE, "./my_log4j.properties");
p.put(Configurable.LOG_CONFIGURATION_FILE_USE_CLASSPATH, "true");
((Configurable) myLoggerFactory).configure(p);

It is needed to declare a Properties variable and to fill it with some values:

  • It is needed to indicates that the configuration mode is PROPERTY. This means that a property file will be specified.
  • The value associated to the LOG_CONFIGURATION_FILE key is the file name of the property file.
  • The last element of the property is a flag to indicate if the file must be found in the classpath or in the file system. The default value is false, ie by default the file is searched in the file system.

With this properties, the configure method is called.

To specify a XML file, the same mechanism must be used. The unique difference is the value of the LOG_CONFIGURATION_TYPE property. In this case the value must be Configurable.XML

To use the monolog API

The monolog API provides a way to manage:



4. Levels

Definition

To each logged message, a level must be associated. This level characterises the importance of the level. The monolog specification defines six levels:

  • FATAL: It characterizes a very high error message.
  • ERROR: It characterizes an error message.
  • WARN: It characterizes a warning message.
  • INFO: It characterizes a information message.
  • DEBUG: It characterizes a debugging message.
  • INHERIT: This level does not characterize the importance of a message but it is used to configure a logger. It permits to specify that a logger must inherit its level of its ancestor.

For each level two fields are declared into the BasicLevel class. First is a Level field. The second i a int field which corresponds to the integer value of the level.

Intermediate levels

Monolog permits to use other levels than the predefined levels described in the previous section. You can do this in the monolog properties files ( see the section Instrumentation) or by a programatic way with the LevelFactory interface.



5. Topics

Definition

A logger has at least one main topic. A topic is a string. By using the logger factory, it permits to reach a logger. A logger can have several topics, but a topic is associated to only one logger.

How to Choose Good Topic Names ?

It is advisable to use dotted strings in order to define a hierachical name space. This hierachy permits to have the inheritance of some logger properties: the level and the handlers.

The topics should also begin by a prefix composed by the organization name and the product name associated to the logger as the following example:

  • org.objectweb.jonas
  • org.objectweb.jorm
  • fr.dyade.joram
  • com.mycompany.myproduct

The aim of this recommendation is to avoid the conflict name between products

An interesting possibility is to associate a logger to an instance and not only to a class. Indeed the topic can be composed by the identifier of an instance. For example you can use a topic composed by the jndi name of your component. This principle offers the possibility to isolate the messages between the instances.



6. Patterns / Formatting

Pattern Elements

To format the message, it is possible to specify a pattern on the handlers. A pattern can be composed of elements. This element is prefixed by the % character. Here is the list of the possible items:

  • l: The level of the message,
  • t: The topic of the logger,
  • m: The message,
  • d: The date of the message,
  • h: The thread name where the message has been logged,
  • n: A new line,
  • O: The class name of the object which invokes the log method (expensive),
  • M: The method name which invoked the log method(expensive),
  • L: The line number in the source code where the log method was invoked (expensive).

By convention the options represented by an upper case letter are very expensive. Indeed these options need to create a throwable and to manage the string which represents the execution stack.

Pattern Examples

PatternResult
%m%nmy message
%l %m%nINFO my message
%l %O{1}.%M: %m%nINFO MyClass.myMethod(): my message



7. Remote administration JMX or RMI

Remote administration JMX or RMI

Since the 1.9 version, Monolog provides two remote administration ways.

  • The first is through JMX: The interface org.objectweb.util.monolog.remote.api.MonologFactoryMBean defines the possible methods which can be invoke on the MBean ( org.objectweb.util.monolog.remote.lib.MonologFactoryMBeanImpl).
  • the second is directly in RMI. The interface org.objectweb.util.monolog.remote.api.MonologFactoryProxy defines the possible methods which can be invoke on the MBean ( org.objectweb.util.monolog.remote.lib.MonologFactoryProxyImpl). The remote object can be registerd using one of the register method of the implementation.

Both way permits to configure loggers, handlers and levels. For more details see the Javadoc of the each interfaces.




Copyright © 1999-2005, ObjectWeb Consortium | contact | webmaster | Last modified at 2005-11-09 05:16 AM