Routing java.util.logging messages to Log4J

Overview

Here's a little Handler I made that routes java.util.logging messsages to Log4J. These are all available here:

This very nicely solves the Facelets 'loadImplicit' error issue as well as giving you the flexibility to enable more detailed logging for the JSF reference implementation.

The java.util.logging Handler Class

JuliToLog4jHandler.java

package org.yajul.log;

import org.apache.log4j.Priority;
import org.apache.log4j.Logger;

import java.text.MessageFormat;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.LogRecord;

/**
 * A JULI (java.util.logging) handler that redirects java.util.logging messages to Log4J
 * http://wiki.apache.org/myfaces/Trinidad_and_Common_Logging
 * <br>
 * User: josh
 * Date: Jun 4, 2008
 * Time: 3:31:21 PM
 */
public class JuliToLog4jHandler extends Handler {

    public void publish(LogRecord record) {
        org.apache.log4j.Logger log4j = getTargetLogger(record.getLoggerName());
        Priority priority = toLog4j(record.getLevel());
        log4j.log(priority, toLog4jMessage(record), record.getThrown());
    }

    static Logger getTargetLogger(String loggerName) {
        return Logger.getLogger(loggerName);
    }

    public static Logger getTargetLogger(Class clazz) {
        return getTargetLogger(clazz.getName());
    }
    
    private String toLog4jMessage(LogRecord record) {
        String message = record.getMessage();
        // Format message
        try {
            Object parameters[] = record.getParameters();
            if (parameters != null && parameters.length != 0) {
                // Check for the first few parameters ?
                if (message.indexOf("{0}") >= 0 ||
                        message.indexOf("{1}") >= 0 ||
                        message.indexOf("{2}") >= 0 ||
                        message.indexOf("{3}") >= 0) {
                    message = MessageFormat.format(message, parameters);
                }
            }
        }
        catch (Exception ex) {
            // ignore Exception
        }
        return message;
    }

    private org.apache.log4j.Level toLog4j(Level level) {//converts levels
        if (Level.SEVERE == level) {
            return org.apache.log4j.Level.ERROR;
        } else if (Level.WARNING == level) {
            return org.apache.log4j.Level.WARN;
        } else if (Level.INFO == level) {
            return org.apache.log4j.Level.INFO;
        } else if (Level.OFF == level) {
            return org.apache.log4j.Level.OFF;
        }
        return org.apache.log4j.Level.OFF;
    }

    @Override
    public void flush() {
        // nothing to do
    }

    @Override
    public void close() {
        // nothing to do
    }
}

JMX MBean Wrapper

Lifecycle.java

/**
 * Standard JMX MBean lifecycle methods.
 * <br>User: Joshua Davis
 * Date: Aug 29, 2007
 * Time: 5:58:12 AM
 */
public interface Lifecycle {

    /**
     * Called when an MBean is started
     *
     * @throws Exception if something went wrong.
     */
    void start() throws Exception;

    /**
     * Called when an MBean is stopped
     */
    void stop();
}

JuliToLog4jServiceMBean.java

package org.yajul.log;

import org.yajul.jmx.Lifecycle;

/**
 * JMX Interface for the Juli->Log4J MBean.
 * <br>
 * User: josh
 * Date: Jun 5, 2008
 * Time: 8:44:16 AM
 */
public interface JuliToLog4JServiceMBean extends Lifecycle {

    /**
     * @return The logging level of the java.util.logging->Log4J 'Handler' as a string
     */
    String getHandlerLevel();

    /**
     * Sets the logging level of the java.util.logging->Log4J 'Handler' to the specified value.
     * @param level the logging level for the adapter, e.g. "INFO"
     */
    void setHandlerLevel(String level);
}

JuliToLog4jService.java

package org.yajul.log;

import java.util.logging.Logger;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.LogManager;
import java.util.List;
import java.util.ArrayList;

/**
 * JMX MBean that plugs in the JULI->Log4j handler on start and unplugs it on stop.
 * Here is an example of a JBoss JMX MBean declaration:
 *   &lt;!-- Redirect java.util.logging to Log4J. -->
 *   &lt;mbean code="org.yajul.log.JuliToLog4JService"
 *           name="org.yajul:service=JuliToLog4J">
 *       &lt;attribute name="HandlerLevel">DEBUG&lt;/attribute>
 *       &lt;depends>jboss.system:type=Log4jService,service=Logging&lt;/depends>
 *   &lt;/mbean>
 * Note that because of a small glitch in the JMX specification, the attribute name
 * is 'HandlerLevel', and not 'handlerLevel' as you might expect.
 * See http://madplanet.com/jboss-docu-wiki/Wiki.jsp?page=40.JMX.MBean
 * <br>
 * User: josh
 * Date: Jun 4, 2008
 * Time: 3:41:44 PM
 */
public class JuliToLog4JService implements JuliToLog4JServiceMBean {
    private Handler activeHandler;
    private List<Handler> oldHandlers = new ArrayList<Handler>();
    private Level handlerLevel = Level.ALL;
    private Level rootLevel = Level.INFO;

    public void start() throws Exception {
        try {
            JuliToLog4jHandler.getTargetLogger(JuliToLog4JService.class).info(
                    "start(): Redirecting java.util.logging to Log4J...");
            Logger rootLogger = LogManager.getLogManager().getLogger("");
            // remove old handlers
            for (Handler handler : rootLogger.getHandlers()) {
                oldHandlers.add(handler);
                rootLogger.removeHandler(handler);
            }
            // add our own
            activeHandler = new JuliToLog4jHandler();
            activeHandler.setLevel(handlerLevel);
            rootLogger.addHandler(activeHandler);
            rootLogger.setLevel(rootLevel);
            // done, let's check it right away!!!

            Logger.getLogger(JuliToLog4JService.class.getName()).info("started: sending JDK log messages to Log4J");
        } catch (Exception exc) {
            JuliToLog4jHandler.getTargetLogger(JuliToLog4JService.class).error("start() failed", exc);
        }
    }

    public void stop() {
        Logger rootLogger = LogManager.getLogManager().getLogger("");
        rootLogger.removeHandler(activeHandler);
        // Put all the old handlers back.
        for (Handler oldHandler : oldHandlers) {
            rootLogger.addHandler(oldHandler);
        }
        Logger.getLogger(JuliToLog4jHandler.class.getName()).info("stopped");
    }

    public String getHandlerLevel() {
        return handlerLevel.getName();
    }

    public void setHandlerLevel(String level) {
        final String parseThis = level.toUpperCase();
        if ("DEBUG".equalsIgnoreCase(parseThis))
            handlerLevel = Level.FINE;
        else
            handlerLevel = Level.parse(parseThis);
    }
}

Adding it to JBoss AS

Once you have the classes in the classpath, just add the following to conf/jboss-service.xml right after the Log4JService declaration:

    <!-- Redirect java.util.logging to Log4J. -->
    <mbean code="org.yajul.log.JuliToLog4JService"
            name="org.yajul:service=JuliToLog4J">
        <attribute name="HandlerLevel">DEBUG</attribute>
        <depends>jboss.system:type=Log4jService,service=Logging</depends>
    </mbean>

NOTE: This is not needed in JBoss 5.x, it already has this feature.

See Also

Labels

yajul yajul Delete
java java Delete
Enter labels to add to this page:
Please wait 
Looking for a label? Just start typing.