| | |
| | | import static org.opends.server.util.ServerConstants.EOL; |
| | | |
| | | /** |
| | | * A DebugStackTraceFormatter converts an exception's stack trace into |
| | | * a String appropriate for tracing, optionally performing filtering |
| | | * of stack frames. |
| | | * A DebugStackTraceFormatter converts an exception's stack trace into a String |
| | | * appropriate for tracing, optionally performing filtering of stack frames. |
| | | */ |
| | | public class DebugStackTraceFormatter |
| | | class DebugStackTraceFormatter |
| | | { |
| | | /** |
| | | * The stack depth value to indicate the entire stack should be printed. |
| | | */ |
| | | public static final int COMPLETE_STACK= Integer.MAX_VALUE; |
| | | public static final int COMPLETE_STACK = Integer.MAX_VALUE; |
| | | /** |
| | | * A nested frame filter that removes debug and trailing no OpenDS frames. |
| | | */ |
| | | * A nested frame filter that removes debug and trailing no OpenDS frames. |
| | | */ |
| | | public static final FrameFilter SMART_FRAME_FILTER = new SmartFrameFilter(); |
| | | |
| | | /** |
| | | * A FrameFilter provides stack frame filtering used during formatting. |
| | | */ |
| | | public interface FrameFilter { |
| | | interface FrameFilter |
| | | { |
| | | |
| | | /** |
| | | * Filters out all undesired stack frames from the given Throwable's |
| | | * stack trace. |
| | | * @param frames the frames to filter |
| | | * Filters out all undesired stack frames from the given Throwable's stack |
| | | * trace. |
| | | * |
| | | * @param frames |
| | | * the frames to filter |
| | | * @return an array of StackTraceElements to be used in formatting. |
| | | */ |
| | | public StackTraceElement[] getFilteredStackTrace( |
| | | StackTraceElement[] frames); |
| | | public StackTraceElement[] getFilteredStackTrace(StackTraceElement[] frames); |
| | | } |
| | | |
| | | /** |
| | | * A basic FrameFilter that filters out frames from the debug logging and |
| | | * non OpenDS classes. |
| | | * A basic FrameFilter that filters out frames from the debug logging and non |
| | | * OpenDS classes. |
| | | */ |
| | | private static class SmartFrameFilter implements FrameFilter { |
| | | private static class SmartFrameFilter implements FrameFilter |
| | | { |
| | | |
| | | private boolean isFrameForPackage(StackTraceElement frame, |
| | | String packageName) |
| | | String packageName) |
| | | { |
| | | boolean isContained= false; |
| | | boolean isContained = false; |
| | | |
| | | if (frame != null) { |
| | | String className= frame.getClassName(); |
| | | isContained= className != null && className.startsWith(packageName); |
| | | if (frame != null) |
| | | { |
| | | String className = frame.getClassName(); |
| | | isContained = className != null && className.startsWith(packageName); |
| | | } |
| | | return isContained; |
| | | } |
| | | |
| | | /** |
| | | * Return the stack trace of an exception with debug and trailing non |
| | | * OpenDS frames filtered out. |
| | | * Return the stack trace of an exception with debug and trailing non OpenDS |
| | | * frames filtered out. |
| | | * |
| | | * @param frames the frames to filter |
| | | * @param frames |
| | | * the frames to filter |
| | | * @return the filtered stack trace. |
| | | */ |
| | | public StackTraceElement[] getFilteredStackTrace( |
| | | StackTraceElement[] frames) |
| | | public StackTraceElement[] getFilteredStackTrace(StackTraceElement[] frames) |
| | | { |
| | | StackTraceElement[] trimmedStack= null; |
| | | if (frames != null && frames.length > 0) { |
| | | int firstFrame= 0; |
| | | StackTraceElement[] trimmedStack = null; |
| | | if (frames != null && frames.length > 0) |
| | | { |
| | | int firstFrame = 0; |
| | | |
| | | // Skip leading frames debug logging classes |
| | | while (firstFrame < frames.length && |
| | | DebugTracer.isLoggingStackTraceElement(frames[firstFrame])) { |
| | | while (firstFrame < frames.length |
| | | && DebugTracer.isLoggingStackTraceElement(frames[firstFrame])) |
| | | { |
| | | firstFrame++; |
| | | } |
| | | |
| | | // Skip trailing frames not in OpenDS classes |
| | | int lastFrame= frames.length - 1; |
| | | while (lastFrame > firstFrame && |
| | | !isFrameForPackage(frames[lastFrame], "org.opends")) { |
| | | int lastFrame = frames.length - 1; |
| | | while (lastFrame > firstFrame |
| | | && !isFrameForPackage(frames[lastFrame], "org.opends")) |
| | | { |
| | | lastFrame--; |
| | | } |
| | | |
| | | trimmedStack= new StackTraceElement[lastFrame - firstFrame + 1]; |
| | | for (int i= firstFrame; i <= lastFrame; i++) { |
| | | trimmedStack[i - firstFrame]= frames[i]; |
| | | trimmedStack = new StackTraceElement[lastFrame - firstFrame + 1]; |
| | | for (int i = firstFrame; i <= lastFrame; i++) |
| | | { |
| | | trimmedStack[i - firstFrame] = frames[i]; |
| | | } |
| | | } |
| | | |
| | |
| | | } |
| | | |
| | | /** |
| | | * Generate a String representation of the entire stack trace of the |
| | | * given Throwable. |
| | | * @param t - the Throwable for which to generate the stack trace. |
| | | * Generate a String representation of the entire stack trace of the given |
| | | * Throwable. |
| | | * |
| | | * @param t |
| | | * - the Throwable for which to generate the stack trace. |
| | | * @return the stack trace. |
| | | */ |
| | | public static String formatStackTrace(Throwable t) |
| | |
| | | } |
| | | |
| | | /** |
| | | * Generate a String representation of the possibly filtered stack trace |
| | | * of the given Throwable. |
| | | * @param t - the Throwable for which to generate the stack trace. |
| | | * @param maxDepth - the maximum number of stack frames to include in the |
| | | * trace. |
| | | * @param includeCause - also include the stack trace for the cause Throwable. |
| | | * Generate a String representation of the possibly filtered stack trace of |
| | | * the given Throwable. |
| | | * |
| | | * @param t |
| | | * - the Throwable for which to generate the stack trace. |
| | | * @param maxDepth |
| | | * - the maximum number of stack frames to include in the trace. |
| | | * @param includeCause |
| | | * - also include the stack trace for the cause Throwable. |
| | | * @return the stack trace. |
| | | */ |
| | | public static String formatStackTrace(Throwable t, int maxDepth, |
| | | boolean includeCause) |
| | | static String formatStackTrace(Throwable t, int maxDepth, boolean includeCause) |
| | | { |
| | | StringBuilder buffer= new StringBuilder(); |
| | | StringBuilder buffer = new StringBuilder(); |
| | | |
| | | StackTraceElement[] trace = t.getStackTrace(); |
| | | int frameLimit = Math.min(maxDepth, trace.length); |
| | | for (int i=0; i < frameLimit; i++) |
| | | for (int i = 0; i < frameLimit; i++) |
| | | { |
| | | buffer.append(" at "); |
| | | buffer.append(trace[i]); |
| | | buffer.append(EOL); |
| | | } |
| | | if(frameLimit < trace.length) |
| | | if (frameLimit < trace.length) |
| | | { |
| | | buffer.append(" ... "); |
| | | buffer.append(trace.length - frameLimit); |
| | |
| | | buffer.append(EOL); |
| | | } |
| | | |
| | | if(includeCause) |
| | | if (includeCause) |
| | | { |
| | | Throwable ourCause = t.getCause(); |
| | | if (ourCause != null) |
| | |
| | | } |
| | | |
| | | private static void formatStackTraceForCause(Throwable t, int maxDepth, |
| | | StringBuilder buffer, |
| | | StackTraceElement[] causedTrace) |
| | | StringBuilder buffer, StackTraceElement[] causedTrace) |
| | | { |
| | | StackTraceElement[] trace = t.getStackTrace(); |
| | | int framesToSkip = Math.max(trace.length - maxDepth, 0); |
| | |
| | | // Compute number of frames in common between this and caused |
| | | int m = trace.length - 1 - framesToSkip; |
| | | int n = causedTrace.length - 1 - framesToSkip; |
| | | while (m >= 0 && n >=0 && trace[m].equals(causedTrace[n])) { |
| | | m--; n--; |
| | | while (m >= 0 && n >= 0 && trace[m].equals(causedTrace[n])) |
| | | { |
| | | m--; |
| | | n--; |
| | | } |
| | | framesToSkip = trace.length - 1 - m; |
| | | |
| | | buffer.append("Caused by: "); |
| | | buffer.append(t); |
| | | buffer.append(EOL); |
| | | for (int i=0; i <= m; i++) |
| | | for (int i = 0; i <= m; i++) |
| | | { |
| | | buffer.append(" at "); |
| | | buffer.append(trace[i]); |
| | |
| | | } |
| | | |
| | | /** |
| | | * Generate a String representation of the possibly filtered stack trace |
| | | * from the current position in executation. |
| | | * Generate a String representation of the possibly filtered stack trace from |
| | | * the current position in executation. |
| | | * |
| | | * @param stackTrace - The stack trace elements to format. |
| | | * @param maxDepth - the maximum number of stack frames to include in the |
| | | * trace. |
| | | * @param stackTrace |
| | | * - The stack trace elements to format. |
| | | * @param maxDepth |
| | | * - the maximum number of stack frames to include in the trace. |
| | | * @return the stack trace. |
| | | */ |
| | | public static String formatStackTrace(StackTraceElement[] stackTrace, |
| | | int maxDepth) |
| | | static String formatStackTrace(StackTraceElement[] stackTrace, int maxDepth) |
| | | { |
| | | StringBuilder buffer= new StringBuilder(); |
| | | StringBuilder buffer = new StringBuilder(); |
| | | |
| | | if (stackTrace != null) { |
| | | int frameLimit= Math.min(maxDepth, stackTrace.length); |
| | | if (frameLimit > 0) { |
| | | if (stackTrace != null) |
| | | { |
| | | int frameLimit = Math.min(maxDepth, stackTrace.length); |
| | | if (frameLimit > 0) |
| | | { |
| | | |
| | | |
| | | for (int i= 0; i < frameLimit; i++) { |
| | | for (int i = 0; i < frameLimit; i++) |
| | | { |
| | | buffer.append(" "); |
| | | buffer.append(stackTrace[i]); |
| | | buffer.append(EOL); |
| | | } |
| | | |
| | | if(frameLimit < stackTrace.length) |
| | | if (frameLimit < stackTrace.length) |
| | | { |
| | | buffer.append(" ...("); |
| | | buffer.append(stackTrace.length - frameLimit); |