[slf4j-dev] Consolidating the LoggerFactory / A better plugin mechanism

Ceki Gülcü listid at qos.ch
Mon Feb 12 21:12:06 CET 2007


Eric,

Many thanks for your contribution. Given that you've gone to the trouble of 
providing an implementation, I'll attempt to solve this problem without 
using class loader tricks by moving LoggerFactory into slf4j-api and make 
it compile by using a "bootstrap" project. I'll let you know how it goes.


At 12:14 AM 2/10/2007, Eric Crahen wrote:
>I've been using the SLF4J API in some of my work and one thing about it 
>that makes it very awkward, from a dependency mangement standpoint, is 
>that one of the core APIs - the LoggerFactory - is actually not a part of 
>the slf4j-api package. Instead, its actually reimplemented in each of the 
>slf4j implementations. This is awkward for various reasons,
>
>1. The API is incomplete. I actually can't build anything against the API 
>since I really do require a LoggerFactory; I need to choose an arbitrary 
>implementation to build against.
>2. It complicates deployments in some situations where 
>compile-time-dependencies + run-time-dependencies because of #1.
>4. All of the LoggerFactory implementations are basically identical
>3. I have to hope everyone uses the same LoggerFactory signature.
>
>The nice part is, that with the mechanism SLF4J has, selecting a Logger 
>implementation ss purely a deployment issue. Just deploy the right jar and 
>the Logger you pick takes effect. That's very handy.
>
>I think that we can resolve the undesirable issues while still retaining 
>the behavior we have today. Here is my proposal:
>
>Create a single LoggerFactory and placed it into slf4j-api, and deleted 
>the LoggerFactory classes everywhere else they exist (slf4j-simple, 
>logback, etc). This new LoggerFactory leverages Sun's ServiceProvider API 
>which exists in all JDK's since 1.4 (maybe 1.3). It looks like this:
>
>package org.slf4j;
>
>import sun.misc.Service;
>import org.slf4j.impl.Util;
>import java.util.Iterator;
>
>/**
>  * This class is a simple wrapper over Sun's Service provider
>  * factory. It provides a standard mechanism for loading plugins
>  * in a simple way.
>  */
>public abstract class LoggerFactory {
>
>   private static final ILoggerFactory factory;
>
>   // Initialize the real ILoggerFactory
>   static {
>
>     ILoggerFactory f = null;
>     try {
>
>       // Use the current context ClassLoader to enumerate all the resources
>       // that define ILoggerFactory services.
>       for(Iterator i = Service.providers(ILoggerFactory.class); 
> i.hasNext(); ) {
>         Object o = i.next();
>         if(f == null)
>           f = (ILoggerFactory)o;
>         else
>           Util.reportWarning("More than once service provider was defined");
>       }
>
>     factory = f;
>     if(f == null) {
>       // TODO: Should there be a simple fall back on a System.out logger?
>       // TODO: Perhaps the simple loggers is included with SLF4J-API and
>       // TODO: Is selected always, unless another implementation is provided
>     }
>
>   }
>
>   public static Logger getLogger(Class name) {
>     return getLogger(name.getName());
>   }
>
>   public static Logger getLogger(String name) {
>     if(factory != null)
>       return factory.getLogger(name);
>     // TODO: Not a problem if the above suggestion is taken
>     throw new IllegalStateException("No " + ILoggerFactory.class + " 
> implementation was provided!");
>   }
>
>}
>
>The simple explanation of this is that all the magic happens in the 
>Service class. What it does, for those who are unfamilair, is that it uses 
>the context ClassLoader to locate a resource named services/<<fully 
>qualified Interface name>>. This resource can contain multiple lines of 
>text, each line should be the fully qualified class name of a concrete 
>implementation of the interface you asked for. This class should have a 
>default constructor.
>
>To give an example of this simple class can be used in place of what we 
>have now I'll walk through an example of how I refitted the slf4j-simple 
>package to utilize this,
>
>Step #1: Delete slf4j-simple/src/main/java/org/slf4j/LoggerFactory.java
>Step #2: Create 
>slf4j-simple/src/main/resources/META-INF/services/org.slf4j.ILoggerFactory
>Step #3: Add a line the the above resource file which reads 
>"org.slf4j.impl.SimpleLoggerFactory"
>
>This can be repeated for each SLF4J provider (implementation of the API).
>
>Benefits:
>
>* slf4j-api is now complete - this is *all* people need to build against 
>and depend on
>* This exact same approach can be used to resolve the similar issue it 
>looks like the MarkerFactory faces.
>* This preserves the existing behavior of deploy-what-you-want. Its still 
>0 config to select an implementation.
>
>
>Drawbacks:
>
>* Depends on sun.misc -- (resolvable)
>   Although this is an internal sun class, they actually do a good job of 
> maintaining it, and it exists in SE4, SE5 & SE6.
>   It's understandable to be nervous about depending on it. Maybe some 
> cleanroom implementations don't support it (blackdown?)
>
>   We could write a simpler version of the Service class which does the 
> same thing, its really not that much code and I could provide this if you 
> want.
>
>
>I would personally like to see such an enhancement to SLF4J, I don't know 
>about others. Any thoughts or comments?
>
>--
>
>- Eric
>
>_______________________________________________
>dev mailing list
>dev at slf4j.org
>http://www.slf4j.org/mailman/listinfo/dev

-- 
Ceki Gülcü
Logback: The reliable, generic, fast and flexible logging framework for Java.
http://logback.qos.ch




More information about the slf4j-dev mailing list