Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rethrowing exceptions with more data #31

Open
senior opened this issue Oct 25, 2012 · 0 comments
Open

Rethrowing exceptions with more data #31

senior opened this issue Oct 25, 2012 · 0 comments

Comments

@senior
Copy link

senior commented Oct 25, 2012

I have a pretty common scenario in my code base that I have had a hard time getting slingshot to handle properly. Not sure if there is already some code that solves this problem or if something could/should be added to make my scenario easier.

I have an exception that occurs at a lower level in the code and as that exception bubbles up, higher levels of the code have additional error context to add. I would like to assoc more information into the map at each of the higher level points without increasing the depth of the exception stack (and possibly not changing the error message). A pretty trivial example is below:

(defn stacktrace-depth
  ([t] (stacktrace-depth 1 t))
  ([i t]
     (if (.getCause t)
       (recur (inc i) (.getCause t))
       i)))

(defn stacking-up []
  (try+
   (try+
    (try+
     (try+
      (throw (RuntimeException. "Something went wrong"))
      (catch RuntimeException e
        (throw+ {:some-info "here"
                 :type 1}
                (.getMessage e))))
     (catch [:type 1] {:as error-stuff}
       (throw+ (assoc error-stuff :more-info "over there")
               (.getMessage (:cause &throw-context)))))
    (catch [:type 1] {:as error-stuff}
      (throw+ (assoc error-stuff :one-last "thing")
              (.getMessage (:cause &throw-context)))))
   (catch (constantly true) {:as err-ctx}
     (println "Exception Depth: "(stacktrace-depth (:throwable &throw-context)))
     (println "Error message: " (.getMessage (:throwable &throw-context)))
     (println "Error map: " err-ctx))))

=> (stacking-up)

;; Exception Depth:  4
;; Error message:  Something went wrong
;; Error map:  {:one-last thing, :more-info over there, :some-info here, :type 1}

The above has:
ExceptionInfo
-->ExceptionInfo
----> ExceptionInfo
------> RuntimeException

Really all I wanted was the additional information (i.e. the :more-info, :one-last, etc from above). It's more difficult to find out the real error now and I have to be careful about the error message (make sure I drag it along with me from the lower level exception).

To make this easier, I created a new macro I called merge-throw+:

(defn wrapped? [^Throwable t]
  (:slingshot.support/wrapper? (meta (ex-data t))))

(defmacro merge-throw+
  [new-obj & [message]]
  `(let [{throwable# :throwable cause# :cause object# :object} ~'&throw-context]
     (throw
      (wrap
       {:message (or ~message (.getMessage throwable#))
        :stack-trace (.getStackTrace throwable#)
        :cause (if (wrapped? throwable#)
                 cause#
                 throwable#)
        :object (if (wrapped? throwable#)
                  (merge object# ~new-obj)
                  ~new-obj)}))))

(defn keeping-it-flat []
  (try+
   (try+
    (try+
     (try+
      (throw (RuntimeException. "Something went wrong"))
      (catch RuntimeException e
        (merge-throw+ {:some-info "here"
                       :type 1})))
     (catch [:type 1] {:as error-stuff}
       (merge-throw+ {:more-info "over there"})))
    (catch [:type 1] {:as error-stuff}
      (merge-throw+ {:one-last "thing"})))
   (catch (constantly true) {:as err-ctx}
     (println "Exception Depth: "(stacktrace-depth (:throwable &throw-context)))
     (println "Error message: " (.getMessage (:throwable &throw-context)))
     (println "Error map: " err-ctx))))

=> (keeping-it-flat)
;; Exception Depth:  2
;; Error message:  Something went wrong
;; Error map:  {:one-last thing, :more-info over there, :some-info here, :type 1}

Am I going about this in the right way? Is there something built in that makes what I'm wanting easier?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant