taoensso / truss

Assertions micro-library for Clojure/Script
https://www.taoensso.com/truss
Eclipse Public License 1.0
304 stars 14 forks source link

Nicer CLJS console output #3

Closed olivergeorge closed 8 years ago

olivergeorge commented 8 years ago

Current assertion output for CLJS is a not super friendly but includes a nice friendly :message key. Perhaps there's a clean way to print that message before the data.

impl.cljs:148Uncaught #error {:message "Invariant violation in `utas.core:12` [pred-form, val]:\n [(nil? app), Assets]", :data {:*?data* nil, :elidable? true, :dt #inst "2016-03-21T00:46:36.807-00:00", :val "Assets", :ns-str "utas.core", :val-type #object[String "function String() { [native code] }"], :?err nil, :*assert* true, :?data nil, :?line 12, :form-str "(nil? app)"}}

I notice om.next uses goog.log which allows loggers to be defined and controlled. Logging is disabled when logger is not defined or logger level requirement is not met. That might provide an unintrusive way to turn off or enable goog.log.error calls which print the message to the console in a cross browser friendly way.

https://google.github.io/closure-library/api/class_goog_debug_Logger.html

ptaoussanis commented 8 years ago

Hi Oliver,

Logging's a bit beyond the scope of Truss. Something like goog.log would be an option, or you can look at something like Timbre.

Re: actually capturing errors- you may want to look into https://developer.mozilla.org/en/docs/Web/API/GlobalEventHandlers/onerror or, depending on your app architecture, you may be able to run your relevant application code in an appropriate try-catch block that'll let you print your errors.

Does that help / make sense?

Another reasonable option may be for Truss to expose a callback fn that triggers on assertion failures. Will see about that next time I'm in the code :-)

Cheers,

olivergeorge commented 8 years ago

Thanks for your thoughts. I see what you mean. Shame it's hard to format things nicely on the browser console... reading errors easily is a critical part of staying efficient.

This is what I'm using for now. Strips out all the nice metadata but leaves the informative message (and line number reference).

(ns my.contract
  (:require [taoensso.truss :as truss :refer [have]]))

(defmacro pred
  [& body]
  `(try (taoensso.truss/have ~@body)
        (catch cljs.core/ExceptionInfo e#
          (throw (.-message e#)))))
ptaoussanis commented 8 years ago

Shame it's hard to format things nicely on the browser console... reading errors easily is a critical part of staying efficient. [...]

Not sure I follow why you'd use that approach as opposed to, say, just printing proper error output with Timbre?

To clarify: not suggesting that clear error formatting isn't important; going further and suggesting it's important enough that you might want to be using a proper tool for the job. Truss's responsibilities involve catching the error and generating the error data; it intentionally leaves formatting to you so that you can reach for your choice of dedicated tool.

Does that make sense?

ptaoussanis commented 8 years ago

In case it's easier, have also just pushed [com.taoensso/truss "1.2.0-alpha2"] to Clojars which provides a set-error-fn! - https://github.com/ptaoussanis/truss/blob/6538f8e632939f307b54b3c4a20118dae86f7760/src/taoensso/truss.cljx#L133

Edit: that's alpha2, not alpha1. Clojars upload trouble.

olivergeorge commented 8 years ago

I see your point. I've not worked with loggers in CLJS. Thanks for the suggestion and update.

ptaoussanis commented 8 years ago

No problem. A proper example in case it's helpful- as of 1.2.0-alpha2, you can do this:

(truss/set-error-fn!
  (fn [msg data-map] ; This fn will get called on Truss violations
    ;; Do whatever kind of logging you like here (Timbre / goog.log / etc.)
))

So you can pretty-print the data-map, output it to your console or cljs REPL tool, send it to your server, etc. - whatever you'd find most handy.

As an example of a basic pretty printer:

(defn pprint->str [x] (with-out-str (cljs.pprint/pprint x)))

If you're using Timbre, then you can go for something like this:

(truss/set-error-fn!
  (fn [msg data-map]
    (timbre/error (str msg "\n\n" (pprint->str data-map)))))

Hope that helps, cheers! :-)