【发布时间】:2015-08-22 21:28:56
【问题描述】:
我使用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 的堆栈跟踪。我的解决方案是创建一个空的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: 有没有另一种聪明的方法来结合这 2 个例外?或者只是将一个线程上下文保留在另一个线程上下文中以进行日志记录?
【问题讨论】:
-
从异常中获取堆栈跟踪并使用它怎么样?
-
@RealSkeptic 所以我尝试了这个
t.setStackTrace(ArrayUtils.addAll(t.getStackTrace(), cause.getStackTrace()));,它似乎有效。这不太好,例如,我很高兴看到线程边界以某种方式突出显示(“由:”是理想的),但它可以工作。把它写下来作为答案,这样我就可以接受了:) -
“我可以克隆
Exception吗?” 你可以通过序列化它并立即反序列化它。它很笨重,但很有效。 -
@vektor,你可以使用
Exception e = new Exception(t); e.setStackTrace(cause.getStackTrace()); LOG.error("Stuff went wrong", e);这样你应该有一个单独的原因。 -
它们是独立的字段。 setStackTrace 的 javadoc 解释了为什么允许它:docs.oracle.com/javase/7/docs/api/java/lang/…
标签: java multithreading logging stack-trace