关于java:仅获取堆栈跟踪的前N行

Fetch only first N lines of a Stack Trace

我有一个从ID调用返回对象的工厂方法。

模拟代码:

1
2
3
4
5
6
7
8
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行(这样我就知道了方法的调用方),而不将整个堆栈跟踪转储到日志中,或者不必依赖外部libs?


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

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

这将告诉你在代码中你需要知道的关于你从哪里来的几乎所有信息。


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

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


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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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("
"
);
    sb.append("
"
);
    if(splitted.length > 2 + i) {
        for(int x = 2; x < i+2; x++) {
            sb.append(splitted[x].trim());
            sb.append("
"
);
        }
        return sb.toString();
    }
    return"Trace too Short.";
}

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

感谢您访问@brianagenew(stackoverflow.com/a/1149712/1532705)了解StringWriter打印作者的想法。


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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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("
"
);
    StringBuilder sb = new StringBuilder();
    for (int i = 0; i < Math.min(lines.length, maxLines); i++) {
        sb.append(lines[i]).append("
"
);
    }
    return sb.toString();
}

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

一些日志框架可以配置为自动截断堆栈跟踪。例如,请参阅关于log4j配置的这个问题和答案。

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

1
Thread.currentThread().getStackTrace();


瓜娃能帮上忙。例如,我们只想看到前十行:

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


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

1
2
3
4
5
6
        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处。