From 04dfafe19f0d3687d0f0b3e51d2d5bf3d19b58bf Mon Sep 17 00:00:00 2001
From: boli <boli@localhost>
Date: Wed, 07 Mar 2007 23:38:55 +0000
Subject: [PATCH] Enable AspectJ weaving for the new debug logging framework: - This commit does not allow for configuring the debug logger over protocol. It can only be configured on server startup using properties. - The settings specified during startup will remain in effect for the duration of the server. - All messages are printed to standard out. - Weaving could be turned off with the -DDEBUG_BUILD=false property when building the server. - By default, the debug logger is off on server startup. It could be enabled by using the -Dorg.opends.server.debug.enabled=true. - Debug targets may be defined with the -Dorg.opends.server.debug.target property. The syntax of this property can be found on the opends.dev.java.net documentation section. - Debug logging is turned on by default on unit tests and printed on test failure.  - Default debug target for unit tests could be changed by using the -Dorg.opends.test.debug.target property.

---
 opends/src/server/org/opends/server/loggers/debug/Tracer.java                     |  390 +++++++--
 opends/src/server/org/opends/server/extensions/TraditionalWorkerThread.java       |   17 
 opends/src/server/org/opends/server/loggers/debug/DebugLogRecord.java             |   26 
 opends/src/server/org/opends/server/api/DirectoryThread.java                      |   21 
 opends/src/server/org/opends/server/util/ServerConstants.java                     |   18 
 opends/src/server/org/opends/server/loggers/LoggerErrorHandler.java               |    4 
 opends/src/server/org/opends/server/backends/task/TaskThread.java                 |   15 
 opends/src/server/org/opends/server/loggers/debug/TraceSettings.java              |  145 +++
 opends/src/server/org/opends/server/loggers/debug/DebugLogger.java                |   74 -
 opends/src/server/org/opends/server/loggers/debug/DebugConfiguration.java         |  274 +++++++
 opends/src/server/org/opends/server/loggers/LoggerConfiguration.java              |  274 +++++++
 opends/src/server/org/opends/server/api/LogPublisher.java                         |    4 
 opends/src/server/org/opends/server/types/FilePermission.java                     |   45 +
 opends/src/server/org/opends/server/loggers/LogCategory.java                      |   46 +
 opends/src/server/org/opends/server/loggers/TextLogPublisher.java                 |    3 
 opends/src/server/org/opends/server/loggers/debug/DebugLogFormatter.java          |   40 
 opends/tests/unit-tests-testng/src/server/org/opends/server/TestCaseUtils.java    |   16 
 opends/tests/unit-tests-testng/src/server/org/opends/server/TestListener.java     |   27 
 opends/src/server/org/opends/server/loggers/Logger.java                           |  139 +--
 opends/src/server/org/opends/server/types/DebugLogCategory.java                   |    2 
 opends/src/server/org/opends/server/loggers/debug/DebugMessageFormatter.java      |  273 +++++++
 /dev/null                                                                         |  165 ----
 opends/tests/unit-tests-testng/src/server/org/opends/server/TestLogPublisher.java |   99 ++
 opends/build.xml                                                                  |   62 +
 opends/src/server/org/opends/server/loggers/AsyncronousLogPublisher.java          |   10 
 opends/src/server/org/opends/server/loggers/LogLevel.java                         |    2 
 26 files changed, 1,739 insertions(+), 452 deletions(-)

diff --git a/opends/build.xml b/opends/build.xml
index 13a470a..2d45b20 100644
--- a/opends/build.xml
+++ b/opends/build.xml
@@ -100,6 +100,10 @@
   <!-- Properties for the EMMA code coverage tool.                 -->
   <property name="emma.dir" location="${ext.dir}/emma/lib"          />
 
+  <!-- Properties for the AspectJ tools                            -->
+  <property name="aj.dir" location="${ext.dir}/aspectj"             />
+  <property name="aj.lib.dir" location="${aj.dir}/lib"              />
+
   <!-- Properties for the TestNG unit testing  tool.               -->
   <property name="testng.dir" location="${ext.dir}/testng"          />
   <property name="testng.lib.dir" location="${testng.dir}/lib"      />
@@ -183,12 +187,16 @@
       <format property="timestamp" pattern="yyyyMMddHHmmss" />
     </tstamp>
 
-    <condition property="DEBUG_BUILD" value="false">
+    <condition property="DEBUG_BUILD" value="true">
       <not>
         <isset property="DEBUG_BUILD" />
       </not>
     </condition>
 
+    <condition property="weave.enabled" value="true">
+      <equals arg1="${DEBUG_BUILD}" arg2="true" />
+    </condition>
+
     <condition property="MEM" value="128M">
       <not>
         <isset property="MEM" />
@@ -367,7 +375,7 @@
 
   <!-- Compile the Directory Server source files. -->
   <target name="cleancompile"
-       depends="cleaninit,compile,compilequicksetup,compilestatuspanel"
+       depends="cleaninit,weave,compilequicksetup,compilestatuspanel"
        description="Recompile the Directory Server source files.">
   </target>
 
@@ -380,7 +388,7 @@
 
     <javac srcdir="${src.dir}" destdir="${classes.dir}" optimize="true"
          excludes="**/package-info.java"
-         debug="on" debuglevel="lines,source" source="1.5" target="1.5"
+         debug="on" debuglevel="lines,vars,source" source="1.5" target="1.5"
          deprecation="true" fork="true" memoryInitialSize="${MEM}"
          memoryMaximumSize="${MEM}">
       <compilerarg value="-Xlint:all" />
@@ -393,8 +401,27 @@
     </javac>
   </target>
 
+  <target name="weave" if="weave.enabled" depends="compile">
+    <taskdef resource="org/aspectj/tools/ant/taskdefs/aspectjTaskdefs.properties">
+      <classpath>
+        <pathelement location="${aj.lib.dir}/aspectjtools.jar" />
+      </classpath>
+    </taskdef>
+
+    <iajc inpath="${classes.dir}" destdir="${classes.dir}"
+          debug="true" debuglevel="lines,source" source="1.5" target="1.5"
+          deprecation="true" fork="true" maxmem="${MEM}">
+      <classpath>
+        <fileset dir="${lib.dir}">
+          <include name="*.jar" />
+        </fileset>
+      </classpath>
+    </iajc>
+  </target>
+
+
   <!-- Compile the Quick Setup source files. -->
-  <target name="compilequicksetup" depends="buildtools,compile"
+  <target name="compilequicksetup" depends="buildtools,weave"
           description="Compile the Quick Setup source files.">
 
     <mkdir dir="${quicksetup.classes.dir}" />
@@ -780,7 +807,7 @@
 
 
   <!-- Prepare to execute the Directory Server TestNG unit tests. -->
-  <target name="testinit" depends="buildtools,compile"
+  <target name="testinit" depends="buildtools,weave"
          description="Prepare to execute the Directory Server TestNG unit tests.">
 
     <!-- If we are to perform coverage tests, then set that up. -->
@@ -994,6 +1021,19 @@
     <echo message="  -Dtest.failed=true"/>
     <echo message="      runs only the tests that failed last time"/>
     <echo message=""/>
+    <echo message="  -DDEBUG_BUILD=false" />
+    <echo message="      builds the server without the debug logging facility." />
+    <echo message="      No debug logging messages will be included on test failures." />
+    <echo message=""/>
+    <echo message="  -Dtest.debug.target=org.opends.server.core:level=verbose,category=data_access"/>
+    <echo message="      for example only include debug messages in the core"/>
+    <echo message="      package that are related to data access and at the" />
+    <echo message="      verbose level or higher. The syntax of this target" />
+    <echo message="      definition is the same as the org.opends.server.debug.target.x" />
+    <echo message="      property when starting OpenDS. " />
+    <echo message="      Default debug target:"/>
+    <echo message="      org.opends.server:level=verbose,category=caught|data|database_access|message|protocol" />
+    <echo message=""/>
     <echo message="  -Dtest.packages=org.opends.server.api"/>
     <echo message="      for example runs only the tests in the api package"/>
     <echo message="      For multiple packages, separate them with a ',' and "/>
@@ -1047,7 +1087,16 @@
       </not>
     </condition>
 
-    <!-- Cleanout the old reports.  Otherwise, the old testng-failed.xml 
+    <!-- This sets org.opends.test.debug.target if and only if its's not
+         alreadly set. -->
+    <condition property="org.opends.test.debug.target"
+               value="org.opends.server:level=verbose,category=caught|data|database_access|message|protocol">
+      <not>
+        <isset property="org.opends.test.debug.target" />
+      </not>
+    </condition>
+
+    <!-- Cleanout the old reports.  Otherwise, the old testng-failed.xml
          will hang around even if all of the tests pass. -->
     <delete>
       <fileset dir="${unittest.report.dir}" includes="*"/>
@@ -1084,6 +1133,7 @@
       <jvmarg value="-Demma.coverage.out.merge=false" />
       <jvmarg value="-Dorg.opends.server.BuildRoot=${basedir}" />
       <jvmarg value="-Dorg.opends.test.suppressOutput=${org.opends.test.suppressOutput}" />
+      <jvmarg value="-Dorg.opends.test.debug.target=${org.opends.test.debug.target}" />
       <jvmarg value="-Xms${MEM}" />
       <jvmarg value="-Xmx${MEM}" />
       <xmlfileset dir="${unittest.resource.dir}" includes="testng.xml" />
diff --git a/opends/src/server/org/opends/server/api/DirectoryThread.java b/opends/src/server/org/opends/server/api/DirectoryThread.java
index 9046dfe..d4c49d2 100644
--- a/opends/src/server/org/opends/server/api/DirectoryThread.java
+++ b/opends/src/server/org/opends/server/api/DirectoryThread.java
@@ -34,6 +34,8 @@
 import static org.opends.server.util.ServerConstants.*;
 import static org.opends.server.util.StaticUtils.*;
 
+import java.util.Map;
+import java.util.LinkedHashMap;
 
 
 /**
@@ -211,5 +213,24 @@
   {
     this.task = task;
   }
+
+
+  /**
+   * Retrieves any relevent debug information with which this tread is
+   * associated so they can be included in debug messages.
+   *
+   * @return debug information about this thread as a string.
+   */
+  public Map<String, String> getDebugProperties()
+  {
+    LinkedHashMap<String, String> properties =
+        new LinkedHashMap<String, String>();
+
+    properties.put("parentThread", parentThread.getName() +
+        "(" + parentThread.getId() + ")");
+    properties.put("isDaemon", String.valueOf(this.isDaemon()));
+
+    return properties;
+  }
 }
 
diff --git a/opends/src/server/org/opends/server/api/LogPublisher.java b/opends/src/server/org/opends/server/api/LogPublisher.java
index 861c534..122d893 100644
--- a/opends/src/server/org/opends/server/api/LogPublisher.java
+++ b/opends/src/server/org/opends/server/api/LogPublisher.java
@@ -27,7 +27,7 @@
 package org.opends.server.api;
 
 import org.opends.server.loggers.LogRecord;
-import org.opends.server.loggers.LogErrorHandler;
+import org.opends.server.loggers.LoggerErrorHandler;
 
 /**
  * LogPublishers are reponsible for distributing logged messages from
@@ -45,7 +45,7 @@
    * @param record the log record to publish.
    * @param handler the error handler to use when an error occurs.
    */
-  public void publish(LogRecord record, LogErrorHandler handler);
+  public void publish(LogRecord record, LoggerErrorHandler handler);
 
   /**
    * Releases any resources and prepare for close.
diff --git a/opends/src/server/org/opends/server/backends/task/TaskThread.java b/opends/src/server/org/opends/server/backends/task/TaskThread.java
index 9f3623e..3929d32 100644
--- a/opends/src/server/org/opends/server/backends/task/TaskThread.java
+++ b/opends/src/server/org/opends/server/backends/task/TaskThread.java
@@ -38,6 +38,7 @@
 import static org.opends.server.messages.MessageHandler.*;
 import static org.opends.server.util.StaticUtils.*;
 
+import java.util.Map;
 
 
 /**
@@ -223,5 +224,19 @@
       taskScheduler.threadDone(this, task);
     }
   }
+
+  /**
+   * Retrieves any relevent debug information with which this tread is
+   * associated so they can be included in debug messages.
+   *
+   * @return debug information about this thread as a string.
+   */
+  public Map<String, String> getDebugProperties()
+  {
+    Map<String, String> properties = super.getDebugProperties();
+    properties.put("task", task.toString());
+
+    return properties;
+  }
 }
 
diff --git a/opends/src/server/org/opends/server/extensions/TraditionalWorkerThread.java b/opends/src/server/org/opends/server/extensions/TraditionalWorkerThread.java
index 0f41e34..a368fd6 100644
--- a/opends/src/server/org/opends/server/extensions/TraditionalWorkerThread.java
+++ b/opends/src/server/org/opends/server/extensions/TraditionalWorkerThread.java
@@ -47,6 +47,7 @@
 import static org.opends.server.messages.MessageHandler.*;
 import static org.opends.server.util.StaticUtils.*;
 
+import java.util.Map;
 
 
 /**
@@ -310,5 +311,21 @@
       }
     }
   }
+
+  /**
+   * Retrieves any relevent debug information with which this tread is
+   * associated so they can be included in debug messages.
+   *
+   * @return debug information about this thread as a string.
+   */
+  public Map<String, String> getDebugProperties()
+  {
+    Map<String, String> properties = super.getDebugProperties();
+    properties.put("clientConnection",
+                   operation.getClientConnection().toString());
+    properties.put("operation", operation.toString());
+
+    return properties;
+  }
 }
 
diff --git a/opends/src/server/org/opends/server/loggers/AsyncronousLogPublisher.java b/opends/src/server/org/opends/server/loggers/AsyncronousLogPublisher.java
index 8670895..3cff741 100644
--- a/opends/src/server/org/opends/server/loggers/AsyncronousLogPublisher.java
+++ b/opends/src/server/org/opends/server/loggers/AsyncronousLogPublisher.java
@@ -61,9 +61,9 @@
   private static class PublishRequest
   {
     public final LogRecord record;
-    public final LogErrorHandler handler;
+    public final LoggerErrorHandler handler;
 
-    PublishRequest(LogRecord record, LogErrorHandler handler)
+    PublishRequest(LogRecord record, LoggerErrorHandler handler)
     {
       this.record = record;
       this.handler = handler;
@@ -129,7 +129,7 @@
         catch (Throwable t) {
           // Forward exception to error handler
           if (request != null  && request.handler != null) {
-            LogErrorHandler handler= request.handler;
+            LoggerErrorHandler handler= request.handler;
             handler.handleError(request.record, t);
           }
         }
@@ -141,7 +141,7 @@
   // want shutdown to start after we check for it, but before we queue
   // request.
   private synchronized void publishAsynchronously(LogRecord record,
-                                                  LogErrorHandler handler)
+                                                  LoggerErrorHandler handler)
   {
     // If shutting down reject, otherwise publish (if we have a publisher!)
     if (isShuttingDown()) {
@@ -167,7 +167,7 @@
    * @param record the log record to publish.
    * @param handler the error handler to use if an error occurs.
    */
-  public void publish(LogRecord record, LogErrorHandler handler)
+  public void publish(LogRecord record, LoggerErrorHandler handler)
   {
     // No publisher?  Off to the bit bucket.
     if (publisher != null) {
diff --git a/opends/src/server/org/opends/server/loggers/LogCategory.java b/opends/src/server/org/opends/server/loggers/LogCategory.java
index e28fc76..df42e4e 100644
--- a/opends/src/server/org/opends/server/loggers/LogCategory.java
+++ b/opends/src/server/org/opends/server/loggers/LogCategory.java
@@ -26,12 +26,17 @@
  */
 package org.opends.server.loggers;
 
+import java.util.ArrayList;
+
 /**
  * The category class defines a set of standard logging types that
  * can be used to control logging output.
  */
-public abstract class LogCategory
+public class LogCategory
 {
+  private static ArrayList<LogCategory> known =  new ArrayList<LogCategory>();
+
+
   /**
    * The non-localized name of the type.
    */
@@ -42,13 +47,15 @@
    * <p>
    * Note that this constructor is "protected" to allow subclassing.
    *
-   * @param name  the name of the Level, for example "SEVERE".
+   * @param name  the name of the category, for example "MESSAGE".
    */
   protected LogCategory(String name) {
     if (name == null) {
       throw new NullPointerException();
     }
     this.name = name;
+
+    known.add(this);
   }
 
   /**
@@ -63,9 +70,42 @@
   /**
    * Retrieves the string reprentation of this log category.
    *
-   * @return the non-localized name of the Level, for example "INFO".
+   * @return the non-localized name of the LogCategory, for example "ENTRY".
    */
   public final String toString() {
     return name;
   }
+
+  /**
+   * Parse a category name string into a LogCategory.
+   * <p>
+   * For example:
+   * <ul>
+   * <li> "EXIT"
+   * <li> "caught"
+   * </ul>
+   * @param  name   string to be parsed
+   * @throws IllegalArgumentException if the value is not valid.
+   * Known names are the categories defined by this class or created
+   * by this class with appropriate package access, or new levels defined
+   * or created by subclasses.
+   *
+   * @return The parsed category
+   */
+  public static synchronized LogCategory parse(String name)
+      throws IllegalArgumentException {
+    // Check that name is not null.
+    name.length();
+
+    // Look for a known Level with the given  name.
+    for (int i = 0; i < known.size(); i++) {
+      LogCategory c = known.get(i);
+      if (name.equalsIgnoreCase(c.name)) {
+        return c;
+      }
+    }
+
+    // OK, we've tried everything and failed
+    throw new IllegalArgumentException("Bad category \"" + name + "\"");
+  }
 }
diff --git a/opends/src/server/org/opends/server/loggers/LogLevel.java b/opends/src/server/org/opends/server/loggers/LogLevel.java
index 206f029..05e2c8f 100644
--- a/opends/src/server/org/opends/server/loggers/LogLevel.java
+++ b/opends/src/server/org/opends/server/loggers/LogLevel.java
@@ -119,7 +119,7 @@
   }
 
   /**
-   * Parse a level name string into a Level.
+   * Parse a level name string into a LogLevel.
    * <p>
    * The argument string may consist of either a level name
    * or an integer value.
diff --git a/opends/src/server/org/opends/server/loggers/Logger.java b/opends/src/server/org/opends/server/loggers/Logger.java
index 5cab7a3..b30383f 100644
--- a/opends/src/server/org/opends/server/loggers/Logger.java
+++ b/opends/src/server/org/opends/server/loggers/Logger.java
@@ -28,8 +28,7 @@
 
 import org.opends.server.api.LogPublisher;
 
-import java.util.concurrent.CopyOnWriteArrayList;
-import java.util.concurrent.locks.ReentrantLock;
+import java.util.List;
 
 /**
  *  A Logger is the entry point into a message distribution
@@ -37,37 +36,36 @@
  * filters out undesired messages using a RecordFilter, and
  * sends them to a LogPublisher for further distribution.
  * Any logging exceptions encountered will be sent to a
- * LoggingErrorHandler.
+ * LoggerErrorHandler.
  */
 public abstract class Logger
 {
+ /**
+   * Whether the debug logger is enabled or disabled.
+   */
+  protected boolean enabled;
+
   /**
    * The logging error handler.
    */
-  protected LogErrorHandler handler;
+  protected LoggerErrorHandler handler;
 
   /**
    * The set of publishers.
    */
-  protected CopyOnWriteArrayList<LogPublisher> publishers;
-
-  /**
-   * A mutex that will be used to provide threadsafe access to methods
-   * changing the set of defined publishers.
-   */
-  protected ReentrantLock publisherMutex;
+  protected List<LogPublisher> publishers;
 
   /**
    * Construct a new logger object.
    *
-   * @param handler the error handler to use when an error occurs.
+   * @param config the logger configuration to use when construting the new
+   *               logger object.
    */
-  protected Logger(LogErrorHandler handler)
+  protected Logger(LoggerConfiguration config)
   {
-    this.publishers = new CopyOnWriteArrayList<LogPublisher>();
-    this.publisherMutex = new ReentrantLock();
-
-    this.handler = handler;
+    this.enabled = config.getEnabled();
+    this.publishers = config.getPublishers();
+    this.handler = config.getErrorHandler();
   }
 
   /**
@@ -75,7 +73,7 @@
    *
    * @param record The log record to publish.
    */
-  protected void publishRecord(LogRecord record)
+  public void publishRecord(LogRecord record)
   {
     for(LogPublisher p : publishers)
     {
@@ -84,97 +82,36 @@
   }
 
   /**
-   * Adds a new publisher to which log records should be sent.
+   * Update this logger with the provided configuration.
    *
-   * @param publisher The publisher to which records should be sent.
+   * @param config the new configuration to use for this logger.
    */
-  protected void addPublisher(LogPublisher publisher)
+  protected void updateConfiguration(LoggerConfiguration config)
   {
-    publisherMutex.lock();
-
-    try
+    boolean newEnabled = config.getEnabled();
+    if(enabled && !newEnabled)
     {
-      for (LogPublisher p : publishers)
+      //it is now disabled. Close all publishers if any.
+      for(LogPublisher publisher : publishers)
       {
-        if (p.equals(publisher))
+        publisher.shutdown();
+        publishers.remove(publisher);
+      }
+    }
+
+    if(newEnabled)
+    {
+      List<LogPublisher> newPublishers = config.getPublishers();
+      for(LogPublisher oldPublisher : publishers)
+      {
+        if(!newPublishers.contains(oldPublisher))
         {
-          return;
+          //A publisher was removed. Make sure to close it before removing it.
+          oldPublisher.shutdown();
         }
       }
-
-      publishers.add(publisher);
-    }
-    catch (Exception e)
-    {
-      // This should never happen.
-      e.printStackTrace();
-    }
-    finally
-    {
-      publisherMutex.unlock();
-    }
-  }
-
-  /**
-   * Removes the provided publisher so records will no longer be sent to it.
-   *
-   * @param publisher The publisher to remove.
-   */
-  protected void removePublisher(LogPublisher publisher)
-  {
-      publisherMutex.lock();
-
-    try
-    {
-      publishers.remove(publisher);
-    }
-    catch (Exception e)
-    {
-      // This should never happen.
-      e.printStackTrace();
-    }
-    finally
-    {
-      publisherMutex.unlock();
-    }
-  }
-
-  /**
-   * Removes all publishers so records are not sent anywhere.
-   *
-   * @param closePublishers whether to close the publishers when removing them.
-   */
-  protected void removeAllPublishers(boolean closePublishers)
-  {
-    publisherMutex.lock();
-
-    try
-    {
-      if(closePublishers)
-      {
-        LogPublisher[] pubs = new LogPublisher[publishers.size()];
-        publishers.toArray(pubs);
-
-        publishers.clear();
-
-        for(LogPublisher pub : pubs)
-        {
-          pub.shutdown();
-        }
-      }
-          else
-    {
-      publishers.clear();
-    }
-    }
-    catch(Exception e)
-    {
-      // This should never happen.
-      e.printStackTrace();
-    }
-    finally
-    {
-      publisherMutex.unlock();
+      this.publishers = config.getPublishers();
+      this.handler = config.getErrorHandler();
     }
   }
 }
diff --git a/opends/src/server/org/opends/server/loggers/LoggerConfiguration.java b/opends/src/server/org/opends/server/loggers/LoggerConfiguration.java
new file mode 100644
index 0000000..52877ef
--- /dev/null
+++ b/opends/src/server/org/opends/server/loggers/LoggerConfiguration.java
@@ -0,0 +1,274 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License").  You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE
+ * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
+ * add the following below this CDDL HEADER, with the fields enclosed
+ * by brackets "[]" replaced with your own identifying information:
+ *      Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ *
+ *      Portions Copyright 2006-2007 Sun Microsystems, Inc.
+ */
+package org.opends.server.loggers;
+
+import org.opends.server.api.LogPublisher;
+
+import java.util.concurrent.locks.ReentrantLock;
+import java.util.concurrent.CopyOnWriteArrayList;
+import java.util.*;
+
+/**
+ * A LoggerConfiguration encapsulates the information defining an
+ * abstract log messaging system.  A LoggerConfiguration maintains at
+ * least three things:
+ * <ul>
+ * <li>a destination to send log messages to (a LogPublisher).</li>
+ * <li>an optional filter used to restrict the log messages sent
+ * (a RecordFilter).</li>
+ * <li>an error handler to be notified in the case of any logging
+ * exceptions (a LoggerErrorHandler).</li>
+ * </ul>
+ *
+ * A Logger will use this information to initialize the log messaging
+ * system.  Additionally, a Logger will register with the LoggerConfiguration
+ * object it used to allow the LoggerConfiguration to provide a single
+ * point of configuration management.  On configuration changes, registered
+ * Loggers will be notified.
+ *
+ */
+public class LoggerConfiguration {
+
+  /**
+   * Whether the debug logger is enabled or disabled.
+   */
+  protected boolean enabled;
+
+  /** The log destination for this configuration. */
+  protected CopyOnWriteArrayList<LogPublisher> publishers;
+
+  /**
+   * A mutex that will be used to provide threadsafe access to methods
+   * changing the set of defined publishers.
+   */
+  protected ReentrantLock publisherMutex;
+
+  /**
+   * The logging error handler.
+   */
+  protected LoggerErrorHandler handler;
+
+  /** The record filter for this configuration. */
+  //protected RecordFilter _filter;
+
+  /** The loggers that need notification of configuration changes. */
+  protected Set<Logger> loggers;
+
+  /**
+   * Creates a LoggerConfiguration describing an disabled logging system.
+   *
+   * @param handler the error handler to use for the logger configured by this
+   *                configuration.
+   */
+  public LoggerConfiguration(LoggerErrorHandler handler)
+  {
+    this.enabled = false;
+    this.publishers = new CopyOnWriteArrayList<LogPublisher>();
+    this.publisherMutex = new ReentrantLock();
+    this.handler = handler;
+    this.loggers = new HashSet<Logger>();
+  }
+
+  /**
+   * Enable or disable the debug logger.
+   *
+   * @param enable if the debug logger should be enabled.
+   */
+  public void setEnabled(boolean enable)
+  {
+    this.enabled = enable;
+  }
+
+  /**
+   * Obtain the status of this logger singleton.
+   *
+   * @return the status of this logger.
+   */
+  public boolean getEnabled()
+  {
+    return enabled;
+  }
+
+  /**
+   * Adds a new publisher to which log records should be sent.
+   *
+   * @param publisher The publisher to which records should be sent.
+   */
+  public void addPublisher(LogPublisher publisher)
+  {
+    publisherMutex.lock();
+
+    try
+    {
+      for (LogPublisher p : publishers)
+      {
+        if (p.equals(publisher))
+        {
+          return;
+        }
+      }
+
+      publishers.add(publisher);
+    }
+    catch (Exception e)
+    {
+      // This should never happen.
+      e.printStackTrace();
+    }
+    finally
+    {
+      publisherMutex.unlock();
+    }
+  }
+
+  /**
+   * Removes the provided publisher so records will no longer be sent to it.
+   *
+   * @param publisher The publisher to remove.
+   */
+  public void removePublisher(LogPublisher publisher)
+  {
+    publisherMutex.lock();
+
+    try
+    {
+      publishers.remove(publisher);
+    }
+    catch (Exception e)
+    {
+      // This should never happen.
+      e.printStackTrace();
+    }
+    finally
+    {
+      publisherMutex.unlock();
+    }
+  }
+
+  /**
+   * Removes all publishers so records are not sent anywhere.
+   *
+   * @param closePublishers whether to close the publishers when removing them.
+   */
+  public void removeAllPublishers(boolean closePublishers)
+  {
+    publisherMutex.lock();
+
+    try
+    {
+      if(closePublishers)
+      {
+        LogPublisher[] pubs = new LogPublisher[publishers.size()];
+        publishers.toArray(pubs);
+
+        publishers.clear();
+
+        for(LogPublisher pub : pubs)
+        {
+          pub.shutdown();
+        }
+      }
+      else
+      {
+        publishers.clear();
+      }
+    }
+    catch(Exception e)
+    {
+      // This should never happen.
+      e.printStackTrace();
+    }
+    finally
+    {
+      publisherMutex.unlock();
+    }
+  }
+
+  /**
+   * Retrieves the set of publishers included in this configuration.
+   *
+   * @return the set of publishers included in this configuration.
+   */
+  public List<LogPublisher> getPublishers()
+  {
+    return Collections.unmodifiableList(publishers);
+  }
+
+  /**
+   * Retrieves the error handler included in this configuration.
+   *
+   * @return the error handler used by this configuration.
+   */
+  public LoggerErrorHandler getErrorHandler()
+  {
+    return handler;
+  }
+
+  /**
+   * Set an error handler for this configuration.
+   *
+   * @param handler the error handler to set for this configuration.
+   */
+  public void setErrorHandler(LoggerErrorHandler handler)
+  {
+    this.handler= handler;
+    notifyLoggers();
+  }
+
+  /**
+   * Request that a logger be notified of configuration changes.
+   *
+   * @param logger - The Logger interested in configuration change
+   * notifications.
+   */
+  public synchronized void registerLogger(Logger logger)
+  {
+    loggers.add(logger);
+  }
+
+  /**
+   * Request that a logger no longer be notifed of configuration changes.
+   *
+   * @param logger - The Logger no longer interested in configuration change
+   * notifications.
+   */
+  public synchronized void deregisterLogger(Logger logger)
+  {
+    loggers.remove(logger);
+  }
+
+  /**
+   * Notify all registered loggers that the configuration has changed.
+   */
+  protected synchronized void notifyLoggers()
+  {
+    for(Logger logger : loggers)
+    {
+      logger.updateConfiguration(this);
+    }
+  }
+}
diff --git a/opends/src/server/org/opends/server/loggers/LogErrorHandler.java b/opends/src/server/org/opends/server/loggers/LoggerErrorHandler.java
similarity index 93%
rename from opends/src/server/org/opends/server/loggers/LogErrorHandler.java
rename to opends/src/server/org/opends/server/loggers/LoggerErrorHandler.java
index a0cd43a..af36c76 100644
--- a/opends/src/server/org/opends/server/loggers/LogErrorHandler.java
+++ b/opends/src/server/org/opends/server/loggers/LoggerErrorHandler.java
@@ -27,13 +27,13 @@
 package org.opends.server.loggers;
 
 /**
- * A LoggingErrorHandler is used for notification of exceptions which
+ * A LoggerErrorHandler is used for notification of exceptions which
  * occur during the publishing of a record.
  *
  * The advantage of using a handler is that we can handle exceptions
  * asynchronously (useful when dealing with an AsynchronousPublisher).
  */
-public interface LogErrorHandler
+public interface LoggerErrorHandler
 {
   /**
    * Handle an exception which occurred during the publishing
diff --git a/opends/src/server/org/opends/server/loggers/TextLogPublisher.java b/opends/src/server/org/opends/server/loggers/TextLogPublisher.java
index 39b558a..e27012e 100644
--- a/opends/src/server/org/opends/server/loggers/TextLogPublisher.java
+++ b/opends/src/server/org/opends/server/loggers/TextLogPublisher.java
@@ -56,7 +56,8 @@
    * @param record the log record to publish.
    * @param handler the error handler to use if an error occurs.
    */
-  public void publish(LogRecord record, LogErrorHandler handler)
+  public synchronized void publish(LogRecord record,
+                                   LoggerErrorHandler handler)
   {
     try
     {
diff --git a/opends/src/server/org/opends/server/loggers/debug/DebugConfiguration.java b/opends/src/server/org/opends/server/loggers/debug/DebugConfiguration.java
new file mode 100644
index 0000000..5672d0c
--- /dev/null
+++ b/opends/src/server/org/opends/server/loggers/debug/DebugConfiguration.java
@@ -0,0 +1,274 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License").  You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE
+ * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
+ * add the following below this CDDL HEADER, with the fields enclosed
+ * by brackets "[]" replaced with your own identifying information:
+ *      Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ *
+ *      Portions Copyright 2006-2007 Sun Microsystems, Inc.
+ */
+package org.opends.server.loggers.debug;
+
+import org.opends.server.loggers.*;
+import org.opends.server.util.DynamicConstants;
+import org.opends.server.types.DebugLogLevel;
+
+import static org.opends.server.util.ServerConstants.PROPERTY_DEBUG_ENABLED;
+import static org.opends.server.util.ServerConstants.PROPERTY_DEBUG_TARGET;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeMap;
+
+/**
+ * A LoggingConfiguration for the debug logging system.
+ */
+public class DebugConfiguration extends LoggerConfiguration
+{
+  private static final String GLOBAL= "_global";
+
+  private Map<String, TraceSettings> classTraceSettings;
+  private Map<String, Map<String, TraceSettings>> methodTraceSettings;
+
+  /**
+   * Error handler for tracing.  Tracing will be disabled
+   * if too many errors occur.
+   */
+  private class DebugErrorHandler implements LoggerErrorHandler
+  {
+    private static final int ERROR_THRESHOLD= 10;
+
+    private int _loggingErrors= 0;
+
+    /**
+     * Error handler for tracing.  Tracing will be disabled
+     * if too many errors occur.
+     *
+     * @param record the log record that caused the error to occur.
+     * @param ex the exception thrown.
+     */
+    public synchronized void handleError(LogRecord record, Throwable ex)
+    {
+      _loggingErrors++;
+
+      DebugLogFormatter formatter = new DebugLogFormatter();
+      System.err.println("Error publishing record: " +
+          formatter.format(record) + ex);
+
+      // If we've had too many write errors, just turn off
+      // tracing to prevent an overflow of messages.
+      if (_loggingErrors >= ERROR_THRESHOLD) {
+        System.err.println("TOO MANY ERRORS FROM DEBUG LOGGER. SHUTTING DOWN");
+
+        enabled = false;
+      }
+    }
+  }
+
+  /**
+   * Construct a default configuration where the logger is disabled and the
+   * global scope will only log at the ERROR level.
+   */
+  public DebugConfiguration()
+  {
+    super(null);
+    this.setErrorHandler(new DebugErrorHandler());
+    classTraceSettings = null;
+    methodTraceSettings = null;
+
+    //Set the global settings so that only errors are logged.
+    addTraceSettings(null, new TraceSettings(DebugLogLevel.ERROR));
+  }
+
+  /**
+   * Gets the method trace levels for a specified class.
+   * @param className - a fully qualified class name to get method trace
+   * levels for
+   * @return an unmodifiable map of trace levels keyed by method name.  If
+   * no method level tracing is configured for the scope, <b>null</b> is
+   * returned.
+   */
+  public Map<String, TraceSettings> getMethodSettings(String className)
+  {
+    Map<String, TraceSettings> levels = null;
+
+    if (enabled && methodTraceSettings != null) {
+      // Method levels are always at leaves in the
+      // hierarchy, so don't bother searching up.
+      Map<String, TraceSettings> value= methodTraceSettings.get(className);
+      if (value != null ) {
+        levels= value;
+      }
+    }
+    return levels != null ? Collections.unmodifiableMap(levels) : null;
+  }
+
+  /**
+   * Get the trace settings for a specified class.
+   * @param className - a fully qualified class name to get the
+   * trace level for
+   * @return the current trace settings for the class.
+   */
+  public TraceSettings getTraceSettings(String className)
+  {
+    TraceSettings settings = TraceSettings.DISABLED;
+
+    // If we're not enabled, trace level is DISABLED.
+    if (enabled  && classTraceSettings != null) {
+      // Find most specific trace setting which covers this
+      // fully qualified class name
+      // Search up the hierarchy for a match.
+      String searchName= className;
+      Object value= null;
+      value= classTraceSettings.get(searchName);
+      while (value == null && searchName != null) {
+        int clipPoint= searchName.lastIndexOf('$');
+        if (clipPoint == -1) clipPoint= searchName.lastIndexOf('.');
+        if (clipPoint != -1) {
+          searchName= searchName.substring(0, clipPoint);
+          value= classTraceSettings.get(searchName);
+        }
+        else {
+          searchName= null;
+        }
+      }
+
+      // Use global settings, if nothing more specific was found.
+      if (value == null) value= classTraceSettings.get(GLOBAL);
+
+      if (value != null) {
+        settings= (TraceSettings)value;
+      }
+    }
+    return settings;
+  }
+
+  /**
+   * Adds a trace settings to the current set for a specified scope. If a
+   * scope is not specified, the settings will be set for the global scope.
+   * The global scope settings are used when no other scope matches.
+   *
+   * @param scope - the scope to set trace settings for; this is a fully
+   * qualified class name or null to set the trace settings for the global
+   * scope.
+   * @param settings - the trace settings for the scope
+   */
+  public void addTraceSettings(String scope, TraceSettings settings)
+  {
+    if (scope == null) {
+      setClassSettings(GLOBAL, settings);
+    }
+    else {
+      int methodPt= scope.lastIndexOf('#');
+      if (methodPt != -1) {
+        String methodName= scope.substring(methodPt+1);
+        scope= scope.substring(0, methodPt);
+        setMethodSettings(scope, methodName, settings);
+      }
+      else {
+        setClassSettings(scope, settings);
+      }
+    }
+  }
+
+  private synchronized void setClassSettings(String className,
+                                             TraceSettings settings)
+  {
+    if(classTraceSettings == null) classTraceSettings =
+        new HashMap<String, TraceSettings>();
+
+    classTraceSettings.put(className, settings);
+  }
+
+  private synchronized void setMethodSettings(String className,
+                                              String methodName,
+                                              TraceSettings settings)
+  {
+    if (methodTraceSettings == null) methodTraceSettings =
+        new HashMap<String, Map<String, TraceSettings>>();
+    Map<String, TraceSettings> methodLevels=
+        methodTraceSettings.get(className);
+    if (methodLevels == null) {
+      methodLevels= new TreeMap<String, TraceSettings>();
+      methodTraceSettings.put(className, methodLevels);
+    }
+
+    methodLevels.put(methodName, settings);
+  }
+
+  /**
+   * Retrieve the initial configuration to use on debug logger startup. Settings
+   * are read from system properties.
+   * If this is not a debug build of OpenDS, the resulting configuration is
+   * always disabled.
+   *
+   * @return the initial configuration to use for the debug logger.
+   */
+  public static DebugConfiguration getStartupConfiguration()
+  {
+
+    String enabledProp = System.getProperty(PROPERTY_DEBUG_ENABLED);
+    if(DynamicConstants.DEBUG_BUILD && (enabledProp != null &&
+        (enabledProp.startsWith("T") || enabledProp.startsWith("t") ||
+            enabledProp.startsWith("Y") || enabledProp.startsWith("y"))))
+    {
+      DebugConfiguration config = new DebugConfiguration();
+      config.setEnabled(true);
+
+      TextLogPublisher consolePublisher =
+          new TextLogPublisher(TextWriter.STDOUT, new DebugLogFormatter());
+      config.addPublisher(consolePublisher);
+
+      Set<Map.Entry<Object, Object>> propertyEntries =
+          System.getProperties().entrySet();
+      for(Map.Entry<Object, Object> entry : propertyEntries)
+      {
+        if(((String)entry.getKey()).startsWith(PROPERTY_DEBUG_TARGET))
+        {
+          String value = (String)entry.getValue();
+          int settingsStart= value.indexOf(":");
+
+          //See if the scope and settings exists
+          if(settingsStart > 0)
+          {
+            String scope = value.substring(0, settingsStart);
+            TraceSettings settings =
+                TraceSettings.parseTraceSettings(
+                    value.substring(settingsStart+1));
+            if(settings != null)
+            {
+              config.addTraceSettings(scope, settings);
+            }
+          }
+        }
+      }
+
+      return config;
+    }
+    else
+    {
+      //If it is not enabled or not a debug build, just return the default
+      //off config.
+      return new DebugConfiguration();
+    }
+  }
+}
diff --git a/opends/src/server/org/opends/server/loggers/debug/DebugErrorHandler.java b/opends/src/server/org/opends/server/loggers/debug/DebugErrorHandler.java
deleted file mode 100644
index 953f866..0000000
--- a/opends/src/server/org/opends/server/loggers/debug/DebugErrorHandler.java
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
- *
- * You can obtain a copy of the license at
- * trunk/opends/resource/legal-notices/OpenDS.LICENSE
- * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at
- * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
- * add the following below this CDDL HEADER, with the fields enclosed
- * by brackets "[]" replaced with your own identifying information:
- *      Portions Copyright [yyyy] [name of copyright owner]
- *
- * CDDL HEADER END
- *
- *
- *      Portions Copyright 2006-2007 Sun Microsystems, Inc.
- */
-package org.opends.server.loggers.debug;
-
-import org.opends.server.loggers.LogErrorHandler;
-import org.opends.server.loggers.LogRecord;
-
-/**
- * Error handler for tracing.  Tracing will be disabled
- * if too many errors occur.
- */
-public class DebugErrorHandler implements LogErrorHandler
-{
-  private static final int ERROR_THRESHOLD= 10;
-
-  private int _loggingErrors= 0;
-
-  /**
-   * Error handler for tracing.  Tracing will be disabled
-   * if too many errors occur.
-   *
-   * @param record the log record that caused the error to occur.
-   * @param ex the exception thrown.
-   */
-  public synchronized void handleError(LogRecord record, Throwable ex)
-  {
-    _loggingErrors++;
-
-    DebugLogFormatter formatter = new DebugLogFormatter();
-    System.err.println("Error publishing record: " +
-        formatter.format(record) + ex);
-
-    // If we've had too many write errors, just turn off
-    // tracing to prevent an overflow of messages.
-    if (_loggingErrors >= ERROR_THRESHOLD) {
-      System.err.println("TOO MANY ERRORS FROM DEBUG LOGGER. SHUTTING DOWN");
-
-      DebugLogger.enabled(false);
-    }
-  }
-}
diff --git a/opends/src/server/org/opends/server/loggers/debug/DebugLogFormatter.java b/opends/src/server/org/opends/server/loggers/debug/DebugLogFormatter.java
index 8a9b29a..13530dd 100644
--- a/opends/src/server/org/opends/server/loggers/debug/DebugLogFormatter.java
+++ b/opends/src/server/org/opends/server/loggers/debug/DebugLogFormatter.java
@@ -30,6 +30,7 @@
 import org.opends.server.loggers.LogRecord;
 
 import java.util.Locale;
+import java.util.Map;
 import java.text.DateFormat;
 import java.text.SimpleDateFormat;
 
@@ -66,25 +67,44 @@
       buf.append(_timestamper.format(dlr.getTimestamp()));
       buf.append(" ");
 
-      // Emit the debug level.
-      buf.append(dlr.getLevel());
+      // Emit the seq num
+      buf.append(dlr.getSequenceNumber());
       buf.append(" ");
 
-      // Emit thread info.
-      buf.append(dlr.getThreadName());
-      buf.append("(");
-      buf.append(dlr.getThreadID());
-      buf.append(") ");
-
       // Emit debug category.
       buf.append(dlr.getCategory());
       buf.append(" ");
 
+      // Emit the debug level.
+      buf.append(dlr.getLevel());
+      buf.append(" ");
+
+      // Emit thread info.
+      buf.append("thread={");
+      buf.append(dlr.getThreadName());
+      buf.append("(");
+      buf.append(dlr.getThreadID());
+      buf.append(")} ");
+
+      if(dlr.getThreadProperties() != null)
+      {
+        buf.append("threadDetail={");
+        for(Map.Entry entry : dlr.getThreadProperties().entrySet())
+        {
+          buf.append(entry.getKey());
+          buf.append("=");
+          buf.append(entry.getValue());
+          buf.append(" ");
+        }
+        buf.append("} ");
+      }
+
       // Emit method info.
+      buf.append("signature={");
       buf.append(dlr.getSignature());
       buf.append(" @ ");
       buf.append(dlr.getSourceLocation());
-      buf.append(" ");
+      buf.append("} ");
 
       // Emit message.
       buf.append(dlr.getMessage());
@@ -92,7 +112,7 @@
       // Emit Stack Trace.
       if(dlr.getStackTrace() != null)
       {
-        buf.append("\nStack Trace\n");
+        buf.append("\nStack Trace:\n");
         buf.append(dlr.getStackTrace());
       }
 
diff --git a/opends/src/server/org/opends/server/loggers/debug/DebugLogRecord.java b/opends/src/server/org/opends/server/loggers/debug/DebugLogRecord.java
index ae94b4f..69ce418 100644
--- a/opends/src/server/org/opends/server/loggers/debug/DebugLogRecord.java
+++ b/opends/src/server/org/opends/server/loggers/debug/DebugLogRecord.java
@@ -34,6 +34,7 @@
 import org.opends.server.types.DebugLogCategory;
 
 import java.util.Date;
+import java.util.Map;
 
 /**
  * A DebugLogRecord is reponsible for passing tracing log messages from the
@@ -69,6 +70,11 @@
   private long threadID;
 
   /**
+   * Detailed debug properties for thread that issued logging call.
+   */
+  private Map<String, String> threadProperties;
+
+  /**
    * Event time in milliseconds since 1970.
    */
   private Date timestamp;
@@ -387,4 +393,24 @@
   public void setSequenceNumber(long seq) {
     sequenceNumber = seq;
   }
+
+  /**
+   * Set the thread properties.
+   *
+   * @param threadProperties the thread properties map to set.
+   */
+  public void setThreadProperties(Map<String, String> threadProperties)
+  {
+    this.threadProperties = threadProperties;
+  }
+
+  /**
+   * Retrives the thread properties.
+   *
+   * @return the thread properties.
+   */
+  public Map<String, String> getThreadProperties()
+  {
+    return threadProperties;
+  }
 }
diff --git a/opends/src/server/org/opends/server/loggers/debug/DebugLogger.java b/opends/src/server/org/opends/server/loggers/debug/DebugLogger.java
index f3013aa..f00b353 100644
--- a/opends/src/server/org/opends/server/loggers/debug/DebugLogger.java
+++ b/opends/src/server/org/opends/server/loggers/debug/DebugLogger.java
@@ -27,10 +27,8 @@
 package org.opends.server.loggers.debug;
 
 import org.opends.server.api.ProtocolElement;
-import org.opends.server.api.LogPublisher;
 import org.opends.server.loggers.Logger;
 import org.opends.server.loggers.LogLevel;
-import org.opends.server.loggers.LogRecord;
 
 import java.util.Map;
 import java.util.HashMap;
@@ -55,35 +53,21 @@
  */
 public class DebugLogger extends Logger
 {
-  /**
-   * Whether the debug logger is enabled or disabled.
-   */
-  static boolean enabled = false;
   private static DebugLogger logger = null;
+  static boolean staticEnabled = false;
 
   private Map<String, Tracer> classTracers;
-  private TraceConfiguration config;
 
-  private DebugLogger()
+  private DebugConfiguration configuration;
+
+  private DebugLogger(DebugConfiguration config)
   {
-    super(new DebugErrorHandler());
-
+    super(config);
+    configuration = config;
     classTracers = new HashMap<String, Tracer>();
-    config = new TraceConfiguration();
+    staticEnabled = enabled;
   }
 
-  /**
-   * Publish a record to all the registered publishers.
-   *
-   * @param record The log record to publish.
-   */
-  protected void publishRecord(LogRecord record)
-  {
-    for(LogPublisher p : publishers)
-    {
-      p.publish(record, handler);
-    }
-  }
 
   /**
    * Obtain the trace logger singleton.
@@ -92,30 +76,26 @@
   public static synchronized DebugLogger getLogger()
   {
     if (logger == null) {
-      logger= new DebugLogger();
+      /**
+       * The debug logger is being intialized for the first time.
+       * Bootstrap the debug logger when the server first starts up so
+       * all debug messages are log from the first initialization of a
+       * server class.
+       */
+      logger= new DebugLogger(DebugConfiguration.getStartupConfiguration());
     }
 
     return logger;
   }
 
   /**
-   * Enable or disable the debug logger.
-   *
-   * @param enable if the debug logger should be enabled.
-   */
-  public static void enabled(boolean enable)
-  {
-    enabled = enable;
-  }
-
-  /**
    * Obtain the status of this logger singleton.
    *
    * @return the status of this logger.
    */
   public static boolean debugEnabled()
   {
-    return enabled;
+    return staticEnabled;
   }
 
   /**
@@ -129,21 +109,8 @@
     Tracer traceLogger = classTracers.get(className);
     if (traceLogger == null) {
       classTracers.put(className, tracer);
+      tracer.updateSettings(this.configuration);
     }
-    else
-    {
-      //TODO: handle dup case!
-    }
-  }
-
-  /**
-   * Retrives the current tracing configuration of the debug logger.
-   *
-   * @return the current tracing configuration of the debug logger.
-   */
-  protected TraceConfiguration getConfiguration()
-  {
-    return config;
   }
 
   /**
@@ -152,14 +119,17 @@
    *
    * @param config the new configuration to apply.
    */
-  public void updateConfiguration(TraceConfiguration config)
+  public synchronized void updateConfiguration(DebugConfiguration config)
   {
-    this.config = config;
+    super.updateConfiguration(config);
+    staticEnabled = enabled;
 
     for(Tracer tracer : classTracers.values())
     {
-      tracer.updateSettings();
+      tracer.updateSettings(config);
     }
+
+    this.configuration = config;
   }
 
   /**
diff --git a/opends/src/server/org/opends/server/loggers/debug/DebugMessageFormatter.java b/opends/src/server/org/opends/server/loggers/debug/DebugMessageFormatter.java
new file mode 100644
index 0000000..41ff2f6
--- /dev/null
+++ b/opends/src/server/org/opends/server/loggers/debug/DebugMessageFormatter.java
@@ -0,0 +1,273 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License").  You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE
+ * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
+ * add the following below this CDDL HEADER, with the fields enclosed
+ * by brackets "[]" replaced with your own identifying information:
+ *      Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ *
+ *      Portions Copyright 2006-2007 Sun Microsystems, Inc.
+ */
+package org.opends.server.loggers.debug;
+
+import java.util.*;
+
+/**
+ * This class is responsible for formatting messages and replacing
+ * format tokens with the text value of message arguments in debug logging
+ * records.
+ */
+public class DebugMessageFormatter
+{
+  /**
+   * Construct a new debug message formatter.
+   */
+  public DebugMessageFormatter() {
+    //no implementation needed.
+  }
+
+  /**
+   * Format the message format string with the provided arguments.
+   *
+   * @param msg the message format string to be formatted.
+   * @param msgArgs the arguments to use when replacing tokens in the message.
+   * @return the formatted message string.
+   */
+  public String format(String msg, Object[] msgArgs)
+  {
+    StringBuilder buffer= new StringBuilder();
+    Object[] decoratedArgs = decorateMessageArgs(msgArgs);
+
+    if (msg == null)
+    {
+      concatenateArgs(decoratedArgs, buffer);
+      return buffer.toString();
+    }
+
+    try
+    {
+      return String.format(msg, decoratedArgs);
+    }
+    catch (IllegalFormatException e)
+    {
+      // Make a more useful message than a stack trace.
+      buffer.append(msg);
+      concatenateArgs(decoratedArgs, buffer);
+
+      return buffer.toString();
+    }
+  }
+
+  private void concatenateArgs(Object[] args, StringBuilder buffer)
+  {
+    for (int i = 0; (args != null) && (i < args.length); i++) {
+      buffer.append(" ").append(args[i]);
+    }
+  }
+
+  private Object[] decorateMessageArgs(Object[] undecoratedArgs)
+  {
+    Object[] args= null;
+    if (undecoratedArgs != null) {
+      args= new Object[undecoratedArgs.length];
+      for (int i= 0; i < args.length; i++) {
+        args[i]= decorateArg(undecoratedArgs[i]);
+      }
+    }
+
+    return args;
+  }
+
+  private Object decorateArg(Object arg)
+  {
+    Object decoratedArg= arg;
+
+    if (arg instanceof Map) {
+      decoratedArg= decorateMapArg((Map)arg);
+    }
+    else if (arg instanceof List) {
+      decoratedArg= decorateListArg((List)arg);
+    }
+    else if (arg instanceof Object[]) {
+      decoratedArg= decorateArrayArg((Object[])arg);
+    }
+    else if (arg instanceof boolean[]) {
+      decoratedArg = decorateArrayArg((boolean[])arg);
+    }
+    else if (arg instanceof byte[]) {
+      decoratedArg = decorateArrayArg((byte[])arg);
+    }
+    else if (arg instanceof char[]) {
+      decoratedArg = decorateArrayArg((char[])arg);
+    }
+    else if (arg instanceof double[]) {
+      decoratedArg = decorateArrayArg((double[])arg);
+    }
+    else if (arg instanceof float[]) {
+      decoratedArg = decorateArrayArg((float[])arg);
+    }
+    else if (arg instanceof int[]) {
+      decoratedArg = decorateArrayArg((int[])arg);
+    }
+    else if (arg instanceof long[]) {
+      decoratedArg = decorateArrayArg((long[])arg);
+    }
+
+    return decoratedArg;
+  }
+
+  private String decorateArrayArg(Object[] array)
+  {
+    return decorateListArg(Arrays.asList(array));
+  }
+
+  private String decorateArrayArg(boolean[] array)
+  {
+    StringBuilder buffer= new StringBuilder();
+    buffer.append("[ ");
+    boolean firstElement= true;
+    for (int i= 0; i < array.length; i++) {
+      if (i > 0) buffer.append(", ");
+      buffer.append(array[i]);
+    }
+    buffer.append(" ]");
+
+    return buffer.toString();
+  }
+
+  private String decorateArrayArg(byte[] array)
+  {
+    StringBuilder buffer= new StringBuilder();
+    buffer.append("[ ");
+    boolean firstElement= true;
+    for (int i= 0; i < array.length; i++) {
+      if (i > 0) buffer.append(", ");
+      buffer.append(array[i]);
+    }
+    buffer.append(" ]");
+
+    return buffer.toString();
+  }
+
+  private String decorateArrayArg(char[] array)
+  {
+    StringBuilder buffer= new StringBuilder();
+    buffer.append("[ ");
+    boolean firstElement= true;
+    for (int i= 0; i < array.length; i++) {
+      if (i > 0) buffer.append(", ");
+      buffer.append(array[i]);
+    }
+    buffer.append(" ]");
+
+    return buffer.toString();
+  }
+
+  private String decorateArrayArg(double[] array)
+  {
+    StringBuilder buffer= new StringBuilder();
+    buffer.append("[ ");
+    boolean firstElement= true;
+    for (int i= 0; i < array.length; i++) {
+      if (i > 0) buffer.append(", ");
+      buffer.append(array[i]);
+    }
+    buffer.append(" ]");
+
+    return buffer.toString();
+  }
+
+  private String decorateArrayArg(float[] array)
+  {
+    StringBuilder buffer= new StringBuilder();
+    buffer.append("[ ");
+    boolean firstElement= true;
+    for (int i= 0; i < array.length; i++) {
+      if (i > 0) buffer.append(", ");
+      buffer.append(array[i]);
+    }
+    buffer.append(" ]");
+
+    return buffer.toString();
+  }
+
+  private String decorateArrayArg(int[] array)
+  {
+    StringBuilder buffer= new StringBuilder();
+    buffer.append("[ ");
+    boolean firstElement= true;
+    for (int i= 0; i < array.length; i++) {
+      if (i > 0) buffer.append(", ");
+      buffer.append(array[i]);
+    }
+    buffer.append(" ]");
+
+    return buffer.toString();
+  }
+
+  private String decorateArrayArg(long[] array)
+  {
+    StringBuilder buffer= new StringBuilder();
+    buffer.append("[ ");
+    boolean firstElement= true;
+    for (int i= 0; i < array.length; i++) {
+      if (i > 0) buffer.append(", ");
+      buffer.append(array[i]);
+    }
+    buffer.append(" ]");
+
+    return buffer.toString();
+  }
+
+  private String decorateListArg(List list)
+  {
+    StringBuilder buffer= new StringBuilder();
+    Iterator iter= list.iterator();
+    buffer.append("[ ");
+    boolean firstElement= true;
+    while (iter.hasNext()) {
+      Object lValue= iter.next();
+      if (!firstElement) buffer.append(", ");
+      buffer.append(decorateArg(lValue));
+      firstElement= false;
+    }
+    buffer.append(" ]");
+
+    return buffer.toString();
+  }
+
+  private String decorateMapArg(Map map)
+  {
+    StringBuilder buffer= new StringBuilder();
+    Iterator iter= map.entrySet().iterator();
+    buffer.append("{ ");
+    boolean firstEntry= true;
+    while (iter.hasNext()) {
+      Map.Entry entry= (Map.Entry)iter.next();
+      if (!firstEntry) buffer.append(", ");
+      buffer.append(decorateArg(entry.getKey()));
+      buffer.append("=");
+      buffer.append(decorateArg(entry.getValue()));
+      firstEntry= false;
+    }
+    buffer.append(" }");
+
+    return buffer.toString();
+  }
+}
diff --git a/opends/src/server/org/opends/server/loggers/debug/TraceConfiguration.java b/opends/src/server/org/opends/server/loggers/debug/TraceConfiguration.java
deleted file mode 100644
index 1f71697..0000000
--- a/opends/src/server/org/opends/server/loggers/debug/TraceConfiguration.java
+++ /dev/null
@@ -1,165 +0,0 @@
-/*
- * CDDL HEADER START
- *
- * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
- *
- * You can obtain a copy of the license at
- * trunk/opends/resource/legal-notices/OpenDS.LICENSE
- * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
- * See the License for the specific language governing permissions
- * and limitations under the License.
- *
- * When distributing Covered Code, include this CDDL HEADER in each
- * file and include the License file at
- * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
- * add the following below this CDDL HEADER, with the fields enclosed
- * by brackets "[]" replaced with your own identifying information:
- *      Portions Copyright [yyyy] [name of copyright owner]
- *
- * CDDL HEADER END
- *
- *
- *      Portions Copyright 2006-2007 Sun Microsystems, Inc.
- */
-package org.opends.server.loggers.debug;
-
-import java.util.Map;
-import java.util.TreeMap;
-import java.util.HashMap;
-import java.util.Collections;
-
-/**
- * A LoggingConfiguration for the debug logging system.
- */
-public class TraceConfiguration
-{
-  private static final String GLOBAL= "_global";
-
-  private Map<String, TraceSettings> classTraceSettings;
-  private Map<String, Map<String, TraceSettings>> methodTraceSettings;
-
-
-  /**
-   * Construct a default configuration where all settings are disabled.
-   */
-  public TraceConfiguration()
-  {
-    classTraceSettings = null;
-    methodTraceSettings = null;
-  }
-
-  /**
-   * Gets the method trace levels for a specified class.
-   * @param className - a fully qualified class name to get method trace
-   * levels for
-   * @return an unmodifiable map of trace levels keyed by method name.  If
-   * no method level tracing is configured for the scope, <b>null</b> is
-   * returned.
-   */
-  public Map<String, TraceSettings> getMethodSettings(String className)
-  {
-    Map<String, TraceSettings> levels = null;
-
-    if (DebugLogger.enabled && methodTraceSettings != null) {
-      // Method levels are always at leaves in the
-      // hierarchy, so don't bother searching up.
-      Map<String, TraceSettings> value= methodTraceSettings.get(className);
-      if (value != null ) {
-        levels= value;
-      }
-    }
-    return levels != null ? Collections.unmodifiableMap(levels) : null;
-  }
-
-  /**
-   * Get the trace settings for a specified class.
-   * @param className - a fully qualified class name to get the
-   * trace level for
-   * @return the current trace settings for the class.
-   */
-  public TraceSettings getTraceSettings(String className)
-  {
-    TraceSettings settings = TraceSettings.DISABLED;
-
-    // If we're not enabled, trace level is DISABLED.
-    if (DebugLogger.enabled  && classTraceSettings != null) {
-      // Find most specific trace setting which covers this
-      // fully qualified class name
-      // Search up the hierarchy for a match.
-      String searchName= className;
-      Object value= null;
-      value= classTraceSettings.get(searchName);
-      while (value == null && searchName != null) {
-        int clipPoint= searchName.lastIndexOf('$');
-        if (clipPoint == -1) clipPoint= searchName.lastIndexOf('.');
-        if (clipPoint != -1) {
-          searchName= searchName.substring(0, clipPoint);
-          value= classTraceSettings.get(searchName);
-        }
-        else {
-          searchName= null;
-        }
-      }
-
-      // Use global settings, if nothing more specific was found.
-      if (value == null) value= classTraceSettings.get(GLOBAL);
-
-      if (value != null) {
-        settings= (TraceSettings)value;
-      }
-    }
-    return settings;
-  }
-
-  /**
-   * Adds a trace settings to the current set for a specified scope.
-   * @param scope - the scope to set trace settings for; this is a fully
-   * qualified class name.
-   * @param settings - the trace settings for the scope
-   */
-  public void addTraceSettings(String scope, TraceSettings settings)
-  {
-    if (scope == null) {
-      setClassSettings(GLOBAL, settings);
-    }
-    else {
-      int methodPt= scope.lastIndexOf('#');
-      if (methodPt != -1) {
-        String methodName= scope.substring(methodPt+1);
-        scope= scope.substring(0, methodPt);
-        setMethodSettings(scope, methodName, settings);
-      }
-      else {
-        setClassSettings(scope, settings);
-      }
-    }
-  }
-
-  private synchronized void setClassSettings(String className,
-                                             TraceSettings settings)
-  {
-    if(classTraceSettings == null) classTraceSettings =
-        new HashMap<String, TraceSettings>();
-
-    classTraceSettings.put(className, settings);
-  }
-
-  private synchronized void setMethodSettings(String className,
-                                              String methodName,
-                                              TraceSettings settings)
-  {
-    if (methodTraceSettings == null) methodTraceSettings =
-        new HashMap<String, Map<String, TraceSettings>>();
-    Map<String, TraceSettings> methodLevels=
-        methodTraceSettings.get(className);
-    if (methodLevels == null) {
-      methodLevels= new TreeMap<String, TraceSettings>();
-      methodTraceSettings.put(className, methodLevels);
-    }
-
-    methodLevels.put(methodName, settings);
-  }
-}
diff --git a/opends/src/server/org/opends/server/loggers/debug/TraceSettings.java b/opends/src/server/org/opends/server/loggers/debug/TraceSettings.java
index 2ea1daa..4cb7f86 100644
--- a/opends/src/server/org/opends/server/loggers/debug/TraceSettings.java
+++ b/opends/src/server/org/opends/server/loggers/debug/TraceSettings.java
@@ -28,10 +28,12 @@
 package org.opends.server.loggers.debug;
 
 import org.opends.server.types.DebugLogLevel;
+import org.opends.server.types.DebugLogCategory;
 import org.opends.server.loggers.LogLevel;
 import org.opends.server.loggers.LogCategory;
 
 import java.util.Set;
+import java.util.HashSet;
 
 /**
  * This class encapsulates the trace settings in effect at a given traceing
@@ -43,6 +45,13 @@
   static final TraceSettings DISABLED =
       new TraceSettings(DebugLogLevel.DISABLED);
 
+  static final String STACK_DUMP_KEYWORD = "stack";
+  static final String INCLUDE_CAUSE_KEYWORD = "cause";
+  static final String SUPPRESS_ARG_KEYWORD = "noargs";
+  static final String SUPPRESS_RETVAL_KEYWORD = "noretval";
+  static final String INCLUDE_CATEGORY_KEYWORD = "category";
+  static final String LEVEL_KEYWORD = "level";
+
   final LogLevel level;
   final Set<LogCategory> includeCategories;
 
@@ -115,4 +124,140 @@
     this.stackDepth = stackDepth;
     this.includeCause = includeCause;
   }
+
+  /**
+   * Parse trace settings from the string representation.
+   *
+   * @param value the trace settings string to be parsed.
+   * @return the trace settings parsed from the string.
+   */
+  protected static TraceSettings parseTraceSettings(String value)
+  {
+    TraceSettings settings = null;
+    if(value != null)
+    {
+      //Touch DebugLogLevel and DebugLogCategory so they are statically
+      //initialized or parse will not see all the levels/categories.
+      LogLevel level = DebugLogLevel.ERROR;
+      LogCategory categoryStub = DebugLogCategory.MESSAGE;
+
+      Set<LogCategory> includeCategories = null;
+      boolean noArgs = false;
+      boolean noRetVal = false;
+      int stackDepth = 0;
+      boolean includeCause = false;
+
+      String[] keywords = value.split(",");
+
+      for(String keyword : keywords)
+      {
+        //See if stack dump keyword is included
+        if(keyword.startsWith(STACK_DUMP_KEYWORD))
+        {
+          //See if a stack depth is included
+          if(keyword.length() == STACK_DUMP_KEYWORD.length())
+          {
+            stackDepth = DebugStackTraceFormatter.COMPLETE_STACK;
+          }
+          else
+          {
+            int depthStart= keyword.indexOf("=", STACK_DUMP_KEYWORD.length());
+            if (depthStart == STACK_DUMP_KEYWORD.length())
+            {
+              try
+              {
+                stackDepth = Integer.valueOf(keyword.substring(depthStart+1));
+              }
+              catch(NumberFormatException nfe)
+              {
+                System.err.println("The keyword " + STACK_DUMP_KEYWORD +
+                    " contains an invalid depth value. The complete stack " +
+                    "will be included.");
+              }
+            }
+          }
+        }
+        //See if to include cause in exception messages.
+        else if(keyword.equals(INCLUDE_CAUSE_KEYWORD))
+        {
+          includeCause = true;
+        }
+        //See if to supress method arguments.
+        else if(keyword.equals(SUPPRESS_ARG_KEYWORD))
+        {
+          noArgs = true;
+        }
+        //See if to supress return values.
+        else if(keyword.equals(SUPPRESS_RETVAL_KEYWORD))
+        {
+          noRetVal = true;
+        }
+        else if(keyword.startsWith(INCLUDE_CATEGORY_KEYWORD))
+        {
+          int categoryStart =
+                keyword.indexOf("=", INCLUDE_CATEGORY_KEYWORD.length());
+
+          if(keyword.length() == INCLUDE_CATEGORY_KEYWORD.length() ||
+              categoryStart != INCLUDE_CATEGORY_KEYWORD.length())
+          {
+            System.err.println("The keyword " + INCLUDE_CATEGORY_KEYWORD +
+                " does not contain an equal sign to define the set of " +
+                "categories to include. All categories will be included.");
+          }
+          else
+          {
+            String[] categories =
+                keyword.substring(categoryStart+1).split("[|]");
+            includeCategories = new HashSet<LogCategory>();
+            for(String category : categories)
+            {
+              try
+              {
+                includeCategories.add(DebugLogCategory.parse(category));
+              }
+              catch(IllegalArgumentException iae)
+              {
+                System.err.println("The keyword " + INCLUDE_CATEGORY_KEYWORD +
+                    " contains an invalid debug log category: " +
+                    iae.toString() + ". It will be ignored.");
+              }
+            }
+
+          }
+        }
+        else if(keyword.startsWith(LEVEL_KEYWORD))
+        {
+          int levelStart =
+                keyword.indexOf("=", LEVEL_KEYWORD.length());
+
+          if(keyword.length() == LEVEL_KEYWORD.length() ||
+              levelStart != LEVEL_KEYWORD.length())
+          {
+            System.err.println("The keyword " + LEVEL_KEYWORD +
+                " does not contain an equal sign to specify the log level. " +
+                "Default level of " + level.toString() + " will be used.");
+          }
+          else
+          {
+            try
+            {
+              level = LogLevel.parse(keyword.substring(levelStart+1));
+            }
+            catch(IllegalArgumentException iae)
+            {
+              System.err.println("The keyword " + LEVEL_KEYWORD +
+                  " contains an invalid debug log level: " +
+                  iae.toString() + ". Default level of " + level.toString() +
+                  " will be used.");
+            }
+          }
+        }
+
+      }
+      settings = new TraceSettings(level, includeCategories, noArgs, noRetVal,
+                                   stackDepth, includeCause);
+    }
+
+    return settings;
+  }
 }
diff --git a/opends/src/server/org/opends/server/loggers/debug/Tracer.java b/opends/src/server/org/opends/server/loggers/debug/Tracer.java
index 687fc8d..c3f5183 100644
--- a/opends/src/server/org/opends/server/loggers/debug/Tracer.java
+++ b/opends/src/server/org/opends/server/loggers/debug/Tracer.java
@@ -39,6 +39,7 @@
 import org.opends.server.util.ServerConstants;
 import org.opends.server.util.StaticUtils;
 import org.opends.server.api.ProtocolElement;
+import org.opends.server.api.DirectoryThread;
 import org.opends.server.loggers.*;
 import org.opends.server.types.DebugLogCategory;
 import org.opends.server.types.DebugLogLevel;
@@ -53,7 +54,11 @@
  * Logging is always done at a level basis, with debug log messages
  * exceeding the trace threshold being traced, others being discarded.
  */
-@Aspect("pertypewithin(*)")
+@Aspect("pertypewithin(!@Tracer.NoDebugTracing org.opends.server..*+ && " +
+    "!org.opends.server.loggers.*+ && " +
+    "!org.opends.server.loggers.debug..*+ &&" +
+    "!org.opends.server.types.DebugLogLevel+ && " +
+    "!org.opends.server.types.DebugLogCategory+)")
 public class Tracer
 {
   /**
@@ -76,7 +81,7 @@
   /**
    * Pointcut for matching all toString() methods.
    */
-  @Pointcut("execution(String *..toString())")
+  @Pointcut("execution(* *..toString(..))")
   private void toStringMethod()
   {
   }
@@ -91,6 +96,16 @@
   }
 
   /**
+   * Pointcut for matching all getDebugProperties() methods.
+   * TODO: Make this less general. Find out if pointcut matches
+   * subclass methods.
+   */
+  @Pointcut("execution(* *..getDebugProperties(..))")
+  private void getDebugPropertiesMethod()
+  {
+  }
+
+  /**
    * Pointcut for matching debugMessage() methods.
    */
   @Pointcut("call(public static void org.opends.server." +
@@ -194,9 +209,8 @@
    * Pointcut to exclude all pointcuts which should not be adviced by the
    * debug logger.
    */
-  @Pointcut("within(Tracer+) || within(org.opends.server.loggers.debug..*) " +
-      "|| toStringMethod() " +
-      "|| getMessageMethod() || logMethods()")
+  @Pointcut("toStringMethod() || getMessageMethod() || " +
+      "getDebugPropertiesMethod() || logMethods()")
   private void excluded()
   {
   }
@@ -204,16 +218,47 @@
   /**
    * Pointcut for matching the execution of all public methods.
    */
-  @Pointcut("execution(!@NoDebugTracing public * *(..)) && !excluded()")
-  void tracedMethod()
+  @Pointcut("execution(!@(Tracer.NoDebugTracing || " +
+      "Tracer.NoEntryDebugTracing) public * *(..)) && " +
+      "!excluded()")
+  void tracedEntryMethod()
+  {
+  }
+
+  /**
+   * Pointcut for matching the execution of all public methods.
+   */
+  @Pointcut("execution(!@(Tracer.NoDebugTracing || " +
+      "Tracer.NoExitDebugTracing) public * *(..)) && " +
+      "!excluded()")
+  void tracedExitMethod()
+  {
+  }
+
+  /**
+   * Pointcut for matching the execution of all public methods.
+   */
+  @Pointcut("execution(@Tracer.TraceThrown public * *(..)) && " +
+      "!excluded()")
+  void tracedThrownMethod()
   {
   }
 
   /**
    * Pointcut for matching the execution of all constructors.
    */
-  @Pointcut("execution(!@NoDebugTracing public new(..)) && !excluded()")
-  void tracedConstructor()
+  @Pointcut("execution(!@(Tracer.NoDebugTracing || " +
+      "Tracer.NoEntryDebugTracing) public new(..)) && !excluded()")
+  void tracedEntryConstructor()
+  {
+  }
+
+  /**
+   * Pointcut for matching the execution of all constructors.
+   */
+  @Pointcut("execution(!@(Tracer.NoDebugTracing || " +
+      "Tracer.NoExitDebugTracing) public new(..)) && !excluded()")
+  void tracedExitConstructor()
   {
   }
 
@@ -222,19 +267,12 @@
    *
    * @return if debug logging is enabled.
    */
-  @Pointcut("if() && tracingScope()")
+  @Pointcut("if()")
   public static boolean shouldTrace()
   {
-    return DebugLogger.enabled;
+    return DebugLogger.staticEnabled;
   }
 
-  /**
-   * Pointcut for matching only within the scope of the server packages.
-   */
-  @Pointcut("within(!@NoDebugTracing org.opends.server..*)")
-  protected void tracingScope()
-  {
-  }
 
   //The default level to log constructor exectuions.
   private static final LogLevel DEFAULT_CONSTRUCTOR_LEVEL =
@@ -242,6 +280,12 @@
   //The default level to log method entry and exit pointcuts.
   private static final LogLevel DEFAULT_ENTRY_EXIT_LEVEL =
       DebugLogLevel.VERBOSE;
+  //The default level to log method entry and exit pointcuts.
+  private static final LogLevel DEFAULT_THROWN_LEVEL =
+      DebugLogLevel.ERROR;
+
+  private static final DebugMessageFormatter msgFormatter =
+      new DebugMessageFormatter();
 
   // The class this tracer traces.
   private String className;
@@ -258,13 +302,12 @@
    *
    * @param thisJoinPointStaticPart the JoinPoint reflection object.
    */
-  @Before("staticinitialization(*) && tracingScope()")
+  @Before("staticinitialization(*)")
   public void initializeTracer(JoinPoint.StaticPart thisJoinPointStaticPart)
   {
     className = thisJoinPointStaticPart.getSignature().getDeclaringTypeName();
     logger = DebugLogger.getLogger();
     logger.registerTracer(className, this);
-    updateSettings();
   }
 
   /**
@@ -272,7 +315,7 @@
    *
    * @param thisJoinPoint the JoinPoint reflection object.
    */
-  @Before("shouldTrace() && tracedConstructor()")
+  @Before("shouldTrace() && tracedEntryConstructor()")
   public void traceConstructor(JoinPoint thisJoinPoint)
   {
     LogCategory category = DebugLogCategory.CONSTRUCTOR;
@@ -294,7 +337,7 @@
    * @param thisJoinPoint the JoinPoint reflection object.
    * @param obj the object this method operations on.
    */
-  @Before("shouldTrace() && tracedMethod() && nonStaticContext(obj)")
+  @Before("shouldTrace() && tracedEntryMethod() && nonStaticContext(obj)")
   public void traceNonStaticMethodEntry(JoinPoint thisJoinPoint, Object obj)
   {
     LogCategory category = DebugLogCategory.ENTER;
@@ -315,7 +358,7 @@
    *
    * @param thisJoinPoint the JoinPoint reflection object.
    */
-  @Before("shouldTrace() && tracedMethod() && staticContext()")
+  @Before("shouldTrace() && tracedEntryMethod() && staticContext()")
   public void traceStaticMethodEntry(JoinPoint thisJoinPoint)
   {
     LogCategory category = DebugLogCategory.ENTER;
@@ -337,8 +380,8 @@
    * @param thisJoinPointStaticPart the JoinPoint reflection object.
    * @param ret the return value of the method.
    */
-  @AfterReturning(pointcut = "shouldTrace() && tracedMethod() &&" +
-                             "traceConstructor()",
+  @AfterReturning(pointcut = "shouldTrace() && " +
+      "(tracedExitMethod() || tracedExitConstructor())",
                   returning = "ret")
   public void traceReturn(JoinPoint.StaticPart thisJoinPointStaticPart,
                           Object ret)
@@ -359,12 +402,42 @@
   /**
    * AspectJ Implementation.
    *
-   * @param thisEnclosingJoinPointStaticPart the JoinPoint reflection object.
+   * @param thisJoinPointStaticPart the JoinPoint reflection object.
+   * @param ex the exception thrown.
+   */
+  @AfterThrowing(pointcut = "shouldTrace() && tracedThrownMethod()",
+                 throwing = "ex")
+  public void traceThrown(JoinPoint.StaticPart thisJoinPointStaticPart,
+                          Throwable ex)
+  {
+    LogCategory category = DebugLogCategory.THROWN;
+    LogLevel level = DEFAULT_THROWN_LEVEL;
+    Signature signature = thisJoinPointStaticPart.getSignature();
+    TraceSettings settings = getSettings(signature.getName());
+    if (level.intValue() >=
+        getEffectiveLevel(settings, category).intValue())
+    {
+      SourceLocation sl = thisJoinPointStaticPart.getSourceLocation();
+      publish(category, level, signature.toLongString(), sl.toString(),
+              null, null , new Object[]{ex}, settings);
+    }
+  }
+
+  /**
+   * AspectJ Implementation.
+   *
+   * @param thisEnclosingJoinPointStaticPart the JoinPoint reflection object
+   *                                         of the code that contains the
+   *                                         debug call.
+   * @param thisJoinPointStaticPart the JoinPoint reflection object.
    * @param msg message to format and log.
    */
   @Around("shouldTrace() && logVerboseMethod() && args(msg)")
   public void traceVerbose(JoinPoint.EnclosingStaticPart
-                             thisEnclosingJoinPointStaticPart, String msg)
+                             thisEnclosingJoinPointStaticPart,
+                           JoinPoint.StaticPart
+                            thisJoinPointStaticPart,
+                           String msg)
   {
     LogLevel level = DebugLogLevel.VERBOSE;
     LogCategory category = DebugLogCategory.MESSAGE;
@@ -373,7 +446,7 @@
     if (level.intValue() >=
         getEffectiveLevel(settings, category).intValue())
     {
-      SourceLocation sl = thisEnclosingJoinPointStaticPart.getSourceLocation();
+      SourceLocation sl = thisJoinPointStaticPart.getSourceLocation();
       publish(category, level, signature.toLongString(),
               sl.toString(), null, msg, null, settings);
     }
@@ -382,13 +455,18 @@
   /**
    * AspectJ Implementation.
    *
-   * @param thisEnclosingJoinPointStaticPart the JoinPoint reflection object.
+   * @param thisEnclosingJoinPointStaticPart the JoinPoint reflection object
+   *                                         of the code that contains the
+   *                                         debug call.
+   * @param thisJoinPointStaticPart the JoinPoint reflection object.
    * @param msg message to format and log.
    * @param msgArgs arguments to place into the format string.
    */
   @Around("shouldTrace() && logVerboseMethod() && args(msg, msgArgs)")
   public void traceVerbose(JoinPoint.EnclosingStaticPart
                              thisEnclosingJoinPointStaticPart,
+                           JoinPoint.StaticPart
+                            thisJoinPointStaticPart,
                            String msg, Object[] msgArgs)
   {
     LogLevel level = DebugLogLevel.VERBOSE;
@@ -398,7 +476,7 @@
     if (level.intValue() >=
         getEffectiveLevel(settings, category).intValue())
     {
-      SourceLocation sl = thisEnclosingJoinPointStaticPart.getSourceLocation();
+      SourceLocation sl = thisJoinPointStaticPart.getSourceLocation();
       publish(category, level, signature.toLongString(),
               sl.toString(), null, msg, msgArgs, settings);
     }
@@ -407,12 +485,18 @@
   /**
    * AspectJ Implementation.
    *
-   * @param thisEnclosingJoinPointStaticPart the JoinPoint reflection object.
+   * @param thisEnclosingJoinPointStaticPart the JoinPoint reflection object
+   *                                         of the code that contains the
+   *                                         debug call.
+   * @param thisJoinPointStaticPart the JoinPoint reflection object.
    * @param msg message to format and log.
    */
   @Around("shouldTrace() && logInfoMethod() && args(msg)")
   public void traceInfo(JoinPoint.EnclosingStaticPart
-                          thisEnclosingJoinPointStaticPart, String msg)
+                          thisEnclosingJoinPointStaticPart,
+                        JoinPoint.StaticPart
+                            thisJoinPointStaticPart,
+                        String msg)
   {
     LogLevel level = DebugLogLevel.INFO;
     LogCategory category = DebugLogCategory.MESSAGE;
@@ -421,7 +505,7 @@
     if (level.intValue() >=
         getEffectiveLevel(settings, category).intValue())
     {
-      SourceLocation sl = thisEnclosingJoinPointStaticPart.getSourceLocation();
+      SourceLocation sl = thisJoinPointStaticPart.getSourceLocation();
       publish(category, level, signature.toLongString(),
               sl.toString(), null, msg, null, settings);
     }
@@ -430,13 +514,18 @@
   /**
    * AspectJ Implementation.
    *
-   * @param thisEnclosingJoinPointStaticPart the JoinPoint reflection object.
+   * @param thisEnclosingJoinPointStaticPart the JoinPoint reflection object
+   *                                         of the code that contains the
+   *                                         debug call.
+   * @param thisJoinPointStaticPart the JoinPoint reflection object.
    * @param msg message to format and log.
    * @param msgArgs arguments to place into the format string.
    */
   @Around("shouldTrace() && logInfoMethod() && args(msg, msgArgs)")
   public void traceInfo(JoinPoint.EnclosingStaticPart
                           thisEnclosingJoinPointStaticPart,
+                        JoinPoint.StaticPart
+                            thisJoinPointStaticPart,
                         String msg, Object[] msgArgs)
   {
     LogLevel level = DebugLogLevel.INFO;
@@ -446,7 +535,7 @@
     if (level.intValue() >=
         getEffectiveLevel(settings, category).intValue())
     {
-      SourceLocation sl = thisEnclosingJoinPointStaticPart.getSourceLocation();
+      SourceLocation sl = thisJoinPointStaticPart.getSourceLocation();
       publish(category, level, signature.toLongString(),
               sl.toString(), null, msg, msgArgs, settings);
     }
@@ -455,12 +544,18 @@
   /**
    * AspectJ Implementation.
    *
-   * @param thisEnclosingJoinPointStaticPart the JoinPoint reflection object.
+   * @param thisEnclosingJoinPointStaticPart the JoinPoint reflection object
+   *                                         of the code that contains the
+   *                                         debug call.
+   * @param thisJoinPointStaticPart the JoinPoint reflection object.
    * @param msg message to format and log.
    */
   @Around("shouldTrace() && logWarningMethod() && args(msg)")
   public void traceWarning(JoinPoint.EnclosingStaticPart
-                             thisEnclosingJoinPointStaticPart, String msg)
+                             thisEnclosingJoinPointStaticPart,
+                           JoinPoint.StaticPart
+                            thisJoinPointStaticPart,
+                           String msg)
 
   {
     LogLevel level = DebugLogLevel.WARNING;
@@ -470,7 +565,7 @@
     if (level.intValue() >=
         getEffectiveLevel(settings, category).intValue())
     {
-      SourceLocation sl = thisEnclosingJoinPointStaticPart.getSourceLocation();
+      SourceLocation sl = thisJoinPointStaticPart.getSourceLocation();
       publish(category, level, signature.toLongString(),
               sl.toString(), null, msg, null, settings);
     }
@@ -479,13 +574,18 @@
   /**
    * AspectJ Implementation.
    *
-   * @param thisEnclosingJoinPointStaticPart the JoinPoint reflection object.
+   * @param thisEnclosingJoinPointStaticPart the JoinPoint reflection object
+   *                                         of the code that contains the
+   *                                         debug call.
+   * @param thisJoinPointStaticPart the JoinPoint reflection object.
    * @param msg message to format and log.
    * @param msgArgs arguments to place into the format string.
    */
   @Around("shouldTrace() && logWarningMethod() && args(msg, msgArgs)")
   public void traceWarning(JoinPoint.EnclosingStaticPart
                              thisEnclosingJoinPointStaticPart,
+                           JoinPoint.StaticPart
+                            thisJoinPointStaticPart,
                            String msg, Object[] msgArgs)
   {
     LogLevel level = DebugLogLevel.WARNING;
@@ -495,7 +595,7 @@
     if (level.intValue() >=
         getEffectiveLevel(settings, category).intValue())
     {
-      SourceLocation sl = thisEnclosingJoinPointStaticPart.getSourceLocation();
+      SourceLocation sl = thisJoinPointStaticPart.getSourceLocation();
       publish(category, level, signature.toLongString(),
               sl.toString(), null, msg, msgArgs, settings);
     }
@@ -504,12 +604,18 @@
   /**
    * AspectJ Implementation.
    *
-   * @param thisEnclosingJoinPointStaticPart the JoinPoint reflection object.
+   * @param thisEnclosingJoinPointStaticPart the JoinPoint reflection object
+   *                                         of the code that contains the
+   *                                         debug call.
+   * @param thisJoinPointStaticPart the JoinPoint reflection object.
    * @param msg message to format and log.
    */
   @Around("shouldTrace() && logErrorMethod() && args(msg)")
   public void traceError(JoinPoint.EnclosingStaticPart
-                           thisEnclosingJoinPointStaticPart, String msg)
+                           thisEnclosingJoinPointStaticPart,
+                         JoinPoint.StaticPart
+                            thisJoinPointStaticPart,
+                         String msg)
 
   {
     LogLevel level = DebugLogLevel.ERROR;
@@ -519,7 +625,7 @@
     if (level.intValue() >=
         getEffectiveLevel(settings, category).intValue())
     {
-      SourceLocation sl = thisEnclosingJoinPointStaticPart.getSourceLocation();
+      SourceLocation sl = thisJoinPointStaticPart.getSourceLocation();
       publish(category, level, signature.toLongString(),
               sl.toString(), null, msg, null, settings);
     }
@@ -528,13 +634,18 @@
   /**
    * AspectJ Implementation.
    *
-   * @param thisEnclosingJoinPointStaticPart the JoinPoint reflection object.
+   * @param thisEnclosingJoinPointStaticPart the JoinPoint reflection object
+   *                                         of the code that contains the
+   *                                         debug call.
+   * @param thisJoinPointStaticPart the JoinPoint reflection object.
    * @param msg message to format and log.
    * @param msgArgs arguments to place into the format string.
    */
   @Around("shouldTrace() && logErrorMethod() && args(msg, msgArgs)")
   public void traceError(JoinPoint.EnclosingStaticPart
                            thisEnclosingJoinPointStaticPart,
+                         JoinPoint.StaticPart
+                            thisJoinPointStaticPart,
                          String msg, Object[] msgArgs)
   {
     LogLevel level = DebugLogLevel.ERROR;
@@ -544,7 +655,7 @@
     if (level.intValue() >=
         getEffectiveLevel(settings, category).intValue())
     {
-      SourceLocation sl = thisEnclosingJoinPointStaticPart.getSourceLocation();
+      SourceLocation sl = thisJoinPointStaticPart.getSourceLocation();
       publish(category, level, signature.toLongString(),
               sl.toString(), null, msg, msgArgs, settings);
     }
@@ -553,13 +664,18 @@
   /**
    * AspectJ Implementation.
    *
-   * @param thisEnclosingJoinPointStaticPart the JoinPoint reflection object.
+   * @param thisEnclosingJoinPointStaticPart the JoinPoint reflection object
+   *                                         of the code that contains the
+   *                                         debug call.
+   * @param thisJoinPointStaticPart the JoinPoint reflection object.
    * @param level the level of the log message.
    * @param msg message to format and log.
    */
   @Around("shouldTrace() && logMessageMethod() && args(level, msg)")
   public void traceMessage(JoinPoint.EnclosingStaticPart
                              thisEnclosingJoinPointStaticPart,
+                           JoinPoint.StaticPart
+                            thisJoinPointStaticPart,
                            LogLevel level, String msg)
   {
     LogCategory category = DebugLogCategory.MESSAGE;
@@ -568,7 +684,7 @@
     if (level.intValue() >=
         getEffectiveLevel(settings, category).intValue())
     {
-      SourceLocation sl = thisEnclosingJoinPointStaticPart.getSourceLocation();
+      SourceLocation sl = thisJoinPointStaticPart.getSourceLocation();
       publish(category, level, signature.toLongString(), sl.toString(),
               null, msg, null, settings);
     }
@@ -577,7 +693,10 @@
   /**
    * AspectJ Implementation.
    *
-   * @param thisEnclosingJoinPointStaticPart the JoinPoint reflection object.
+   * @param thisEnclosingJoinPointStaticPart the JoinPoint reflection object
+   *                                         of the code that contains the
+   *                                         debug call.
+   * @param thisJoinPointStaticPart the JoinPoint reflection object.
    * @param level the level of the log message.
    * @param msg message to format and log.
    * @param msgArgs arguments to place into the format string.
@@ -585,6 +704,8 @@
   @Around("shouldTrace() && logMessageMethod() && args(level, msg, msgArgs)")
   public void traceMessage(JoinPoint.EnclosingStaticPart
                              thisEnclosingJoinPointStaticPart,
+                           JoinPoint.StaticPart
+                            thisJoinPointStaticPart,
                            LogLevel level, String msg, Object... msgArgs)
   {
     LogCategory category = DebugLogCategory.MESSAGE;
@@ -593,7 +714,7 @@
     if (level.intValue() >=
         getEffectiveLevel(settings, category).intValue())
     {
-      SourceLocation sl = thisEnclosingJoinPointStaticPart.getSourceLocation();
+      SourceLocation sl = thisJoinPointStaticPart.getSourceLocation();
       publish(category, level, signature.toLongString(), sl.toString(),
               null, msg, msgArgs, settings);
     }
@@ -602,13 +723,18 @@
   /**
    * AspectJ Implementation.
    *
-   * @param thisEnclosingJoinPointStaticPart the JoinPoint reflection object.
+   * @param thisEnclosingJoinPointStaticPart the JoinPoint reflection object
+   *                                         of the code that contains the
+   *                                         debug call.
+   * @param thisJoinPointStaticPart the JoinPoint reflection object.
    * @param level the level of the log message.
    * @param ex the exception thrown.
    */
   @Around("shouldTrace() && logThrownMethod() && args(level, ex)")
   public void traceThrown(JoinPoint.EnclosingStaticPart
                             thisEnclosingJoinPointStaticPart,
+                          JoinPoint.StaticPart
+                            thisJoinPointStaticPart,
                           LogLevel level, Throwable ex)
   {
     LogCategory category = DebugLogCategory.THROWN;
@@ -617,7 +743,7 @@
     if (level.intValue() >=
         getEffectiveLevel(settings, category).intValue())
     {
-      SourceLocation sl = thisEnclosingJoinPointStaticPart.getSourceLocation();
+      SourceLocation sl = thisJoinPointStaticPart.getSourceLocation();
       publish(category, level, signature.toLongString(), sl.toString(),
               null, null , new Object[]{ex}, settings);
     }
@@ -626,13 +752,18 @@
   /**
    * AspectJ Implementation.
    *
-   * @param thisEnclosingJoinPointStaticPart the JoinPoint reflection object.
+   * @param thisEnclosingJoinPointStaticPart the JoinPoint reflection object
+   *                                         of the code that contains the
+   *                                         debug call.
+   * @param thisJoinPointStaticPart the JoinPoint reflection object.
    * @param level the level of the log message.
    * @param ex the exception caught.
    */
   @Around("shouldTrace() && logCaughtMethod() && args(level, ex)")
   public void traceCaught(JoinPoint.EnclosingStaticPart
                             thisEnclosingJoinPointStaticPart,
+                          JoinPoint.StaticPart
+                            thisJoinPointStaticPart,
                           LogLevel level, Throwable ex)
   {
     LogCategory category = DebugLogCategory.CAUGHT;
@@ -641,7 +772,7 @@
     if (level.intValue() >=
         getEffectiveLevel(settings, category).intValue())
     {
-      SourceLocation sl = thisEnclosingJoinPointStaticPart.getSourceLocation();
+      SourceLocation sl = thisJoinPointStaticPart.getSourceLocation();
       publish(category, level, signature.toLongString(), sl.toString(),
               null, null , new Object[]{ex}, settings);
     }
@@ -650,7 +781,10 @@
   /**
    * AspectJ Implementation.
    *
-   * @param thisEnclosingJoinPointStaticPart the JoinPoint reflection object.
+   * @param thisEnclosingJoinPointStaticPart the JoinPoint reflection object
+   *                                         of the code that contains the
+   *                                         debug call.
+   * @param thisJoinPointStaticPart the JoinPoint reflection object.
    * @param level the level of the log message.
    * @param status status of the JE operation.
    * @param database the database handle.
@@ -662,6 +796,8 @@
       "database, txn, key, data)")
   public void traceJEAccess(JoinPoint.EnclosingStaticPart
                               thisEnclosingJoinPointStaticPart,
+                            JoinPoint.StaticPart
+                              thisJoinPointStaticPart,
                             LogLevel level, OperationStatus status,
                             Database database, Transaction txn,
                             DatabaseEntry key, DatabaseEntry data)
@@ -704,26 +840,29 @@
         builder.append(" txnid=none");
       }
 
-      // If the operation was successful we log the same common information
-      // plus the key and data under category DATABASE_READ or DATABASE_WRITE
-      if (status == OperationStatus.SUCCESS)
+      builder.append(ServerConstants.EOL);
+      if(key != null)
       {
-        builder.append(ServerConstants.EOL);
-        builder.append(" key:");
+        builder.append("key:");
         builder.append(ServerConstants.EOL);
         StaticUtils.byteArrayToHexPlusAscii(builder, key.getData(), 4);
-        if (data != null)
-        {
-          builder.append("data(len=");
-          builder.append(data.getSize());
-          builder.append("):");
-          builder.append(ServerConstants.EOL);
-          StaticUtils.byteArrayToHexPlusAscii(builder, data.getData(), 4);
-        }
+      }
+
+      // If the operation was successful we log the same common information
+      // plus the data
+      if (status == OperationStatus.SUCCESS && data != null)
+      {
+
+        builder.append("data(len=");
+        builder.append(data.getSize());
+        builder.append("):");
+        builder.append(ServerConstants.EOL);
+        StaticUtils.byteArrayToHexPlusAscii(builder, data.getData(), 4);
+
       }
 
 
-      SourceLocation sl = thisEnclosingJoinPointStaticPart.getSourceLocation();
+      SourceLocation sl = thisJoinPointStaticPart.getSourceLocation();
       publish(category, level, signature.toLongString(), sl.toString(), null,
               builder.toString(), null, settings);
     }
@@ -731,13 +870,18 @@
 
   /**
    * AspectJ Implementation.
-   * @param thisEnclosingJoinPointStaticPart the JoinPoint reflection object.
+   * @param thisEnclosingJoinPointStaticPart the JoinPoint reflection object
+   *                                         of the code that contains the
+   *                                         debug call.
+   * @param thisJoinPointStaticPart the JoinPoint reflection object.
    * @param level the level of the log message.
    * @param data the data to dump.
    */
   @Around("shouldTrace() && logDataMethod() && args(level, data)")
   public void traceData(JoinPoint.EnclosingStaticPart
                           thisEnclosingJoinPointStaticPart,
+                        JoinPoint.StaticPart
+                          thisJoinPointStaticPart,
                         LogLevel level, byte[] data)
   {
     LogCategory category = DebugLogCategory.DATA;
@@ -756,7 +900,7 @@
         builder.append(ServerConstants.EOL);
         StaticUtils.byteArrayToHexPlusAscii(builder, data, 4);
         SourceLocation sl =
-            thisEnclosingJoinPointStaticPart.getSourceLocation();
+            thisJoinPointStaticPart.getSourceLocation();
         publish(category, level, signature.toLongString(), sl.toString(), null,
                 builder.toString(), null, settings);
       }
@@ -766,13 +910,18 @@
   /**
    * AspectJ Implementation.
    *
-   * @param thisEnclosingJoinPointStaticPart the JoinPoint reflection object.
+   * @param thisEnclosingJoinPointStaticPart the JoinPoint reflection object
+   *                                         of the code that contains the
+   *                                         debug call.
+   * @param thisJoinPointStaticPart the JoinPoint reflection object.
    * @param level the level of the log message.
    * @param element the protocol element to dump.
    */
   @Around("shouldTrace() && logProtocolElementMethod() && args(level, element)")
   public void traceProtocolElement(JoinPoint.EnclosingStaticPart
                                      thisEnclosingJoinPointStaticPart,
+                                   JoinPoint.StaticPart
+                                     thisJoinPointStaticPart,
                                    LogLevel level, ProtocolElement element)
   {
     LogCategory category = DebugLogCategory.PROTOCOL;
@@ -787,7 +936,7 @@
         builder.append(ServerConstants.EOL);
         element.toString(builder, 4);
         SourceLocation sl =
-            thisEnclosingJoinPointStaticPart.getSourceLocation();
+            thisJoinPointStaticPart.getSourceLocation();
         publish(category, level, signature.toLongString(), sl.toString(), null,
                 builder.toString(), null, settings);
       }
@@ -797,13 +946,18 @@
   /**
    * AspectJ Implementation.
    *
-   * @param thisEnclosingJoinPointStaticPart the JoinPoint reflection object.
+   * @param thisEnclosingJoinPointStaticPart the JoinPoint reflection object
+   *                                         of the code that contains the
+   *                                         debug call.
+   * @param thisJoinPointStaticPart the JoinPoint reflection object.
    * @param level the level of the log message.
    * @param buffer the data to dump.
    */
   @Around("shouldTrace() && logDataMethod() && args(level, buffer)")
   public void traceData(JoinPoint.EnclosingStaticPart
                           thisEnclosingJoinPointStaticPart,
+                        JoinPoint.StaticPart
+                          thisJoinPointStaticPart,
                         LogLevel level, ByteBuffer buffer)
   {
     LogCategory category = DebugLogCategory.DATA;
@@ -823,7 +977,7 @@
         builder.append(ServerConstants.EOL);
         StaticUtils.byteArrayToHexPlusAscii(builder, data, 4);
         SourceLocation sl =
-            thisEnclosingJoinPointStaticPart.getSourceLocation();
+            thisJoinPointStaticPart.getSourceLocation();
         publish(category, level, signature.toLongString(), sl.toString(), null,
                 builder.toString(), null, settings);
       }
@@ -839,9 +993,10 @@
   {
     int stackDepth = 0;
 
-    if(DebugLogCategory.ENTER.equals(category))
+    if (DebugLogCategory.ENTER.equals(category) ||
+        DebugLogCategory.CONSTRUCTOR.equals(category))
     {
-      if (settings.noArgs)
+      if(settings.noArgs)
       {
         msgArgs = null;
       }
@@ -849,12 +1004,11 @@
       {
         msg = buildDefaultEntryMessage(msgArgs.length);
       }
-
-      stackDepth = settings.stackDepth;
     }
-    if(DebugLogCategory.EXIT.equals(category))
+
+    else if(DebugLogCategory.EXIT.equals(category))
     {
-      if (settings.noRetVal)
+      if(settings.noRetVal)
       {
         msgArgs = null;
       }
@@ -863,18 +1017,26 @@
         msg = "returned={%s}";
       }
     }
-    if(DebugLogCategory.THROWN.equals(category))
+
+    else if(DebugLogCategory.THROWN.equals(category))
     {
-      if (msg == null)
+      if(msg == null)
       {
         msg = "threw={%s}";
       }
-      stackDepth = settings.stackDepth;
+    }
+
+    else if(DebugLogCategory.CAUGHT.equals(category))
+    {
+      if(msg == null)
+      {
+        msg = "caught={%s}";
+      }
     }
 
     if (msg != null && msgArgs != null)
     {
-      msg = String.format(msg, msgArgs);
+      msg = msgFormatter.format(msg, msgArgs);
     }
 
 
@@ -883,21 +1045,25 @@
     record.setSignature(method);
     record.setSourceLocation(srcLocation);
 
+    Thread thread = Thread.currentThread();
+    if(thread instanceof DirectoryThread)
+    {
+      record.setThreadProperties(
+          ((DirectoryThread)thread).getDebugProperties());
+    }
+
+    //Stack trace applies only to entry and thrown exception messages.
+    if(DebugLogCategory.ENTER.equals(category) ||
+        DebugLogCategory.THROWN.equals(category))
+    {
+      stackDepth = settings.stackDepth;
+    }
+
     // Inject a stack trace if requested
     if (stackDepth > 0) {
 
       //Generate a dummy exception to get stack trace if necessary
-      Throwable t;
-      if(!DebugLogCategory.THROWN.equals(category) || msgArgs == null
-          || msgArgs[0] == null)
-      {
-       t= new NullPointerException();
-      }
-      else
-      {
-        t = (Throwable)msgArgs[0];
-      }
-
+      Throwable t= new NullPointerException();
       String stack=
           DebugStackTraceFormatter.formatStackTrace(t,
                                    DebugStackTraceFormatter.SMART_FRAME_FILTER,
@@ -988,15 +1154,15 @@
 
   /**
    * Update the settings for this tracer.
+   *
+   * @param config the new trace configuration.
    */
-  protected void updateSettings()
+  protected void updateSettings(DebugConfiguration config)
   {
     synchronized (this)
     {
-      this.settings =
-          logger.getConfiguration().getTraceSettings(className);
-      this.methodSettings =
-          logger.getConfiguration().getMethodSettings(className);
+      this.settings = config.getTraceSettings(className);
+      this.methodSettings = config.getMethodSettings(className);
     }
   }
 
@@ -1027,4 +1193,28 @@
     return getEffectiveLevel(settings, category);
   }
 
+  /**
+   * Classes and methods annotated with @NoDebugTracing will not be weaved with
+   * debug logging statements by AspectJ.
+   */
+  public @interface NoDebugTracing {}
+
+  /**
+   * Methods annotated with @NoEntryDebugTracing will not be weaved with
+   * entry debug logging statements by AspectJ.
+   */
+  public @interface NoEntryDebugTracing {}
+
+  /**
+   * Methods annotated with @NoExitDebugTracing will not be weaved with
+   * exit debug logging statements by AspectJ.
+   */
+  public @interface NoExitDebugTracing {}
+
+  /**
+   * Methods annotated with @TraceThrown will not be weaved by AspectJ with
+   * debug logging statements when an exception is thrown from the method.
+   */
+  public @interface TraceThrown {}
+
 }
diff --git a/opends/src/server/org/opends/server/types/DebugLogCategory.java b/opends/src/server/org/opends/server/types/DebugLogCategory.java
index b8af073..67171c9 100644
--- a/opends/src/server/org/opends/server/types/DebugLogCategory.java
+++ b/opends/src/server/org/opends/server/types/DebugLogCategory.java
@@ -67,7 +67,7 @@
    * Only logger related classes may use this.
    */
   public static final LogCategory CAUGHT = new DebugLogCategory(
-      DEBUG_CATEGORY_THROWN);
+      DEBUG_CATEGORY_CAUGHT);
 
   /**
    * The log category that will be used for method entry messages.
diff --git a/opends/src/server/org/opends/server/types/FilePermission.java b/opends/src/server/org/opends/server/types/FilePermission.java
index 7ad9cce..ba7c383 100644
--- a/opends/src/server/org/opends/server/types/FilePermission.java
+++ b/opends/src/server/org/opends/server/types/FilePermission.java
@@ -1054,9 +1054,48 @@
    */
   public void toString(StringBuilder buffer)
   {
-    buffer.append("FilePermission(");
-    toUNIXMode(buffer, this);
-    buffer.append(")");
+    buffer.append("Owner=");
+
+    if (isOwnerReadable())
+    {
+      buffer.append("r");
+    }
+    if (isOwnerWritable())
+    {
+      buffer.append("w");
+    }
+    if (isOwnerExecutable())
+    {
+      buffer.append("x");
+    }
+    buffer.append(", Group=");
+
+    if (isGroupReadable())
+    {
+      buffer.append("r");
+    }
+    if (isGroupWritable())
+    {
+      buffer.append("w");
+    }
+    if (isGroupExecutable())
+    {
+      buffer.append("x");
+    }
+    buffer.append(", Other=");
+
+    if (isOtherReadable())
+    {
+      buffer.append("r");
+    }
+    if (isOtherWritable())
+    {
+      buffer.append("w");
+    }
+    if (isOtherExecutable())
+    {
+      buffer.append("x");
+    }
   }
 }
 
diff --git a/opends/src/server/org/opends/server/util/ServerConstants.java b/opends/src/server/org/opends/server/util/ServerConstants.java
index 72b3678..7ceca54 100644
--- a/opends/src/server/org/opends/server/util/ServerConstants.java
+++ b/opends/src/server/org/opends/server/util/ServerConstants.java
@@ -2250,6 +2250,24 @@
 
 
   /**
+   * The name of the system property that can be used to enable or disable
+   * the debug logger on startup.
+   */
+  public static final String PROPERTY_DEBUG_ENABLED =
+      "org.opends.server.debug.enabled";
+
+
+
+  /**
+   * The name of the system property that can be used to specify a target
+   * for the debug logger on startup.
+   */
+  public static final String PROPERTY_DEBUG_TARGET =
+      "org.opends.server.debug.target";
+
+
+
+  /**
    * The column at which to wrap long lines of output in the command-line tools.
    */
   public static final int MAX_LINE_WIDTH = 79;
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/TestCaseUtils.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/TestCaseUtils.java
index c2b72ab..f9bd769 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/TestCaseUtils.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/TestCaseUtils.java
@@ -56,6 +56,9 @@
 import org.opends.server.extensions.ConfigFileHandler;
 import org.opends.server.loggers.Access;
 import org.opends.server.loggers.Error;
+import org.opends.server.loggers.debug.DebugLogFormatter;
+import org.opends.server.loggers.debug.DebugConfiguration;
+import org.opends.server.loggers.debug.DebugLogger;
 import org.opends.server.plugins.InvocationCounterPlugin;
 import org.opends.server.protocols.internal.InternalClientConnection;
 import org.opends.server.types.DN;
@@ -147,6 +150,19 @@
       return;
     }
 
+    String debugTarget = System.getProperty("org.opends.test.debug.target");
+    if(debugTarget != null)
+    {
+      System.setProperty("org.opends.server.debug.target.1", debugTarget);
+    }
+    DebugConfiguration testDebugConfig =
+        DebugConfiguration.getStartupConfiguration();
+    testDebugConfig.removeAllPublishers(true);
+    testDebugConfig.addPublisher(TestListener.DEBUG_LOG_PUBLISHER);
+
+    DebugLogger debugLogger = DebugLogger.getLogger();
+    debugLogger.updateConfiguration(testDebugConfig);
+
     InvocationCounterPlugin.resetStartupCalled();
 
     // Get the build root and use it to create a test package directory.
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/TestListener.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/TestListener.java
index ee14f82..8b45097 100644
--- a/opends/tests/unit-tests-testng/src/server/org/opends/server/TestListener.java
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/TestListener.java
@@ -36,6 +36,12 @@
 import org.testng.xml.XmlSuite;
 import static org.opends.server.util.ServerConstants.EOL;
 import static org.opends.server.TestCaseUtils.originalSystemErr;
+import org.opends.server.loggers.debug.DebugLogFormatter;
+import org.opends.server.loggers.debug.DebugConfiguration;
+import org.opends.server.loggers.debug.TraceSettings;
+import org.opends.server.loggers.debug.DebugLogger;
+import org.opends.server.loggers.LogLevel;
+import org.opends.server.types.DebugLogLevel;
 
 import java.util.List;
 import java.util.LinkedHashMap;
@@ -64,6 +70,12 @@
   // fails, we can do the coverage report before failing the build.
   public static final String ANT_TESTS_FAILED_FILE_NAME = ".tests-failed-marker";
 
+  /**
+   * The Log Publisher for the Debug Logger
+   */
+  public static TestLogPublisher DEBUG_LOG_PUBLISHER =
+      new TestLogPublisher(new DebugLogFormatter());
+
   private static final String DIVIDER_LINE = "-------------------------------------------------------------------------------" + EOL;
 
   public void onStart(ITestContext testContext) {
@@ -173,6 +185,8 @@
     TestErrorLogger.clear();
     TestCaseUtils.clearSystemOutContents();
     TestCaseUtils.clearSystemErrContents();
+
+    DEBUG_LOG_PUBLISHER.clear();
   }
 
 
@@ -231,6 +245,19 @@
       }
     }
 
+    messages = DEBUG_LOG_PUBLISHER.getMessages();
+    if(! messages.isEmpty())
+    {
+      failureInfo.append(EOL);
+      failureInfo.append("Debug Log Messages:");
+      failureInfo.append(EOL);
+      for (String message : messages)
+      {
+        failureInfo.append(message);
+        failureInfo.append(EOL);
+      }
+    }
+
     String systemOut = TestCaseUtils.getSystemOutContents();
     if (systemOut.length() > 0) {
       failureInfo.append(EOL + "System.out contents:" + EOL + systemOut);
diff --git a/opends/tests/unit-tests-testng/src/server/org/opends/server/TestLogPublisher.java b/opends/tests/unit-tests-testng/src/server/org/opends/server/TestLogPublisher.java
new file mode 100644
index 0000000..aeb3c84
--- /dev/null
+++ b/opends/tests/unit-tests-testng/src/server/org/opends/server/TestLogPublisher.java
@@ -0,0 +1,99 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License").  You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE
+ * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at
+ * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
+ * add the following below this CDDL HEADER, with the fields enclosed
+ * by brackets "[]" replaced with your own identifying information:
+ *      Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ *
+ *
+ *      Portions Copyright 2006-2007 Sun Microsystems, Inc.
+ */
+package org.opends.server;
+
+import org.opends.server.api.LogPublisher;
+import org.opends.server.loggers.LoggerErrorHandler;
+import org.opends.server.loggers.TextLogFormatter;
+import org.opends.server.loggers.LogRecord;
+
+import java.util.LinkedList;
+import java.util.List;
+import java.util.ArrayList;
+
+/**
+ * This class provides an implementation of an log publisher which will store
+ * all messages logged in memory.  It provides methods to retrieve and clear the
+ * sets of accumulated log messages.  It is only intended for use in the context
+ * of the unit test framework, where it will provide a means of getting any
+ * log messages associated with failed test cases.
+ */
+public class TestLogPublisher implements LogPublisher
+{
+  private TextLogFormatter formatter;
+
+  // The list that will hold the messages logged.
+  private final LinkedList<String> messageList;
+
+  public TestLogPublisher(TextLogFormatter formatter)
+  {
+    this.messageList = new LinkedList<String>();
+    this.formatter = formatter;
+  }
+
+  public synchronized void publish(LogRecord record,
+                                   LoggerErrorHandler handler)
+  {
+    try
+    {
+      messageList.add(formatter.format(record));
+    }
+    catch(Throwable t)
+    {
+      if(handler != null)
+      {
+        handler.handleError(record, t);
+      }
+    }
+  }
+
+  public synchronized void shutdown()
+  {
+    messageList.clear();
+  }
+
+  /**
+   * Retrieves a copy of the set of messages logged to this error logger since
+   * the last time it was cleared.  A copy of the list is returned to avoid
+   * a ConcurrentModificationException.
+   *
+   * @return  The set of messages logged to this error logger since the last
+   *          time it was cleared.
+   */
+  public synchronized List<String> getMessages()
+  {
+      return new ArrayList<String>(messageList);
+  }
+
+  /**
+   * Clears any messages currently stored by this logger.
+   */
+  public synchronized void clear()
+  {
+    messageList.clear();
+  }
+}

--
Gitblit v1.10.0