Logging in OSGI Enterprise Applications, Part 2

Part 2 shows you how to catch all log events logged by OSGI Bundles using “classic” Log-Frameworks instead of OSGI Log Services.

In Enterprise Applications following log frameworks are often in use:

My example is building a server containing Equinox + Eclipse Riena + EasyBeans / Hibernate. (Later in another blog I’ll talk in detail about this)

java.util.logging:

  • Java-internal Logging will be used from EasyBeans – Bundles. Java.util package needs no own bundle, but we have to handle how to catch those log events.


org.apache.commons.logging will be used by these bundles:

  • org.mortbay.jetty (without version)
  • org.apache.commons.httpclient (version 1.0.4 – 2.0.0)
  • org.ow2.easybeans.core (without version)
  • org.ow2.bundles.ow2-util-jmx-impl (without version)
  • org.ow2.easybeans.component.carol (without version)
  • org.ow2.easybeans.component.jotm (without version)
  • org.ow2.easybeans.component.quartz (without version)

org.apache.log4j will be used from:

  • org.eclipse.riena.core (without version)

org.slf4j is in use from:

  • org.ow2.easybeans.core (>= version 1.5.0) from contained Hibernate 3.4

Similar situations will be found in many enterprise applications. I’m using the API from SLF4J to bring it all together.

As implementation I’ve choosen LOGBack – I’ll explain the reasons later – this blog will only talk about technical things how to get the right bundles working to integrate it all.

Lets start from bottom – the LOGBack implementation of SLF4J API. At first (as „good“ OSGI citizens) we’ll search for LOGBack bundles in repositories und we’ll find the actual version in SpringSource Enterprise Bundle Repository 🙂

com.springsource.ch.qos.logback.core (version 0.9.9)

exports core packages (version 0.9.9)


com.springsource.ch.qos.logback.classic (version 0.9.9)

imports core packages (version 0.9.9) and org.slf4j api packages (version 1.5.0 – 2.0.0)
exports classic packages and org.slf4j.impl (version 1.5.0)

Remark: This blog only notes dependencies and exported packages important for logging requirements – If you look into the MANIFEST-MF, you’ll see all of them.

Now we need some SLF4J bundles – API and some bridges between SLF4J and „classic“ logging frameworks. Of course at first we’re looking into the repositories and will find SLF4J bundles at SpringSource – but only version 1.5.0. The actual version is 1.5.3 – so in this case we have to build the bundles by ourself and also enter a JIRA at SpringSource to ask for version 1.5.3.

Remark: its a good idea to look at the current 1.5.0 bundles at SpringSource to watch dependencies and exported packages to compare it later with your own solution.

After downloading SLF4J JARs (1.5.3) we unzip the archiv. Here’s an overview about all SLF4J JAR f we need from download:

  • slf4j-api-1.5.3.jar
  • jcl-over-slf4j-1.5.3.jar (already with OSGI compatible MANIFEST.MF)
  • jul-to-slf4j-1.5.3.jar
  • log4j-over-slf4j-1.5.3.jar

We build the bundles (Plug-Ins) this way:

New | Plug-In Development | Plug-In from existing JAR-archives:

Now select the external JAR file. We’ll start with the API: slf4j-api-1.5.3.jar

If you create bundles from „foreign“ JAR files its good practice to prefix the name with your own namespace. Also: please dont forget to set the version !

PDE opens then the MANIFEST.MF file. Please check / add:

  • Dependencies: Version correct ? (1.5.0 – 1.5.3) Because bundle com.springsource.ch.qos.logback.classic exports package org.slf4j.impl in version 1.5.0 we have to use the range from 1.5.0 to 1.5.3 !
  • Runtime | Exported Packages: Set the version property (1.5.3) and click Calculate Uses
  • Overview | Execution Environment set the environment value

Then your MANIFEST.MF should look like:

Manifest-Version: 1.0

Bundle-ManifestVersion: 2

Bundle-Name: SLF4J Api Plug-in

Bundle-SymbolicName: org.ekkehard.slf4j.api

Bundle-Version: 1.5.3

Bundle-ClassPath: slf4j-api-1.5.3.jar

Bundle-Vendor: org.ekkehard

Export-Package: org.slf4j;version=”1.5.3″;uses:=”org.slf4j.spi”,org.sl

f4j.helpers;version=”1.5.3″;uses:=”org.slf4j.spi,org.slf4j”,org.slf4j

.spi;version=”1.5.3″;uses:=”org.slf4j”

Import-Package: org.slf4j.impl;version=”[1.5.0,1.5.3)”

Bundle-RequiredExecutionEnvironment: J2SE-1.5

Now we can export our Plug-In project:

That’s easy – isn’t it ?

But please always follow the rule: “If there’s a bundle for your JAR already available in one of the repositiories then use this one“.

The we repeat our steps for

  • jul-to-slf4j-1.5.3.jar
  • log4j-over-slf4j-1.5.3.jar

and we’ll get following MANIFEST.MF files:

Manifest-Version: 1.0

Bundle-ManifestVersion: 2

Bundle-Name: JUL to Slf4j Plug-in

Bundle-SymbolicName: org.ekkehard.jul.to.slf4j

Bundle-Version: 1.5.3

Bundle-ClassPath: jul-to-slf4j-1.5.3.jar

Bundle-Vendor: org.ekkehard

Export-Package: org.slf4j.bridge;version=”1.5.3″;uses:=”org.slf4j.spi,org.slf4j”

Import-Package: org.slf4j;version=”1.5.3″,org.slf4j.spi;version=”1.5.3″

Bundle-RequiredExecutionEnvironment: J2SE-1.5

and

Manifest-Version: 1.0

Bundle-ManifestVersion: 2

Bundle-Name: Log4J over Slf4j Plug-in

Bundle-SymbolicName: org.ekkehard.log4j.over.slf4j

Bundle-Version: 1.5.3

Bundle-ClassPath: log4j-over-slf4j-1.5.3.jar

Bundle-Vendor: org.ekkehaerd

Export-Package: org.apache.log4j;version=”1.2.15″;uses:=”org.slf4j”

Import-Package: org.slf4j;version=”1.5.3″,

org.slf4j.spi;version=”1.5.3″

Bundle-RequiredExecutionEnvironment: J2SE-1.5

We can use the JAR File jcl-over-slf4j-1.5.3.jar directly as bundle (Plug-In) because the included MANIFEST.MF contains all relevant informations for use under OSGI:

Manifest-Version: 1.0

Archiver-Version: Plexus Archiver

Created-By: Apache Maven

Built-By: ceki

Build-Jdk: 1.5.0_06

Bundle-Description: JCL 1.1.1 implementation over SLF4J

Bundle-Version: 1.5.3

Implementation-Version: 1.5.3

Implementation-Title: jcl-over-slf4j

Bundle-ManifestVersion: 2

Bundle-SymbolicName: jcl.over.slf4j

Bundle-Name: jcl-over-slf4j

Bundle-Vendor: SLF4J.ORG

Bundle-RequiredExecutionEnvironment: J2SE-1.3

Export-Package: org.apache.commons.logging;version=1.1.1, org.apache.

commons.logging.impl;version=1.1.1

Import-Package: org.slf4j;version=1.5.3, org.slf4j.spi;version=1.5.3

The last part we’re missing is the configuration file to configure LOGBack – the logback.xml. Also for test purposes we’ll use the logback-test.xml. LOGBack always at first is looking for logback-test.xml and only if there’s none, the logback.xml will will be used.

Its a good idea to use the logback.xml for normal use and while testing and developing to use the logback-test.xml. We’ll show later how to switch easy between them.

Now we create two Fragment-Plug-In projects.

New | Plug-In Development | Fragment Project:

As HOST we have to choose Plug-In com.springsource.ch.qos.logback.core :

The Plug-In Fragment contains only one single file directly in the src folder:

src/logback.xml or src/logback-test.xml

Later we’ll talk about the content of these files.

Now we’re ready 🙂

We have all bundles we need to catch all log events from commons-logging, Log4J, SLF4J or java.util.logging, to configure all of them in one configuration file and to log all using a single backend – the LOGBack Implementation.

An overview of the bundles:

To catch loggers from java.util.logging , one of your bundles has to contain this code:

import org.slf4j.bridge.SLF4JBridgeHandler;

SLF4JBridgeHandler.install();

All bundles you were using in the past which are exporting packages from org.apache.log4j or org.apache.commons.logging or slf4j.org cannot be used anymore. Please remove them from your target platform or from OSGI Launch Configurations.

This was the second part of my blog series “Logging in OSGI Enterprise Applications“:

  • An overview
  • How to catch all log events from “classic” logging – frameworks
  • Part 3: … follows

Perhaps some of my older blogs about Logging und OSGI are also interesting:

the blog in german.

8 responses

  1. Hello Ekke

    First up, really great Blog series you made here!

    However I’m having some trouble with JUL logging and was wondering if you encountered the same issue.
    I installed everything as you described here except I’m using slf4j version 1.5.6 and got the bundles from springsource since there available now.

    My problem is that logback settings seem to be ignored by JUL. So if I have the following example:

    java.util.logging.Logger logger = java.util.logging.Logger.getLogger(“test”);
    logger.log(Level.FINEST, “finest”);
    logger.log(Level.FINER, “finer”);
    logger.log(Level.FINE, “fine”);
    logger.log(Level.INFO, “info”);

    Only the “info” will be logged. I found the following JavaDoc which is the root of the problem:
    http://www.slf4j.org/api/org/slf4j/bridge/SLF4JBridgeHandler.html#install()
    “This handler will redirect jul logging to SLF4J. However, only logs enabled in j.u.l. will be redirected. For example, if a log statement invoking a j.u.l. logger disabled that statement, by definition, will not reach any SLF4JBridgeHandler instance and cannot be redirected”

    Did you find a solution for this problem? Like a logging.properties which enables everything on trace level?

    Greets
    Flavio

  2. Hello Ekke

    As I mentioned I implemented your logging framework. As I did that I made only one fragment for the logback configuration (thought I’ll split it when I need it). My fragment contains both logback-test.xml and logback.xml.

    So now I thought I want to clean that up. Instead of creating a new fragment I did the following.

    build.properties:
    source..=src/
    bin.includes = META-INF/,\
    .,\
    OSGI-INF/l10n/bundle.properties
    bin.excludes=*test*

    So in my development environment, logback uses logback-test.xml and during the build process it is ignored and I end up with a fragment containing only the logback.xml.

    Just thought it may be of interest for you if you don’t like to have a lot of fragments with small content :-).

    BTW: I added “Eclipse-BundleShape: dir” to my MANIFEST.MF to build a directory instead of a jar, easier to change logging configuration in production state.

    cheers
    Flavio

    • Hi Flavio,
      fine that it works for you.
      I added some more things to my logging framework
      ..have to blog about this soon
      ekke

  3. Hi Ekke,
    Thanks for the great series of posts. One problem I had using bundles from logback (version 0.9.20), I tried to attach my fragment containing the logging config to the ch.qos.logback.core plugin and it could never find it. However I tried attaching it to ch.qos.logback.classic and it was picked up right away. Just an FYI to save any future frustration.

    -David

Leave a comment