Monolog Documentation
-
Instrumentation
-
Initialisation
-
Configuration
-
Levels
-
Topics
-
Patterns / Formatting
-
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:
- 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.
- 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.
- 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
- 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
- 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
Pattern | Result |
%m%n | my message |
%l %m%n | INFO my message |
%l %O{1}.%M: %m%n | INFO 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.
|