Welcome! Please see the About page for a little more info on how this works.

0 votes
in Clojure by

Recently, I fixed a bug in a library that exposed the capability to modify the data within an ex-info before printing (logging) it, by creating a new ex-info to store the updated data. This naturally overwrote the existing stack trace on the given ex-info, so my fix was to use interop to set the stack trace of the new ex-info to the stack trace of the original ex-info:

(let [cause (process-ex-data-map ex-data-field-fn (ex-cause ex))
      new-ex (ex-info (ex-message ex)
                      (into {} (map (fn [[k v]] {k (ex-data-field-fn v)}) (ex-data ex)))
                      cause)]
  (.setStackTrace ^ExceptionInfo new-ex (.getStackTrace ^ExceptionInfo ex))
  new-ex)

This is a fine solution, but it feels bad or awkward to be directly modifying the internals of the ex-info. I understand that ExceptionInfo probably can't be immutable for interop reasons, but I think it would be helpful if there were functions in clojure.core that operated on ExceptionInfos as if they were immutable.

Maybe something like this?

(defn ex-stacktrace
  ([ex]
   (when (instance? Throwable ex)
     (.getStackTrace ^Throwable ex)))
  ([ex other]
   (when (and (instance? clojure.lang.ExceptionInfo ex)
              (instance? Throwable other))
     (let [new-ex (ex-info (ex-message ex) (ex-data ex) (ex-cause ex))]
       (.setStackTrace ^clojure.lang.ExceptionInfo new-ex
                       (.getStackTrace ^Throwable other))
       new-ex))))

1 Answer

+1 vote
by
selected by
 
Best answer

I think this is unusual enough that we don't need an api for it beyond interop.

by
Cool, thanks for the answer.
...