Java 确定哪一行打印了堆栈跟踪?

Java 确定哪一行打印了堆栈跟踪?,java,Java,我看到一个错误的堆栈跟踪被打印到系统。err,我想清除它,但是我在识别调用printStackTrace()的行时遇到了问题。有没有一个聪明的方法来判断是哪条线路在打那个电话 特别是,我还不能确定调用是在我的代码中进行的,还是在库中进行的。甚至缩小搜索范围——我的代码或其他人的代码——都会很有用 EDIT:为了清楚起见,我正在查找调用printStackTrace()的行,而不是引发异常的行,该异常的堆栈跟踪正在打印。(前者的答案是……嗯……堆栈跟踪。:)我在所有明显的地方都进行了查找,通过遍历

我看到一个错误的堆栈跟踪被打印到
系统。err
,我想清除它,但是我在识别调用
printStackTrace()
的行时遇到了问题。有没有一个聪明的方法来判断是哪条线路在打那个电话

特别是,我还不能确定调用是在我的代码中进行的,还是在库中进行的。甚至缩小搜索范围——我的代码或其他人的代码——都会很有用

EDIT:为了清楚起见,我正在查找调用
printStackTrace()
的行,而不是引发
异常的行,该异常的堆栈跟踪正在打印。(前者的答案是……嗯……堆栈跟踪。:)我在所有明显的地方都进行了查找,通过遍历堆栈跟踪,在每个步骤中查找可能的
printStackTrace()
调用,但没有找到任何结果。要么[a]电话在那里,而我是个白痴(当然有可能),要么[b]这个
例外情况正在四处传播,并在其他地方打印出来。这就是为什么我很难找到
printStackTrace()
调用;调用
printStackTrace()
似乎发生在距离抛出
异常的代码“很远”的地方

EDIT:监视
系统的输出。err
是一个很好的建议,效果很好。以下是我尝试过的有效方法:

final PrintStream systemErr=System.err;
System.setErr(new PrintStream(new OutputStream() {
    @Override
    public void flush() throws IOException {
        systemErr.flush();
    }

    @Override
    public void close() throws IOException {
        systemErr.close();
    }

    @Override
    public void write(byte[] buf, int off, int len) throws IOException {
        String s=new String(buf, Charset.defaultCharset());
        if(s.contains("Socket closed"))
            new Exception().printStackTrace();
        systemErr.write(buf, off, len);
    }

    @Override
    public void write(int b) throws IOException {
        systemErr.write(b);
    }
}));

在这里,我监视的消息是
“socketclosed”
,它出现在
异常消息中。我有点幸运,(a)底层代码最终是通过
write(byte[],int,int)
调用的,而不是
write(int)
,以及(b)块没有将我监视的消息分割到不同的调用中。然而,尽管如此,这还是很有魅力。谢谢大家的帮助

第一个堆栈打印由try包围的行,查找相关的catch:打印在这里

如果捕获的异常作为普通参数传递给另一个方法进行打印,那么它也在这里。对于任何现代IDE,如Eclipse,都可以遵循代码和/或类型


有关您的问题的更多代码将帮助我们尝试帮助您……

您可以为System.err和System.out提供新值,例如包装原始值

然后可以在新值中测试\n,并在那里设置断点或以编程方式查看调用堆栈


您很可能希望在执行此操作时禁用正常日志记录。

如果您能够复制日志记录,您只需在程序开始时调用
System.setErr()
,并通过堆栈跟踪传递一个自定义流,记录流上的每个调用,以便能够找到谁正在打印到
System.err
。它甚至可以是智能的,只在打印出某个关键字(错误堆栈跟踪的一部分)时记录调用。

这里有一个用于调试错误流输出的通用类。主要是从sigpwned的代码和Thorbjorn的想法中复制出来的,但是有一个友好的API。此外,跟踪在每一行上都打印有前缀,因此您可以区分创建异常的调用的stacktrace和打印异常的stacktrace的行的stacktrace

import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.nio.charset.Charset;

/** Utility methods for figuring out when a given string is being printed to System.out or System.err. */
public class StreamDebug {
    /** Stores the pristine System.err stream before it is clobbered by other methods. */
    private static final PrintStream PRISTINE_SYS_ERR = System.err;

    /** Dumps a stack trace if the trigger string is printed to System.out. */
    public static void dumpIfSysOutContains(String trigger) {
        System.setOut(wrapAndDumpIfContains(System.out, trigger));
    }

    /** Dumps a stack trace if the trigger string is printed to System.err. */
    public static void dumpIfSysErrContains(String trigger) {
        System.setErr(wrapAndDumpIfContains(System.err, trigger));
    }

    /**
     * When dumping the stack trace, all lines in the trace before this delimiter will be ignored.
     * This is chosen to match the "new Throwable().printStackTrace(new PrintWriter(sw));" line below.
     */
    private static final String INTERESTING_DELIMITER = "java.lang.Throwable.printStackTrace";

    /** 
     * Returns a PrintStream which will redirect all of its output to the source PrintStream.  If
     * the trigger string is passed through the wrapped PrintStream, then it will dump the
     * stack trace of the call that printed the trigger. 
     * 
     * @param source    the returned PrintStream will delegate to this stream
     * @param trigger   the string which triggers a stack dump
     * @return          a PrintStream with the above properties
     */
    public static PrintStream wrapAndDumpIfContains(final PrintStream source, final String trigger) {
        return new PrintStream(new OutputStream() {
            @Override
            public void flush() throws IOException {
                source.flush();
            }

            @Override
            public void close() throws IOException {
                source.close();
            }

            @Override
            public void write(byte[] buf, int off, int len) throws IOException {
                String s = new String(buf, off, len, Charset.defaultCharset());
                if (s.contains(trigger)) {
                    // print the triggered header
                    PRISTINE_SYS_ERR.println("+----------\\");
                    PRISTINE_SYS_ERR.println("| TRIGGERED \\");

                    // put the stack trace into an array of strings
                    StringWriter sw = new StringWriter();
                    new Throwable().printStackTrace(new PrintWriter(sw));
                    String[] lines = sw.toString().replaceAll("\\r\\n", "\n").split("\\n"); // stack trace as a string

                    // print each line of the stacktrace with a prefix to differentiate from the "standard" stream
                    // but don't print until we've gotten past the INTERESTING_DELIMITER
                    boolean foundInterestingDelimiter = false;
                    boolean pastInterestingDelimiter = false;
                    for (String line : lines) {
                        // set foundInterestingDelimiter to true when we find the delimiter
                        if (!foundInterestingDelimiter && line.contains(INTERESTING_DELIMITER)) {
                            foundInterestingDelimiter = true;
                        }
                        // set pastInterestingDelimiter to true when the line no longer contains the delimiter
                        if (foundInterestingDelimiter && !pastInterestingDelimiter && !line.contains(INTERESTING_DELIMITER)) {
                            pastInterestingDelimiter = true;
                        }
                        // only print the stack trace once we've gotten past the interesting delimiter
                        if (pastInterestingDelimiter) {
                            PRISTINE_SYS_ERR.print("| ");
                            PRISTINE_SYS_ERR.println(line.trim());
                        }
                    }

                    // print the triggered footer
                    PRISTINE_SYS_ERR.println("| TRIGGERED /");
                    PRISTINE_SYS_ERR.println("+----------/");
                }
                source.write(buf, off, len);
            }

            @Override
            public void write(int b) throws IOException {
                source.write(b);
            }
        });
    }
}

该信息应该在堆栈跟踪中。这就是问题的关键所在。堆栈跟踪告诉您是哪一行引发了异常,但没有告诉您异常是在哪里捕获和处理的,这正是海报试图确定的。请发布您的代码。由于生成
异常的代码的性质,发布SSCCE将非常困难,由于我不确定是什么生成了堆栈跟踪,我也不确定我会发布什么。好消息是,我已经按照下面的一些建议对它进行了分类。我现在发布了对我有用的东西。Eclipse请求在console视图中添加一个不可见的堆栈跟踪,以便您可以找到它的来源。显然,这是相当麻烦的实现,我仍然认为这将是一个了不起的调试工具。我已经尝试过了。似乎
异常
正在被传递并打印到其他地方,这就是为什么我在找到正确的行时遇到如此大的问题。我将更新问题以反映这一事实。不一定。在好的程序中,通常避免写入System.err(甚至System.out)。通常使用日志框架。这是最终对我有效的方法+但是我先看到了别人的答案,所以接受了他的。谢谢你的建议!