Skip to content

Commit

Permalink
Merge pull request #63 from rymndhng/add-pretty-app-frame
Browse files Browse the repository at this point in the history
Add custom app frames with bolded clojure frame font
  • Loading branch information
Paudi Moriarty committed Dec 22, 2018
2 parents 48949a0 + a1b34c4 commit 496c197
Show file tree
Hide file tree
Showing 5 changed files with 119 additions and 2 deletions.
22 changes: 21 additions & 1 deletion docs/exceptions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,26 @@ The related function, ``format-exception``, produces the same output, but return

For both ``format-exception`` and ``write-exception``, output of the stack trace is optional, or can be limited to a certain number of stack frames.

Frames can also be highlighted by customizing ``io.aviso.exception/*app-frame-names*``. This adds extra visual clarity to identify frames that belong in your clojure code vs. library code.

Before:

.. image:: images/without-app-frame-names-exceptions.png
:alt: Without app-frame-names

After:

.. image:: images/with-app-frame-names-exception.png
:alt: With custom app-frame-names

Notice with custom app-frame-names, the matched frame names are also bolded. This is customized by re-binding or altering
``*app-frame-names*``, which is a list of string or patterns to match on the frame's name.

::

;; marks any frame that begins with demo
(alter-var-root #'io.aviso.exception/*app-frame-names* (constantly [#"my-app.*"]))

io.aviso.repl
-------------

Expand All @@ -124,4 +144,4 @@ io.aviso.logging
----------------

This namespace includes functions to change ``clojure.tools.logging`` to use Pretty to output exceptions, and to add a
default Thread.UncaughtExceptionHandler that uses ``clojure.tools.logging``.
default Thread.UncaughtExceptionHandler that uses ``clojure.tools.logging``.
Binary file added docs/images/with-app-frame-names-exception.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
17 changes: 16 additions & 1 deletion src/io/aviso/exception.clj
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,16 @@
:message italic-font
:property bold-font
:source green-font
:app-frame bold-yellow-font
:function-name bold-yellow-font
:clojure-frame yellow-font
:java-frame white-font
:omitted-frame white-font})

(def ^:dynamic *app-frame-names*
"Set of filters (belong to your applications) to create more visual clarity."
nil)

(def ^:dynamic *fonts*
"Current set of fonts used in exception formatting"
(when-not (System/getenv "DISABLE_DEFAULT_PRETTY_FONTS")
Expand Down Expand Up @@ -325,6 +330,16 @@
(flush)))
elements))

(defn- clj-frame-font
"Returns the font to use for a clojure frame.
When provided a frame matching *app-frame-names*, returns :app-frame, otherwise :clojure-frame
"
[frame]
(-> (keep #(apply-rule frame [:name % :app-frame]) *app-frame-names*)
first
(or :clojure-frame)))

(defn- preformat-stack-frame
[frame]
(cond
Expand All @@ -343,7 +358,7 @@
:else
(let [names (:names frame)
formatted-name (str
(:clojure-frame *fonts*)
(get *fonts* (clj-frame-font frame))
(->> names drop-last (str/join "/"))
"/"
(:function-name *fonts*) (last names) (:reset *fonts*))]
Expand Down
82 changes: 82 additions & 0 deletions test/demo_app_frames.clj
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
(ns demo-app-frames
"This namespace demonstrates how customizing io.aviso.exception/*app-frames*
helps highlight application logic in stacktraces
The `comment` block at end of file demonstrates this feature.
"
(:require [io.aviso.repl :as repl]))
(repl/install-pretty-exceptions)

;; -- provided.* namespaces are libraries we're consuming ---------------------
(ns provided.db
(:import (java.sql SQLException)))
(defn jdbc-update
[]
(throw (SQLException. "Database failure" "ABC" 123)))


(ns provided.worker)
(defprotocol Worker
(do-work [this]))


(ns provided.db-worker)
(defn make-jdbc-update-worker
[]
(reify
provided.worker/Worker
(provided.worker/do-work [this] (provided.db/jdbc-update))))

;; -- my-app are namespaces belonging to our application ----------------------
(ns my-app.db)
(defn update-row
[]
(try
(-> (provided.db-worker/make-jdbc-update-worker) provided.worker/do-work)
(catch Throwable e
(throw (RuntimeException. "Failure updating row" e)))))


(ns my-app.handler)
(defn make-exception
"Creates a sample exception used to test the exception formatting logic."
[]
(try
(my-app.db/update-row)
(catch Throwable e
;; 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))))


(ns my-app.handler-test
(:require [clojure.test :refer [report]]))

(defn test-failure
[]
(report {:type :error :expected nil :actual (my-app.handler/make-ex-info)}))


(comment
;; Run these commands in a REPL
(require '[demo-appframes] :reload)

;; Should show no app-frames highlighted
(alter-var-root #'io.aviso.exception/*app-frame-names* (constantly []))
(my-app.handler-test/test-failure)

;; Should show app-frames (beginning with my-app) highlighted
(alter-var-root #'io.aviso.exception/*app-frame-names* (constantly [#"my-app.*"]))
(my-app.handler-test/test-failure)

)

0 comments on commit 496c197

Please sign in to comment.