I am using ExecutorService
to send mails asynchronously, so there is a class:
class Mailer implements Runnable { ...
That handles the sending. Any exception that gets caught is logged, for (anonymized) example:
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]
Not very helpful - I need to see the stacktrace that invoked the ExecutorService
that caused all of this. My solution is to create an empty Exception
and pass it into Mailer
:
executorService.submit(new Mailer(foo, bar, new Exception()));
...
// constructor
public Mailer(foo, bar, Exception cause) { this.cause = cause; ...
And now in the case of exception I want to log the problem itself and its cause from the other thread:
try {
// send the mail...
} catch (Throwable t) {
LOG.error("Stuff went wrong", t);
LOG.error("This guy invoked us", cause);
}
This works great but produces two logs. I want to combine t
and cause
into a single exception and log that one. In my opinion, t
caused cause
, so using cause.initCause(t)
should be the right way. And works. I see a full stack trace: from where the call originated all the way up to the AddressException
.
Problem is, initCause()
works only once and then crashes. Question 1: can I clone Exception
? I'd clone cause
and init it with t
every time.
I tried t.initCause(cause)
, but that crashes right away.
Question 2: is there another smart way to combine these 2 exceptions? Or just keep one thread context in the other thread context for logging purposes?