ch.qos.logback.classic.spi.ThrowableProxyUtil Maven / Gradle / Ivy
/**
* Logback: the reliable, generic, fast and flexible logging framework.
* Copyright (C) 1999-2015, QOS.ch. All rights reserved.
*
* This program and the accompanying materials are dual-licensed under
* either the terms of the Eclipse Public License v1.0 as published by
* the Eclipse Foundation
*
* or (per the licensee's choosing)
*
* under the terms of the GNU Lesser General Public License version 2.1
* as published by the Free Software Foundation.
*/
package ch.qos.logback.classic.spi;
import ch.qos.logback.core.CoreConstants;
/**
* Convert a throwable into an array of ThrowableDataPoint objects.
*
*
* @author Ceki Gülcü
*/
public class ThrowableProxyUtil {
public static final int REGULAR_EXCEPTION_INDENT = 1;
public static final int SUPPRESSED_EXCEPTION_INDENT = 1;
private static final int BUILDER_CAPACITY = 2048;
public static void build(ThrowableProxy nestedTP, Throwable nestedThrowable, ThrowableProxy parentTP) {
StackTraceElement[] nestedSTE = nestedThrowable.getStackTrace();
int commonFramesCount = -1;
if (parentTP != null) {
commonFramesCount = findNumberOfCommonFrames(nestedSTE, parentTP.getStackTraceElementProxyArray());
}
nestedTP.commonFrames = commonFramesCount;
nestedTP.stackTraceElementProxyArray = steArrayToStepArray(nestedSTE);
}
static StackTraceElementProxy[] steArrayToStepArray(StackTraceElement[] stea) {
if (stea == null) {
return new StackTraceElementProxy[0];
}
StackTraceElementProxy[] stepa = new StackTraceElementProxy[stea.length];
for (int i = 0; i < stepa.length; i++) {
stepa[i] = new StackTraceElementProxy(stea[i]);
}
return stepa;
}
static int findNumberOfCommonFrames(StackTraceElement[] steArray, StackTraceElementProxy[] parentSTEPArray) {
if (parentSTEPArray == null || steArray == null) {
return 0;
}
int steIndex = steArray.length - 1;
int parentIndex = parentSTEPArray.length - 1;
int count = 0;
while (steIndex >= 0 && parentIndex >= 0) {
StackTraceElement ste = steArray[steIndex];
StackTraceElement otherSte = parentSTEPArray[parentIndex].ste;
if (ste.equals(otherSte)) {
count++;
} else {
break;
}
steIndex--;
parentIndex--;
}
return count;
}
public static String asString(IThrowableProxy tp) {
StringBuilder sb = new StringBuilder(BUILDER_CAPACITY);
recursiveAppend(sb, null, REGULAR_EXCEPTION_INDENT, tp);
return sb.toString();
}
private static void recursiveAppend(StringBuilder sb, String prefix, int indent, IThrowableProxy tp) {
if (tp == null)
return;
subjoinFirstLine(sb, prefix, indent, tp);
sb.append(CoreConstants.LINE_SEPARATOR);
subjoinSTEPArray(sb, indent, tp);
IThrowableProxy[] suppressed = tp.getSuppressed();
if (suppressed != null) {
for (IThrowableProxy current : suppressed) {
recursiveAppend(sb, CoreConstants.SUPPRESSED, indent + SUPPRESSED_EXCEPTION_INDENT, current);
}
}
recursiveAppend(sb, CoreConstants.CAUSED_BY, indent, tp.getCause());
}
public static void indent(StringBuilder buf, int indent) {
for (int j = 0; j < indent; j++) {
buf.append(CoreConstants.TAB);
}
}
private static void subjoinFirstLine(StringBuilder buf, String prefix, int indent, IThrowableProxy tp) {
indent(buf, indent - 1);
if (prefix != null) {
buf.append(prefix);
}
subjoinExceptionMessage(buf, tp);
}
public static void subjoinPackagingData(StringBuilder builder, StackTraceElementProxy step) {
if (step != null) {
ClassPackagingData cpd = step.getClassPackagingData();
if (cpd != null) {
if (!cpd.isExact()) {
builder.append(" ~[");
} else {
builder.append(" [");
}
builder.append(cpd.getCodeLocation()).append(':').append(cpd.getVersion()).append(']');
}
}
}
public static void subjoinSTEP(StringBuilder sb, StackTraceElementProxy step) {
sb.append(step.toString());
subjoinPackagingData(sb, step);
}
/**
* @param sb The StringBuilder the STEPs are appended to.
* @param tp the IThrowableProxy containing the STEPs.
* @deprecated Use subjoinSTEPArray(StringBuilder sb, int indentLevel,
* IThrowableProxy tp) instead.
*/
public static void subjoinSTEPArray(StringBuilder sb, IThrowableProxy tp) {
// not called anymore - but it is public
subjoinSTEPArray(sb, REGULAR_EXCEPTION_INDENT, tp);
}
/**
* @param sb The StringBuilder the STEPs are appended to.
* @param indentLevel indentation level used for the STEPs, usually
* REGULAR_EXCEPTION_INDENT.
* @param tp the IThrowableProxy containing the STEPs.
*/
public static void subjoinSTEPArray(StringBuilder sb, int indentLevel, IThrowableProxy tp) {
StackTraceElementProxy[] stepArray = tp.getStackTraceElementProxyArray();
int commonFrames = tp.getCommonFrames();
for (int i = 0; i < stepArray.length - commonFrames; i++) {
StackTraceElementProxy step = stepArray[i];
indent(sb, indentLevel);
subjoinSTEP(sb, step);
sb.append(CoreConstants.LINE_SEPARATOR);
}
if (commonFrames > 0) {
indent(sb, indentLevel);
sb.append("... ").append(commonFrames).append(" common frames omitted")
.append(CoreConstants.LINE_SEPARATOR);
}
}
public static void subjoinFirstLine(StringBuilder buf, IThrowableProxy tp) {
int commonFrames = tp.getCommonFrames();
if (commonFrames > 0) {
buf.append(CoreConstants.CAUSED_BY);
}
subjoinExceptionMessage(buf, tp);
}
public static void subjoinFirstLineRootCauseFirst(StringBuilder buf, IThrowableProxy tp) {
if (tp.getCause() != null) {
buf.append(CoreConstants.WRAPPED_BY);
}
subjoinExceptionMessage(buf, tp);
}
private static void subjoinExceptionMessage(StringBuilder buf, IThrowableProxy tp) {
if (tp.isCyclic()) {
buf.append("[CIRCULAR REFERENCE: ").append(tp.getClassName()).append(": ").append(tp.getMessage())
.append(']');
} else {
buf.append(tp.getClassName()).append(": ").append(tp.getMessage());
}
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy