|
5 | 5 | :author "Jeff Valk, Oleksandr Yakushev"}
|
6 | 6 | (:require
|
7 | 7 | [clojure.java.io :as io]
|
| 8 | + [clojure.main] |
8 | 9 | [clojure.pprint :as pp]
|
9 | 10 | [clojure.repl :as repl]
|
10 | 11 | [clojure.spec.alpha :as s]
|
11 | 12 | [clojure.string :as str]
|
12 | 13 | [orchard.info :as info]
|
13 |
| - [orchard.java.resource :as resource]) |
| 14 | + [orchard.java.resource :as resource] |
| 15 | + [orchard.misc :refer [assoc-some]]) |
14 | 16 | (:import
|
15 | 17 | (java.io StringWriter)
|
16 | 18 | (java.net URL)
|
|
166 | 168 | (if (< i 0)
|
167 | 169 | frames
|
168 | 170 | (let [frame-name (:name (get frames i))
|
169 |
| - tooling? (or (tooling-frame-name? frame-name) |
170 |
| - ;; Everything runs from a Thread, so this frame, if at |
171 |
| - ;; the end, is irrelevant. However one can invoke this |
172 |
| - ;; method 'by hand', which is why we only skip |
173 |
| - ;; consecutive frames that match this. |
174 |
| - (and all-tooling-so-far? |
175 |
| - (re-find #"^java\.lang\.Thread/run|^java\.util\.concurrent" |
176 |
| - frame-name)))] |
| 171 | + tooling? (and frame-name |
| 172 | + (or (tooling-frame-name? frame-name) |
| 173 | + ;; Everything runs from a Thread, so this frame, |
| 174 | + ;; if at the end, is irrelevant. However one can |
| 175 | + ;; invoke this method 'by hand', which is why we |
| 176 | + ;; only skip consecutive frames that match this. |
| 177 | + (and all-tooling-so-far? |
| 178 | + (re-find #"^java\.lang\.Thread/run|^java\.util\.concurrent" |
| 179 | + frame-name))))] |
177 | 180 | (recur (cond-> frames
|
178 | 181 | tooling? (update i flag-frame :tooling))
|
179 | 182 | (dec i) (and all-tooling-so-far? tooling?))))))
|
|
260 | 263 | (print-fn % writer)
|
261 | 264 | (str writer))
|
262 | 265 | phase (-> cause-data :data :clojure.error/phase)
|
263 |
| - m {:class (name (:type cause-data)) |
264 |
| - :phase phase |
265 |
| - :message (:message cause-data) |
266 |
| - :stacktrace (analyze-stacktrace-data |
267 |
| - (cond (seq (:trace cause-data)) (:trace cause-data) |
268 |
| - (:at cause-data) [(:at cause-data)]))}] |
| 266 | + m (-> {:class (name (:type cause-data)) |
| 267 | + :phase phase |
| 268 | + :message (:message cause-data) |
| 269 | + :stacktrace (analyze-stacktrace-data |
| 270 | + (cond (seq (:trace cause-data)) (:trace cause-data) |
| 271 | + (:at cause-data) [(:at cause-data)]))} |
| 272 | + (assoc-some :triage (:triage cause-data)))] |
269 | 273 | (if-let [data (filter-ex-data (:data cause-data))]
|
270 | 274 | (if (::s/failure data)
|
271 | 275 | (assoc m
|
|
280 | 284 | :clojure.error/symbol])))
|
281 | 285 | m)))
|
282 | 286 |
|
| 287 | +(defn- maybe-triage-message |
| 288 | + "If the exception is a compiler error which carries Spec-based explanation data, |
| 289 | + transform it into human readable error message string." |
| 290 | + [exception-data] |
| 291 | + (try |
| 292 | + ;; ex-triage may throw an exception if :phase is incorrect |
| 293 | + (when-let [explanation-data (:clojure.error/spec |
| 294 | + (clojure.main/ex-triage exception-data))] |
| 295 | + (with-out-str (s/explain-out explanation-data))) |
| 296 | + (catch Exception _))) |
| 297 | + |
283 | 298 | (defn- analyze-causes
|
284 | 299 | "Analyze the cause chain of the `exception-data` in `Throwable->map` format."
|
285 | 300 | [exception-data print-fn]
|
286 |
| - (let [causes (vec (:via exception-data)) |
287 |
| - ;; If the first cause lacks :trace, add :trace of the exception there. |
288 |
| - causes (if (:trace (first causes)) |
289 |
| - causes |
290 |
| - (assoc-in causes [0 :trace] (:trace exception-data)))] |
| 301 | + (let [triage-message (maybe-triage-message exception-data) |
| 302 | + causes (update (vec (:via exception-data)) 0 |
| 303 | + #(cond-> % |
| 304 | + ;; If the first cause lacks :trace, add :trace of the |
| 305 | + ;; exception there. |
| 306 | + (nil? (:trace %)) (assoc :trace (:trace exception-data)) |
| 307 | + ;; If non-nil, assoc triage-message to first cause. |
| 308 | + triage-message (assoc :triage triage-message)))] |
291 | 309 | (mapv #(extract-location (analyze-cause % print-fn)) causes)))
|
292 | 310 |
|
293 | 311 | (defn analyze
|
|
0 commit comments