From d755882f59202fe62b2ad5a141b3c044c1898aa6 Mon Sep 17 00:00:00 2001
From: boli <boli@localhost>
Date: Thu, 03 May 2007 21:55:23 +0000
Subject: [PATCH] Major changes made to the logging framework. It should resolve the following issues:
---
opends/src/server/org/opends/server/loggers/debug/DebugLogger.java | 528 +++++++++++++++++++++++++++++++++++++++++++++++++++-------
1 files changed, 464 insertions(+), 64 deletions(-)
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 f00b353..2c203a9 100644
--- a/opends/src/server/org/opends/server/loggers/debug/DebugLogger.java
+++ b/opends/src/server/org/opends/server/loggers/debug/DebugLogger.java
@@ -22,22 +22,38 @@
* CDDL HEADER END
*
*
- * Portions Copyright 2006-2007 Sun Microsystems, Inc.
+ * Portions Copyright 2007 Sun Microsystems, Inc.
*/
+
package org.opends.server.loggers.debug;
-import org.opends.server.api.ProtocolElement;
-import org.opends.server.loggers.Logger;
-import org.opends.server.loggers.LogLevel;
-
-import java.util.Map;
-import java.util.HashMap;
+import java.util.*;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.CopyOnWriteArraySet;
import java.nio.ByteBuffer;
+import java.lang.reflect.Method;
+import java.lang.reflect.InvocationTargetException;
-import com.sleepycat.je.OperationStatus;
-import com.sleepycat.je.Database;
-import com.sleepycat.je.Transaction;
-import com.sleepycat.je.DatabaseEntry;
+import org.opends.server.api.ProtocolElement;
+import org.opends.server.api.DebugLogPublisher;
+import org.opends.server.loggers.*;
+import org.opends.server.types.*;
+import org.opends.server.util.DynamicConstants;
+import org.opends.server.util.StaticUtils;
+import org.opends.server.admin.std.server.DebugLogPublisherCfg;
+import org.opends.server.admin.std.meta.DebugLogPublisherCfgDefn;
+import org.opends.server.admin.server.ConfigurationAddListener;
+import org.opends.server.admin.server.ConfigurationChangeListener;
+import org.opends.server.admin.server.ConfigurationDeleteListener;
+import org.opends.server.admin.ClassPropertyDefinition;
+import org.opends.server.config.ConfigException;
+import org.opends.server.core.DirectoryServer;
+
+import static org.opends.server.messages.MessageHandler.getMessage;
+import static org.opends.server.messages.ConfigMessages.*;
+import static org.opends.server.util.StaticUtils.*;
+
+import com.sleepycat.je.*;
/**
* A logger for debug and trace logging. DebugLogger provides a debugging
@@ -51,85 +67,446 @@
*
* DebugLogger is self-initializing.
*/
-public class DebugLogger extends Logger
+public class DebugLogger implements
+ ConfigurationAddListener<DebugLogPublisherCfg>,
+ ConfigurationDeleteListener<DebugLogPublisherCfg>,
+ ConfigurationChangeListener<DebugLogPublisherCfg>
{
- private static DebugLogger logger = null;
- static boolean staticEnabled = false;
+ //The default level to log constructor exectuions.
+ static final LogLevel DEFAULT_CONSTRUCTOR_LEVEL =
+ DebugLogLevel.VERBOSE;
+ //The default level to log method entry and exit pointcuts.
+ static final LogLevel DEFAULT_ENTRY_EXIT_LEVEL =
+ DebugLogLevel.VERBOSE;
+ //The default level to log method entry and exit pointcuts.
+ static final LogLevel DEFAULT_THROWN_LEVEL =
+ DebugLogLevel.ERROR;
- private Map<String, Tracer> classTracers;
+ // The set of all DebugTracer aspect instances.
+ static CopyOnWriteArraySet<DebugTracer> classTracers =
+ new CopyOnWriteArraySet<DebugTracer>();
- private DebugConfiguration configuration;
+ // The set of debug loggers that have been registered with the server. It
+ // will initially be empty.
+ static ConcurrentHashMap<DN,
+ DebugLogPublisher> debugPublishers =
+ new ConcurrentHashMap<DN,
+ DebugLogPublisher>();
- private DebugLogger(DebugConfiguration config)
+ // Trace methods will use this static boolean to determine if debug is
+ // enabled so to not incur the cost of calling debugPublishers.isEmtpty().
+ static boolean enabled = false;
+
+ // The singleton instance of this class for configuration purposes.
+ static final DebugLogger instance = new DebugLogger();
+
+ static
{
- super(config);
- configuration = config;
- classTracers = new HashMap<String, Tracer>();
- staticEnabled = enabled;
+ // Install the startup publishers if necessary until the config kicks in and
+ // adds the real publishers.
+
+ if(DynamicConstants.WEAVE_ENABLED)
+ {
+ try
+ {
+ TextDebugLogPublisher startupDebugPublisher =
+ TextDebugLogPublisher.getStartupTextDebugPublisher(
+ new TextWriter.STDOUT());
+
+ debugPublishers.put(DN.NULL_DN,
+ startupDebugPublisher);
+ enabled = true;
+
+ // Update all existing aspect instances
+ addTracerSettings(startupDebugPublisher);
+ }
+ catch(Exception e)
+ {
+ System.err.println("Error installing the startup debug logger: " +
+ StaticUtils.stackTraceToSingleLineString(e));
+ }
+ }
}
+ /**
+ * Add an debug log publisher to the debug logger.
+ *
+ * @param dn The DN of the configuration entry for the publisher.
+ * @param publisher The error log publisher to add.
+ */
+ public synchronized static void addDebugLogPublisher(DN dn,
+ DebugLogPublisher publisher)
+ {
+ debugPublishers.put(dn, publisher);
+ enabled = DynamicConstants.WEAVE_ENABLED;
+ }
/**
- * Obtain the trace logger singleton.
- * @return the trace logger singleton.
+ * Remove an debug log publisher from the debug logger.
+ *
+ * @param dn The DN of the publisher to remove.
+ * @return The publisher that was removed or null if it was not found.
*/
- public static synchronized DebugLogger getLogger()
+ public synchronized static DebugLogPublisher removeDebugLogPublisher(DN dn)
{
- if (logger == null) {
- /**
- * 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());
+ DebugLogPublisher removed = debugPublishers.remove(dn);
+
+ if(removed != null)
+ {
+ removed.close();
}
- return logger;
+ if(debugPublishers.isEmpty())
+ {
+ enabled = false;
+ }
+
+ return removed;
}
/**
- * Obtain the status of this logger singleton.
+ * Removes all existing debug log publishers from the logger.
+ */
+ public synchronized static void removeAllDebugLogPublishers()
+ {
+ for(DebugLogPublisher publisher : debugPublishers.values())
+ {
+ publisher.close();
+ }
+
+ debugPublishers.clear();
+
+ enabled = false;
+ }
+
+ /**
+ * Initializes all the debug log publishers.
*
- * @return the status of this logger.
+ * @param configs The debug log publisher configurations.
+ * @throws ConfigException
+ * If an unrecoverable problem arises in the process of
+ * performing the initialization as a result of the server
+ * configuration.
+ * @throws InitializationException
+ * If a problem occurs during initialization that is not
+ * related to the server configuration.
+ */
+ public void initializeDebugLogger(List<DebugLogPublisherCfg> configs)
+ throws ConfigException, InitializationException
+ {
+ for(DebugLogPublisherCfg config : configs)
+ {
+ config.addDebugChangeListener(this);
+
+ if(config.isEnabled())
+ {
+ DebugLogPublisher debugLogPublisher = getDebugPublisher(config);
+
+ addDebugLogPublisher(config.dn(), debugLogPublisher);
+
+ // Update all existing aspect instances
+ addTracerSettings(debugLogPublisher);
+ }
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean isConfigurationAddAcceptable(DebugLogPublisherCfg config,
+ List<String> unacceptableReasons)
+ {
+ return !config.isEnabled() ||
+ isJavaClassAcceptable(config, unacceptableReasons);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean isConfigurationChangeAcceptable(DebugLogPublisherCfg config,
+ List<String> unacceptableReasons)
+ {
+ return !config.isEnabled() ||
+ isJavaClassAcceptable(config, unacceptableReasons);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public ConfigChangeResult applyConfigurationAdd(DebugLogPublisherCfg config)
+ {
+ // Default result code.
+ ResultCode resultCode = ResultCode.SUCCESS;
+ boolean adminActionRequired = false;
+ ArrayList<String> messages = new ArrayList<String>();
+
+ config.addDebugChangeListener(this);
+
+ if(config.isEnabled())
+ {
+ try
+ {
+ DebugLogPublisher debugLogPublisher =
+ getDebugPublisher(config);
+
+ addDebugLogPublisher(config.dn(), debugLogPublisher);
+
+ addTracerSettings(debugLogPublisher);
+ }
+ catch(ConfigException e)
+ {
+ if (debugEnabled())
+ {
+ debugCaught(DebugLogLevel.ERROR, e);
+ }
+ messages.add(e.getMessage());
+ resultCode = DirectoryServer.getServerErrorResultCode();
+ }
+ catch (Exception e)
+ {
+ if (debugEnabled())
+ {
+ debugCaught(DebugLogLevel.ERROR, e);
+ }
+ int msgID = MSGID_CONFIG_LOGGER_CANNOT_CREATE_LOGGER;
+ messages.add(getMessage(msgID, String.valueOf(config.dn().toString()),
+ stackTraceToSingleLineString(e)));
+ resultCode = DirectoryServer.getServerErrorResultCode();
+ }
+ }
+ return new ConfigChangeResult(resultCode, adminActionRequired, messages);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public ConfigChangeResult applyConfigurationChange(
+ DebugLogPublisherCfg config)
+ {
+ // Default result code.
+ ResultCode resultCode = ResultCode.SUCCESS;
+ boolean adminActionRequired = false;
+ ArrayList<String> messages = new ArrayList<String>();
+
+ DN dn = config.dn();
+ DebugLogPublisher debugLogPublisher = debugPublishers.get(dn);
+
+ if(debugLogPublisher == null)
+ {
+ if(config.isEnabled())
+ {
+ // Needs to be added and enabled.
+ return applyConfigurationAdd(config);
+ }
+ }
+ else
+ {
+ if(config.isEnabled())
+ {
+ // The publisher is currently active, so we don't need to do anything.
+ // Changes to the class name cannot be
+ // applied dynamically, so if the class name did change then
+ // indicate that administrative action is required for that
+ // change to take effect.
+ String className = config.getJavaImplementationClass();
+ if(!className.equals(debugLogPublisher.getClass().getName()))
+ {
+ adminActionRequired = true;
+ }
+ }
+ else
+ {
+ // The publisher is being disabled so shut down and remove.
+ removeTracerSettings(debugLogPublisher);
+ removeDebugLogPublisher(config.dn());
+ }
+ }
+
+ return new ConfigChangeResult(resultCode, adminActionRequired, messages);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public boolean isConfigurationDeleteAcceptable(DebugLogPublisherCfg config,
+ List<String> unacceptableReasons)
+ {
+ DN dn = config.dn();
+ DebugLogPublisher debugLogPublisher = debugPublishers.get(dn);
+ return debugLogPublisher != null;
+
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public ConfigChangeResult
+ applyConfigurationDelete(DebugLogPublisherCfg config)
+ {
+ // Default result code.
+ ResultCode resultCode = ResultCode.SUCCESS;
+ boolean adminActionRequired = false;
+
+ DebugLogPublisher publisher = removeDebugLogPublisher(config.dn());
+ if(publisher != null)
+ {
+ removeTracerSettings(publisher);
+ }
+
+ return new ConfigChangeResult(resultCode, adminActionRequired);
+ }
+
+ private boolean isJavaClassAcceptable(DebugLogPublisherCfg config,
+ List<String> unacceptableReasons)
+ {
+ String className = config.getJavaImplementationClass();
+ DebugLogPublisherCfgDefn d = DebugLogPublisherCfgDefn.getInstance();
+ ClassPropertyDefinition pd =
+ d.getJavaImplementationClassPropertyDefinition();
+ // Load the class and cast it to a DebugLogPublisher.
+ Class<? extends DebugLogPublisher> theClass;
+ try {
+ theClass = pd.loadClass(className, DebugLogPublisher.class);
+ theClass.newInstance();
+ } catch (Exception e) {
+ int msgID = MSGID_CONFIG_LOGGER_INVALID_DEBUG_LOGGER_CLASS;
+ String message = getMessage(msgID, className,
+ config.dn().toString(),
+ String.valueOf(e));
+ unacceptableReasons.add(message);
+ return false;
+ }
+ // Check that the implementation class implements the correct interface.
+ try {
+ // Determine the initialization method to use: it must take a
+ // single parameter which is the exact type of the configuration
+ // object.
+ theClass.getMethod("initializeDebugLogPublisher", config.definition()
+ .getServerConfigurationClass());
+ } catch (Exception e) {
+ int msgID = MSGID_CONFIG_LOGGER_INVALID_DEBUG_LOGGER_CLASS;
+ String message = getMessage(msgID, className,
+ config.dn().toString(),
+ String.valueOf(e));
+ unacceptableReasons.add(message);
+ return false;
+ }
+ // The class is valid as far as we can tell.
+ return true;
+ }
+
+ private DebugLogPublisher getDebugPublisher(DebugLogPublisherCfg config)
+ throws ConfigException {
+ String className = config.getJavaImplementationClass();
+ DebugLogPublisherCfgDefn d = DebugLogPublisherCfgDefn.getInstance();
+ ClassPropertyDefinition pd =
+ d.getJavaImplementationClassPropertyDefinition();
+ // Load the class and cast it to a DebugLogPublisher.
+ Class<? extends DebugLogPublisher> theClass;
+ DebugLogPublisher debugLogPublisher;
+ try {
+ theClass = pd.loadClass(className, DebugLogPublisher.class);
+ debugLogPublisher = theClass.newInstance();
+
+ // Determine the initialization method to use: it must take a
+ // single parameter which is the exact type of the configuration
+ // object.
+ Method method = theClass.getMethod("initializeDebugLogPublisher",
+ config.definition().getServerConfigurationClass());
+ method.invoke(debugLogPublisher, config);
+ }
+ catch (InvocationTargetException ite)
+ {
+ // Rethrow the exceptions thrown be the invoked method.
+ Throwable e = ite.getTargetException();
+ int msgID = MSGID_CONFIG_LOGGER_INVALID_DEBUG_LOGGER_CLASS;
+ String message = getMessage(msgID, className,
+ config.dn().toString(),
+ stackTraceToSingleLineString(e));
+ throw new ConfigException(msgID, message, e);
+ }
+ catch (Exception e)
+ {
+ int msgID = MSGID_CONFIG_LOGGER_INVALID_DEBUG_LOGGER_CLASS;
+ String message = getMessage(msgID, className,
+ config.dn().toString(),
+ String.valueOf(e));
+ throw new ConfigException(msgID, message, e);
+ }
+
+ // The debug publisher has been successfully initialized.
+ return debugLogPublisher;
+ }
+
+ /**
+ * Adds the settings for the provided publisher in all existing tracers.
+ * If existing settings exist for the given publisher, it will be updated
+ * with the new settings.
+ *
+ * @param publisher The debug log publisher with the new settings.
+ */
+ @SuppressWarnings("unchecked")
+ public static void addTracerSettings(DebugLogPublisher publisher)
+ {
+ // Make sure this publisher is still registered with us. If not, don't
+ // use its settings.
+ if(debugPublishers.contains(publisher))
+ {
+ for(DebugTracer tracer : classTracers)
+ {
+ tracer.classSettings.put(publisher,
+ publisher.getClassSettings(tracer.className));
+
+ // For some reason, the compiler doesn't see that
+ // debugLogPublihser.getMethodSettings returns a parameterized Map.
+ // This problem goes away if a parameterized verson of
+ // DebugLogPublisher is used. However, we can't not use reflection to
+ // instantiate a generic
+ // DebugLogPublisher<? extends DebugLogPublisherCfg> type. The only
+ // thing we can do is to just suppress the compiler warnings.
+ Map<String, TraceSettings> methodSettings =
+ publisher.getMethodSettings(tracer.className);
+ if(methodSettings != null)
+ {
+ tracer.methodSettings.put(publisher, methodSettings);
+ }
+ }
+ }
+ }
+
+ /**
+ * Removes the settings for the provided publisher in all existing tracers.
+ *
+ * @param publisher The debug log publisher to remove.
+ */
+ public static void removeTracerSettings(DebugLogPublisher publisher)
+ {
+ for(DebugTracer tracer : classTracers)
+ {
+ tracer.classSettings.remove(publisher);
+ tracer.methodSettings.remove(publisher);
+ }
+ }
+
+
+ /**
+ * Indicates if debug logging is enabled.
+ *
+ * @return True if debug logging is enabled. False otherwise.
*/
public static boolean debugEnabled()
{
- return staticEnabled;
+ return enabled;
}
/**
- * Register a trace logger for the specified class.
- * @param className - the class for which to register the tracer under.
- * @param tracer - the tracer object to register.
- */
- public synchronized void registerTracer(String className,
- Tracer tracer)
- {
- Tracer traceLogger = classTracers.get(className);
- if (traceLogger == null) {
- classTracers.put(className, tracer);
- tracer.updateSettings(this.configuration);
- }
- }
-
- /**
- * Update the tracing configuration of the debug logger with the specified
- * trace configuration.
+ * Retrieve the singleton instance of this class.
*
- * @param config the new configuration to apply.
+ * @return The singleton instance of this logger.
*/
- public synchronized void updateConfiguration(DebugConfiguration config)
+ public static DebugLogger getInstance()
{
- super.updateConfiguration(config);
- staticEnabled = enabled;
-
- for(Tracer tracer : classTracers.values())
- {
- tracer.updateSettings(config);
- }
-
- this.configuration = config;
+ return instance;
}
/**
@@ -305,5 +682,28 @@
ProtocolElement element) {}
+ /**
+ * 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 be weaved by AspectJ with
+ * debug logging statements when an exception is thrown from the method.
+ */
+ public @interface TraceThrown {}
}
--
Gitblit v1.10.0