Skip to content

Commit 2f2affe

Browse files
alexander-yakushevbbatsov
authored andcommitted
[stacktrace] Add support for directly inspecting ex-data
1 parent fbabdeb commit 2f2affe

File tree

4 files changed

+22
-11
lines changed

4 files changed

+22
-11
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
* Bump `orchard` to [0.33.0](https://github.com/clojure-emacs/orchard/blob/master/CHANGELOG.md#0330-2025-04-08).
66
* [#929](https://github.com/clojure-emacs/cider-nrepl/pull/929): Migrate profiling middleware to orchard.profile.
7+
* [#930](https://github.com/clojure-emacs/cider-nrepl/pull/930): Stacktrace: add support for directly inspecting ex-data
78

89
## 0.54.0 (2025-04-05)
910

doc/modules/ROOT/pages/nrepl-api/ops.adoc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -475,7 +475,8 @@ Required parameters::
475475

476476

477477
Optional parameters::
478-
{blank}
478+
* `:ex-data` When equal to "true", inspect ex-data of the exception instead of full exception.
479+
479480

480481
Returns::
481482
* `:status` "done", or "no-error" if ``analyze-last-stacktrace`` wasn't called beforehand (or the ``index`` was out of bounds).

src/cider/nrepl.clj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -686,6 +686,7 @@ those configured directories will be honored."
686686
"inspect-last-exception" {:doc "Returns an Inspector response for the last exception that has been processed through `analyze-last-stacktrace` for the current nrepl session.
687687
Assumes that `analyze-last-stacktrace` has been called first, returning \"no-error\" otherwise."
688688
:requires {"index" "0 for inspecting the top-level exception, 1 for its ex-cause, 2 for its ex-cause's ex-cause, and so on."}
689+
:optional {"ex-data" "When equal to \"true\", inspect ex-data of the exception instead of full exception."}
689690
:returns {"status" "\"done\", or \"no-error\" if `analyze-last-stacktrace` wasn't called beforehand (or the `index` was out of bounds)."
690691
"value" "A value, as produced by the Inspector middleware."}}
691692
"stacktrace" {:doc "Return messages describing each cause and

src/cider/nrepl/middleware/stacktrace.clj

Lines changed: 18 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,13 @@
1717

1818
;; Analyze the last stacktrace
1919

20-
(def ^:dynamic *last-exception* nil)
21-
2220
(defn- analyze-last-stacktrace
2321
"Analyze the last exception."
2422
[{:keys [session] :as msg}]
2523
(let [last-exception (@session #'*e)]
26-
(swap! session assoc #'*last-exception* last-exception) ;; note that *e can change later, so this entry isn't redundant
24+
;; We need to remember the analyzed exception separately because we need to
25+
;; provide a way to inspect it while *e can change.
26+
(alter-meta! session assoc ::analyzed-exception last-exception)
2727
(send-analysis msg (stacktrace/analyze last-exception))))
2828

2929
(defn- handle-analyze-last-stacktrace-op
@@ -42,14 +42,22 @@
4242
(handle-analyze-last-stacktrace-op msg)
4343
(notify-client msg "The `stacktrace` op is deprecated, please use `analyze-last-stacktrace` instead." :warning))
4444

45+
(defn- get-last-exception-cause [{:keys [session index] :as msg}]
46+
(when index
47+
(let [last-exception (::analyzed-exception (meta session))
48+
causes (when last-exception
49+
(->> (iterate #(.getCause ^Throwable %) last-exception)
50+
(take-while some?)))]
51+
(nth causes index nil))))
52+
4553
(defn handle-inspect-last-exception-op [{:keys [session index transport] :as msg}]
46-
(let [last-exception (@session #'*last-exception*)
47-
causes (->> (iterate #(.getCause ^Throwable %) last-exception)
48-
(take-while some?))
49-
cause (when index
50-
(nth causes index nil))]
51-
(if cause
52-
(t/send transport (middleware.inspect/inspect-reply* msg cause))
54+
(let [inspect-ex-data? (= (:ex-data msg) "true")
55+
cause (get-last-exception-cause msg)
56+
object (if inspect-ex-data?
57+
(ex-data cause)
58+
cause)]
59+
(if object
60+
(t/send transport (middleware.inspect/inspect-reply* msg object))
5361
(respond-to msg :status :no-error))
5462
(respond-to msg :status :done)))
5563

0 commit comments

Comments
 (0)