仅获取堆栈跟踪的前N行

时间:2014-02-11 15:57:32

标签: java exception stack-trace

我有一个Factory方法,它从ID调用中返回一个对象。

模拟代码:

public static Object getById(String id) {
    Object o = CRUD.doRecovery(Class, id);
    if(o == null) {
         printLogMessage("recovery by ID returned Null: " + id);
         // would really like to show only a few lines of stack trace.
    }
    return o;
}

如何只显示堆栈跟踪的前N行(所以我知道方法的调用者)而不将整个堆栈跟踪转储到日志上或者必须依赖外部库?

8 个答案:

答案 0 :(得分:8)

我假设您要求的是,您没有例外处理。在这种情况下,您可以从以下位置获取当前堆栈跟踪:

StackTraceElement[] elements = Thread.currentThread().getStackTrace()

这将告诉您几乎所有关于您在代码中来自何处的信息。

答案 1 :(得分:6)

您可以使用ex.getStackTrace()获取堆栈元素,StackTraceElement包含完整堆栈的一行,然后打印您想要的内容。

StackTraceElement[] elements = ex.getStackTrace();
print(elements[0]);

答案 2 :(得分:3)

此方法显示堆栈跟踪的i行,跳过前两行。

public static String traceCaller(Exception ex, int i) {
    StringWriter sw = new StringWriter();
    PrintWriter pw = new PrintWriter(sw);
    StringBuilder sb = new StringBuilder();
    ex.printStackTrace(pw);
    String ss = sw.toString();
    String[] splitted = ss.split("\n");
    sb.append("\n");
    if(splitted.length > 2 + i) {
        for(int x = 2; x < i+2; x++) {
            sb.append(splitted[x].trim());
            sb.append("\n");
        }
        return sb.toString();
    }
    return "Trace too Short.";
}

前两行是异常名称和调用traceCaller()的方法。如果你想显示这些行,请调整它。

感谢@ BrianAgnewstackoverflow.com/a/1149712/1532705)了解StringWriter PrintWriter的想法

答案 3 :(得分:2)

如果您只想截断堆栈跟踪,可以将整个堆栈跟踪打印到StringWriter,然后删除您不想要的内容:

public static void main(String[] args) throws ParseException {
    try {
        throw new Exception("Argh!");
    } catch (Exception e) {
        System.err.println(shortenedStackTrace(e, 1));
    }
}

public static String shortenedStackTrace(Exception e, int maxLines) {
    StringWriter writer = new StringWriter();
    e.printStackTrace(new PrintWriter(writer));
    String[] lines = writer.toString().split("\n");
    StringBuilder sb = new StringBuilder();
    for (int i = 0; i < Math.min(lines.length, maxLines); i++) {
        sb.append(lines[i]).append("\n");
    }
    return sb.toString();
}

或者,使用e.getStackTrace()获取StackTraceElement[]数组。这为您提供了调用者堆栈(从内部到外部),但不是错误消息。您必须使用e.getMessage()来获取错误消息。

某些日志记录框架可以配置为自动截断堆栈跟踪。例如。有关log4j配置,请参阅this question and answer

如果您只想在代码中的任何位置查看堆栈跟踪,可以从Thread.currentThread()对象中获取元素:

Thread.currentThread().getStackTrace();

答案 4 :(得分:1)

番石榴可以提供帮助。例如,我们只希望看到前十行:

log.error("Error:", Joiner.on("\n").join(Iterables.limit(asList(ex.getStackTrace()), 10)));

答案 5 :(得分:0)

对于e.printStackTrace()的缩写版本:

        Exception e = ...
        System.out.println(e.toString());
        StackTraceElement[] elements = e.getStackTrace();
        for(int i = 0; i<elements.length && i < STACK_TRACE_LIMIT; i++) {
            System.out.println("\tat "+elements[i]);
        }

STACK_TRACE_LIMIT替换为您想要的限制,或删除&& i < STACK_TRACE_LIMIT以重现简单堆栈跟踪的输出(例如,无嵌套异常)

最里面的方法调用在索引0处,主要在索引长度1处。

答案 6 :(得分:0)

例如显示第五行:

        final int nbLinesToShow = 5;
        try {
            /* your code here */
        } catch (final NullPointerException e) {
            // catch error
            final StackTraceElement[] elements = e.getStackTrace();
            System.err.println(
                    "===================================== \n" + "[ERROR] lorem ipsum");
            for (int i = 0; i < nbLinesToShow; i++) {
                System.err.println(elements[i]);
            }
        }

答案 7 :(得分:-1)

以下链接中的代码段适用于 N 行。

下面的代码片段有助于剥离异常堆栈跟踪。

public class LoggerHelper {

private static final String SEPARATOR = "\r\n";
private static final String CAUSE_CAPTION = "Caused by: ";
private static final String SUPPRESSED_CAPTION = "Suppressed: ";

/**
 * The first 10 lines of exception stack information are returned by default
 *
 * @param e
 * @return
 */
public static String printTop10StackTrace(Throwable e) {
    if (e == null) {
        return "";
    }
    return printStackTrace(e, 20);
}

public static String printStackTrace(Throwable e, int maxLineCount) {
    if (e == null || maxLineCount <= 0) {
        return "";
    }
    StringBuilder sb = new StringBuilder(maxLineCount * 10);
    sb.append(e.toString()).append(SEPARATOR);
    StackTraceElement[] trace = e.getStackTrace();
    if (trace == null) {
        return e.toString();
    }
    int count = maxLineCount > trace.length ? trace.length : maxLineCount;
    int framesInCommon = trace.length - count;
    for (int i = 0; i < count; i++) {
        sb.append("\tat ").append(trace[i]).append(SEPARATOR);
    }
    if (framesInCommon != 0) {
        sb.append("\t... ").append(framesInCommon).append(" more").append(SEPARATOR);
    }
    // Print suppressed exceptions, if any
    Throwable[] suppressedExceptions = e.getSuppressed();
    if (ArrayUtils.isNotEmpty(suppressedExceptions)) {
        for (Throwable suppressedException : suppressedExceptions) {
            sb.append(printEnclosedStackTrace(suppressedException, maxLineCount, trace, SUPPRESSED_CAPTION, "\t"));
        }
    }
    // Print cause, if any
    Throwable cause = e.getCause();
    if (cause != null) {
        sb.append(printEnclosedStackTrace(cause, maxLineCount, trace, CAUSE_CAPTION, ""));
    }
    return sb.toString();
}

private static String printEnclosedStackTrace(Throwable e, int maxLineCount, StackTraceElement[] enclosingTrace,
                                              String caption, String prefix) {
    StringBuilder sb = new StringBuilder(maxLineCount * 5);
    StackTraceElement[] trace = e.getStackTrace();
    int m = trace.length - 1;
    int n = enclosingTrace.length - 1;
    while (m >= 0 && n >= 0 && trace[m].equals(enclosingTrace[n])) {
        m--;
        n--;
    }
    int count = maxLineCount > (m + 1) ? (m + 1) : maxLineCount;
    int framesInCommon = trace.length - count;
    // Print our stack trace
    sb.append(prefix).append(caption).append(e.toString()).append(SEPARATOR);
    for (int i = 0; i < count; i++) {
        sb.append(prefix).append("\tat ").append(trace[i]).append(SEPARATOR);
    }
    if (framesInCommon != 0) {
        sb.append(prefix).append("\t... ").append(framesInCommon).append(" more").append(SEPARATOR);
    }
    // Print suppressed exceptions, if any
    Throwable[] suppressedExceptions = e.getSuppressed();
    if (ArrayUtils.isNotEmpty(suppressedExceptions)) {
        for (Throwable suppressedException : suppressedExceptions) {
            sb.append(printEnclosedStackTrace(suppressedException, maxLineCount, trace, SUPPRESSED_CAPTION, prefix + "\t"));
        }
    }
    // Print cause, if any
    Throwable cause = e.getCause();
    if (cause != null) {
        sb.append(printEnclosedStackTrace(cause, maxLineCount, trace, CAUSE_CAPTION, prefix));
    }
    return sb.toString();
 }

}