Reputation: 3784
I'm just starting to learn Clojure and struggling to extract Exception metadata. When I run this:
(try
(/ 1 0)
(catch Exception error (println error)))
I get an ArithmeticException, as expected. The stacktrace printed looks like this:
#error {
:cause Divide by zero
:via
[{:type java.lang.ArithmeticException
:message Divide by zero
:at [clojure.lang.Numbers divide Numbers.java 188]}]
:trace
[[clojure.lang.Numbers divide Numbers.java 188]
[clojure.lang.Numbers divide Numbers.java 3901]
...
]}
It looks like a map
to me, so I tried to extract the value from :cause
with (:cause error)
, but it evaluates to nil
.
How can I do that?
After digging a bit, I found that #error {...}
is a java.lang.Throwable class, is that correct?
I tried using Java interop (.getCause error)
, but also returns nil
. Turns out (.getMessage) error)
does return "Divide by zero".
Are there other ways to get specific attributes from that class, other than .getMessage()
?
Upvotes: 4
Views: 563
Reputation: 6666
Clojure has ex-message
to retrieve the message from an exception and ex-cause
to retrieve the cause -- if there is one. The printed display of #error
is a bit misleading here because there actually is no "cause" in the exception (in the Java sense of .getCause
) because there is no chained exception.
Another useful function is Throwable->map
which turns the exception (all exceptions are java.lang.Throwable
at their root) into a regular Clojure hash map on which you can perform all the regular operations:
user=> (ex-message (try (/ 1 0) (catch Exception e e)))
"Divide by zero"
user=> (keys (Throwable->map (try (/ 1 0) (catch Exception e e))))
(:via :trace :cause)
user=> (:cause (Throwable->map (try (/ 1 0) (catch Exception e e))))
"Divide by zero"
user=>
Upvotes: 13