Updates to the Logging System page of Guide

http://www.jmonkeyengine.com/wiki/doku.php?id=logging_system



The rather important topic of runtime configuration was neglected.  I also cover integration with other logging frameworks.


Cool.

If it's of any use, I use this to bridge JUL to my logging library of choice: Log4j.


package net.jgf.core;

import java.util.logging.ErrorManager;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.LogManager;
import java.util.logging.LogRecord;

import org.apache.log4j.Logger;

/**
 * <p>JUL bridge/router for log4j. Since jMonkeyEngine uses JUL (Java Unified Logging), and JGF
 * uses log4j, this bridge is installed so logging statements sent to JUL are handled by
 * JGF logging system.</p>
 *
 * @author Christian Stein
 * @author jjmontes
 */
public class JULLoggingBridge extends Handler {


  protected final boolean classname;

  protected final boolean format;

  /**
   * Resets the entire JUL logging system and adds a single JulLoggingBridge handler.
   * instance to the root logger.
   */
  public static void install() {
    install(new JULLoggingBridge(true, true));
  }

  /**
   * Resets the entire JUL logging system and adds the JULLoggingBridge instance
   * to the root logger.
   */
  public static void install(JULLoggingBridge handler) {
    LogManager.getLogManager().reset();
    LogManager.getLogManager().getLogger("").addHandler(handler);
  }

  /**
   * Rereads the JUL configuration.
   */
  public static void uninstall() throws Exception {
    LogManager.getLogManager().readConfiguration();
  }

  /**
   * Initialize this handler.
   *
   * @param classname
   *            Use the source class name provided by the LogRecord to get
   *            the log4j Logger name. If <code>false</code>, the raw name
   *            of the JUL logger is used.
   * @param format
   *            If <code>true</code>, use the attached formatter if
   *            available. If <code>false</code> the formatter is ignored.
   */
  public JULLoggingBridge(boolean classname, boolean format) {
    this.classname = classname;
    this.format = format;
  }

  /**
   * No-op implementation.
   */
  @Override
  public void close() {
    // Empty
  }

  /**
   * No-op implementation.
   */
  @Override
  public void flush() {
    // Empty
  }

  /**
   * Return the Logger instance that will be used for logging.
   */
  protected Logger getPublisher(LogRecord record) {
    String name = null;
    if (classname) {
      if (name == null) {
        name = record.getSourceClassName();
      }
    }
    if (name == null) {
      name = record.getLoggerName();
    }
    if (name == null) {
      name = JULLoggingBridge.class.getName();
    }
    return Logger.getLogger(name);
  }

  /**
   * Returns {@code Level.ALL} as this cares about discarding log
   * statements.
   */
  @Override
  public final synchronized Level getLevel() {
    return Level.ALL;
  }

  /**
   * <p>Publish a LogRecord.</p>
   * <p>The logging request was made initially to a Logger object, which
   * initialized the LogRecord and forwarded it here.</p>
   * <p>This handler ignores the Level attached to the LogRecord, as this cares
   * about discarding log statements.</p>
   * @param record
   *            Description of the log event. A null record is silently
   *            ignored and is not published.
   */
  @Override
  public void publish(LogRecord record) {
    /*
     * Silently ignore null records.
     */
    if (record == null) {
      return;
    }
    /*
     * Get our logger for publishing the record.
     */
    Logger publisher = getPublisher(record);
    Throwable thrown = record.getThrown(); // can be null!
    String message = record.getMessage(); // can be null!
    if (format && getFormatter() != null) {
      try {
        message = getFormatter().format(record);
      }
      catch (Exception ex) {
        reportError(null, ex, ErrorManager.FORMAT_FAILURE);
        return;
      }
    }
    if (message == null) {
      return;
    }
    /*
     * TRACE
     */
    if (record.getLevel().intValue() <= Level.FINEST.intValue()) {
      publisher.trace(message, thrown);
      return;
    }
    /*
     * DEBUG
     */
    if (record.getLevel() == Level.FINER) {
      publisher.debug(message, thrown);
      return;
    }
    if (record.getLevel() == Level.FINE) {
      publisher.debug(message, thrown);
      return;
    }
    /*
     * INFO
     */
    if (record.getLevel() == Level.CONFIG) {
      publisher.info(message, thrown);
      return;
    }
    if (record.getLevel() == Level.INFO) {
      publisher.info(message, thrown);
      return;
    }
    /*
     * WARN
     */
    if (record.getLevel() == Level.WARNING) {
      publisher.warn(message);
      return;
    }
    /*
     * ERROR
     */
    if (record.getLevel().intValue() >= Level.SEVERE.intValue()) {
      publisher.error(message, thrown);
      return;
    }

    /*
     * Still here? Fallback and out.
     */
    publishFallback(record, publisher);
  }

  /**
   * <p>Called by publish if no level value matched.</p>
   * <p>This implementation uses log4j DEBUG level.</p>
   *
   * @param record
   *            to publish
   * @param publisher
   *            who logs out
   */
  protected void publishFallback(LogRecord record, Logger publisher) {
    publisher.debug(record.getMessage(), record.getThrown());
  }

}

jjmontes said:


Cool.

If it's of any use, I use this to bridge JUL to my logging library of choice: Log4j.
...


That's great.  I added a reference to the Guide page.