Skip to content

Commit

Permalink
Make sure ex-info stack trace appears even if root
Browse files Browse the repository at this point in the history
Fixes #39
  • Loading branch information
hlship committed Feb 11, 2016
1 parent e5ed093 commit 759fd7a
Show file tree
Hide file tree
Showing 3 changed files with 45 additions and 27 deletions.
5 changes: 5 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@
`parse-exception` can now handle method names containing '<' and '>' (used for instance and class
constructor methods), as well as other cases from real-life stack traces.

Stack traces were omitted when the deepest stack frame was via `ex-info`; this has been corrected.

[Closed issues](https://github.com/AvisoNovate/pretty/issues?q=milestone%3A0.1.23)


## 0.1.22 - 5 Feb 2016

Fixed a bug where `parse-exception` would fail if the source was "Unknown Source" instead
Expand Down
56 changes: 29 additions & 27 deletions src/io/aviso/exception.clj
Original file line number Diff line number Diff line change
Expand Up @@ -363,40 +363,42 @@
[exception options]
(transform-stack-trace-elements (expand-stack-trace exception) options))

(defn- is-throwable? [v]
(.isInstance Throwable v))

(defn- wrap-exception
[^Throwable exception properties next-exception stack-trace]
[{:class-name (-> exception .getClass .getName)
:message (.getMessage exception)
:properties properties
:stack-trace stack-trace}
next-exception])
[^Throwable exception properties options]
(let [throwable-property-keys (match-keys properties is-throwable?)
nested-exception (or (->> (select-keys properties throwable-property-keys)
vals
(remove nil?)
;; Avoid infinite loop!
(remove #(= % exception))
first)
(.getCause exception))
stack-trace (when-not nested-exception
(extract-stack-trace exception options))]
[{:class-name (-> exception .getClass .getName)
:message (.getMessage exception)
;; Don't ever want to include throwables since they will wreck the output format.
;; Would only expect a single throwable (either an explicit property, or as the cause)
;; per exception.
:properties (apply dissoc properties throwable-property-keys)
:stack-trace stack-trace}
nested-exception]))

(defn- expand-exception
[^Throwable exception options]
(if (instance? ExceptionInfo exception)
(wrap-exception exception (.getData ^ExceptionInfo exception) (.getCause exception) nil)
(let [properties (bean exception)
nil-property-keys (match-keys properties nil?)
throwable-property-keys (match-keys properties #(.isInstance Throwable %))
remove' #(remove %2 %1)
nested-exception (-> properties
(select-keys throwable-property-keys)
vals
(remove' nil?)
;; Avoid infinite loop!
(remove' #(= % exception))
first)
(wrap-exception exception (ex-data exception) options)
(let [properties (bean exception)
;; Ignore basic properties of Throwable, any nil properties, and any properties
;; that are themselves Throwables
discarded-keys (concat [:suppressed :message :localizedMessage :class :stackTrace]
nil-property-keys
throwable-property-keys)
retained-properties (apply dissoc properties discarded-keys)
;; Just extract a stack trace at the root exception (when the nested-exception
;; is nil).
stack-trace (when-not nested-exception
(extract-stack-trace exception options))]
(wrap-exception exception retained-properties nested-exception stack-trace))))
discarded-keys (concat [:suppressed :message :localizedMessage :class :stackTrace :cause]
(match-keys properties nil?)
(match-keys properties is-throwable?))
retained-properties (apply dissoc properties discarded-keys)]
(wrap-exception exception retained-properties options))))

(defn analyze-exception
"Converts an exception into a seq of maps representing nested exceptions.
Expand Down
11 changes: 11 additions & 0 deletions test/user.clj
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,17 @@
;; Return it, not rethrow it.
(RuntimeException. "Request handling exception" e))))

(defn make-ex-info
""
[]
(try
(throw (make-exception))
(catch Throwable t
;; Return it, not rethrow it.
(ex-info "Exception in make-ex-info."
{:function 'make-exception}
t))))

(defn infinite-loop
[]
(infinite-loop))
Expand Down

0 comments on commit 759fd7a

Please sign in to comment.