(defn Throwable->map
"Constructs a data representation for a Throwable."
{:added "1.7"}
[^Throwable o]
(let [base (fn [^Throwable t]
(merge {:type (symbol (.getName (class t)))
:message (.getLocalizedMessage t)}
(when-let [ed (ex-data t)]
{:data ed})
(let [st (.getStackTrace t)]
(when (pos? (alength st))
{:at (StackTraceElement->vec (aget st 0))}))))
via (loop [via [], ^Throwable t o]
(if t
(recur (conj via t) (.getCause t))
via))
^Throwable root (peek via)
m {:cause (.getLocalizedMessage root)
:via (vec (map base via))
:trace (vec (map StackTraceElement->vec
(.getStackTrace ^Throwable (or root o))))}
data (ex-data root)]
(if data
(assoc m :data data)
m)))