• Stars
    star
    511
  • Rank 83,329 (Top 2 %)
  • Language
    Clojure
  • License
    Other
  • Created over 9 years ago
  • Updated about 3 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Better exception reporting middleware for Ring.

prone Build Status

Better exception reporting middleware for Ring. Heavily inspired by better_errors for Rails.

See it to believe it: a quick video demoing Prone.

Prone presents your stack traces in a consumable form. It optionally filters out stack frames that did not originate in your application, allowing you to focus on your code. It allows you to browse environment data, such as the request map and exception data (when using ex-info). Prone also provides a debug function that enables you to visually browse local bindings and any piece of data you pass to debug.

Install

Add [prone "2021-04-23"] to :dependencies in your project.clj.

This project no longer uses Semantic Versioning. Instead we're aiming to never break the API. Feel free to check out the change log.

Usage

  • with lein-ring

    Using lein-ring version 0.9.1 or above, add this to your project.clj:

    {:profiles {:dev {:ring {:stacktrace-middleware prone.middleware/wrap-exceptions}}}
  • without lein-ring

    Add it as a middleware to your Ring stack:

    (ns example
      (:require [prone.middleware :as prone]))
    
    (def app
      (-> my-app
          prone/wrap-exceptions))

    Please note, with this configuration you should make sure to only enable Prone in development.

  • with pedestal

    See prone-pedestal

  • with catacumba

    See catacumba-prone

Debugging

Whether you've tripped on an exception or not, you can use Prone to debug your application:

(ns example
  (:require [prone.debug :refer [debug]]))

(defn myhandler [req]
  ;; ...
  (let [person (lookup-person (:id (:params req)))]
    (debug)))

Calling debug without any arguments like this will cause Prone to render the exception page with information about your environment: the request map, and any local bindings (req and person in the above example).

You can call debug multiple times. To differentiate calls, you can pass a message as the first argument, but Prone will also indicate the source location that triggered debugging.

debug accepts any number of forms to present in a value browser on the error/debug page:

(debug) ;; Inspect locals
        ;; Halts the page if there are no exceptions

(debug "Here be trouble") ;; Same as above, with a message

(debug {:id 42}) ;; Inspect locals and the specific map
                 ;; Halts the page if there are no exceptions

(debug person project) ;; Same as above, with multiple values

(debug "What's this?" person project) ;; Same as above, with message

Q & A

Should I use Prone in production?

No. You would be exposing your innards to customers, and maybe even to someone with nefarious purposes.

Here's one way to avoid it:

(def prone-enabled? (= "true" (System.getProperty "prone.enable")))

(def app
  (cond-> my-app
          prone-enabled? prone/wrap-exceptions))

You can chain more optional middlewares in this cond-> too. Pretty nifty.

How does Prone determine what parts of a stack trace belongs to the application?

By default it reads your project.clj and looks for namespaces starting with the project name.

You can change this behavior by passing in some options to wrap-exceptions, like so:

(-> app
    (prone/wrap-exceptions 
      {:app-namespaces ["our" "app" "namespace" "prefixes"]}))

All frames from namespaces prefixed with the names in the list will be marked as application frames.

How do I skip prone for certain requests?

Pass a predicate function skip-prone? to wrap-exceptions. For example, to exclude Postman requests check for postman-token in the headers:

(-> app
    (prone/wrap-exceptions 
      {:skip-prone? (fn [req] (contains? (:headers req) "postman-token"))}))

What about AJAX requests?

Yeah, that's a bit trickier. There's no point in serving a beautiful exception page when you have to inspect it in devtools.

The prone response includes a Link header with a rel=help attribute. Like this:

Link:</prone/d97fa078-7638-4fd1-8e4a-9a22576a321f>; rel=help

Use this in your frontend code to display the page. Here's an example from one of our sites:

(def rel-help-regex #"<(.+)>; rel=help")

(defn check-err [result]
  (if-let [url (->> (get-in result [:headers "link"] "")
                    (re-find rel-help-regex)
                    second)]
    (set! js/location url)
    (do (js/alert "fail")
        (prn result))))

(defn GET [url params]
  (go
    (let [result (<! (http/get url {:query-params params}))]
      (if (:success result)
        (do-some-successful-stuff)
        (check-err result)))))

A little trick

The latest prone error page can also be found under /prone/latest, so if you haven't fixed your frontend code to use the rel=help header quite yet, you can always go there to check it out.

I'm getting double printing of error messages

Yeah, I guess you already have a logging framework to print errors for you? And then prone goes and prints them as well. Turn it off like so:

(-> app
    (prone/wrap-exceptions 
      {:print-stacktraces? false}))

Known problems

  • We have not yet found a way to differentiate some-name and some_name function names by inspecting the stack trace. Currently, we assume kebab case.
  • Using a middleware to always load the Austin browser-connected-repl for ClojureScript causes JavaScript errors that partly trips up Prone

Change log

From 1.6.3 to 2019-07-08

  • Add ability to copy values into clipboard
  • Navigation now starts directly at the root cause exception
  • Serialized values are now displayed better and more consistently
  • Improved display of functions

From 1.6.1 to 1.6.3

  • Can now navigate into sets + weeded out some weird set bugs
  • Update realize, it now guards against infinite lazy seqs

From 1.6 to 1.6.1

  • Don't crash without a project.clj-file.

From 1.5 to 1.6

  • Support SQLException getNextException (timothypratley)
  • Add column in addition to line number (timothypratley)
  • Display java.util.Date like #inst

From 1.4 to 1.5

  • Avoid expanding Datomic databases
  • Don't show too many extra exceptions
  • Always select the first source location when switching between exceptions

From 1.3 to 1.4

  • Exceptions thrown when realizing lazy sequences are now handled properly.

From 1.2 to 1.3

  • Add function to render self-contained page.

    This can be used to store prone-pages for later perusal even when the prone process is no longer running.

    (spit "my-error.html" (render-self-contained-page (create-exception-page e {})))
    

From 1.1 to 1.2

  • Serve contents as UTF-8 - fixes occasional regexp error warning
  • Upgrade Prism.JS - fixes graphical glitch with highlighted line
  • Upgrade ClojureScript version - now supports namespaced keys.
  • Show error page for assertion errors as well (alephyud)
  • Fix error when showing maps with complex keys
  • Fix compatibility Clojure 1.9 (lvh)
  • Don't crash on invalid or missing line-numbers

From 1.0 to 1.1

  • Added option :print-stacktraces? (Max Ovsiankin)
  • Added latest prone error to /prone/latest (Daniel Lebrero)

Contributors

Thanks!

Contribute

Yes, please do. And add tests for your feature or fix, or we'll certainly break it later.

Up and running

Prerequisites:

To start the server:

  • run lein cljsbuild auto in one terminal
  • run lein ring server-headless in another.

./bin/kaocha will run all tests. (run lein cljsbuild once to generate required js files)

To run tests continuously: ./bin/kaocha --watch

After making changes to static files in dev-resources, run ./build-js-sources.sh again to update the concatenated files.

License: BSD

Copyright © 2014-2018 Christian Johansen & Magnar Sveen. All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

  1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.

  2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.

  3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

More Repositories

1

multiple-cursors.el

Multiple cursors for emacs.
Emacs Lisp
2,221
star
2

dash.el

A modern list library for Emacs
Emacs Lisp
1,632
star
3

expand-region.el

Emacs extension to increase selected region by semantic units.
Emacs Lisp
1,334
star
4

s.el

The long lost Emacs string manipulation library.
Emacs Lisp
1,023
star
5

optimus

A Ring middleware for frontend performance optimization.
Clojure
364
star
6

stasis

Some Clojure functions for creating static websites.
Clojure
345
star
7

parens-of-the-dead

A series of zombie-themed games written with Clojure and ClojureScript.
Clojure
152
star
8

mark-multiple.el

An extension to emacs that sorta lets you mark several regions at once
Emacs Lisp
114
star
9

string-edit.el

Avoid escape nightmares by editing strings in a separate buffer
Emacs Lisp
100
star
10

tagedit

A collection of paredit-like functions for editing in html-mode.
Emacs Lisp
96
star
11

multifiles.el

Work in progress: View and edit parts of multiple files in one buffer
Emacs Lisp
74
star
12

fold-this.el

Fold the active region in Emacs
Emacs Lisp
71
star
13

change-inner.el

Emacs version of vim's ci and co commands
Emacs Lisp
60
star
14

angular-snippets.el

Yasnippets for AngularJS
Emacs Lisp
45
star
15

autolint

Autolint watches your files for jslint-errors
JavaScript
43
star
16

kaocha-runner.el

An emacs package for running Kaocha tests via CIDER.
Emacs Lisp
32
star
17

smart-forward.el

semantic navigation based on expand-region.el
Emacs Lisp
31
star
18

hardcore-mode.el

Disable arrow keys + optionally backspace and return
Emacs Lisp
28
star
19

java-time-literals

A Clojure library that defines literals for java.time classes.
Clojure
27
star
20

confair

Confair is a configuration library for Clojure.
Clojure
26
star
21

parens-of-the-dead-s2

The code for Parens of the Dead season 2
Clojure
21
star
22

yesql-ghosts

Display ghostly yesql defqueries inline, in Emacs
Emacs Lisp
18
star
23

catenate

A deprecated Ring middleware to serve concatenated static files with cache buster URLs in production.
Clojure
16
star
24

emacsd-reboot

Reboot of .emacs.d
Emacs Lisp
16
star
25

emacsrocks.com

The emacsrocks.com site implemented in Clojure with Stasis and Optimus
Clojure
15
star
26

realize

Realizing clojure data structures, no more laziness
Clojure
15
star
27

test-with-files

A Clojure library to easily write tests with files.
Clojure
15
star
28

datomic-type-extensions

A Clojure library that wraps Datomic API functions to add type extensions.
Clojure
14
star
29

datoms-differ

Find the diff between two txes in datoms.
Clojure
14
star
30

datomic-snippets

Yasnippets for Datomic.
Emacs Lisp
14
star
31

mapdown

A lightweight markup format to turn strings into maps in Clojure.
Clojure
13
star
32

cljs-styles

Vendor prefixes for React inline styles with ClojureScript.
Clojure
13
star
33

html5-walker

Search and replace in HTML5 strings.
Clojure
12
star
34

zombie-clj

An zombie themed web game made with Clojure and ClojureScript
Clojure
12
star
35

what-the-emacsd

The code for http://whattheemacsd.com
HTML
11
star
36

www.parens-of-the-dead.com

The code that generates parens-of-the-dead.com
Clojure
11
star
37

kaocha-noyoda

Don't talk like yoda. This kaocha plugin lets you write `(is (= actual expected))`.
Clojure
11
star
38

Zombie-TDD

Bli med når jeg lager et nettspill fra scratch med javascript på både frontend og backend. Det blir zombier, mafia og testdrevet utvikling.
JavaScript
10
star
39

annoying-arrows-mode.el

Emacs gets annoyed when you navigate around your document one char at a time.
Emacs Lisp
10
star
40

helpful-loader

A Clojure library to load resources with helpful error messages.
Clojure
9
star
41

buster-mode

A minor mode for emacs to speed up development when writing tests with Buster.JS
Emacs Lisp
8
star
42

stubadub

A small stubbing library for Clojure and ClojureScript
Clojure
8
star
43

bang.el

Used to be a modern list library for Emacs (renamed to dash)
Emacs Lisp
8
star
44

optimus-angular

Angular.JS optimizations for Optimus
Clojure
8
star
45

buster.tmbundle

TextMate bundle for Buster.js
6
star
46

java-time-dte

Datomic type extensions for java.time classes
Clojure
6
star
47

optimus-img-transform

An Optimus image transformation middleware.
Clojure
6
star
48

simplezen.el

A simple subset of zencoding-mode for Emacs
Emacs Lisp
5
star
49

zombieclj-s02

Koden til ZombieCLJ Sesong 2
CSS
5
star
50

server-facade

Code and slides belonging to my JavaZone-talk about wrapping your ajax-calls to get cleaner code and nicer testing.
JavaScript
4
star
51

naive-xml-reader

A naive Clojure library that turns XML into maps.
Clojure
4
star
52

blockout

Recreating one of my first games for the web to learn Canvas.
JavaScript
4
star
53

norsk-extreme-startup

Oversatt til norsk og tilpassett FINN
Ruby
3
star
54

crappy-jsp-mode

Seriously, this is not a good jsp-mode, it just solves some of my problems
Emacs Lisp
3
star
55

optimus-jsx

A React JSX asset loader for Optimus.
JavaScript
3
star
56

optimus-less

A LESS asset loader for Optimus.
Clojure
3
star
57

zombieclj.no

Koden bak www.zombieclj.no
Clojure
2
star
58

zombieclj-s2

Koden for andre sesong av Zombie CLJ.
CSS
2
star
59

mytomatoes.clj

mytomatoes.com rescue operation
Clojure
2
star
60

creator.js

A tiny library for creating create-methods for your objects.
JavaScript
2
star
61

roll20-scripts

Scripts for roll20
JavaScript
2
star
62

buster-snippets.el

Yasnippets for the Buster test framework.
Emacs Lisp
2
star
63

jquery-autogrow

Chrys Bader's Auto Growing Textareas: This plugin makes it easy to have auto-growing textareas. Meaning, if you have a textarea, as the user types it will expand vertically to accommodate the size of the entry. This was inspired by Facebook's auto-expanding text areas.
JavaScript
1
star