/*
* 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 Sun Microsystems, Inc.
*/
package org.opends.server.loggers;
import java.io.PrintWriter;
import java.nio.ByteBuffer;
import java.util.HashMap;
import java.util.HashSet;
import java.util.StringTokenizer;
import org.opends.server.api.DebugLogger;
import org.opends.server.api.ProtocolElement;
import org.opends.server.config.ConfigEntry;
import org.opends.server.types.DebugLogCategory;
import org.opends.server.types.DebugLogSeverity;
import org.opends.server.util.TimeThread;
import static org.opends.server.util.ServerConstants.*;
import static org.opends.server.util.StaticUtils.*;
/**
* This class defines a Directory Server debug logger that will be used only
* during startup. It makes it possible for informational, warning, and error
* messages to be generated during startup and made available to the user for
* things that happen before the configuration can be parsed and all of the
* actual debug loggers instantiated and registered. This debug logger will be
* taken out of service once the startup is complete.
*
* By default, errors and warnings will be logged. This can be modified on a
* per-category basis using a "DS_DEBUG_LEVEL" environment variable that should
* be a semicolon-delimited list in which each element in that list should
* contain the name of the category, an equal sign, and a comma-delimited list
* of the severity levels to use for that category.
*/
public class StartupDebugLogger
extends DebugLogger
{
/**
* The name of the environment variable that may be used to alter the kinds of
* messages that get logged with this startup debug logger.
*/
public static final String ENV_VARIABLE_DEBUG_LOG_LEVEL = "DS_DEBUG_LEVEL";
// The hash map that will be used to define specific log severities for the
// various categories.
private HashMap> definedSeverities;
// The set of default log severities that will be used if no custom severities
// have been defined for the associated category.
private HashSet defaultSeverities;
// The writer that will be used to actually write the messages.
private PrintWriter writer;
/**
* Creates a new instance of this startup debug logger. It does not actually
* do anything, since all initialization is performed in the
* initializeDebugLogger method.
*/
public StartupDebugLogger()
{
super();
}
/**
* Initializes this debug logger based on the information in the provided
* configuration entry.
*
* @param configEntry The configuration entry that contains the information
* to use to initialize this debug logger.
*/
public void initializeDebugLogger(ConfigEntry configEntry)
{
writer = new PrintWriter(System.err, true);
defaultSeverities = new HashSet();
defaultSeverities.add(DebugLogSeverity.ERROR);
defaultSeverities.add(DebugLogSeverity.WARNING);
definedSeverities =
new HashMap>();
String logLevelInfo = System.getenv(ENV_VARIABLE_DEBUG_LOG_LEVEL);
if (logLevelInfo != null)
{
StringTokenizer tokenizer = new StringTokenizer(logLevelInfo, ";");
while (tokenizer.hasMoreTokens())
{
String token = tokenizer.nextToken();
int equalPos = token.indexOf('=');
if (equalPos < 0)
{
writer.println("StartupDebugLogger: Token \"" + token +
"\" read from environment variable " +
ENV_VARIABLE_DEBUG_LOG_LEVEL + " does not contain " +
"an equal sign to separate the category from the " +
"severity list. It will be ignored");
continue;
}
String categoryName = token.substring(0, equalPos);
DebugLogCategory category = DebugLogCategory.getByName(categoryName);
if (category == null)
{
writer.println("StartupDebugLogger: Unknown debug log category \"" +
categoryName + "\" read from environment variable " +
ENV_VARIABLE_DEBUG_LOG_LEVEL + " will be ignored.");
continue;
}
HashSet severities = new HashSet();
StringTokenizer sevTokenizer =
new StringTokenizer(token.substring(equalPos+1), ",");
while (sevTokenizer.hasMoreElements())
{
String severityName = sevTokenizer.nextToken();
DebugLogSeverity severity = DebugLogSeverity.getByName(severityName);
if (severity == null)
{
writer.println("StartupDebugLogger: Unknown debug log severity " +
"\"" + severityName + "\" read from environment " +
"variable " + ENV_VARIABLE_DEBUG_LOG_LEVEL +
" will be ignored.");
continue;
}
else
{
severities.add(severity);
}
}
definedSeverities.put(category, severities);
}
}
}
/**
* Closes this debug logger and releases any resources it might have held.
*/
public void closeDebugLogger()
{
// No action is required, and this logger will remain usable.
}
/**
* Writes a message to the debug logger indicating that the specified raw data
* was read.
*
* @param className The fully-qualified name of the Java class in which the
* data was read.
* @param methodName The name of the method in which the data was read.
* @param buffer The byte buffer containing the data that has been read.
* The byte buffer must be in the same state when this
* method returns as when it was entered.
*/
public void debugBytesRead(String className, String methodName,
ByteBuffer buffer)
{
HashSet severities =
definedSeverities.get(DebugLogCategory.DATA_READ);
if (severities == null)
{
severities = defaultSeverities;
}
if (severities.contains(DebugLogSeverity.COMMUNICATION))
{
StringBuilder msg = new StringBuilder();
msg.append('[');
msg.append(TimeThread.getLocalTime());
msg.append("] category=" + DEBUG_CATEGORY_DATA_READ + ", data:" + EOL);
byteArrayToHexPlusAscii(msg, buffer, 5);
writer.println(msg.toString());
}
}
/**
* Writes a message to the debug logger indicating that the specified raw data
* was written.
*
* @param className The fully-qualified name of the Java class in which the
* data was written.
* @param methodName The name of the method in which the data was written.
* @param buffer The byte buffer containing the data that has been
* written. The byte buffer must be in the same state
* when this method returns as when it was entered.
*/
public void debugBytesWritten(String className, String methodName,
ByteBuffer buffer)
{
HashSet severities =
definedSeverities.get(DebugLogCategory.DATA_WRITE);
if (severities == null)
{
severities = defaultSeverities;
}
if (severities.contains(DebugLogSeverity.COMMUNICATION))
{
StringBuilder msg = new StringBuilder();
msg.append('[');
msg.append(TimeThread.getLocalTime());
msg.append("] category=" + DEBUG_CATEGORY_DATA_WRITE + ", data:" + EOL);
byteArrayToHexPlusAscii(msg, buffer, 5);
writer.println(msg.toString());
}
}
/**
* Writes a message to the debug logger indicating that the constructor for
* the specified class has been invoked.
*
* @param className The fully-qualified name of the Java class whose
* constructor has been invoked.
* @param args The set of arguments provided for the constructor.
*/
public void debugConstructor(String className, String... args)
{
HashSet severities =
definedSeverities.get(DebugLogCategory.CONSTRUCTOR);
if (severities == null)
{
severities = defaultSeverities;
}
if (severities.contains(DebugLogSeverity.INFO))
{
StringBuilder msg = new StringBuilder();
msg.append('[');
msg.append(TimeThread.getLocalTime());
msg.append("] category=" + DEBUG_CATEGORY_CONSTRUCTOR + " - ");
msg.append(className);
msg.append("(");
switch (args.length)
{
case 0:
// No action required;
break;
case 1:
msg.append(args[0]);
break;
default:
msg.append(args[0]);
for (int i=1; i < args.length; i++)
{
msg.append(",");
msg.append(args[i]);
}
break;
}
msg.append(")");
writer.println(msg.toString());
}
}
/**
* Writes a message to the debug logger indicating that the specified method
* has been entered.
*
* @param className The fully-qualified name of the Java class in which the
* specified method resides.
* @param methodName The name of the method that has been entered.
* @param args The set of arguments provided to the method.
*/
public void debugEnter(String className, String methodName, String... args)
{
HashSet severities =
definedSeverities.get(DebugLogCategory.METHOD_ENTER);
if (severities == null)
{
severities = defaultSeverities;
}
if (severities.contains(DebugLogSeverity.INFO))
{
StringBuilder msg = new StringBuilder();
msg.append('[');
msg.append(TimeThread.getLocalTime());
msg.append("] category=" + DEBUG_CATEGORY_ENTER + " - ");
msg.append(className);
msg.append(".");
msg.append(methodName);
msg.append("(");
switch (args.length)
{
case 0:
// No action required;
break;
case 1:
msg.append(args[0]);
break;
default:
msg.append(args[0]);
for (int i=1; i < args.length; i++)
{
msg.append(",");
msg.append(args[i]);
}
break;
}
msg.append(")");
writer.println(msg.toString());
}
}
/**
* Writes a generic message to the debug logger using the provided
* information.
*
* @param category The category associated with this debug message.
* @param severity The severity associated with this debug message.
* @param className The fully-qualified name of the Java class in which the
* debug message was generated.
* @param methodName The name of the method in which the debug message was
* generated.
* @param message The actual contents of the debug message.
*/
public void debugMessage(DebugLogCategory category, DebugLogSeverity severity,
String className, String methodName, String message)
{
HashSet severities = definedSeverities.get(category);
if (severities == null)
{
severities = defaultSeverities;
}
if (severities.contains(severity))
{
StringBuilder msg = new StringBuilder();
msg.append('[');
msg.append(TimeThread.getLocalTime());
msg.append("] category=");
msg.append(category.getCategoryName());
msg.append(", severity=");
msg.append(severity.getSeverityName());
msg.append(", class=");
msg.append(className);
msg.append(", method=");
msg.append(methodName);
msg.append(", msg=\"");
msg.append(message);
msg.append("\"");
writer.println(msg);
}
}
/**
* Writes a message to the debug logger containing information from the
* provided exception that was thrown.
*
* @param className The fully-qualified name of the Java class in which the
* exception was thrown.
* @param methodName The name of the method in which the exception was
* thrown.
* @param exception The exception that was thrown.
*/
public void debugException(String className, String methodName,
Throwable exception)
{
HashSet severities =
definedSeverities.get(DebugLogCategory.EXCEPTION);
if (severities == null)
{
severities = defaultSeverities;
}
if (severities.contains(DebugLogSeverity.ERROR))
{
StringBuilder msg = new StringBuilder();
msg.append('[');
msg.append(TimeThread.getLocalTime());
msg.append("] category=" + DEBUG_CATEGORY_EXCEPTION + ", class=");
msg.append(className);
msg.append(", method=");
msg.append(methodName);
msg.append(", trace:" + EOL);
stackTraceToString(msg, exception);
writer.println(msg);
}
}
/**
* Writes a message to the debug logger indicating that the provided protocol
* element has been read.
*
* @param className The fully-qualified name of the Java class in
* which the protocol element was read.
* @param methodName The name of the method in which the protocol
* element was read.
* @param protocolElement The protocol element that was read.
*/
public void debugProtocolElementRead(String className, String methodName,
ProtocolElement protocolElement)
{
HashSet severities =
definedSeverities.get(DebugLogCategory.PROTOCOL_READ);
if (severities == null)
{
severities = defaultSeverities;
}
if (severities.contains(DebugLogSeverity.COMMUNICATION))
{
StringBuilder msg = new StringBuilder();
msg.append('[');
msg.append(TimeThread.getLocalTime());
msg.append("] category=" + DEBUG_CATEGORY_PROTOCOL_READ +
", element:" + EOL);
protocolElement.toString(msg, 5);
writer.println(msg.toString());
}
}
/**
* Writes a message to the debug logger indicating that the provided protocol
* element has been written.
*
* @param className The fully-qualified name of the Java class in
* which the protocol element was written.
* @param methodName The name of the method in which the protocol
* element was written.
* @param protocolElement The protocol element that was written.
*/
public void debugProtocolElementWritten(String className, String methodName,
ProtocolElement protocolElement)
{
HashSet severities =
definedSeverities.get(DebugLogCategory.PROTOCOL_WRITE);
if (severities == null)
{
severities = defaultSeverities;
}
if (severities.contains(DebugLogSeverity.COMMUNICATION))
{
StringBuilder msg = new StringBuilder();
msg.append('[');
msg.append(TimeThread.getLocalTime());
msg.append("] category=" + DEBUG_CATEGORY_PROTOCOL_WRITE+
", element:" + EOL);
protocolElement.toString(msg, 5);
writer.println(msg.toString());
}
}
/**
* Indicates whether the provided object is equal to this debug logger.
*
* @param o The object for which to make the determination.
*
* @return true if the provided object is determined to be equal
* to this debug logger, or false if not.
*/
public boolean equals(Object o)
{
if (this == o)
{
return true;
}
if ((o == null) || (! (o instanceof StartupDebugLogger)))
{
return false;
}
return true;
}
/**
* Retrieves the hash code for this debug logger.
*
* @return The hash code for this debug logger.
*/
public int hashCode()
{
// Just make one up, since there should never be a need to have more than
// one instance of this debug logger.
return 12345;
}
}