[mod] pr-signal-fn: key opts API tweaks

This commit is contained in:
Peter Taoussanis 2024-05-10 10:16:16 +02:00
parent 050cd1fa0f
commit d6c9a856dc
3 changed files with 90 additions and 32 deletions

View file

@ -225,6 +225,8 @@
(do (enc/def-print-impl [sig Signal] (str "#" `Signal (pr-str (into {} sig)))))
#?(:clj (enc/def-print-dup [sig Signal] (str "#" `Signal (pr-str (into {} sig))))) ; NB intentionally verbose, to support extra keys
(def ^:no-doc standard-signal-keys "Private, don't use." (set (keys (map->Signal {:schema 0}))))
(comment
(def s1 (with-signal (signal! {:level :info, :my-k1 :my-v1})))
(read-string (str (assoc s1 :my-k2 :my-v2)))

View file

@ -560,39 +560,39 @@
"Experimental, subject to change.
Returns a (fn pr [signal]) that:
- Takes a Telemere signal (map).
- Returns a machine-readable (minified) signal string.
- Returns a machine-readable signal ?string.
Options:
`:pr-fn` - ∈ #{<unary-fn> :edn (default) :json (Cljs only)}
`:incl-thread?` - Include signal `:thread` info? (default false)
`:incl-kvs?` - Include signal `:kvs` info? (default false)
`:incl-newline?` - Include terminating system newline? (default true)
`:incl-kvs?` - Include signal's user-level kvs? (default false)
`:incl-nils?` - Include signal's keys with nil values? (default false)
`:incl-newline?` - Include terminating system newline? (default true)
`:incl-keys` - Subset of signal keys to retain from those otherwise
excluded by default: #{:location :kvs :file :thread}
Examples:
(pr-signal-fn {:pr-fn :edn ...}) ; Outputs edn
(pr-signal-fn {:pr-fn :json ...}) ; Outputs JSON (Cljs only)
To output JSON for Clj, you must provide an appropriate `:pr-fn`.
`jsonista` is one good option, Ref. <https://github.com/metosin/jsonista>:
`jsonista` offers one good option, Ref. <https://github.com/metosin/jsonista>:
(require '[jsonista.core :as jsonista])
(pr-signal-fn {:pr-fn jsonista/write-value-as-string ...})
See also `format-signal-fn` for human-readable output."
([] (pr-signal-fn nil))
([{:keys [incl-thread? incl-kvs? incl-newline?, pr-fn prep-fn]
([{:keys [pr-fn, incl-kvs? incl-nils? incl-newline? incl-keys] :as opts
:or
{incl-newline? true
pr-fn :edn
prep-fn
(comp expand-signal-error
remove-signal-nils)}}]
{pr-fn :edn
incl-newline? true}}]
(let [nl newline
pr-fn
(or
(case pr-fn
:edn pr-edn
(case pr-fn
:none nil ; Undocumented, used for unit tests
:edn pr-edn
:json
#?(:cljs pr-json
:clj
@ -607,23 +607,61 @@
:param 'pr-fn
:expected
#?(:clj '#{:edn unary-fn}
:cljs '#{:edn :json unary-fn})}))))]
:cljs '#{:edn :json unary-fn})}))))
assoc!*
(if-not incl-nils?
(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-thread? (contains? incl-keys :thread)]
(fn pr-signal [signal]
(let [not-map? (not (map? signal))
signal (if (or incl-kvs? not-map?) signal (dissoc signal :kvs))
signal (if (or incl-thread? not-map?) signal (dissoc signal :thread))
signal (if not-map? signal (force-signal-msg signal))
signal (if prep-fn (prep-fn signal) signal)
output (pr-fn signal)]
(when (map? signal)
(let [signal
(persistent!
(reduce-kv
(fn [m k v]
(enc/case-eval k
:msg_ (assoc!* m k (force v)) ; As force-signal-msg
:error (if-let [chain (enc/ex-chain :as-map v)] (assoc! m k chain) m) ; As expand-signal-error
(if incl-newline?
(str output nl)
(do output)))))))
;;; Keys excluded 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)
(clojure.core/into ()
(clojure.core/disj
taoensso.telemere.impl/standard-signal-keys
:msg_ :error :location :kvs :file :thread))
(assoc!* m k v)
(if incl-kvs? (assoc!* m k v) m) ; As remove-signal-kvs
))
(transient {}) signal))]
(if-not pr-fn
signal
(let [output (pr-fn signal)]
(if incl-newline?
(str output nl)
(do output))))))))))
(comment
((pr-signal-fn {:pr-fn :edn}) (tel/with-signal (tel/event! ::ev-id {:kvs {:k1 "v1"}})))
((pr-signal-fn {:pr-fn (fn [_] "str")}) (tel/with-signal (tel/event! ::ev-id {:kvs {:k1 "v1"}}))))
(def s1 (tel/with-signal (tel/event! ::ev-id {:kvs {:k1 "v1"}})))
((pr-signal-fn {:pr-fn :edn}) s1)
((pr-signal-fn {:pr-fn (fn [_] "str")}) s1)
((pr-signal-fn {:pr-fn :none}) s1)
(let [pr-fn (pr-signal-fn {:pr-fn :none})]
(enc/qb 1e6 ; 817.78
(pr-fn s1))))
(defn format-signal-fn
"Experimental, subject to change.

View file

@ -33,6 +33,7 @@
(def ex-info-type (#'enc/ex-type (ex-info "" {})))
(def ex1 (ex-info "Ex1" {}))
(def ex2 (ex-info "Ex2" {:k2 "v2"} (ex-info "Ex1" {:k1 "v1"})))
(def ex2-chain (enc/ex-chain :as-map ex2))
(defn ex1! [] (throw ex1))
(defn ex1? [x] (= (enc/ex-root x) ex1))
@ -645,9 +646,7 @@
[(is (= (utils/remove-signal-kvs {:a :A, :b :B, :kvs {:b :B}}) {:a :A}))
(is (= (utils/remove-signal-nils {:a :A, :b nil}) {:a :A}))
(is (= (utils/force-signal-msg {:a :A, :msg_ (delay "msg")}) {:a :A, :msg_ "msg"}))
(is (= (utils/expand-signal-error {:level :info, :error ex2})
{:level :info, :error [{:type ex-info-type, :msg "Ex2", :data {:k2 "v2"}}
{:type ex-info-type, :msg "Ex1", :data {:k1 "v1"}}]}))])
(is (= (utils/expand-signal-error {:level :info, :error ex2}) {:level :info, :error ex2-chain}))])
#?(:clj
(testing "File writer"
@ -692,7 +691,7 @@
(testing "pr-signal-fn"
(let [sig (with-sig :raw :trap (tel/event! ::ev-id {:inst t0, :msg ["a" "b"]}))]
[(testing ":edn"
[(testing ":edn pr-fn"
(let [sig (update sig :inst enc/inst->udt)
sig*1 (enc/read-edn ((tel/pr-signal-fn {:pr-fn :edn}) sig))
sig*2 (enc/read-edn ((tel/pr-signal-fn) sig))]
@ -708,7 +707,7 @@
:column pnat-int?}))]))
#?(:cljs
(testing ":json"
(testing ":json pr-fn"
(let [sig* (enc/read-json ((tel/pr-signal-fn {:pr-fn :json}) sig))]
(is
(enc/submap? sig*
@ -719,8 +718,27 @@
"line" pnat-int?
"column" pnat-int?})))))
(testing "user fn"
(is (= ((tel/pr-signal-fn {:pr-fn (fn [_] "str")}) sig) (str "str" utils/newline))))]))
(testing "User pr-fn"
(is (= ((tel/pr-signal-fn {:pr-fn (fn [_] "str")}) sig) (str "str" utils/newline))))
(testing "Other options"
(let [sig
{:msg_ (delay "msg")
:error ex2
:id nil
:location "loc"
:kvs "kvs"
:file "file"
:thread "thread"
:user-key "user-val"}]
[(is (= ((tel/pr-signal-fn {:pr-fn :none}) sig) {:msg_ "msg", :error ex2-chain}))
(is (= ((tel/pr-signal-fn {:pr-fn :none, :incl-kvs? true}) sig) {:msg_ "msg", :error ex2-chain, :user-key "user-val"}))
(is (= ((tel/pr-signal-fn {:pr-fn :none, :incl-nils? true}) sig) {:msg_ "msg", :error ex2-chain, :id nil}))
(is (= ((tel/pr-signal-fn {:pr-fn :none, :incl-keys #{:kvs}}) sig) {:msg_ "msg", :error ex2-chain, :kvs "kvs"}))
(is (= ((tel/pr-signal-fn {:pr-fn :none, :incl-keys
#{:location :kvs :file :thread}}) sig) {:msg_ "msg", :error ex2-chain,
:location "loc", :kvs "kvs", :file "file", :thread "thread"}))]))]))
(testing "format-signal-fn"
(let [sig (with-sig :raw :trap (tel/event! ::ev-id {:inst t0, :msg ["a" "b"]}))]