Routing java.util.logging messages to Log4J

From Shrubbery

Jump to: navigation, search


Contents

[edit] 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.

[edit] 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
    }
}

[edit] 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:
 *   <!-- 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 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);
    }
}

[edit] 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>

[edit] See Also

Personal tools