我正在使用ExecutorService
异步发送邮件,所以有一个类:
class Mailer implements Runnable { ...
处理发送。对于(匿名)示例,记录捕获的任何异常:
javax.mail.internet.AddressException: foo is bar
at javax.mail.internet.InternetAddress.checkAddress(InternetAddress.java:1213) ~[mail.jar:1.4.5]
at javax.mail.internet.InternetAddress.parse(InternetAddress.java:1091) ~[mail.jar:1.4.5]
at javax.mail.internet.InternetAddress.parse(InternetAddress.java:633) ~[mail.jar:1.4.5]
at javax.mail.internet.InternetAddress.parse(InternetAddress.java:610) ~[mail.jar:1.4.5]
at mycompany.Mailer.sendMail(Mailer.java:107) [Mailer.class:?]
at mycompany.Mailer.run(Mailer.java:88) [Mailer.class:?]
... suppressed 5 lines
at java.lang.Thread.run(Thread.java:680) [?:1.6.0_35]
不是很有帮助-我需要查看引起所有这些的
ExecutorService
调用的stacktrace。我的解决方案是创建一个空的Exception
并将其传递到Mailer
:executorService.submit(new Mailer(foo, bar, new Exception()));
...
// constructor
public Mailer(foo, bar, Exception cause) { this.cause = cause; ...
现在,在发生异常的情况下,我想从另一个线程记录问题本身及其原因:
try {
// send the mail...
} catch (Throwable t) {
LOG.error("Stuff went wrong", t);
LOG.error("This guy invoked us", cause);
}
这很好用,但是会产生两个日志。我想将
t
和cause
合并为一个异常并记录该异常。我认为t
会导致cause
,因此使用cause.initCause(t)
应该是正确的方法。和工程。我看到了完整的堆栈跟踪:从调用始发地一直到AddressException
。问题是,
initCause()
仅工作一次,然后崩溃。 问题1:我可以克隆Exception
吗?我会克隆cause
并每次使用t
对其进行初始化。我尝试了
t.initCause(cause)
,但是立即崩溃了。问题2:是否有另一种巧妙的方式来组合这两个异常?还是仅将一个线程上下文保留在另一个线程上下文中以进行记录?
最佳答案
根据我的评论,这实际上是我的想法。提醒您,我目前无法进行测试。
您从父线程传递的是New Exception().getStackTrace()
。或者更好,正如@Radiodef所说的Thread.currentThread().getStackTrace()
。因此,它基本上是一个StackTraceElement[]
数组。
现在,您可以拥有以下内容:
public class CrossThreadException extends Exception {
public CrossThreadException( Throwable cause, StackTraceElement[] originalStackTrace ) {
// No message, given cause, no supression, stack trace writable
super( null, cause, false, true );
setStackTrace( originalStackTrace );
}
}
现在,在您的catch子句中,您可以执行以下操作:
catch ( Throwable cause ) {
LOG( "This happened", new CrossThreadException( cause, originalStackTrace ) );
}
这将为您提供两个堆栈跟踪之间的边界。