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)。通常使用日志框架。这是最终对我有效的方法+但是我先看到了别人的答案,所以接受了他的。谢谢你的建议!