Exo Logger

ExoLogger

This article details the logging framework in eXo. It is targeted at eXo developers. To learn how to configure logs see Logs Configuration.

1 Prerequisites

We need a unified, simple and fast way for logging application activities. The proposed framework is an evolution of the previous logging system that was done in order to improve the integration with the various runtimes in which exo products are executed. The evolution is backward compatible API wise which means that the code using exo logging does not require to be changed and recompiled.

2 Logging API versus logging engine

It is important to distinguish clearly between the logging API and the logging engine.

  • The logging API is what exo product use. Before kernel 2.1.2, it used to be based on Java Commons Logging's org.apache.commons.logging.Log interface. Now it is based on the org.exoplatform.services.logging.ExoLogger class, which implements the org.apache.commons.logging.Log for backward compatibility. The point about using a custom interface is to isolate the codebase from the underlying engine and it is possible to make the API evolve to add new features (such as message interpolation).
  • The logging engine is what takes logging messages at runtime and process them (process means, format them, route them, etc...). Previously it was based on Java Commons Logging and now it is based on SLF4J logging facade.

3 Changes since kernel 2.1.1

It is important to outline the major changes that were done for the end user.

  • package org.exoplatform.services.log (minus the class LogConfigurationInitializer) is moved to the exo.kernel.commons module in order to have it usable by all modules. Previously the exo.kernel.commons and exo.kernel.container did not have access to the logging framework
  • class org.exoplatform.services.log. LogConfigurationInitializer is moved to the exo.kernel.container module as it uses the container API for configuration.
  • org.exoplatform.services.log.ExoLogger implements the org.apache.commons.logging.Log interface for backward compatibility
  • new methods org.exoplatform.services.log.ExoLogger#getExoLogger(String name) and org.exoplatform.services.log.ExoLogger#getExoLogger(Class name) that have for return type ExoLogger.
This has several minor consequences for migration

  • Sometime compile dependencies of a module needs to be updated to depend on the exo.kernel.commons module that contains now the logging framework
  • The pom dependencies should be updated to depends on an SLF4J binding implementation scoped at test phase for unit tests
  • ExoLogger getLogger methods should be replaced by getExoLogger methods instead, note that this is a should and not a must

4 Logger framework

The Logger service consists of two main classes LogConfigurationInitializer and ExoLogger

org.exoplatform.services.log.LogConfigurationInitializer that reads init parameters and configures the logging system. Read more about Logs Configuration.

org.exoplatform.services.log.ExoLogger a class with two static methods to obtain a logger:

  • ExoLogger.getExoLogger(Class)
  • ExoLogger.geExotLogger(String)
How do I know which logging engine will be used ?
Previously, the LogConfigurationInitializer used to specify a logger parameter to configure the target logging engine. But now that SLF4F is used, the logger selection logic is different. SLF4J chooses the logging engine by looking into the classpath. It uses the notion of binding which are bundled in separate binding jars (simple,jdk,log4j). At runtime, only one binding jar is required in the classpath and SLF4J uses the corresponding engine to log.

What happens if no SLF4J binding jar exists in the classpath?
This situation can arise during the maven build of JCR where the JiBX class generation uses eXo code that requires himself a logger binding. In that case, the eXo logging framework will detect the absence of bindind and delegate logging to Java Commons Logging SimpleLog engine.

5 How to use

The framework uses by default the SLF4J library. Make sure you understand how to configure and use it. It is not really neccessary to know all its aspects, just configuration and usage should be enough. In case of using Log4J or JDK's logger familiarize yourself with their configuration parameters as well.

Now, as an eXo developper here is how you need to proceed :

  • Configure a logger you want to use :
see examples in Logs Configuration

  • Add a (preferably static to make it faster) Log attribute to your class :
private static ExoLogger log = ExoLogger.getExoLogger("jcr.YourCategory");

  • Use this log with desired logging level :
log.info("My message");

6 Configuration use cases

As described before SLF4J use the concept of binding at runtime for executing the correct logging framework. We have three major use case to distinguish:

  • Unit tests executed in maven: they must have one SLF4J binding dependency for the test scope. It is important to specify the test scope so it does not affect other project that would use the project as the binding will be used only for executing tests.
  • Server runtime such as eXo Portal in tomcat: in that situation the javascript assembly needs to add the correct binding to the product classpath.
  • Build time : JiBX class generation (done at build time) will usually use no SLF4J binding. As we don't want to create a compile dependency to the SLF4J bindings, we simply let the ExoLogger system delegate to the JCL's SimpleLog logger.

6.1 Unit test example

Usually modifying the parent pom of the project and adding the dependency is a good thing:

<dependency>
      <groupId>org.slf4j</groupId>
      <artifactId>slf4j-simple</artifactId>
      <version>1.5.6</version>
      <scope>test</scope>
    </dependency>

That declares a dependency to the "simple" binding of SLF4J which uses directly the console. It is just an example, choose whatever binding you want. For example, the JCR tests use log4j binding.

6.2 Server runtime example

In this example we show the Exo Build packaging changes for the portal deployed on Tomcat using the JDK binding.

Tomcat.prototype.preDeploy = function(product) {
  product.addDependencies(new Project("org.slf4j", "slf4j-api", "jar", "1.5.6")) ;
  product.addDependencies(new Project("org.slf4j", "slf4j-jdk14", "jar", "1.5.6")) ;
  ...
}

Indeed it is important to notice that the binding is done per server and that two different server integrations will use different bindings.

Tags:
Created by Julien Viet on 06/04/2009
Last modified by Julien Viet on 06/04/2009

Products

generated on Thu Sep 02 15:48:23 UTC 2010

eXo Optional Modules

eXo Core Foundations


Copyright (c) 2000-2010. All Rights Reserved - eXo platform SAS
2.4.30451