我有一个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行(所以我知道方法的调用者)而不将整个堆栈跟踪转储到日志上或者必须依赖外部库?
答案 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()
的方法。如果你想显示这些行,请调整它。
感谢@ BrianAgnew(stackoverflow.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();
}
}