Java 仅获取堆栈跟踪的前N行

Java 仅获取堆栈跟踪的前N行,java,exception,stack-trace,Java,Exception,Stack Trace,我有一个工厂方法,它从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 lin

我有一个工厂方法,它从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行(因此我知道该方法的调用方),而不将整个堆栈跟踪转储到日志上或必须依赖外部libs?

此方法显示堆栈跟踪的
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.";
}
publicstaticstringtracecaller(异常exinti){
StringWriter sw=新的StringWriter();
PrintWriter pw=新的PrintWriter(sw);
StringBuilder sb=新的StringBuilder();
例如printStackTrace(pw);
字符串ss=sw.toString();
String[]splitted=ss.split(“\n”);
某人附加(“\n”);
如果(拆分长度>2+i){
对于(int x=2;x
前两行是异常名称和调用
traceCaller()
的方法。如果要显示这些线,请调整它


感谢转到@()了解StringWriter PrintWriter的想法

如果您只想截断堆栈跟踪,您可以将整个堆栈跟踪打印到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();
}

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

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

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

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

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

番石榴可能会有所帮助。例如,我们只希望看到前十行:

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

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

异常e=。。。 System.out.println(例如toString()); StackTraceElement[]元素=e.getStackTrace();
对于(int i=0;i示例)显示第五行第一行:

final int nbLinesToShow=5;
试一试{
/*你的代码在这里*/
}捕获(最终NullPointerException e){
//捕捉错误
最终StackTraceElement[]元素=e.getStackTrace();
System.err.println(
“====================================================\n”+“[ERROR]lorem ipsum”);
对于(int i=0;i
感谢@BrianAgnew()提供
StringWriter
PrintWriter
idea.IMO您应该将此评论作为答案的一部分。对于问题中要求的非异常用例,最全面的答案。只需输出“元素”的前两个元素数组的格式对您来说很方便。警告一句,Stacktraces的计算成本非常高。您将看到性能在4个数量级上恶化。不要将此用于高性能函数!进行分析,然后将此想法放入容器中,并传递一些标识符作为参数。然后每个调用方都必须使用som这是一种通过契约进行方法调用的自我识别论证。虽然不方便,但速度要快得多。性能不是问题,因为我们处理的是逻辑异常,例如,当应用程序的某个部分引用了不存在的实体id时。然后,我们可以确定违规者。我认为让调用方识别自己是一种挑战一个附加的耦合层,我更愿意以性能为代价。但是mikea的答案非常优雅,我正在绿化它。最内部的方法调用在索引0处,main在索引长度-1处。请参阅一个复制堆栈跟踪的示例(如果您碰巧有完整的异常对象)。请不要使用堆栈跟踪来了解方法的调用方。这非常昂贵(比较它也有一些分析数据)。而是使用第二个参数,并根据合同要求调用方使用一些有意义的自识别ID。“不必依赖外部libs”应该是
Joiner.on(“\n”)。join(Iterables.limit(Arrays.asList(例如getStackTrace()),10))
在提出的问题中不会引发异常;因此这不是给定问题的答案。
log.error("Error:", Joiner.on("\n").join(Iterables.limit(asList(ex.getStackTrace()), 10)));
        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]);
        }