Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Omit frames #10

Open
wants to merge 7 commits into from

1 participant

@technomancy
Collaborator

Would like to get some discussion going on this. The meat is in the omit-frames function in utils.clj, but the notion of accepting an options map in the pst function is something that will probably be used more in the future; in particular @alexbaranosky wants to allow the colors to be customized.

Thoughts?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
This page is out of date. Refresh to see the latest.
View
19 README.md
@@ -7,6 +7,8 @@ For example, to print a nice stack trace in a REPL:
=> (use 'clj-stacktrace.repl)
=> ("foo")
java.lang.ClassCastException: java.lang.String cannot be cast to clojure.lang.IFn (NO_SOURCE_FILE:0)
+ => (pst)
+ java.lang.ClassCastException: java.lang.String cannot be cast to clojure.lang.IFn (NO_SOURCE_FILE:0)
Compiler.java:5440 clojure.lang.Compiler.eval
Compiler.java:5391 clojure.lang.Compiler.eval
core.clj:2382 clojure.core/eval
@@ -25,18 +27,23 @@ For example, to print a nice stack trace in a REPL:
NO_SOURCE_FILE:2 user/eval100
Compiler.java:5424 clojure.lang.Compiler.eval
-
In stack traces printed by `pst`:
-* Java methods are described with the usual `name.space.ClassName.methodName` convention and Clojure functions with their own `name.space/function-name` convention.
-* Anonymous clojure functions are denoted by adding an `[fn]` to their enclosing, named function.
+* Java methods are described with the usual
+ `name.space.ClassName.methodName` convention and Clojure functions
+ with their own `name.space/function-name` convention.
+* Anonymous clojure functions are denoted by adding an `[fn]` to their
+ enclosing, named function.
* "Caused by" cascades are shown as in regular java stack traces.
* Elements are vertically aligned for better readability.
* Printing is directed to `*out*`.
-If you want to direct the printing to somewhere other than `*out*`, either use `pst-on` to specify the output location or `pst-str` to capture the printing as a string.
+If you want to direct the printing to somewhere other than `*out*`,
+either use `pst-on` to specify the output location.
-The library also offers an API for programatically 'parsing' exceptions. This API is used internal for `pst` and can be used to e.g. improve development tools. Try for example:
+The library also offers an API for programatically 'parsing'
+exceptions. This API is used internal for `pst` and can be used to
+e.g. improve development tools. Try for example:
```clj
(use 'clj-stacktrace.core)
@@ -46,7 +53,7 @@ The library also offers an API for programatically 'parsing' exceptions. This AP
(parse-exception e)))
```
-If you use Leiningen, you can install clj-stacktrace on a per-user basis:
+If you use Leiningen, you can install clj-stacktrace on a user-level basis:
$ lein plugin install clj-stacktrace 0.2.4
View
4 src/clj_stacktrace/core.clj
@@ -76,7 +76,7 @@
:method (.getMethodName elem)))))
(defn parse-trace-elems
- "Returns a seq of maps providing usefull information about the java stack
+ "Returns a seq of maps providing useful information about the java stack
trace elements. See parse-trace-elem."
[elems]
(map parse-trace-elem elems))
@@ -110,7 +110,7 @@
base)))
(defn parse-exception
- "Returns a Clojure map providing usefull informaiton about the exception.
+ "Returns a Clojure map providing useful information about the exception.
The map has keys
:class Class of the exception.
:message Regular exception message string.
View
41 src/clj_stacktrace/repl.clj
@@ -1,6 +1,6 @@
(ns clj-stacktrace.repl
- (:use clj-stacktrace.core)
- (:require [clj-stacktrace.utils :as utils]))
+ (:use [clj-stacktrace.core :only [parse-exception]]
+ [clj-stacktrace.utils :only [omit-frames fence rjust]]))
(def color-codes
{:red "\033[31m"
@@ -59,16 +59,14 @@
(defn pst-elem-str
[color? parsed-elem print-width]
(colored color? (elem-color parsed-elem)
- (str (utils/rjust print-width (source-str parsed-elem))
+ (str (rjust print-width (source-str parsed-elem))
" " (method-str parsed-elem))))
(defn pst-elems-on
[^java.io.Writer on color? parsed-elems & [source-width]]
(let [print-width (+ 6 (or source-width
- (utils/fence
- (sort
- (map #(.length ^String %)
- (map source-str parsed-elems))))))]
+ (fence (sort (for [elem parsed-elems]
+ (count (source-str elem)))))))]
(doseq [parsed-elem parsed-elems]
(.append on ^String (pst-elem-str color? parsed-elem print-width))
(.append on "\n")
@@ -80,11 +78,12 @@
(.flush on))
(defn- pst-cause-on
- [^java.io.Writer on color? exec source-width]
+ [^java.io.Writer on exec {:keys [source-width omit color?]}]
(pst-caused-by-on on color?)
(pst-class-on on color? (:class exec))
(pst-message-on on color? (:message exec))
- (pst-elems-on on color? (:trimmed-elems exec) source-width)
+ (pst-elems-on on color? (omit-frames (:trimmed-elems exec) omit)
+ source-width)
(if-let [cause (:cause exec)]
(pst-cause-on on color? cause source-width)))
@@ -94,29 +93,33 @@
[excp]
(let [this-source-width (->> (:trace-elems excp)
(map (comp count source-str))
- (sort)
- (utils/fence))]
+ (sort) (fence))]
(if-let [cause (:cause excp)]
(max this-source-width (find-source-width cause))
this-source-width)))
-(defn pst-on [on color? e]
+(defn pst-on
"Prints to the given Writer on a pretty stack trace for the given exception e,
ANSI colored if color? is true."
+ [on e {:keys [omit color?] :as opts}]
(let [exec (parse-exception e)
- source-width (find-source-width exec)]
+ source-width (find-source-width exec)
+ color? (or color? (:color? opts) (:test-color opts))]
(pst-class-on on color? (:class exec))
(pst-message-on on color? (:message exec))
- (pst-elems-on on color? (:trace-elems exec) source-width)
+ (pst-elems-on on color? (omit-frames (:trace-elems exec) omit) source-width)
(if-let [cause (:cause exec)]
- (pst-cause-on on color? cause source-width))))
+ (pst-cause-on on cause
+ (assoc opts
+ :source-width source-width
+ :color? color?)))))
(defn pst
"Print to *out* a pretty stack trace for an exception, by default *e."
- [& [e]]
- (pst-on *out* false (or e *e)))
+ [& [e & {:as opts}]]
+ (pst-on *out* (or e *e) opts))
(defn pst+
"Like pst, but with ANSI terminal color coding."
- [& [e]]
- (pst-on *out* true (or e *e)))
+ [& [e & {:as opts}]]
+ (pst-on *out* (or e *e) (assoc opts :color? true)))
View
16 src/clj_stacktrace/utils.clj
@@ -37,3 +37,19 @@
q3 (quartile3 coll)
iqr (- q3 q1)]
(int (+ q3 (/ (* 3 iqr) 2)))))
+
+(defn- omitter-fn [to-omit]
+ (if (instance? java.util.regex.Pattern to-omit)
+ ;; Curse you, non ifn regexes!
+ (comp (partial re-find to-omit) pr-str)
+ to-omit))
+
+(defn omit-frames
+ "Remove frames matching to-omit, which can be a function or regex."
+ [trace-elems to-omit]
+ (if-let [omit? (omitter-fn to-omit)]
+ (reduce (fn [trace-elems elem]
+ (if (omit? elem)
+ trace-elems
+ (conj trace-elems elem))) [] trace-elems)
+ trace-elems))
View
11 src/leiningen/hooks/clj_stacktrace_test.clj
@@ -3,12 +3,11 @@
[robert.hooke :only [add-hook]]))
(defn- hook-form [form project]
- (let [pst (if (:test-color (:clj-stacktrace project))
- 'clj-stacktrace.repl/pst+
- 'clj-stacktrace.repl/pst)]
- `(do (alter-var-root (resolve '~'clojure.stacktrace/print-cause-trace)
- (constantly @(resolve '~pst)))
- ~form)))
+ `(do (alter-var-root (resolve '~'clojure.stacktrace/print-cause-trace)
+ (constantly (fn [e#]
+ (@(resolve '~'pst) e#
+ ~(:clj-stacktrace project)))))
+ ~form))
(defn- add-stacktrace-hook [eval-in-project project form & [h s init]]
(eval-in-project project (hook-form form project)
View
20 test/clj_stacktrace/repl_test.clj
@@ -1,7 +1,6 @@
(ns clj-stacktrace.repl-test
- (:use clojure.test)
- (:use clj-stacktrace.utils)
- (:use clj-stacktrace.repl))
+ (:use [clojure.test]
+ [clj-stacktrace.repl]))
(defmacro with-cascading-exception
"Execute body in the context of a variable bound to an exception instance
@@ -18,14 +17,17 @@
(binding [*e e]
(is (with-out-str (pst))))))
-(deftest test-pst-str
- (with-cascading-exception e
- (is (pst-str e))
- (binding [*e e]
- (is (pst-str)))))
-
(deftest test-pst+
(with-cascading-exception e
(is (with-out-str (pst+ e)))
(binding [*e e]
(is (with-out-str (pst+))))))
+
+(deftest test-omit
+ (with-cascading-exception e
+ (is (not (re-find #"repl-test" (with-out-str
+ (pst e :omit #"repl-test")))))
+ (is (not (re-find #"Compiler.java"
+ (with-out-str
+ (pst e :omit (fn [e]
+ (= "Compiler.java" (:file e))))))))))
Something went wrong with that request. Please try again.