[jboss-svn-commits] JBoss Common SVN: r3047 - jboss-logmanager/trunk/src/main/java/org/jboss/logmanager.

jboss-svn-commits at lists.jboss.org jboss-svn-commits at lists.jboss.org
Mon Mar 9 17:46:50 EDT 2009


Author: david.lloyd at jboss.com
Date: 2009-03-09 17:46:49 -0400 (Mon, 09 Mar 2009)
New Revision: 3047

Modified:
   jboss-logmanager/trunk/src/main/java/org/jboss/logmanager/ExtLogRecord.java
   jboss-logmanager/trunk/src/main/java/org/jboss/logmanager/LogContext.java
   jboss-logmanager/trunk/src/main/java/org/jboss/logmanager/LoggerInstance.java
   jboss-logmanager/trunk/src/main/java/org/jboss/logmanager/LoggerNode.java
Log:
Lock-free handlers; (mostly) lock-free log methods; fix a couple bugs...

Modified: jboss-logmanager/trunk/src/main/java/org/jboss/logmanager/ExtLogRecord.java
===================================================================
--- jboss-logmanager/trunk/src/main/java/org/jboss/logmanager/ExtLogRecord.java	2009-03-09 15:36:51 UTC (rev 3046)
+++ jboss-logmanager/trunk/src/main/java/org/jboss/logmanager/ExtLogRecord.java	2009-03-09 21:46:49 UTC (rev 3047)
@@ -43,6 +43,7 @@
      */
     public ExtLogRecord(java.util.logging.Level level, String msg) {
         super(level, msg);
+        setSourceClassName(null);
         ndc = NDC.get();
     }
 

Modified: jboss-logmanager/trunk/src/main/java/org/jboss/logmanager/LogContext.java
===================================================================
--- jboss-logmanager/trunk/src/main/java/org/jboss/logmanager/LogContext.java	2009-03-09 15:36:51 UTC (rev 3046)
+++ jboss-logmanager/trunk/src/main/java/org/jboss/logmanager/LogContext.java	2009-03-09 21:46:49 UTC (rev 3047)
@@ -34,14 +34,15 @@
  */
 public final class LogContext {
     private static final LogContext SYSTEM_CONTEXT = new LogContext();
-    private static final Permission CREATE_CONTEXT_PERMISSION = new RuntimePermission("createLogContext", null);
-    private static final Permission SET_CONTEXT_SELECTOR_PERMISSION = new RuntimePermission("setLogContextSelector", null);
-    private static final Permission CONTROL_PERMISSION = new LoggingPermission("control", null);
 
+    static final Permission CREATE_CONTEXT_PERMISSION = new RuntimePermission("createLogContext", null);
+    static final Permission SET_CONTEXT_SELECTOR_PERMISSION = new RuntimePermission("setLogContextSelector", null);
+    static final Permission CONTROL_PERMISSION = new LoggingPermission("control", null);
+
     @SuppressWarnings({ "ThisEscapedInObjectConstruction" })
     private final LoggerNode rootLogger = new LoggerNode(this);
 
-    final Lock levelTreeLock = new ReentrantLock(false);
+    final Lock treeLock = new ReentrantLock(false);
 
     LogContext() {
     }
@@ -109,7 +110,7 @@
         logContextSelector = newSelector;
     }
 
-    void checkAccess() {
+    static void checkAccess() {
         final SecurityManager sm = System.getSecurityManager();
         if (sm != null) {
             sm.checkPermission(CONTROL_PERMISSION);

Modified: jboss-logmanager/trunk/src/main/java/org/jboss/logmanager/LoggerInstance.java
===================================================================
--- jboss-logmanager/trunk/src/main/java/org/jboss/logmanager/LoggerInstance.java	2009-03-09 15:36:51 UTC (rev 3046)
+++ jboss-logmanager/trunk/src/main/java/org/jboss/logmanager/LoggerInstance.java	2009-03-09 21:46:49 UTC (rev 3047)
@@ -22,6 +22,9 @@
 
 package org.jboss.logmanager;
 
+import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
+import java.util.concurrent.locks.Lock;
+
 import java.util.logging.Filter;
 import java.util.logging.Handler;
 import java.util.logging.Level;
@@ -31,7 +34,7 @@
 /**
  * An actual logger instance.  This is the end-user interface into the logging system.
  */
-public final class LoggerInstance extends Logger {
+public class LoggerInstance extends Logger {
 
     /**
      * The named logger tree node.
@@ -39,6 +42,33 @@
     private final LoggerNode loggerNode;
 
     /**
+     * The handlers for this logger.  May only be updated using the {@link #handlersUpdater} atomic updater.  The array
+     * instance should not be modified (treat as immutable).
+     */
+    @SuppressWarnings({ "UnusedDeclaration" })
+    private volatile Handler[] handlers;
+
+    /**
+     * Flag to specify whether parent handlers are used.
+     */
+    private volatile boolean useParentHandlers = true;
+
+    /**
+     * The filter for this logger instance.
+     */
+    private volatile Filter filter;
+
+    /**
+     * The atomic updater for the {@link #handlers} field.
+     */
+    private static final AtomicReferenceFieldUpdater<LoggerInstance, Handler[]> handlersUpdater = AtomicReferenceFieldUpdater.newUpdater(LoggerInstance.class, Handler[].class, "handlers");
+
+    /**
+     * The empty handler list.
+     */
+    private static final Handler[] EMPTY_HANDLERS = new Handler[0];
+
+    /**
      * Construct a new instance of an actual logger.
      *
      * @param loggerNode the node in the named logger tree
@@ -47,22 +77,22 @@
     LoggerInstance(final LoggerNode loggerNode, final String name) {
         // Logger.getLogger(*) will set up the resource bundle for us, how kind
         super(name, null);
-        // We maintain our own "level"
+        // We maintain our own level
         super.setLevel(Level.ALL);
         this.loggerNode = loggerNode;
-        setLevel(null);
     }
 
     // Filter mgmt
 
     /** {@inheritDoc} */
-    public void setFilter(Filter newFilter) throws SecurityException {
-        super.setFilter(newFilter);
+    public void setFilter(Filter filter) throws SecurityException {
+        LogContext.checkAccess();
+        this.filter = filter;
     }
 
     /** {@inheritDoc} */
     public Filter getFilter() {
-        return super.getFilter();
+        return filter;
     }
 
     // Level mgmt
@@ -76,7 +106,7 @@
      * The effective level.  May only be modified when the logmanager's level change lock is held; in addition, changing
      * this field must be followed immediately by recursively updating the effective loglevel of the child tree.
      */
-    private volatile int effectiveLevel = Level.INFO.intValue();
+    private volatile int effectiveLevel = INFO_INT;
 
     /**
      * {@inheritDoc}  This implementation grabs a lock, so that only one thread may update the log level of any
@@ -85,27 +115,32 @@
      */
     public void setLevel(Level newLevel) throws SecurityException {
         final LogContext context = loggerNode.getContext();
-        context.checkAccess();
-        context.levelTreeLock.lock();
+        LogContext.checkAccess();
+        final Lock lock = context.treeLock;
+        lock.lock();
         try {
-            final Level oldLevel = level;
-            level = newLevel;
+            final int oldEffectiveLevel = effectiveLevel;
+            final int newEffectiveLevel;
             if (newLevel != null) {
-                effectiveLevel = newLevel.intValue();
+                level = newLevel;
+                newEffectiveLevel = newLevel.intValue();
             } else {
                 final LoggerInstance parent = (LoggerInstance) getParent();
                 if (parent == null) {
-                    effectiveLevel = Level.INFO.intValue();
+                    level = Level.INFO;
+                    newEffectiveLevel = INFO_INT;
                 } else {
-                    effectiveLevel = parent.effectiveLevel;
+                    level = null;
+                    newEffectiveLevel = parent.effectiveLevel;
                 }
             }
-            if (oldLevel != newLevel) {
+            effectiveLevel = newEffectiveLevel;
+            if (oldEffectiveLevel != newEffectiveLevel) {
                 // our level changed, recurse down to children
-                loggerNode.updateChildEffectiveLevel(effectiveLevel);
+                loggerNode.updateChildEffectiveLevel(newEffectiveLevel);
             }
         } finally {
-            context.levelTreeLock.unlock();
+            lock.unlock();
         }
     }
 
@@ -129,42 +164,84 @@
 
     /** {@inheritDoc} */
     public boolean isLoggable(Level level) {
-        if (true) return true;
         final int effectiveLevel = this.effectiveLevel;
-        return effectiveLevel <= level.intValue() && effectiveLevel != Level.OFF.intValue();
+        return level.intValue() >= effectiveLevel && effectiveLevel != OFF_INT;
     }
 
     // Handler mgmt
 
     /** {@inheritDoc} */
     public void addHandler(Handler handler) throws SecurityException {
-        super.addHandler(handler);
+        boolean ok;
+        do {
+            final Handler[] oldHandlers = handlers;
+            final Handler[] newHandlers;
+            if (oldHandlers != null) {
+                final int len = oldHandlers.length;
+                newHandlers = new Handler[len + 1];
+                System.arraycopy(oldHandlers, 0, newHandlers, 0, len);
+            } else {
+                newHandlers = new Handler[] { handler };
+            }
+            ok = handlersUpdater.compareAndSet(this, oldHandlers, newHandlers);
+        } while (! ok);
     }
 
     /** {@inheritDoc} */
     public void removeHandler(Handler handler) throws SecurityException {
-        super.removeHandler(handler);
+        boolean ok;
+        do {
+            final Handler[] oldHandlers = handlers;
+            final Handler[] newHandlers;
+            final int len = oldHandlers.length;
+            if (len == 0) {
+                return;
+            } else if (len == 1) {
+                if (oldHandlers[0] == handler) {
+                    newHandlers = null;
+                } else {
+                    return;
+                }
+            } else {
+                boolean found = false;
+                newHandlers = new Handler[len - 1];
+                for (int i = 0, j = 0; i < oldHandlers.length; i++) {
+                    Handler oldHandler = oldHandlers[i];
+                    if (handler != oldHandler) {
+                        newHandlers[j++] = oldHandler;
+                    } else {
+                        found = true;
+                    }
+                }
+                if (! found) {
+                    return;
+                }
+                System.arraycopy(oldHandlers, 0, newHandlers, 0, len);
+            }
+            ok = handlersUpdater.compareAndSet(this, oldHandlers, newHandlers);
+        } while (! ok);
     }
 
     /** {@inheritDoc} */
     public Handler[] getHandlers() {
-        return super.getHandlers();
+        final Handler[] handlers = this.handlers;
+        return handlers == null ? EMPTY_HANDLERS : handlers.clone();
     }
 
     /** {@inheritDoc} */
-    public synchronized void setUseParentHandlers(boolean useParentHandlers) {
-        super.setUseParentHandlers(useParentHandlers);
+    public void setUseParentHandlers(boolean useParentHandlers) {
+        this.useParentHandlers = useParentHandlers;
     }
 
     /** {@inheritDoc} */
-    public synchronized boolean getUseParentHandlers() {
-        return super.getUseParentHandlers();
+    public boolean getUseParentHandlers() {
+        return useParentHandlers;
     }
 
     // Parent/child
 
     /** {@inheritDoc} */
-    public Logger getParent() {
+    public LoggerInstance getParent() {
         return loggerNode.getParentLogger();
     }
 
@@ -178,20 +255,313 @@
 
     // Logger
 
-    /** {@inheritDoc} */
-    public void log(LogRecord record) {
-        // defeat inferring class name
-        record.setSourceClassName(null);
+    /**
+     * Do the logging with no level checks (they've already been done).
+     *
+     * @param record the log record
+     */
+    private void doLog(final LogRecord record) {
+        // todo - resource bundle
+        record.setLoggerName(getName());
+        final Filter filter = this.filter;
         try {
-            super.log(record);
+            if (filter != null && ! filter.isLoggable(record)) {
+                return;
+            }
         } catch (VirtualMachineError e) {
-            // VM errors should be sent back, but otherwise...
             throw e;
         } catch (Throwable t) {
-            // ignore problems
+            // todo - error handler
+            // treat an errored filter as "pass" (I guess?)
         }
+        for (LoggerInstance current = this; current != null; current = current.getParent()) {
+            final Handler[] handlers = current.handlers;
+            if (handlers != null) {
+                for (Handler handler : handlers) try {
+                    handler.publish(record);
+                } catch (VirtualMachineError e) {
+                    throw e;
+                } catch (Throwable t) {
+                    // todo - error handler
+                }
+            }
+            if (! current.useParentHandlers) {
+                break;
+            }
+        }
     }
 
+    private static final int OFF_INT = Level.OFF.intValue();
+    private static final int SEVERE_INT = Level.SEVERE.intValue();
+    private static final int WARNING_INT = Level.WARNING.intValue();
+    private static final int INFO_INT = Level.INFO.intValue();
+    private static final int CONFIG_INT = Level.CONFIG.intValue();
+    private static final int FINE_INT = Level.FINE.intValue();
+    private static final int FINER_INT = Level.FINER.intValue();
+    private static final int FINEST_INT = Level.FINEST.intValue();
+
+    /** {@inheritDoc} */
+    public void log(LogRecord record) {
+        final int effectiveLevel = this.effectiveLevel;
+        if (record.getLevel().intValue() < effectiveLevel || effectiveLevel == OFF_INT) {
+            return;
+        }
+        doLog(record);
+    }
+
+    public void entering(final String sourceClass, final String sourceMethod) {
+        if (FINER_INT < effectiveLevel) {
+            return;
+        }
+        final ExtLogRecord rec = new ExtLogRecord(Level.FINER, "ENTRY");
+        rec.setSourceClassName(sourceClass);
+        rec.setSourceMethodName(sourceMethod);
+        doLog(rec);
+    }
+
+    public void entering(final String sourceClass, final String sourceMethod, final Object param1) {
+        if (FINER_INT < effectiveLevel) {
+            return;
+        }
+        final ExtLogRecord rec = new ExtLogRecord(Level.FINER, "ENTRY {0}");
+        rec.setSourceClassName(sourceClass);
+        rec.setSourceMethodName(sourceMethod);
+        rec.setParameters(new Object[] { param1 });
+        doLog(rec);
+    }
+
+    public void entering(final String sourceClass, final String sourceMethod, final Object[] params) {
+        if (FINER_INT < effectiveLevel) {
+            return;
+        }
+        final StringBuilder builder = new StringBuilder("ENTRY");
+        for (int i = 0; i < params.length; i++) {
+            builder.append(" {").append(i).append('}');
+        }
+        final ExtLogRecord rec = new ExtLogRecord(Level.FINER, builder.toString());
+        rec.setSourceClassName(sourceClass);
+        rec.setSourceMethodName(sourceMethod);
+        if (params != null) rec.setParameters(params);
+        doLog(rec);
+    }
+
+    public void exiting(final String sourceClass, final String sourceMethod) {
+        if (FINER_INT < effectiveLevel) {
+            return;
+        }
+        final ExtLogRecord rec = new ExtLogRecord(Level.FINER, "RETURN");
+        rec.setSourceClassName(sourceClass);
+        rec.setSourceMethodName(sourceMethod);
+        doLog(rec);
+    }
+
+    public void exiting(final String sourceClass, final String sourceMethod, final Object result) {
+        if (FINER_INT < effectiveLevel) {
+            return;
+        }
+        final ExtLogRecord rec = new ExtLogRecord(Level.FINER, "RETURN {0}");
+        rec.setSourceClassName(sourceClass);
+        rec.setSourceMethodName(sourceMethod);
+        rec.setParameters(new Object[] { result });
+        doLog(rec);
+    }
+
+    public void throwing(final String sourceClass, final String sourceMethod, final Throwable thrown) {
+        if (FINER_INT < effectiveLevel) {
+            return;
+        }
+        final ExtLogRecord rec = new ExtLogRecord(Level.FINER, "THROW");
+        rec.setSourceClassName(sourceClass);
+        rec.setSourceMethodName(sourceMethod);
+        rec.setThrown(thrown);
+        doLog(rec);
+    }
+
+    public void severe(final String msg) {
+        if (SEVERE_INT < effectiveLevel) {
+            return;
+        }
+        doLog(new ExtLogRecord(Level.SEVERE, msg));
+    }
+
+    public void warning(final String msg) {
+        if (WARNING_INT < effectiveLevel) {
+            return;
+        }
+        doLog(new ExtLogRecord(Level.WARNING, msg));
+    }
+
+    public void info(final String msg) {
+        if (INFO_INT < effectiveLevel) {
+            return;
+        }
+        doLog(new ExtLogRecord(Level.INFO, msg));
+    }
+
+    public void config(final String msg) {
+        if (CONFIG_INT < effectiveLevel) {
+            return;
+        }
+        doLog(new ExtLogRecord(Level.CONFIG, msg));
+    }
+
+    public void fine(final String msg) {
+        if (FINE_INT < effectiveLevel) {
+            return;
+        }
+        doLog(new ExtLogRecord(Level.FINE, msg));
+    }
+
+    public void finer(final String msg) {
+        if (FINER_INT < effectiveLevel) {
+            return;
+        }
+        doLog(new ExtLogRecord(Level.FINER, msg));
+    }
+
+    public void finest(final String msg) {
+        if (FINEST_INT < effectiveLevel) {
+            return;
+        }
+        doLog(new ExtLogRecord(Level.FINEST, msg));
+    }
+
+    public void log(final Level level, final String msg) {
+        final int effectiveLevel = this.effectiveLevel;
+        if (level.intValue() < effectiveLevel || effectiveLevel == OFF_INT) {
+            return;
+        }
+        doLog(new ExtLogRecord(level, msg));
+    }
+
+    public void log(final Level level, final String msg, final Object param1) {
+        final int effectiveLevel = this.effectiveLevel;
+        if (level.intValue() < effectiveLevel || effectiveLevel == OFF_INT) {
+            return;
+        }
+        final ExtLogRecord rec = new ExtLogRecord(level, msg);
+        rec.setParameters(new Object[] { param1 });
+        doLog(rec);
+    }
+
+    public void log(final Level level, final String msg, final Object[] params) {
+        final int effectiveLevel = this.effectiveLevel;
+        if (level.intValue() < effectiveLevel || effectiveLevel == OFF_INT) {
+            return;
+        }
+        final ExtLogRecord rec = new ExtLogRecord(level, msg);
+        if (params != null) rec.setParameters(params);
+        doLog(rec);
+    }
+
+    public void log(final Level level, final String msg, final Throwable thrown) {
+        final int effectiveLevel = this.effectiveLevel;
+        if (level.intValue() < effectiveLevel || effectiveLevel == OFF_INT) {
+            return;
+        }
+        final ExtLogRecord rec = new ExtLogRecord(level, msg);
+        rec.setThrown(thrown);
+        doLog(rec);
+    }
+
+    public void logp(final Level level, final String sourceClass, final String sourceMethod, final String msg) {
+        final int effectiveLevel = this.effectiveLevel;
+        if (level.intValue() < effectiveLevel || effectiveLevel == OFF_INT) {
+            return;
+        }
+        final ExtLogRecord rec = new ExtLogRecord(level, msg);
+        rec.setSourceClassName(sourceClass);
+        rec.setSourceMethodName(sourceMethod);
+        doLog(rec);
+    }
+
+    public void logp(final Level level, final String sourceClass, final String sourceMethod, final String msg, final Object param1) {
+        final int effectiveLevel = this.effectiveLevel;
+        if (level.intValue() < effectiveLevel || effectiveLevel == OFF_INT) {
+            return;
+        }
+        final ExtLogRecord rec = new ExtLogRecord(level, msg);
+        rec.setSourceClassName(sourceClass);
+        rec.setSourceMethodName(sourceMethod);
+        rec.setParameters(new Object[] { param1 });
+        doLog(rec);
+    }
+
+    public void logp(final Level level, final String sourceClass, final String sourceMethod, final String msg, final Object[] params) {
+        final int effectiveLevel = this.effectiveLevel;
+        if (level.intValue() < effectiveLevel || effectiveLevel == OFF_INT) {
+            return;
+        }
+        final ExtLogRecord rec = new ExtLogRecord(level, msg);
+        rec.setSourceClassName(sourceClass);
+        rec.setSourceMethodName(sourceMethod);
+        if (params != null) rec.setParameters(params);
+        doLog(rec);
+    }
+
+    public void logp(final Level level, final String sourceClass, final String sourceMethod, final String msg, final Throwable thrown) {
+        final int effectiveLevel = this.effectiveLevel;
+        if (level.intValue() < effectiveLevel || effectiveLevel == OFF_INT) {
+            return;
+        }
+        final ExtLogRecord rec = new ExtLogRecord(level, msg);
+        rec.setSourceClassName(sourceClass);
+        rec.setSourceMethodName(sourceMethod);
+        rec.setThrown(thrown);
+        doLog(rec);
+    }
+
+    public void logrb(final Level level, final String sourceClass, final String sourceMethod, final String bundleName, final String msg) {
+        final int effectiveLevel = this.effectiveLevel;
+        if (level.intValue() < effectiveLevel || effectiveLevel == OFF_INT) {
+            return;
+        }
+        final ExtLogRecord rec = new ExtLogRecord(level, msg);
+        rec.setSourceClassName(sourceClass);
+        rec.setSourceMethodName(sourceMethod);
+        rec.setResourceBundleName(bundleName);
+        doLog(rec);
+    }
+
+    public void logrb(final Level level, final String sourceClass, final String sourceMethod, final String bundleName, final String msg, final Object param1) {
+        final int effectiveLevel = this.effectiveLevel;
+        if (level.intValue() < effectiveLevel || effectiveLevel == OFF_INT) {
+            return;
+        }
+        final ExtLogRecord rec = new ExtLogRecord(level, msg);
+        rec.setSourceClassName(sourceClass);
+        rec.setSourceMethodName(sourceMethod);
+        rec.setResourceBundleName(bundleName);
+        rec.setParameters(new Object[] { param1 });
+        doLog(rec);
+    }
+
+    public void logrb(final Level level, final String sourceClass, final String sourceMethod, final String bundleName, final String msg, final Object[] params) {
+        final int effectiveLevel = this.effectiveLevel;
+        if (level.intValue() < effectiveLevel || effectiveLevel == OFF_INT) {
+            return;
+        }
+        final ExtLogRecord rec = new ExtLogRecord(level, msg);
+        rec.setSourceClassName(sourceClass);
+        rec.setSourceMethodName(sourceMethod);
+        rec.setResourceBundleName(bundleName);
+        if (params != null) rec.setParameters(params);
+        doLog(rec);
+    }
+
+    public void logrb(final Level level, final String sourceClass, final String sourceMethod, final String bundleName, final String msg, final Throwable thrown) {
+        final int effectiveLevel = this.effectiveLevel;
+        if (level.intValue() < effectiveLevel || effectiveLevel == OFF_INT) {
+            return;
+        }
+        final ExtLogRecord rec = new ExtLogRecord(level, msg);
+        rec.setSourceClassName(sourceClass);
+        rec.setSourceMethodName(sourceMethod);
+        rec.setResourceBundleName(bundleName);
+        rec.setThrown(thrown);
+        doLog(rec);
+    }
+
     // GC
 
     /**

Modified: jboss-logmanager/trunk/src/main/java/org/jboss/logmanager/LoggerNode.java
===================================================================
--- jboss-logmanager/trunk/src/main/java/org/jboss/logmanager/LoggerNode.java	2009-03-09 15:36:51 UTC (rev 3046)
+++ jboss-logmanager/trunk/src/main/java/org/jboss/logmanager/LoggerNode.java	2009-03-09 21:46:49 UTC (rev 3047)
@@ -30,7 +30,7 @@
 /**
  * A node in the tree of logger names.  Maintains weak references to children and a strong reference to its parent.
  */
-final class LoggerNode {
+class LoggerNode {
 
     /**
      * The log manager.
@@ -126,6 +126,7 @@
             if (instance == null) {
                 instance = new LoggerInstance(this, fullName);
                 loggerRef = new WeakReference<LoggerInstance>(instance);
+                instance.setLevel(null);
             }
             return instance;
         }
@@ -169,11 +170,13 @@
     void updateChildEffectiveLevel(int newLevel) {
         for (LoggerNode node : children.values()) {
             if (node != null) {
-                final WeakReference<LoggerInstance> loggerRef = node.loggerRef;
-                if (loggerRef != null) {
-                    final LoggerInstance instance = loggerRef.get();
-                    if (instance != null) {
-                        instance.setEffectiveLevel(newLevel);
+                synchronized (node) {
+                    final WeakReference<LoggerInstance> loggerRef = node.loggerRef;
+                    if (loggerRef != null) {
+                        final LoggerInstance instance = loggerRef.get();
+                        if (instance != null) {
+                            instance.setEffectiveLevel(newLevel);
+                        }
                     }
                 }
             }




More information about the jboss-svn-commits mailing list