[mod] Signal content: drop :location, add :coords

This is a BREAKING change to get in before v1 final.

Signal keys BEFORE this commit:
  `:location` ---- ?{:keys [ns file line column]} signal creator callsite
  `:ns` ---------- ?str namespace of signal creator callsite, same as (:ns     location)
  `:line` -------- ?int line      of signal creator callsite, same as (:line   location)
  `:column` ------ ?int column    of signal creator callsite, same as (:column location)
  `:file` -------- ?str filename  of signal creator callsite, same as (:file   location)

Signal keys AFTER this commit:
  `:ns` ---------- ?str namespace of signal creator callsite
  `:coords` ------ ?[line column] of signal creator callsite

Motivation for the breaking change:

  The new callsite schema is simpler to use/override, reduces noise, and can reduce
  code expansion size (and so Cljs build size).

  - `:file` was rarely useful, but often added large embedded strings.
  - `:location` was redundant, and often difficult for Closure's
    advanced build to properly de-duplicate.

  This schema will be shared by Truss v2 and Tufte v3.
This commit is contained in:
Peter Taoussanis 2025-02-26 17:47:58 +01:00
parent bb715fb206
commit 1f99f7186b
6 changed files with 78 additions and 88 deletions

View file

@ -23,11 +23,8 @@ Default signal keys:
`:parent` ------ ?{:keys [id uid]} of parent signal, present in nested signals when tracing
`:root` -------- ?{:keys [id uid]} of root signal, present in nested signals when tracing
`:location` ---- ?{:keys [ns file line column]} signal creator callsite
`:ns` ---------- ?str namespace of signal creator callsite, same as (:ns location)
`:line` -------- ?int line of signal creator callsite, same as (:line location)
`:column` ------ ?int column of signal creator callsite, same as (:column location)
`:file` -------- ?str filename of signal creator callsite, same as (:file location)
`:ns` ---------- ?str namespace of signal creator callsite
`:coords` ------ ?[line column] of signal creator callsite
`:host` -------- (Clj only) {:keys [name ip]} info for network host
`:thread` ------ (Clj only) {:keys [name id group]} info for thread that created signal

View file

@ -248,8 +248,8 @@
(defrecord Signal
;; Telemere's main public data type, we avoid nesting and duplication
[schema inst uid,
location ns line column file, #?@(:clj [host thread _otel-context]),
[schema inst uid, ns coords,
#?@(:clj [host thread _otel-context]),
sample-rate, kind id level, ctx parent root, data kvs msg_,
error run-form run-val end-inst run-nsecs]
@ -556,6 +556,8 @@
column-form :column
file-form :file} location
coords (when line-form [line-form column-form])
{inst-form :inst
level-form :level
kind-form :kind
@ -625,10 +627,10 @@
(let [record-form
(let [clause [(if run-form :run :no-run) (if clj? :clj :cljs)]]
(case clause
[:run :clj ] `(Signal. 1 ~'__inst ~'__uid, ~location ~'__ns ~line-form ~column-form ~file-form, (enc/host-info) ~'__thread ~'__otel-context1, ~sample-rate-form, ~'__kind ~'__id ~'__level, ~ctx-form ~parent-form ~'__root1, ~data-form ~kvs-form ~'_msg_, ~'_run-err '~show-run-form ~show-run-val ~'_end-inst ~'_run-nsecs)
[:run :cljs] `(Signal. 1 ~'__inst ~'__uid, ~location ~'__ns ~line-form ~column-form ~file-form, ~sample-rate-form, ~'__kind ~'__id ~'__level, ~ctx-form ~parent-form ~'__root1, ~data-form ~kvs-form ~'_msg_, ~'_run-err '~show-run-form ~show-run-val ~'_end-inst ~'_run-nsecs)
[:no-run :clj ] `(Signal. 1 ~'__inst ~'__uid, ~location ~'__ns ~line-form ~column-form ~file-form, (enc/host-info) ~'__thread ~'__otel-context1, ~sample-rate-form, ~'__kind ~'__id ~'__level, ~ctx-form ~parent-form ~'__root1, ~data-form ~kvs-form ~msg-form, ~error-form nil nil nil nil)
[:no-run :cljs] `(Signal. 1 ~'__inst ~'__uid, ~location ~'__ns ~line-form ~column-form ~file-form, ~sample-rate-form, ~'__kind ~'__id ~'__level, ~ctx-form ~parent-form ~'__root1, ~data-form ~kvs-form ~msg-form, ~error-form nil nil nil nil)
[:run :clj ] `(Signal. 1 ~'__inst ~'__uid, ~'__ns ~coords (enc/host-info) ~'__thread ~'__otel-context1, ~sample-rate-form, ~'__kind ~'__id ~'__level, ~ctx-form ~parent-form ~'__root1, ~data-form ~kvs-form ~'_msg_, ~'_run-err '~show-run-form ~show-run-val ~'_end-inst ~'_run-nsecs)
[:run :cljs] `(Signal. 1 ~'__inst ~'__uid, ~'__ns ~coords ~sample-rate-form, ~'__kind ~'__id ~'__level, ~ctx-form ~parent-form ~'__root1, ~data-form ~kvs-form ~'_msg_, ~'_run-err '~show-run-form ~show-run-val ~'_end-inst ~'_run-nsecs)
[:no-run :clj ] `(Signal. 1 ~'__inst ~'__uid, ~'__ns ~coords (enc/host-info) ~'__thread ~'__otel-context1, ~sample-rate-form, ~'__kind ~'__id ~'__level, ~ctx-form ~parent-form ~'__root1, ~data-form ~kvs-form ~msg-form, ~error-form nil nil nil nil)
[:no-run :cljs] `(Signal. 1 ~'__inst ~'__uid, ~'__ns ~coords ~sample-rate-form, ~'__kind ~'__id ~'__level, ~ctx-form ~parent-form ~'__root1, ~data-form ~kvs-form ~msg-form, ~error-form nil nil nil nil)
(truss/unexpected-arg! clause {:context :signal-constructor-args})))
record-form

View file

@ -164,11 +164,12 @@
(when data ; Non-standard
(merge-attrs! ab "exception.data" data)))
(let [{:keys [ns line column]} signal]
(let [ns (get signal :ns)]
;; All standard
(put-attr! ab "code.namespace" ns)
(put-attr! ab "code.line.number" line)
(put-attr! ab "code.column.number" column))
(put-attr! ab "code.namespace" ns)
(when-let [[line column] (get signal :coords)]
(when line (put-attr! ab "code.line.number" line))
(when column (put-attr! ab "code.column.number" column))))
(let [{:keys [kind id uid]} signal]
(put-attr! ab "kind" kind)

View file

@ -16,7 +16,7 @@
;;;;
(enc/defaliases #_sigs/upper-qn sigs/format-level sigs/format-id sigs/format-location)
(enc/defaliases #_sigs/upper-qn sigs/format-level sigs/format-id)
;;;; Unique IDs (UIDs)
@ -509,7 +509,7 @@
Returns a (fn preamble [signal]) that:
- Takes a Telemere signal (map).
- Returns a signal preamble ?string like:
\"2024-03-26T11:14:51.806Z INFO EVENT Hostname taoensso.telemere(2,21) ::ev-id msg\"
\"2024-03-26T11:14:51.806Z INFO EVENT Hostname taoensso.telemere[2,21] ::ev-id msg\"
Options:
`:format-inst-fn` - (fn format [instant]) => string.
@ -532,14 +532,12 @@
(if kind (s+spc (sigs/upper-qn kind)) (s+spc "DEFAULT"))
#?(:clj (s+spc (hostname)))
;; As `format-location`
(when-let [base (or ns (get signal :file))]
(let [s+ (partial enc/sb-append sb)] ; Without separator
(s+ " " base)
(when-let [l (get signal :line)]
(s+ "(" l)
(when-let [c (get signal :column)] (s+ "," c))
(s+ ")"))))
(when ns
(enc/sb-append sb " " ns)
(when-let [[line column] (get signal :coords)]
(if column
(enc/sb-append sb "[" line "," column "]")
(enc/sb-append sb "[" line "]"))))
(when id (when-let [ff format-id-fn] (s+spc (ff ns id))))
(enc/when-let [ff format-msg-fn
@ -653,7 +651,7 @@
`:incl-nils?` - Include signal's keys with nil values? (default false)
`:incl-kvs?` - Include signal's app-level root kvs? (default false)
`:incl-keys` - Subset of signal keys to retain from those otherwise
excluded by default: #{:location :kvs :file :host :thread}"
excluded by default: #{:kvs :host :thread}"
([] (clean-signal-fn nil))
([{:keys [incl-kvs? incl-nils? incl-keys] :as opts}]
(let [assoc!*
@ -661,11 +659,9 @@
(fn [m k v] (if (nil? v) m (assoc! m k v))) ; As `remove-signal-nils`
(do assoc!))
incl-location? (contains? incl-keys :location)
incl-kvs-key? (contains? incl-keys :kvs)
incl-file? (contains? incl-keys :file)
incl-host? (contains? incl-keys :host)
incl-thread? (contains? incl-keys :thread)]
incl-kvs-key? (contains? incl-keys :kvs)
incl-host? (contains? incl-keys :host)
incl-thread? (contains? incl-keys :thread)]
(fn clean-signal [signal]
(when (map? signal)
@ -677,7 +673,7 @@
(clojure.core/into ()
(clojure.core/disj
taoensso.telemere.impl/standard-signal-keys
:msg_ :error :location :kvs :file :host :thread))
:msg_ :error :kvs :host :thread))
(assoc!* m k v)
;; Main keys to include with modified val
@ -689,11 +685,9 @@
taoensso.telemere.impl/impl-signal-keys) m ; noop
;;; Other keys to exclude by default
:location (if incl-location? (assoc!* m k v) m)
:kvs (if incl-kvs-key? (assoc!* m k v) m)
:file (if incl-file? (assoc!* m k v) m)
:thread (if incl-thread? (assoc!* m k v) m)
:host (if incl-host? (assoc!* m k v) m)
:kvs (if incl-kvs-key? (assoc!* m k v) m)
:thread (if incl-thread? (assoc!* m k v) m)
:host (if incl-host? (assoc!* m k v) m)
;; Other (app-level) keys
(enc/cond

View file

@ -76,6 +76,8 @@
"x y nil [\"z1\" nil \"z2\" \"z3\"] s1 nil s2 s3 s4 :kw"))])
(defn coords? [x] (and (vector? x) (let [[line column] x] (and (enc/nat-int? line) (enc/nat-int? column)))))
(deftest _signal-macro
[(is (= (with-sigs (sig! {:level :info, :elide? true })) {:value nil}) "With compile-time elision")
(is (= (with-sigs (sig! {:level :info, :elide? true, :run (+ 1 2)})) {:value 3}) "With compile-time elision, run-form")
@ -567,26 +569,26 @@
(deftest _common-signals
[(testing "event!" ; id + ?level => allowed?
[(let [{rv :value, [sv] :signals} (with-sigs (tel/event! :id1 ))] [(is (= rv true)) (is (sm? sv {:kind :event, :line :submap/some, :level :info, :id :id1}))])
(let [{rv :value, [sv] :signals} (with-sigs (tel/event! :id1 :warn)) ] [(is (= rv true)) (is (sm? sv {:kind :event, :line :submap/some, :level :warn, :id :id1}))])
(let [{rv :value, [sv] :signals} (with-sigs (tel/event! :id1 {:level :warn}))] [(is (= rv true)) (is (sm? sv {:kind :event, :line :submap/some, :level :warn, :id :id1}))])
(let [{rv :value, [sv] :signals} (with-sigs (tel/event! {:id :id1, :level :warn}))] [(is (= rv true)) (is (sm? sv {:kind :event, :line :submap/some, :level :warn, :id :id1}))])
[(let [{rv :value, [sv] :signals} (with-sigs (tel/event! :id1 ))] [(is (= rv true)) (is (sm? sv {:kind :event, :coords coords?, :level :info, :id :id1}))])
(let [{rv :value, [sv] :signals} (with-sigs (tel/event! :id1 :warn)) ] [(is (= rv true)) (is (sm? sv {:kind :event, :coords coords?, :level :warn, :id :id1}))])
(let [{rv :value, [sv] :signals} (with-sigs (tel/event! :id1 {:level :warn}))] [(is (= rv true)) (is (sm? sv {:kind :event, :coords coords?, :level :warn, :id :id1}))])
(let [{rv :value, [sv] :signals} (with-sigs (tel/event! {:id :id1, :level :warn}))] [(is (= rv true)) (is (sm? sv {:kind :event, :coords coords?, :level :warn, :id :id1}))])
(let [{rv :value, [sv] :signals} (with-sigs (tel/event! :id1 {:allow? false})) ] [(is (= rv nil)) (is (nil? sv))])])
(testing "log!" ; ?level + msg => allowed?
[(let [{rv :value, [sv] :signals} (with-sigs (tel/log! "msg")) ] [(is (= rv true)) (is (sm? sv {:kind :log, :line :submap/some, :msg_ "msg", :level :info}))])
(let [{rv :value, [sv] :signals} (with-sigs (tel/log! :warn "msg")) ] [(is (= rv true)) (is (sm? sv {:kind :log, :line :submap/some, :msg_ "msg", :level :warn}))])
(let [{rv :value, [sv] :signals} (with-sigs (tel/log! {:level :warn} "msg")) ] [(is (= rv true)) (is (sm? sv {:kind :log, :line :submap/some, :msg_ "msg", :level :warn}))])
(let [{rv :value, [sv] :signals} (with-sigs (tel/log! {:level :warn, :msg "msg"}))] [(is (= rv true)) (is (sm? sv {:kind :log, :line :submap/some, :msg_ "msg", :level :warn}))])
[(let [{rv :value, [sv] :signals} (with-sigs (tel/log! "msg")) ] [(is (= rv true)) (is (sm? sv {:kind :log, :coords coords?, :msg_ "msg", :level :info}))])
(let [{rv :value, [sv] :signals} (with-sigs (tel/log! :warn "msg")) ] [(is (= rv true)) (is (sm? sv {:kind :log, :coords coords?, :msg_ "msg", :level :warn}))])
(let [{rv :value, [sv] :signals} (with-sigs (tel/log! {:level :warn} "msg")) ] [(is (= rv true)) (is (sm? sv {:kind :log, :coords coords?, :msg_ "msg", :level :warn}))])
(let [{rv :value, [sv] :signals} (with-sigs (tel/log! {:level :warn, :msg "msg"}))] [(is (= rv true)) (is (sm? sv {:kind :log, :coords coords?, :msg_ "msg", :level :warn}))])
(let [{rv :value, [sv] :signals} (with-sigs (tel/log! {:allow? false} "msg")) ] [(is (= rv nil)) (is (nil? sv))])])
(testing "trace!" ; ?id + run => unconditional run result (value or throw)
[(let [{rv :value, [sv] :signals} (with-sigs (tel/trace! (+ 1 2))) ] [(is (= rv 3)) (is (sm? sv {:kind :trace, :line :submap/some, :level :info, :id nil, :msg_ "(+ 1 2) => 3"}))])
(let [{rv :value, [sv] :signals} (with-sigs (tel/trace! {:msg nil} (+ 1 2))) ] [(is (= rv 3)) (is (sm? sv {:kind :trace, :line :submap/some, :level :info, :id nil, :msg_ nil}))])
(let [{rv :value, [sv] :signals} (with-sigs (tel/trace! :id1 (+ 1 2))) ] [(is (= rv 3)) (is (sm? sv {:kind :trace, :line :submap/some, :level :info, :id :id1}))])
(let [{rv :value, [sv] :signals} (with-sigs (tel/trace! {:id :id1} (+ 1 2))) ] [(is (= rv 3)) (is (sm? sv {:kind :trace, :line :submap/some, :level :info, :id :id1}))])
(let [{rv :value, [sv] :signals} (with-sigs (tel/trace! {:id :id1, :run (+ 1 2)}))] [(is (= rv 3)) (is (sm? sv {:kind :trace, :line :submap/some, :level :info, :id :id1}))])
(let [{re :error, [sv] :signals} (with-sigs (tel/trace! :id1 (ex1!))) ] [(is (ex1? re)) (is (sm? sv {:kind :trace, :line :submap/some, :level :info, :id :id1, :error ex1,
[(let [{rv :value, [sv] :signals} (with-sigs (tel/trace! (+ 1 2))) ] [(is (= rv 3)) (is (sm? sv {:kind :trace, :coords coords?, :level :info, :id nil, :msg_ "(+ 1 2) => 3"}))])
(let [{rv :value, [sv] :signals} (with-sigs (tel/trace! {:msg nil} (+ 1 2))) ] [(is (= rv 3)) (is (sm? sv {:kind :trace, :coords coords?, :level :info, :id nil, :msg_ nil}))])
(let [{rv :value, [sv] :signals} (with-sigs (tel/trace! :id1 (+ 1 2))) ] [(is (= rv 3)) (is (sm? sv {:kind :trace, :coords coords?, :level :info, :id :id1}))])
(let [{rv :value, [sv] :signals} (with-sigs (tel/trace! {:id :id1} (+ 1 2))) ] [(is (= rv 3)) (is (sm? sv {:kind :trace, :coords coords?, :level :info, :id :id1}))])
(let [{rv :value, [sv] :signals} (with-sigs (tel/trace! {:id :id1, :run (+ 1 2)}))] [(is (= rv 3)) (is (sm? sv {:kind :trace, :coords coords?, :level :info, :id :id1}))])
(let [{re :error, [sv] :signals} (with-sigs (tel/trace! :id1 (ex1!))) ] [(is (ex1? re)) (is (sm? sv {:kind :trace, :coords coords?, :level :info, :id :id1, :error ex1,
:msg_ #?(:clj "(ex1!) !> clojure.lang.ExceptionInfo"
:cljs "(ex1!) !> cljs.core/ExceptionInfo")}))])
(let [{rv :value, [sv] :signals} (with-sigs (tel/trace! {:allow? false} (+ 1 2)))] [(is (= rv 3)) (is (nil? sv))])
@ -594,8 +596,8 @@
(testing "Use with `catch->error!`"
(let [{re :error, [sv1 sv2] :signals} (with-sigs (tel/trace! ::id1 (tel/catch->error! ::id2 (ex1!))))]
[(is (ex1? re))
(is (sm? sv1 {:kind :error, :line :submap/some, :level :error, :id ::id2, :error ex1, :parent {:id ::id1}}))
(is (sm? sv2 {:kind :trace, :line :submap/some, :level :info, :id ::id1, :error ex1, :root {:id ::id1}}))]))
(is (sm? sv1 {:kind :error, :coords coords?, :level :error, :id ::id2, :error ex1, :parent {:id ::id1}}))
(is (sm? sv2 {:kind :trace, :coords coords?, :level :info, :id ::id1, :error ex1, :root {:id ::id1}}))]))
(testing ":run-form" ; Undocumented, experimental
[(is (sm? (with-sig (tel/trace! :non-list)) {:run-form :non-list}))
@ -608,12 +610,12 @@
(is (sm? (with-sig (tel/trace! {:run-val "custom"} (+ 2 2))) {:run-val "custom", :msg_ "(+ 2 2) => custom", :kvs nil}))])])
(testing "spy" ; ?level + run => unconditional run result (value or throw)
[(let [{rv :value, [sv] :signals} (with-sigs (tel/spy! (+ 1 2))) ] [(is (= rv 3)) (is (sm? sv {:kind :spy, :line :submap/some, :level :info, :msg_ "(+ 1 2) => 3"}))])
(let [{rv :value, [sv] :signals} (with-sigs (tel/spy! {:msg nil} (+ 1 2))) ] [(is (= rv 3)) (is (sm? sv {:kind :spy, :line :submap/some, :level :info, :msg_ nil}))])
(let [{rv :value, [sv] :signals} (with-sigs (tel/spy! :warn (+ 1 2))) ] [(is (= rv 3)) (is (sm? sv {:kind :spy, :line :submap/some, :level :warn}))])
(let [{rv :value, [sv] :signals} (with-sigs (tel/spy! {:level :warn} (+ 1 2))) ] [(is (= rv 3)) (is (sm? sv {:kind :spy, :line :submap/some, :level :warn}))])
(let [{rv :value, [sv] :signals} (with-sigs (tel/spy! {:level :warn, :run (+ 1 2)}))] [(is (= rv 3)) (is (sm? sv {:kind :spy, :line :submap/some, :level :warn}))])
(let [{re :error, [sv] :signals} (with-sigs (tel/spy! :warn (ex1!)))] [(is (ex1? re)) (is (sm? sv {:kind :spy, :line :submap/some, :level :warn, :error ex1,
[(let [{rv :value, [sv] :signals} (with-sigs (tel/spy! (+ 1 2))) ] [(is (= rv 3)) (is (sm? sv {:kind :spy, :coords coords?, :level :info, :msg_ "(+ 1 2) => 3"}))])
(let [{rv :value, [sv] :signals} (with-sigs (tel/spy! {:msg nil} (+ 1 2))) ] [(is (= rv 3)) (is (sm? sv {:kind :spy, :coords coords?, :level :info, :msg_ nil}))])
(let [{rv :value, [sv] :signals} (with-sigs (tel/spy! :warn (+ 1 2))) ] [(is (= rv 3)) (is (sm? sv {:kind :spy, :coords coords?, :level :warn}))])
(let [{rv :value, [sv] :signals} (with-sigs (tel/spy! {:level :warn} (+ 1 2))) ] [(is (= rv 3)) (is (sm? sv {:kind :spy, :coords coords?, :level :warn}))])
(let [{rv :value, [sv] :signals} (with-sigs (tel/spy! {:level :warn, :run (+ 1 2)}))] [(is (= rv 3)) (is (sm? sv {:kind :spy, :coords coords?, :level :warn}))])
(let [{re :error, [sv] :signals} (with-sigs (tel/spy! :warn (ex1!)))] [(is (ex1? re)) (is (sm? sv {:kind :spy, :coords coords?, :level :warn, :error ex1,
:msg_ #?(:clj "(ex1!) !> clojure.lang.ExceptionInfo"
:cljs "(ex1!) !> cljs.core/ExceptionInfo")}))])
(let [{rv :value, [sv] :signals} (with-sigs (tel/spy! {:allow? false} (+ 1 2))) ] [(is (= rv 3)) (is (nil? sv))])
@ -621,23 +623,23 @@
(testing "Use with `catch->error!`"
(let [{re :error, [sv1 sv2] :signals} (with-sigs (tel/spy! :warn (tel/catch->error! :error (ex1!))))]
[(is (ex1? re))
(is (sm? sv1 {:kind :error, :line :submap/some, :level :error, :error ex1, :parent {}}))
(is (sm? sv2 {:kind :spy, :line :submap/some, :level :warn, :error ex1, :root {}}))]))])
(is (sm? sv1 {:kind :error, :coords coords?, :level :error, :error ex1, :parent {}}))
(is (sm? sv2 {:kind :spy, :coords coords?, :level :warn, :error ex1, :root {}}))]))])
(testing "error!" ; ?id + error => unconditional given error
[(let [{rv :value, [sv] :signals} (with-sigs (tel/error! ex1)) ] [(is (ex1? rv)) (is (sm? sv {:kind :error, :line :submap/some, :level :error, :error ex1, :id nil}))])
(let [{rv :value, [sv] :signals} (with-sigs (tel/error! :id1 ex1)) ] [(is (ex1? rv)) (is (sm? sv {:kind :error, :line :submap/some, :level :error, :error ex1, :id :id1}))])
(let [{rv :value, [sv] :signals} (with-sigs (tel/error! {:id :id1} ex1)) ] [(is (ex1? rv)) (is (sm? sv {:kind :error, :line :submap/some, :level :error, :error ex1, :id :id1}))])
(let [{rv :value, [sv] :signals} (with-sigs (tel/error! {:id :id1, :error ex1}))] [(is (ex1? rv)) (is (sm? sv {:kind :error, :line :submap/some, :level :error, :error ex1, :id :id1}))])
[(let [{rv :value, [sv] :signals} (with-sigs (tel/error! ex1)) ] [(is (ex1? rv)) (is (sm? sv {:kind :error, :coords coords?, :level :error, :error ex1, :id nil}))])
(let [{rv :value, [sv] :signals} (with-sigs (tel/error! :id1 ex1)) ] [(is (ex1? rv)) (is (sm? sv {:kind :error, :coords coords?, :level :error, :error ex1, :id :id1}))])
(let [{rv :value, [sv] :signals} (with-sigs (tel/error! {:id :id1} ex1)) ] [(is (ex1? rv)) (is (sm? sv {:kind :error, :coords coords?, :level :error, :error ex1, :id :id1}))])
(let [{rv :value, [sv] :signals} (with-sigs (tel/error! {:id :id1, :error ex1}))] [(is (ex1? rv)) (is (sm? sv {:kind :error, :coords coords?, :level :error, :error ex1, :id :id1}))])
(let [{rv :value, [sv] :signals} (with-sigs (tel/error! {:allow? false} ex1)) ] [(is (ex1? rv)) (is (nil? sv))])
(let [c (enc/counter)] (tel/error! (do (c) ex1)) (is (= @c 1) "Error form evaluated exactly once"))])
(testing "catch->error!" ; ?id + run => unconditional run value or ?return
[(let [{rv :value, [sv] :signals} (with-sigs (tel/catch->error! (+ 1 2)))] [(is (= rv 3)) (is (nil? sv))])
(let [{re :error, [sv] :signals} (with-sigs (tel/catch->error! (ex1!)))] [(is (ex1? re)) (is (sm? sv {:kind :error, :line :submap/some, :level :error, :error ex1, :id nil}))])
(let [{re :error, [sv] :signals} (with-sigs (tel/catch->error! :id1 (ex1!)))] [(is (ex1? re)) (is (sm? sv {:kind :error, :line :submap/some, :level :error, :error ex1, :id :id1}))])
(let [{re :error, [sv] :signals} (with-sigs (tel/catch->error! {:id :id1} (ex1!)))] [(is (ex1? re)) (is (sm? sv {:kind :error, :line :submap/some, :level :error, :error ex1, :id :id1}))])
(let [{rv :value, [sv] :signals} (with-sigs (tel/catch->error! {:catch-val :foo} (ex1!)))] [(is (= rv :foo)) (is (sm? sv {:kind :error, :line :submap/some, :level :error, :error ex1, :id nil}))])
(let [{re :error, [sv] :signals} (with-sigs (tel/catch->error! (ex1!)))] [(is (ex1? re)) (is (sm? sv {:kind :error, :coords coords?, :level :error, :error ex1, :id nil}))])
(let [{re :error, [sv] :signals} (with-sigs (tel/catch->error! :id1 (ex1!)))] [(is (ex1? re)) (is (sm? sv {:kind :error, :coords coords?, :level :error, :error ex1, :id :id1}))])
(let [{re :error, [sv] :signals} (with-sigs (tel/catch->error! {:id :id1} (ex1!)))] [(is (ex1? re)) (is (sm? sv {:kind :error, :coords coords?, :level :error, :error ex1, :id :id1}))])
(let [{rv :value, [sv] :signals} (with-sigs (tel/catch->error! {:catch-val :foo} (ex1!)))] [(is (= rv :foo)) (is (sm? sv {:kind :error, :coords coords?, :level :error, :error ex1, :id nil}))])
(let [{rv :value, [sv] :signals} (with-sigs (tel/catch->error! {:catch-val :foo} (+ 1 2)))] [(is (= rv 3)) (is (nil? sv))])])
#?(:clj
@ -646,13 +648,13 @@
[(do (enc/set-var-root! impl/*sig-handlers* [(sigs/wrap-handler "h1" (fn h1 [x] (reset! sv_ x)) nil {:async nil})]) :set-handler)
;;
(is (nil? (tel/uncaught->error!)))
(is (do (.join (enc/threaded :user (ex1!))) (sm? @sv_ {:kind :error, :line :submap/some, :level :error, :error ex1, :id nil})))
(is (do (.join (enc/threaded :user (ex1!))) (sm? @sv_ {:kind :error, :coords coords?, :level :error, :error ex1, :id nil})))
;;
(is (nil? (tel/uncaught->error! :id1)))
(is (do (.join (enc/threaded :user (ex1!))) (sm? @sv_ {:kind :error, :line :submap/some, :level :error, :error ex1, :id :id1})))
(is (do (.join (enc/threaded :user (ex1!))) (sm? @sv_ {:kind :error, :coords coords?, :level :error, :error ex1, :id :id1})))
;;
(is (nil? (tel/uncaught->error! {:id :id1})))
(is (do (.join (enc/threaded :user (ex1!))) (sm? @sv_ {:kind :error, :line :submap/some, :level :error, :error ex1, :id :id1})))
(is (do (.join (enc/threaded :user (ex1!))) (sm? @sv_ {:kind :error, :coords coords?, :level :error, :error ex1, :id :id1})))
;;
(do (enc/set-var-root! impl/*sig-handlers* nil) :unset-handler)])))])
@ -664,7 +666,7 @@
(deftest _dispatch-signal!
[(sm? (tel/with-signal (tel/dispatch-signal! (assoc (tel/with-signal :trap (tel/log! "hello")) :level :warn)))
{:kind :log, :level :warn, :line :submap/some})])
{:kind :log, :level :warn, :coords coords?})])
#?(:clj
(deftest _uncaught->handler!
@ -701,7 +703,7 @@
:system/err {:sending->telemere? false, :telemere-receiving? false}}))
(is (sm? (with-sig (tel/with-out->telemere (println "Hello" "x" "y")))
{:level :info, :location nil, :ns nil, :kind :system/out, :msg_ "Hello x y"}))])
{:level :info, :coords nil, :ns nil, :kind :system/out, :msg_ "Hello x y"}))])
(testing "SLF4J -> Telemere"
[(is (sm? (tel/check-interop) {:slf4j {:present? true, :sending->telemere? true, :telemere-receiving? true}}))
@ -777,9 +779,7 @@
:id nil
:msg_ (delay "msg")
:error ex2
:location "loc"
:kvs "kvs"
:file "file"
:thread "thread"
:a "a"
:b "b"}]
@ -790,8 +790,7 @@
(is (= ((utils/clean-signal-fn {:incl-keys #{:kvs}}) sig) {:level :info, :msg_ "msg", :error ex2-chain, :kvs "kvs"}))
(is (= ((utils/clean-signal-fn {:incl-keys #{:a}}) sig) {:level :info, :msg_ "msg", :error ex2-chain, :a "a"}))
(is (= ((utils/clean-signal-fn {:incl-keys
#{:location :kvs :file :thread}}) sig) {:level :info, :msg_ "msg", :error ex2-chain,
:location "loc", :kvs "kvs", :file "file", :thread "thread"}))]))
#{:kvs :thread}}) sig) {:level :info, :msg_ "msg", :error ex2-chain, :kvs "kvs", :thread "thread"}))]))
(testing "Misc utils"
[(is (= (utils/remove-signal-kvs {:a :A, :b :B, :kvs {:b :B}}) {:a :A}))
@ -834,10 +833,10 @@
(testing "signal-preamble-fn"
(let [sig (with-sig :raw :trap (tel/event! ::ev-id {:inst t1, :msg ["a" "b"]}))
preamble ((utils/signal-preamble-fn) sig)] ; "2024-06-09T21:15:20.170Z INFO EVENT taoensso.telemere-tests(592,35) ::ev-id"
preamble ((utils/signal-preamble-fn) sig)] ; "2024-06-09T21:15:20.170Z INFO EVENT taoensso.telemere-tests[592,35] ::ev-id"
[(is (enc/str-starts-with? preamble "2024-01-01T01:01:01.110Z INFO EVENT"))
(is (enc/str-ends-with? preamble "::ev-id a b"))
(is (string? (re-find #"taoensso.telemere-tests\(\d+,\d+\)" preamble)))]))
(is (string? (re-find #"taoensso.telemere-tests\[\d+,\d+\]" preamble)))]))
(testing "pr-signal-fn"
(let [sig (with-sig :raw :trap (tel/event! ::ev-id {:inst t1, :msg ["a" "b"]}))]
@ -854,8 +853,7 @@
:ns "taoensso.telemere-tests"
:msg_ "a b"
:inst udt1
:line enc/nat-int?
:column enc/nat-int?}))]))
:coords vector?}))]))
#?(:cljs
(testing ":json pr-fn"
@ -866,8 +864,7 @@
"level" "info", "ns" "taoensso.telemere-tests"
"msg_" "a b"
"inst" t1s
"line" enc/nat-int?
"column" enc/nat-int?})))))
"coords" vector?})))))
(testing "Custom pr-fn"
(is (= ((tel/pr-signal-fn {:pr-fn (fn [_] "str")}) sig) (str "str" utils/newline))))]))
@ -1012,9 +1009,8 @@
{:kind :event
:level :info
:ns "ns"
:line 10
:column 20
:ns "ns"
:coords [10 20]
:id ::id1
:uid #uuid "7e9c1df6-78e4-40ac-8c5c-e2353df9ab82"

View file

@ -21,7 +21,7 @@ And they're represented by plain **Clojure/Script maps** with those attributes (
Fundamentally **all signals**:
- Occur or are observed at a particular **location** in your code (file, namespace, line, column).
- Occur or are observed at a particular **location** in your code (namespace, line, column).
- Occur or are observed *within* a particular **program state** / context.
- Convey something of value *about* that **program state** / context.