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

Using expound printer for instrument exceptions in the browser #152

Closed
mhuebert opened this issue Mar 22, 2019 · 2 comments
Closed

Using expound printer for instrument exceptions in the browser #152

mhuebert opened this issue Mar 22, 2019 · 2 comments

Comments

@mhuebert
Copy link

Recent updates in cljs removed the explain-out string from exception messages. This means exceptions thrown by instrument will not contain a nicely formatted string even if all the instructions for setting up expound have been followed (eg. setting up s/*explain-out*).

These changes to cljs were made with the intention that exceptions should contain only data, and leave formatting/printing to the edges of the system, eg. by a REPL. To help with this, we have the cljs.repl/error->str function, which handles printing of exceptions in a general way (not only spec errors).

What does this mean for the browser? Well, to start, we'll find that exceptions have become less informative than they used to be, until we somehow leverage these new tools to make them meaningful again. There may be numerous approaches to this, each with their own tradeoffs.

a couple of approaches to consider:

  1. print all uncaught exceptions using repl/error->str using a global error handler:
(ns app.core 
  (:require [cljs.spec.alpha :as s]
            [expound.alpha :as expound]
            [cljs.repl :as repl]))

(set! s/*explain-out* expound/printer)

(defn error-handler [message url line column e]
  (js/console.error e)
  (print (repl/error->str e))
  true)

(set! (.-onerror js/window) error-handler)
  1. extend the ExceptionInfo type to always rely on the repl error->str function, so that errors you print in your own try/catch blocks are also formatted:
(extend-type ExceptionInfo
  IPrintWithWriter
  (-pr-writer [o writer opts]
    (-write writer (repl/error->str o))))
  1. augment the console itself to use cljs.repl/error->str to format errors - this would be the domain of tools like cljs-devtools

  2. patch/extend tools to (optionally) include formatted messages in exceptions

@mhuebert
Copy link
Author

mhuebert commented Mar 22, 2019

re: (3), here's a snippet for adding a custom formatter to the Chrome devtools console that will use repl/error->str to format any ExceptionInfo encountered:

(ns app.core
  (:require [cljs.repl :as repl]))

(def devtools-error-formatter
  "Uses cljs.repl utilities to format ExceptionInfo objects in Chrome devtools console."
  #js{:header
      (fn [object config]
        (when (instance? ExceptionInfo object)
          (let [message (some->> (repl/error->str object)
                                 (re-find #"[^\n] "))]
            #js["span" message])))
      :hasBody (constantly true)
      :body (fn [object config]
              #js["div" (repl/error->str object)])})
(defonce _
         (some-> js/window.devtoolsFormatters
                 (.unshift devtools-error-formatter)))

This should be more general and less intrusive than the other approaches.

@bhb
Copy link
Owner

bhb commented Dec 29, 2019

@mhuebert Thanks for the write up and the code! I've included these instructions in the README and linked to this issue.

@bhb bhb closed this as completed Dec 29, 2019
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

2 participants