/* * 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 2007 Sun Microsystems, Inc. */ package org.opends.server.loggers.debug; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.Signature; import org.aspectj.lang.annotation.*; import org.aspectj.lang.reflect.SourceLocation; import java.util.Map; import java.nio.ByteBuffer; import static org.opends.server.messages.MessageHandler.getMessage; import org.opends.server.util.ServerConstants; import org.opends.server.util.StaticUtils; import org.opends.server.api.ProtocolElement; import org.opends.server.loggers.*; import org.opends.server.types.DebugLogCategory; import org.opends.server.types.DebugLogLevel; import com.sleepycat.je.*; /** * An aspect for source-code tracing at the method level. * * One Tracer aspect instance exists for each Java class using tracing. * Tracer must be registered with the DebugLogger. * * Logging is always done at a level basis, with debug log messages * exceeding the trace threshold being traced, others being discarded. */ @Aspect("pertypewithin(*)") public class Tracer { /** * Pointcut for matching static context events. */ @Pointcut("!this(Object)") private void staticContext() { } /** * Pointcut for matching non static context events. * @param obj The object being operated on. */ @Pointcut("this(obj)") private void nonStaticContext(Object obj) { } /** * Pointcut for matching all toString() methods. */ @Pointcut("execution(String *..toString())") private void toStringMethod() { } /** * Pointcut for matching all getMessage() methods. */ @Pointcut("execution(String org.opends.server." + "messages.MessageHandler.getMessage(..))") private void getMessageMethod() { } /** * Pointcut for matching debugMessage() methods. */ @Pointcut("call(public static void org.opends.server." + "loggers.debug.DebugLogger.debugMessage(..))") private void logMessageMethod() { } /** * Pointcut for matching debugVerbose() methods. */ @Pointcut("call(public static void org.opends.server." + "loggers.debug.DebugLogger.debugVerbose(..))") private void logVerboseMethod() { } /** * Pointcut for matching debugInfo() methods. */ @Pointcut("call(public static void org.opends.server." + "loggers.debug.DebugLogger.debugInfo(..))") private void logInfoMethod() { } /** * Pointcut for matching debugWarning() methods. */ @Pointcut("call(public static void org.opends.server." + "loggers.debug.DebugLogger.debugWarning(..))") private void logWarningMethod() { } /** * Pointcut for matching debugError() methods. */ @Pointcut("call(public static void org.opends.server." + "loggers.debug.DebugLogger.debugError(..))") private void logErrorMethod() { } /** * Pointcut for matching debugThrown() methods. */ @Pointcut("call(public static void org.opends.server." + "loggers.debug.DebugLogger.debugThrown(..))") private void logThrownMethod() { } /** * Pointcut for matching debugCought() methods. */ @Pointcut("call(public static void org.opends.server." + "loggers.debug.DebugLogger.debugCought(..))") private void logCoughtMethod() { } /** * Pointcut for matching debugJEAccess() methods. */ @Pointcut("call(public static void org.opends.server." + "loggers.debug.DebugLogger.debugJEAccess(..))") private void logJEAccessMethod() { } /** * Pointcut for matching debugData() methods. */ @Pointcut("call(public static void org.opends.server." + "loggers.debug.DebugLogger.debugData(..))") private void logDataMethod() { } /** * Pointcut for matching debugProtocolElement() methods. */ @Pointcut("call(public static void org.opends.server." + "loggers.debug.DebugLogger.debugProtocolElement(..))") private void logProtocolElementMethod() { } /** * Pointcut for matching all debug logging methods. */ @Pointcut("logMessageMethod() || logVerboseMethod() || logInfoMethod() || " + "logWarningMethod() || logErrorMethod() || logCoughtMethod() || " + "logJEAccessMethod() || logDataMethod() || logProtocolElementMethod()") private void logMethods() { } /** * 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()") private void excluded() { } /** * Pointcut for matching the execution of all public methods. */ @Pointcut("execution(public * *(..)) && !excluded()") void tracedMethod() { } /** * Pointcut for matching the execution of all constructors. */ @Pointcut("execution(public new(..)) && !excluded()") void tracedConstructor() { } /** * Pointcut for matching only if tracing is enabled. * * @return if debug logging is enabled. */ @Pointcut("if() && tracingScope()") public static boolean shouldTrace() { return DebugLogger.enabled; } /** * Pointcut for matching only within the scope of the server packages. */ @Pointcut("within(org.opends.server..*)") protected void tracingScope() { } //The default level to log constructor exectuions. private static final LogLevel DEFAULT_CONSTRUCTOR_LEVEL = DebugLogLevel.VERBOSE; //The default level to log method entry and exit pointcuts. private static final LogLevel DEFAULT_ENTRY_EXIT_LEVEL = DebugLogLevel.VERBOSE; // The class this tracer traces. private String className; //The current settings for this tracer. private TraceSettings settings; private Map methodSettings; // The DebugLogger this tracer is genereated by. private DebugLogger logger; /** * AspectJ Implementation. * * @param thisJoinPointStaticPart the JoinPoint reflection object. */ @Before("staticinitialization(*) && tracingScope()") public void initializeTracer(JoinPoint.StaticPart thisJoinPointStaticPart) { className = thisJoinPointStaticPart.getSignature().getDeclaringTypeName(); logger = DebugLogger.getLogger(); logger.registerTracer(className, this); updateSettings(); } /** * AspectJ Implementation. * * @param thisJoinPoint the JoinPoint reflection object. */ @Before("shouldTrace() && tracedConstructor()") public void traceConstructor(JoinPoint thisJoinPoint) { LogCategory category = DebugLogCategory.CONSTRUCTOR; LogLevel level = DEFAULT_CONSTRUCTOR_LEVEL; Signature signature = thisJoinPoint.getSignature(); TraceSettings settings = getSettings(signature.getName()); if (level.intValue() >= getEffectiveLevel(settings, category).intValue()) { SourceLocation sl = thisJoinPoint.getSourceLocation(); Object[] args = thisJoinPoint.getArgs(); publish(category, level, signature.toLongString(), sl.toString(), null, null, args, settings); } } /** * AspectJ Implementation. * * @param thisJoinPoint the JoinPoint reflection object. * @param obj the object this method operations on. */ @Before("shouldTrace() && tracedMethod() && nonStaticContext(obj)") public void traceNonStaticMethodEntry(JoinPoint thisJoinPoint, Object obj) { LogCategory category = DebugLogCategory.ENTER; LogLevel level = DEFAULT_ENTRY_EXIT_LEVEL; Signature signature = thisJoinPoint.getSignature(); TraceSettings settings = getSettings(signature.getName()); if (level.intValue() >= getEffectiveLevel(settings, category).intValue()) { SourceLocation sl = thisJoinPoint.getSourceLocation(); Object[] args = thisJoinPoint.getArgs(); publish(category, level, signature.toLongString(), sl.toString(), obj, null, args, settings); } } /** * AspectJ Implementation. * * @param thisJoinPoint the JoinPoint reflection object. */ @Before("shouldTrace() && tracedMethod() && staticContext()") public void traceStaticMethodEntry(JoinPoint thisJoinPoint) { LogCategory category = DebugLogCategory.ENTER; LogLevel level = DEFAULT_ENTRY_EXIT_LEVEL; Signature signature = thisJoinPoint.getSignature(); TraceSettings settings = getSettings(signature.getName()); if (level.intValue() >= getEffectiveLevel(settings, category).intValue()) { SourceLocation sl = thisJoinPoint.getSourceLocation(); Object[] args = thisJoinPoint.getArgs(); publish(category, level, signature.toLongString(), sl.toString(), null, null, args, settings); } } /** * AspectJ Implementation. * * @param thisJoinPointStaticPart the JoinPoint reflection object. * @param ret the return value of the method. */ @AfterReturning(pointcut = "shouldTrace() && tracedMethod()", returning = "ret") public void traceReturn(JoinPoint.StaticPart thisJoinPointStaticPart, Object ret) { LogCategory category = DebugLogCategory.EXIT; LogLevel level = DEFAULT_ENTRY_EXIT_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[]{ret}, settings); } } /** * AspectJ Implementation. * * @param thisEnclosingJoinPointStaticPart the JoinPoint reflection object. * @param msg message to format and log. */ @Around("shouldTrace() && logVerboseMethod() && args(msg)") public void traceVerbose(JoinPoint.EnclosingStaticPart thisEnclosingJoinPointStaticPart, String msg) { LogLevel level = DebugLogLevel.VERBOSE; LogCategory category = DebugLogCategory.MESSAGE; Signature signature = thisEnclosingJoinPointStaticPart.getSignature(); TraceSettings settings = getSettings(signature.getName()); if (level.intValue() >= getEffectiveLevel(settings, category).intValue()) { SourceLocation sl = thisEnclosingJoinPointStaticPart.getSourceLocation(); publish(category, level, signature.toLongString(), sl.toString(), null, msg, null, settings); } } /** * AspectJ Implementation. * * @param thisEnclosingJoinPointStaticPart 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, String msg, Object[] msgArgs) { LogLevel level = DebugLogLevel.VERBOSE; LogCategory category = DebugLogCategory.MESSAGE; Signature signature = thisEnclosingJoinPointStaticPart.getSignature(); TraceSettings settings = getSettings(signature.getName()); if (level.intValue() >= getEffectiveLevel(settings, category).intValue()) { SourceLocation sl = thisEnclosingJoinPointStaticPart.getSourceLocation(); publish(category, level, signature.toLongString(), sl.toString(), null, msg, msgArgs, settings); } } /** * AspectJ Implementation. * * @param thisEnclosingJoinPointStaticPart the JoinPoint reflection object. * @param msg message to format and log. */ @Around("shouldTrace() && logInfoMethod() && args(msg)") public void traceInfo(JoinPoint.EnclosingStaticPart thisEnclosingJoinPointStaticPart, String msg) { LogLevel level = DebugLogLevel.INFO; LogCategory category = DebugLogCategory.MESSAGE; Signature signature = thisEnclosingJoinPointStaticPart.getSignature(); TraceSettings settings = getSettings(signature.getName()); if (level.intValue() >= getEffectiveLevel(settings, category).intValue()) { SourceLocation sl = thisEnclosingJoinPointStaticPart.getSourceLocation(); publish(category, level, signature.toLongString(), sl.toString(), null, msg, null, settings); } } /** * AspectJ Implementation. * * @param thisEnclosingJoinPointStaticPart 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, String msg, Object[] msgArgs) { LogLevel level = DebugLogLevel.INFO; LogCategory category = DebugLogCategory.MESSAGE; Signature signature = thisEnclosingJoinPointStaticPart.getSignature(); TraceSettings settings = getSettings(signature.getName()); if (level.intValue() >= getEffectiveLevel(settings, category).intValue()) { SourceLocation sl = thisEnclosingJoinPointStaticPart.getSourceLocation(); publish(category, level, signature.toLongString(), sl.toString(), null, msg, msgArgs, settings); } } /** * AspectJ Implementation. * * @param thisEnclosingJoinPointStaticPart the JoinPoint reflection object. * @param msg message to format and log. */ @Around("shouldTrace() && logWarningMethod() && args(msg)") public void traceWarning(JoinPoint.EnclosingStaticPart thisEnclosingJoinPointStaticPart, String msg) { LogLevel level = DebugLogLevel.WARNING; LogCategory category = DebugLogCategory.MESSAGE; Signature signature = thisEnclosingJoinPointStaticPart.getSignature(); TraceSettings settings = getSettings(signature.getName()); if (level.intValue() >= getEffectiveLevel(settings, category).intValue()) { SourceLocation sl = thisEnclosingJoinPointStaticPart.getSourceLocation(); publish(category, level, signature.toLongString(), sl.toString(), null, msg, null, settings); } } /** * AspectJ Implementation. * * @param thisEnclosingJoinPointStaticPart 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, String msg, Object[] msgArgs) { LogLevel level = DebugLogLevel.WARNING; LogCategory category = DebugLogCategory.MESSAGE; Signature signature = thisEnclosingJoinPointStaticPart.getSignature(); TraceSettings settings = getSettings(signature.getName()); if (level.intValue() >= getEffectiveLevel(settings, category).intValue()) { SourceLocation sl = thisEnclosingJoinPointStaticPart.getSourceLocation(); publish(category, level, signature.toLongString(), sl.toString(), null, msg, msgArgs, settings); } } /** * AspectJ Implementation. * * @param thisEnclosingJoinPointStaticPart the JoinPoint reflection object. * @param msg message to format and log. */ @Around("shouldTrace() && logErrorMethod() && args(msg)") public void traceError(JoinPoint.EnclosingStaticPart thisEnclosingJoinPointStaticPart, String msg) { LogLevel level = DebugLogLevel.ERROR; LogCategory category = DebugLogCategory.MESSAGE; Signature signature = thisEnclosingJoinPointStaticPart.getSignature(); TraceSettings settings = getSettings(signature.getName()); if (level.intValue() >= getEffectiveLevel(settings, category).intValue()) { SourceLocation sl = thisEnclosingJoinPointStaticPart.getSourceLocation(); publish(category, level, signature.toLongString(), sl.toString(), null, msg, null, settings); } } /** * AspectJ Implementation. * * @param thisEnclosingJoinPointStaticPart 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, String msg, Object[] msgArgs) { LogLevel level = DebugLogLevel.ERROR; LogCategory category = DebugLogCategory.MESSAGE; Signature signature = thisEnclosingJoinPointStaticPart.getSignature(); TraceSettings settings = getSettings(signature.getName()); if (level.intValue() >= getEffectiveLevel(settings, category).intValue()) { SourceLocation sl = thisEnclosingJoinPointStaticPart.getSourceLocation(); publish(category, level, signature.toLongString(), sl.toString(), null, msg, msgArgs, settings); } } /** * AspectJ Implementation. * * @param thisEnclosingJoinPointStaticPart 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, LogLevel level, String msg) { LogCategory category = DebugLogCategory.MESSAGE; Signature signature = thisEnclosingJoinPointStaticPart.getSignature(); TraceSettings settings = getSettings(signature.getName()); if (level.intValue() >= getEffectiveLevel(settings, category).intValue()) { SourceLocation sl = thisEnclosingJoinPointStaticPart.getSourceLocation(); publish(category, level, signature.toLongString(), sl.toString(), null, msg, null, settings); } } /** * AspectJ Implementation. * * @param thisEnclosingJoinPointStaticPart 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. */ @Around("shouldTrace() && logMessageMethod() && args(level, msg, msgArgs)") public void traceMessage(JoinPoint.EnclosingStaticPart thisEnclosingJoinPointStaticPart, LogLevel level, String msg, Object... msgArgs) { LogCategory category = DebugLogCategory.MESSAGE; Signature signature = thisEnclosingJoinPointStaticPart.getSignature(); TraceSettings settings = getSettings(signature.getName()); if (level.intValue() >= getEffectiveLevel(settings, category).intValue()) { SourceLocation sl = thisEnclosingJoinPointStaticPart.getSourceLocation(); publish(category, level, signature.toLongString(), sl.toString(), null, msg, msgArgs, settings); } } /** * AspectJ Implementation. * * @param thisEnclosingJoinPointStaticPart 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, LogLevel level, Throwable ex) { LogCategory category = DebugLogCategory.THROWN; Signature signature = thisEnclosingJoinPointStaticPart.getSignature(); TraceSettings settings = getSettings(signature.getName()); if (level.intValue() >= getEffectiveLevel(settings, category).intValue()) { SourceLocation sl = thisEnclosingJoinPointStaticPart.getSourceLocation(); publish(category, level, signature.toLongString(), sl.toString(), null, null , new Object[]{ex}, settings); } } /** * AspectJ Implementation. * * @param thisEnclosingJoinPointStaticPart the JoinPoint reflection object. * @param level the level of the log message. * @param ex the exception cought. */ @Around("shouldTrace() && logCoughtMethod() && args(level, ex)") public void traceCought(JoinPoint.EnclosingStaticPart thisEnclosingJoinPointStaticPart, LogLevel level, Throwable ex) { LogCategory category = DebugLogCategory.COUGHT; Signature signature = thisEnclosingJoinPointStaticPart.getSignature(); TraceSettings settings = getSettings(signature.getName()); if (level.intValue() >= getEffectiveLevel(settings, category).intValue()) { SourceLocation sl = thisEnclosingJoinPointStaticPart.getSourceLocation(); publish(category, level, signature.toLongString(), sl.toString(), null, null , new Object[]{ex}, settings); } } /** * AspectJ Implementation. * * @param thisEnclosingJoinPointStaticPart the JoinPoint reflection object. * @param level the level of the log message. * @param status status of the JE operation. * @param database the database handle. * @param txn transaction handle (may be null). * @param key the key to dump. * @param data the data to dump. */ @Around("shouldTrace() && logJEAccessMethod() && args(level, status, " + "database, txn, key, data)") public void traceJEAccess(JoinPoint.EnclosingStaticPart thisEnclosingJoinPointStaticPart, LogLevel level, OperationStatus status, Database database, Transaction txn, DatabaseEntry key, DatabaseEntry data) { LogCategory category = DebugLogCategory.DATABASE_ACCESS; Signature signature = thisEnclosingJoinPointStaticPart.getSignature(); TraceSettings settings = getSettings(signature.getName()); if (level.intValue() >= getEffectiveLevel(settings, category).intValue()) { // Build the string that is common to category DATABASE_ACCESS. StringBuilder builder = new StringBuilder(); builder.append(" ("); builder.append(status.toString()); builder.append(")"); builder.append(" db="); try { builder.append(database.getDatabaseName()); } catch(DatabaseException de) { builder.append(de.toString()); } if (txn != null) { builder.append(" txnid="); try { builder.append(txn.getId()); } catch(DatabaseException de) { builder.append(de.toString()); } } else { 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); 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); } } SourceLocation sl = thisEnclosingJoinPointStaticPart.getSourceLocation(); publish(category, level, signature.toLongString(), sl.toString(), null, builder.toString(), null, settings); } } /** * AspectJ Implementation. * @param thisEnclosingJoinPointStaticPart 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, LogLevel level, byte[] data) { LogCategory category = DebugLogCategory.DATA; Signature signature = thisEnclosingJoinPointStaticPart.getSignature(); TraceSettings settings = getSettings(signature.getName()); if (level.intValue() >= getEffectiveLevel(settings, category).intValue()) { if(data != null) { StringBuilder builder = new StringBuilder(); builder.append(ServerConstants.EOL); builder.append("data(len="); builder.append(data.length); builder.append("):"); builder.append(ServerConstants.EOL); StaticUtils.byteArrayToHexPlusAscii(builder, data, 4); SourceLocation sl = thisEnclosingJoinPointStaticPart.getSourceLocation(); publish(category, level, signature.toLongString(), sl.toString(), null, builder.toString(), null, settings); } } } /** * AspectJ Implementation. * * @param thisEnclosingJoinPointStaticPart 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, LogLevel level, ProtocolElement element) { LogCategory category = DebugLogCategory.PROTOCOL; Signature signature = thisEnclosingJoinPointStaticPart.getSignature(); TraceSettings settings = getSettings(signature.getName()); if (level.intValue() >= getEffectiveLevel(settings, category).intValue()) { if(element != null) { StringBuilder builder = new StringBuilder(); builder.append(ServerConstants.EOL); element.toString(builder, 4); SourceLocation sl = thisEnclosingJoinPointStaticPart.getSourceLocation(); publish(category, level, signature.toLongString(), sl.toString(), null, builder.toString(), null, settings); } } } /** * AspectJ Implementation. * * @param thisEnclosingJoinPointStaticPart 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, LogLevel level, ByteBuffer buffer) { LogCategory category = DebugLogCategory.DATA; Signature signature = thisEnclosingJoinPointStaticPart.getSignature(); TraceSettings settings = getSettings(signature.getName()); if (level.intValue() >= getEffectiveLevel(settings, category).intValue()) { if(buffer != null) { byte[] data = buffer.array(); StringBuilder builder = new StringBuilder(); builder.append(ServerConstants.EOL); builder.append("data(len="); builder.append(data.length); builder.append("):"); builder.append(ServerConstants.EOL); StaticUtils.byteArrayToHexPlusAscii(builder, data, 4); SourceLocation sl = thisEnclosingJoinPointStaticPart.getSourceLocation(); publish(category, level, signature.toLongString(), sl.toString(), null, builder.toString(), null, settings); } } } // Publishes a record, optionally performing some "special" work: // - injecting a stack trace into the message // - format the message with argument values private void publish(LogCategory category, LogLevel level, String method, String srcLocation, Object srcObject, String msg, Object[] msgArgs, TraceSettings settings) { int stackDepth = 0; if(DebugLogCategory.ENTER.equals(category)) { if (settings.noArgs) { msgArgs = null; } else if(msg == null) { msg = buildDefaultEntryMessage(msgArgs.length); } stackDepth = settings.stackDepth; } if(DebugLogCategory.EXIT.equals(category)) { if (settings.noRetVal) { msgArgs = null; } else if(msg == null) { msg = "returned={%s}"; } } if(DebugLogCategory.THROWN.equals(category)) { if (msg == null) { msg = "threw={%s}"; } stackDepth = settings.stackDepth; } if (msg != null && msgArgs != null) { msg = String.format(msg, msgArgs); } DebugLogRecord record = new DebugLogRecord(category, level, srcObject, logger, msg); record.setSignature(method); record.setSourceLocation(srcLocation); // 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]; } String stack= DebugStackTraceFormatter.formatStackTrace(t, DebugStackTraceFormatter.SMART_FRAME_FILTER, stackDepth, settings.includeCause); if (stack != null) record.setStackTrace(stack); } logger.publishRecord(record); } // Publishes a record with a message ID private void publish(LogCategory category, LogLevel level, String method, String srcLocation, Object srcObject, int msgID, Object[] msgArgs, TraceSettings settings) { String msg = getMessage(msgID); publish(category, level, method, srcLocation, srcObject, msg, msgArgs, settings); } /** * Get the current trace settings in effect for the specified method. * * @param method - the method to get trace settings for * @return the current trace settings in effect */ protected TraceSettings getSettings(String method) { TraceSettings settings = this.settings; if (methodSettings != null) { TraceSettings mSettings = methodSettings.get(method); if (mSettings == null) { // Try looking for an undecorated method name int idx = method.indexOf('('); if (idx != -1) { mSettings = methodSettings.get(method.substring(0, idx)); } } if (mSettings != null) settings = mSettings; } return settings; } /** * Retrieve the current log level given the trace settings and log category. * * @param settings the trace settings to test from. * @param category the log category to test. * @return the effective log level. */ protected LogLevel getEffectiveLevel(TraceSettings settings, LogCategory category) { LogLevel level = settings.level; if(settings.includeCategories != null && !settings.includeCategories.contains(category)) { level = DebugLogLevel.DISABLED; } return level; } private static String buildDefaultEntryMessage(int argCount) { StringBuffer format = new StringBuffer(); for (int i = 0; i < argCount; i++) { if (i != 0) format.append(", "); format.append("arg"); format.append(i + 1); format.append("={"); format.append("%s"); format.append("}"); } return format.toString(); } /** * Update the settings for this tracer. */ protected void updateSettings() { synchronized (this) { this.settings = logger.getConfiguration().getTraceSettings(className); this.methodSettings = logger.getConfiguration().getMethodSettings(className); } } /** * Indicates whether a method is traced at the specified level. * * @param level - the trace level to test. * @param category - the category to test. * @param method - the method to test. * @return true if the logger would trace a message for the * method at the level, false otherwise. */ public boolean isLogging(LogLevel level, LogCategory category, String method) { return level.intValue() >= getLevel(method, category).intValue(); } /** * Get the current trace level for the specified method. * * @param method the method to get the trace level for. * @param category the category to get the trace level for. * @return the current trace level for the method. */ protected LogLevel getLevel(String method, LogCategory category) { TraceSettings settings = getSettings(method); return getEffectiveLevel(settings, category); } }