SLF4J is becoming complex by the day (Marker feature for instance) while JUL (java.util.logging) is becoming more powerful and better. It is easy to replace SLF4J from any existing codebase without having to change anything but internally it will use JUL. Let’s see how.

Create org/slf4j (org\slfj for windows users) directory under your source tree and place the following files:

Logger.java
// Licensed under Apache License version 2.0
package org.slf4j; // Mimicked slf4j package structure to avoid changing existing codebase or usage

import java.util.StringTokenizer;
import java.util.logging.Level;
import java.util.logging.Handler;
/** 
 * Replacement for slf4j Logger. Uses java.util.logging framework.
 */
public class Logger {
    private static java.util.logging.Logger logger;
    // DO NOT CHANGE
    public Logger(java.util.logging.Logger l) { logger = l; }
    
    // DO NOT CHANGE
    /**
     * Clean room implementation of slf4j delayed evaluation of Strings
     */
    public void log(Level level, String message, Object ... args) {
        if(logger.isLoggable(level)) {
            int aL = args.length;
            int index = 0;
            StringBuilder b = new StringBuilder();
            StringTokenizer st = new StringTokenizer(message, "{}");
            while(st.hasMoreTokens()) {
                if(index < aL) b.append(args[index++]);
                b.append(st.nextToken());                
            }
            logger.log(level, b.toString());
        }
    }
    
    // Add additional mapping methods below
    public void addHandler(Handler handler) { logger.addHandler(handler); }
    
    public boolean isInfoEnabled()  { return logger.isLoggable(Level.INFO); }
    public boolean isErrorEnabled() { return logger.isLoggable(Level.SEVERE); }
    public boolean isDebugEnabled() { return logger.isLoggable(Level.FINE);    }
    public boolean isTraceEnabled() { return logger.isLoggable(Level.FINEST); }
    
    public void  info(String message, Object ... args) { log(Level.INFO,    message, args);    }
    public void debug(String message, Object ... args) { log(Level.FINE,    message, args); }
    public void  warn(String message, Object ... args) { log(Level.WARNING, message, args); }
    public void error(String message, Object ... args) { log(Level.SEVERE,  message, args); }
    public void trace(String message, Object ... args) { log(Level.FINEST,  message, args); }
}
LoggerFactory.java
package org.slf4j;

import java.util.HashMap;
import java.util.Map;

/** Replacement for slf4j package */
public class LoggerFactory {
    private static final Map<String, Logger> loggers = new HashMap<String, Logger>();
    
    public static Logger getLogger(String name) {
        Logger l = loggers.get(name);
        if(l == null) {
            l = new Logger(java.util.logging.Logger.getLogger(name));
            loggers.put(name, l);
        }
        return l;
    }
}

The much vaunted capability of Slf4j – delayed evaluation of Strings substitutions has been implemented in the log() method. The String substitutions will be made only if required for output. It improves performance.

You can also pass Objects whose toString() method will be called only if required.

Logger implements most of the common methods used in Slf4j. If you need to add any method, follow the examples shown in Logger.java. It should be one line of code, calling log() or a method in logger. Marker feature has not been implemented. Does anyone use it!?