How to use Pax Logging in my bundles
First of all, look at the example in pax/logging/example, which is complete with both Jakarta Commons Logging API, Log4J Logger API and usage of 3rd party library that depends on Jakarta Commons Logging, namely the Jetty HTTP server.
You need to;
- ensure that log4j.jar, commons-logging.jar, and any other legacy API that you want to use, are NOT included in your bundle jar.
- Import the logging APIs that are used in your client bundle. To ensure that your bundle's logging will get routed to Pax Logging Service, and not linked to another JCL or Log4J implementation (perhaps exported by a third-party bundle), you should specify the attribute provider=paxlogging (see below).
Manifest.MF
You will need to import the legacy API you want to use. For instance, importing the Log4J and Jakarta Commons Logging;
Import-Package: org.apache.log4j; version="[1.2,1.3)"; provider=paxlogging, org.apache.commons.logging; version="[1.0,1.1)"; provider=paxlogging
Setting up the OSGi application
The Pax Logging API bundle and each legacy API bundle from the Pax Logging project is needed to load before starting your client bundle. The Pax Logging Servicebundle can be loaded and reloaded at any point in time, and the fallback of Pax Logging is a simple output to the system console.
The java.util.logging API and Knopflerfish Log API are natively available and do not require any additional bundles to be loaded, only the API bundle and the service bundle.
Client code
The intent is that each user of these logging systems, just carry on and use them as normal. This is true for all but the Avalon Logging API, which is only an API which does not define the lookup, discovery or factory mechanism, and instead rely on the Inversion-of-Control pattern.
Log4J
public class MyPojo { private static final Logger logger = Logger.getLogger( MyPojo.class ); private void doSomething() { if( logger.isDebugEnabled() ) { logger.debug( "Doing something." ); } } }
Jakarta Commons Logging
public class MyPojo { private static final Log logger = LogFactory.getLog( MyPojo.class ); private void doSomething() { if( logger.isDebugEnabled() ) { logger.debug( "Doing something." ); } } }
SLF4J - Simple Logging Facade for Java
public class Zogotounga { private static final Logger logger = LogFactory.getLogger( Zogotounga.class ); private void treatment() { if( logger.isDebugEnabled() ) { logger.debug( "Zogotounga treatment in progress." ); } } }
Avalon Logging API
Avalon uses a totally different approach to logging, known as Inversion of Control (IoC) where the class is given the Logger from the user of the class, such as;
public class MyPojo1 { private MyPojo2 m_pojo2; public MyPojo1( Logger logger ) { if( logger.isDebugEnabled() ) { logger.debug( "Created MyPojo1." ); } Logger childLogger = logger.getChildLogger( "pojo2" ); pojo2 = new MyPojo2( childLogger ); } } public class MyPojo2 { public MyPojo2( Logger logger ) { if( logger.isDebugEnabled() ) { logger.debug( "Created MyPojo2." ); } } }
To obtain the RootLogger, or any other arbitrary Logger for that matter, you call the AvalonLogFactory, such as;
import org.apache.avalon.framework.logger.Logger; import org.ops4j.pax.logging.avalon.AvalonLogFactory; public class MyController { public MyController() { Logger root = AvalonLogFactory.getLogger( "" ); Logger pojo1Logger = root.getChildLogger( "pojo1" ); MyPojo1 pojo1 = new MyPojo1( logger ); } } // or something like; public class MyStuff { private static final Logger m_logger = AvalonLogFactory.getLogger( MyStuff.class.getName() ); public MyStuff() { if( m_logger.isDebugEnabled() ) { m_logger.debug( "MyStuff was created on " + new Date() ); } } }
JDK Logging a.k.a. java.util.logging
For JDK Logging you just use it as normal, without any extra considerations. Example;import java.util.logging.Logger;
public class PloukPlouk { private static final Logger m_logger = Logger.getLogger( PloukPlouk.class.getName() ); public PloukPlouk() { if( m_logger.isDebugEnabled() ) { m_logger.debug( "Death by Zogotounga on " + new Date() ); } } }
In the case of JDK Logging there is a mapping occuring between the Levels in JDK Logging and in Log4J. The definition chosen is as follows;
JDK Logging Level |
Log4J Level |
Comment |
OFF |
OFF |
|
WARNING |
WARN |
|
SEVERE |
ERROR |
|
INFO |
INFO |
|
FINE |
DEBUG |
|
FINER |
TRACE |
|
FINEST |
TRACE |
|
CONFIG |
n/a |
CONFIG events are ignored. |
n/a |
FATAL |
No such thing in JDK Logging. |
Knopflerfish Log
The Knopflerfish community has a lot of good bundles, that all uses the KF Log service and its bundle. Pax Logging implements the same interface and is a drop-in replacement of KF Log. No configuration or other changes are required.
To use Knopflerfish Log interface you do;
import org.knopflerfish.service.log.LogRef; : : private LogRef m_logger; public void start( BundleContext context ) throws Exception { m_logger = new LogRef( context ); if( m_logger.doDebug() ) { m_logger.debug( "some debug statement" ); } }
Pax Logging native
You could also use the Pax Logging Service directly, without bothering about any of the other APIs. You need to look up the PaxLoggingService, and ask it for a PaxLogger. Note: The plan is to include a simple factory for using the native Pax Logging API, similar to Log4J and JCL.
private PaxLogger m_logger; public void start( BundleContext context ) throws Exception { ServiceReference ref = context.getServiceReference( PaxLoggingService.class.getName() ); PaxLoggingService service = (PaxLoggingService) context.getService( ref ); m_logger = service.getLogger( MyActivator.class.getName() ); m_logger.info( "MyActivator is started." ); }