Skip to main content

Notice: this Wiki will be going read only early in 2024 and edits will no longer be possible. Please see: https://gitlab.eclipse.org/eclipsefdn/helpdesk/-/wikis/Wiki-shutdown-plan for the plan.

Jump to: navigation, search

COSMOS Logging

Logging for Web Applications and Web Services

Log4j will be used to do logging in web applications (such as the COSMOS UI) and web services (data managers). Information about log4j can be found at the log4j website.

Logging Configurations

To configure a web applciation to use log4j, we need a configuration file called log4j.properties in the classpath, usually put under WebContent/WEB-INF/classes. Axis2.jar comes with a log4j.properties that contains some default settings.

The installation/configuration program of the COSMOS demo should update the log4j.properties file to include settings appropriate for the COSMOS demo. Deployers can also customize the logging settings.

In order to log all log entries to the same log file, we need to add the following lines to the log4j.properties:

# Configure all classes in the org.eclipse.cosmos namespace to use the COSMOSLOG logger
# Change "ALL" to the desired log level
log4j.logger.org.eclipse.cosmos=ALL, COSMOSLOG

# COSMOSLOG is set to be a File appender using a PatternLayout.
log4j.appender.COSMOSLOG=org.apache.log4j.FileAppender
log4j.appender.COSMOSLOG.File=${catalina.base}/logs/cosmos.log
log4j.appender.COSMOSLOG.Append=true
log4j.appender.COSMOSLOG.layout=org.apache.log4j.PatternLayout
log4j.appender.COSMOSLOG.layout.ConversionPattern=%d [%t] %-5p %c %x - %m%n

The above configuration will write the logs to cosmos.log file in the logs directory under the Tomcat install directory.

We can also configure log4j to open a log file for each web application or web service, assume each web application or web service has a unique package namespace. For example, if we want the broker to have a separate log file, we can add the following lines to the log4j.properties:

# Logger for COSMOS Broker
log4j.logger.org.eclipse.cosmos.dc.broker=ALL, BROKERLOG

# COSMOSLOG is set to be a File appender using a PatternLayout.
log4j.appender.BROKERLOG=org.apache.log4j.FileAppender
log4j.appender.BROKERLOG.File=${catalina.base}/logs/cosmos-broker.log
log4j.appender.BROKERLOG.Append=true
log4j.appender.BROKERLOG.layout=org.apache.log4j.PatternLayout
log4j.appender.BROKERLOG.layout.ConversionPattern=%d [%t] %-5p %c %x - %m%n

Logging API

In a java class that requires logging, get an instance of a logger with the following code:

import org.apache.log4j.Logger;
Logger logger = Logger.getLogger(getClass());

The logger can be made a private class variable.

Log4j comes with some convenient methods for logging in different "levels" - the severity of log entry.

This methods are:

public void debug(Object message);
public void info(Object message);
public void warn(Object message);
public void error(Object message);
public void fatal(Object message);

// the following methods will also include the stack trace of the Throwable t passed in as parameter.
public void debug(Object message, Throwable t);
public void info(Object message, Throwable t);
public void warn(Object message, Throwable t);
public void error(Object message, Throwable t);
public void fatal(Object message, Throwable t);

log4j also provided more general logging API that supports localization:

l7dlog(Priority priority, java.lang.String key, java.lang.Throwable t);
l7dlog(Priority priority, java.lang.String key, java.lang.Object[] params, java.lang.Throwable t);

We will discuss the use of log levels and localization of log messages in a subsequent section.

Log Levels

FATAL - rarely used, usually imply imminent crash of the application or the relevant sub-component

ERROR - used for logging a Java exception or an error condition

WARN - indicate minor problems or potential errors.

INFO - provide information about significant events in the normal life cycle of the application

DEBUG - provides information useful for debugging purpose, such as values of some variables or some trace information.

Externalize Log Messages

All messages, with the exception of debug statements, have to be externalized to allow for translation. Debug statements are usually used for during development and not printed at production. That's why debug statement don't need to be translated.

All messages to be translated are declared in a properties file (resource bundle). The resource bundle can be accessed with a fully qualifed package name. For example, message resource bundle of the example MDR and its translations can be placed under org/eclipse/cosmos/example/mdr.

org/eclipse/cosmos/example/mdr/messages.properties
org/eclipse/cosmos/example/mdr/messages_fr.properties 
org/eclipse/cosmos/example/mdr/messages_ja.properties
org/eclipse/cosmos/example/mdr/messages_zh_TW.properties

The bundle is accessed using "org.eclipse.cosmos.example.mdr.messages".

There are several ways to use the resource bundle together with the log4j logging API.

Using the l7dlog API

l7d stands for "localized". (There are 7 letters between 'l' and 'd'.)

Set the resource bundle in the logger immediately after you get the reference of the logger.

logger = Logger.getLogger(getClass());
logger.setResourceBundle(ResourceBundle.getBundle("org.eclipse.cosmos.example.mdr.messages"));

The 2nd line above will instruct the logger to a bundle with the default locale (the locale of the web server). The assumption is that log records should logged in the language of the web server, but not the locale of the client. Once logged into the log file, the message cannot be translated to another language.

(For error messages that are displayed in the user interface, however, will need to be displayed in the locale of the client. The method to provide error message in the SOAP fault is still an open issue under investigation.)

Define messages in messages.properties:

STARTUP_INFO=COSMOS broker is starting up.
REG_FAILED_ERR=Registration of data manager {0} failed.

Note that the curly bracket with a number in it is for substituting values into the message. You can use {1}, {2}, etc, for subsequent values to be substituted.

Call l7dlog as follows:

logger.l7dlog(Level.INFO, "STARTUP_INFO", null);
logger.l7dlog(Level.ERROR, "REG_FAILED_ERR", new Object[] {"Example MDR"}, exception));

The exeption parameter can be null.

Handling Resource Bundle using java.util

You can use log4j's convevient APIs that correspond to the different message levels, and use the ResourceBundle and MessageFormat classes from java.util to retrieve and format strings from the resource bundle.

ResourceBundle bundle = ResourceBundle.getBundle("org.eclipse.cosmos.example.mdr.messages");
logger.info(bundle.getString(STARTUP_INFO));
String message = MessageFormat.format(bundle.getString("REG_FAILED_ERR"), new Object[] {"Example MDR"});
logger.error(message, exception); 

Eclipse Externalize Strings Wizard

Eclipse comes with tooling to externalize strings in Java source code. A resource bundle properties file will be generated along with a Java class that contain convenience methods to retrieve and format strings. The Java helper class that is generated has two flavors. If the class org.eclipse.osgi.util.NLS is in the classpath, the user has the choice of using the "Eclipse string externalization mechanism" or the standard Java approach in the generated code. The NLS class is in the org.eclipse.osgi plugin. The Eclipse approach claims to have better performance and less memory footprint. However, the org.eclipse.osgi jar file is not in the web application and web services, unless it's packaged for this purpose. So it's not mandatory to use the "Eclipse string externalization mechanism" in the web environment. The Eclipse string externalization wizard will still be useful for generating the properties file and the help class.

Side note: String externalization in Eclipse plugins should always use the Eclipse string externalization mechanism.

Please see these links for reference on Eclipse string externalization mechanism:

[1] http://help.eclipse.org/help33/index.jsp?topic=/org.eclipse.jdt.doc.user/reference/ref-wizard-externalize-strings.htm
[2] http://dev.eclipse.org/viewcvs/index.cgi/platform-core-home/documents/3.1/message_bundles.html?view=co

A Note About String Substitution in Message Strings

DO NOT concatenate fragments of a sentence and variables with '+' operator because it will make translation impossible. The variable may be placed in a different part of the sentence in another language. That is, do not do the following...

Message file:

MSG_PART1=Registration of data manager
MSG_PART2=failed.

Your code:

logger.info(Messages.getString(MSG_PART1) + dataManagerName + Messages.getString(MSG_PART2);

You have to use MessageFormat class or the Eclipse string externalization mechanism (i.e. NLS.bind()) to substitute values in the string. For the above example, using MessageFormat, that would be done like this...

Message file:

REGISTRATION_FAILED=Registration of data manager {0} failed.

Your code:

logger.info(MessageFormat.format(Messages.getString("REGISTRATION_FAILED"), new Object[] {dataManagerName});

Naming Convention for Message Keys

Since log messages can be translated, we need a unique identifier for each message so the support team can tell easily what the messages are. This section describes a tool and a process for assigning unique message identifiers to log messages.

The message identifier is a string that starts with 3 letters and a 4 numerical digits, followed by a letter. The first 3 letters are used to indicate which product or subcomponent that generated the error. The number is a unique number assigned to the log message. The last letter indicate the type of message - error(E), warning(W) and info(I). For example, if we use CMS to denote COSMOS, a message ID can be CMS0123E.

The FATAL log level in log4j is considered ERROR.

The message ID assignment is based on the message keys in the In properties files, the keys for messsages need to follow a naming convention. The keys need to contain a substring to indicate the message type.

Error: _ERR
Warning: _WARN
Info: _INFO

For example:

REGISTRATION_ERR=Data manager registration failed.
DM_EXISTS_WARN=The data manager to be register is already registered at the broker.
INFO=COSMOS broker is started.  EPR is {0}.  

We will have a program that can scan through all properties files in COSMOS, and assign a message ID to a message if the message key follows the above convention and does not already have a message ID assigned. For messages that already have an message ID, the ID will not be changed.

For example, if you have the following in a properties file:

button_ok=OK
DM_EXISTS_WARN=The data manager to be register is already registered at the broker.
INFO=CMS0032I COSMOS broker is started.  EPR is {0}.  

After running the message ID assignment tool, the properties will become:

button_ok=OK
DM_EXISTS_WARN=CMS0057W The data manager to be register is already registered at the broker.
INFO=CMS0032I COSMOS broker is started.  EPR is {0}.  

The first property is not changed because its key does not indicate it is a log message. A new message ID is assigned to the second property because it is a warning message and it does not have a message ID. The third property is an INFO message, but since it already have an ID, it is left unchanged.

This tool can potentially be automated by the build or run weekly.

The code for this message ID assignment program is in COSMOS CVS. It can be run within eclipse. Location in CVS: org.eclipse.cosmos/releng/org.eclipse.cosmos.releng.msgid

Possible Extensions to Logging Capabilities

  1. Add/change appenders to log messages in a different format or to a different media. (e.g. logging web service)
  2. Provide UI to view log records from COSMOS UI.

Logging for Eclipse Plugins

To be completed...

Back to the top