[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