Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 22 additions & 2 deletions src/circleci/rollcage/core.clj
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@

(def ^:private Client {:access-token (s/maybe String)
:block-fields (s/maybe [s/Keyword])
:indexed-ex-data (s/maybe (s/cond-pre s/Bool s/Str s/Keyword s/Num))
:result-fn clojure.lang.IFn
:send-fn clojure.lang.IFn
:data {:environment (s/maybe String)
Expand Down Expand Up @@ -212,7 +213,7 @@

(s/defn ^:private client* :- Client
[access-token :- (s/maybe String)
{:keys [os hostname environment code-version file-root result-fn block-fields]
{:keys [os hostname environment code-version file-root result-fn block-fields indexed-ex-data]
:or {environment "production"}}]
(let [os (or os (guess-os))
hostname (or hostname (guess-hostname))
Expand All @@ -221,6 +222,7 @@
{:access-token access-token
:result-fn result-fn
:block-fields block-fields
:indexed-ex-data indexed-ex-data
:send-fn (if (string/blank? access-token)
send-item-null
send-item-http)
Expand Down Expand Up @@ -253,6 +255,24 @@
-- git SHA (i.e. '3da541559918a808c2402bba5012f6c60b27661c')
There is no default value.

`:indexed-ex-data` Tells rollcage to send nested exception's
`ex-data` under an indexed numeric level. It can be also a
string used instead of the \"__exception\" keys.

```clojure
(ex-info \"Second error\" {:bar 3} (ex-info \"First error\" {:foo 1 :bar 2}))
```

Sending the previous exception will generate the following params:

```
custom.0.__exception First error
custom.0.foo 1
custom.0.bar 2
custom.1.__exception Second error
custom.1.bar 3
```

`:result-fn` (for advanced usage) a function that will be called after each
exception is sent to Rollbar. The function will be passed 2 parameters:
- The Throwable that was being reported
Expand Down Expand Up @@ -315,7 +335,7 @@
([^String level client ^Throwable exception]
(notify level client exception {}))
([^String level {:keys [result-fn send-fn block-fields] :as client} ^Throwable exception {:keys [url params]}]
(let [params (merge params (throwables/merged-ex-data exception))
(let [params (merge params (throwables/merged-ex-data client exception))
scrubbed (scrub params block-fields)
item (make-rollbar client level exception url scrubbed)
result (try
Expand Down
38 changes: 37 additions & 1 deletion src/circleci/rollcage/throwables.clj
Original file line number Diff line number Diff line change
@@ -1,13 +1,49 @@
(ns circleci.rollcage.throwables
{:no-doc true})

(def default-exception-key "__exception")

(defn- cause-seq
[^Throwable t]
(take-while some?
(iterate (fn [^Throwable e]
(and e
(.getCause e))) t)))

(defn merged-ex-data
(defn merge-ex-data
[^Throwable ex]
(reduce merge {} (map ex-data (cause-seq ex))))

(defn enriched-ex-data
[exception-name-field ^Throwable ex]
(assoc (ex-data ex)
exception-name-field
(ex-message ex)))

(defn index-ex-data
[exception-name-field ^Throwable ex]
(let [exes (reverse (cause-seq ex))
quantity (count exes)]
(if (= 1 quantity)
(ex-data (first exes))
(let [indexes (range 0 quantity)
rich-ex-data (map (partial enriched-ex-data exception-name-field)
exes)]
(zipmap indexes rich-ex-data)))))

(defn select-exception-key
[indexed-ex-data]
(let [ekey (if-not (boolean? indexed-ex-data)
(str indexed-ex-data)
default-exception-key)]
(if-not (seq ekey)
default-exception-key
ekey)))

(defn merged-ex-data
[{:keys [indexed-ex-data] :as client}
^Throwable ex]
(if-not indexed-ex-data
(merge-ex-data ex)
(index-ex-data (select-exception-key indexed-ex-data)
ex)))
47 changes: 44 additions & 3 deletions test/circleci/rollcage/test_throwables.clj
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
(ns circleci.rollcage.test-throwables
(:require [circleci.rollcage.throwables :as throwables]
[clojure.test :refer (deftest is)]
[clojure.test :refer (deftest is are)]
[speculative.instrument]))

(deftest cause-seq-works
Expand All @@ -11,8 +11,49 @@
:c-added "this"} b)]
(is (= [a] (#'throwables/cause-seq a)))
(is (= [c b a] (#'throwables/cause-seq c)))
(is (= {:name "a"} (throwables/merged-ex-data a)))
(is (= {:name "a"} (throwables/merge-ex-data a)))
(is (= {:name "a"
:b-added "this"
:c-added "this"}
(throwables/merged-ex-data c)))))
(throwables/merge-ex-data c)))))

(deftest select-exception-key-works
(are [input expected] (= expected (throwables/select-exception-key input))
nil throwables/default-exception-key
"" throwables/default-exception-key
123 "123"
"some-key" "some-key"
:some-key ":some-key"
identity (str identity)))

(deftest merged-ex-data-works
(let [simple-error-data {:a 1 :b 2}
simple-error (ex-info "An error" simple-error-data)
nested-error (ex-info "outer" {:foo 2 :bar 3} (ex-info "inner" {:foo 1}))]
(are [args expected] (= expected
(apply throwables/merged-ex-data args))
[{} simple-error]
simple-error-data

[{} nested-error]
{:foo 1 :bar 3}

[{:indexed-ex-data false} nested-error]
{:foo 1 :bar 3}

[{:indexed-ex-data true} simple-error]
simple-error-data

[{:indexed-ex-data true} nested-error]
{0 {"__exception" "inner"
:foo 1}
1 {"__exception" "outer"
:foo 2
:bar 3}}

[{:indexed-ex-data "KEY"} nested-error]
{0 {"KEY" "inner"
:foo 1}
1 {"KEY" "outer"
:foo 2
:bar 3}})))