[new] Add :ctx+, :middleware+ signal options

This commit is contained in:
Peter Taoussanis 2024-10-11 10:51:16 +02:00
parent c1e1c1e4cc
commit 5a8c407528
4 changed files with 77 additions and 56 deletions

View file

@ -15,17 +15,19 @@ Signal options (shared by all signal creators):
`:do` ---------- ?form to execute conditionally (iff signal allowed), before establishing `:let` ?binding
`:let` --------- ?bindings to establish conditionally (iff signal allowed), BEFORE evaluating `:data` and `:msg` (useful!)
`:ctx` --------- Custom ?val to override auto (dynamic `*ctx*`) in signal
`:parent` ------ Custom ?{:keys [id uid]} to override auto (dynamic) parent signal tracing info
`:root` -------- Custom ?{:keys [id uid]} to override auto (dynamic) root signal tracing info
`:location` ---- Custom ?{:keys [ns line column file]} to override auto signal creator callsite location
`:ctx` --------- Custom ?val to override auto (dynamic `*ctx*`) in signal, as per `with-ctx`
`:ctx+` -------- Custom ?val to update auto (dynamic `*ctx*`) in signal, as per `with-ctx+`
`:elidable?` --- Should signal be subject to compile-time elision? (Default: true)
`:sample-rate` - ?rate ∈ℝ[0,1] for signal sampling (0.75 => allow 75% of signals, nil => allow all)
`:when` -------- Arb ?form; when present, form must return truthy to allow signal
`:rate-limit` -- ?spec as given to `taoensso.telemere/rate-limiter`, see its docstring for details
`:rate-limit-by` When present, rate limits will be enforced independently for each id (any Clojure value!)
`:middleware` -- Optional (fn [signal]) => ?modified-signal to apply when signal is created
`:middleware` -- Optional (fn [signal]) => ?modified-signal to apply when signal is created, as per `with-middleware`
`:middleware+` - Optional (fn [signal]) => ?modified-signal to apply when signal is created, as per `with-middleware+`
`:trace?` ------ Should tracing be enabled for `:run` form?
<kvs> ---------- Other arb app-level ?kvs to incl. in signal. Typically NOT included in

View file

@ -385,16 +385,16 @@
:signal! ; [opts] => allowed? / run result (value or throw)
'([{:as opts :keys
[#_defaults #_elide? #_allow? #_expansion-id, ; Undocumented
elidable? location #_location* inst uid middleware,
elidable? location #_location* inst uid middleware middleware+,
sample-rate kind ns id level when rate-limit rate-limit-by,
ctx parent root trace?, do let data msg error run & kvs]}])
ctx ctx+ parent root trace?, do let data msg error run & kvs]}])
:signal-allowed?
'([{:as opts :keys
[#_defaults #_elide? #_allow? #_expansion-id, ; Undocumented
elidable? location #_location* #_inst #_uid #_middleware,
elidable? location #_location* #_inst #_uid #_middleware #_middleware+,
sample-rate kind ns id level when rate-limit rate-limit-by,
#_ctx #_parent #_root #_trace?, #_do #_let #_data #_msg #_error #_run #_& #_kvs]}])
#_ctx #_ctx+ #_parent #_root #_trace?, #_do #_let #_data #_msg #_error #_run #_& #_kvs]}])
:event! ; [id] [id level-or-opts] => allowed?
'([id ]
@ -402,18 +402,18 @@
[id
{:as opts :keys
[#_defaults #_elide? #_allow? #_expansion-id,
elidable? location #_location* inst uid middleware,
elidable? location #_location* inst uid middleware middleware+,
sample-rate kind ns id level when rate-limit rate-limit-by,
ctx parent root trace?, do let data msg error #_run & kvs]}])
ctx ctx+ parent root trace?, do let data msg error #_run & kvs]}])
:log! ; [msg] [level-or-opts msg] => allowed?
'([ msg]
[level msg]
[{:as opts :keys
[#_defaults #_elide? #_allow? #_expansion-id,
elidable? location #_location* inst uid middleware,
elidable? location #_location* inst uid middleware middleware+,
sample-rate kind ns id level when rate-limit rate-limit-by,
ctx parent root trace?, do let data msg error #_run & kvs]}
ctx ctx+ parent root trace?, do let data msg error #_run & kvs]}
msg])
:error! ; [error] [id-or-opts error] => given error
@ -421,9 +421,9 @@
[id error]
[{:as opts :keys
[#_defaults #_elide? #_allow? #_expansion-id,
elidable? location #_location* inst uid middleware,
elidable? location #_location* inst uid middleware middleware+,
sample-rate kind ns id level when rate-limit rate-limit-by,
ctx parent root trace?, do let data msg error #_run & kvs]}
ctx ctx+ parent root trace?, do let data msg error #_run & kvs]}
error])
:trace! ; [form] [id-or-opts form] => run result (value or throw)
@ -431,9 +431,9 @@
[id form]
[{:as opts :keys
[#_defaults #_elide? #_allow? #_expansion-id,
elidable? location #_location* inst uid middleware,
elidable? location #_location* inst uid middleware middleware+,
sample-rate kind ns id level when rate-limit rate-limit-by,
ctx parent root trace?, do let data msg error run & kvs]}
ctx ctx+ parent root trace?, do let data msg error run & kvs]}
form])
:spy! ; [form] [level-or-opts form] => run result (value or throw)
@ -441,9 +441,9 @@
[level form]
[{:as opts :keys
[#_defaults #_elide? #_allow? #_expansion-id,
elidable? location #_location* inst uid middleware,
elidable? location #_location* inst uid middleware middleware+,
sample-rate kind ns id level when rate-limit rate-limit-by,
ctx parent root trace?, do let data msg error run & kvs]}
ctx ctx+ parent root trace?, do let data msg error run & kvs]}
form])
:catch->error! ; [form] [id-or-opts form] => run result (value or throw)
@ -451,9 +451,9 @@
[id form]
[{:as opts :keys
[#_defaults #_elide? #_allow? #_expansion-id, rethrow? catch-val,
elidable? location #_location* inst uid middleware,
elidable? location #_location* inst uid middleware middleware+,
sample-rate kind ns id level when rate-limit rate-limit-by,
ctx parent root trace?, do let data msg error #_run & kvs]}
ctx ctx+ parent root trace?, do let data msg error #_run & kvs]}
form])
:uncaught->error! ; [] [id-or-opts] => nil
@ -461,9 +461,9 @@
[id]
[{:as opts :keys
[#_defaults #_elide? #_allow? #_expansion-id,
elidable? location #_location* inst uid middleware,
elidable? location #_location* inst uid middleware middleware+,
sample-rate kind ns id level when rate-limit rate-limit-by,
ctx parent root trace?, do let data msg error #_run & kvs]}])
ctx ctx+ parent root trace?, do let data msg error #_run & kvs]}])
(enc/unexpected-arg! macro-id))))
@ -637,15 +637,22 @@
let-form (or let-form '[])
msg-form (parse-msg-form msg-form)
ctx-form (get opts :ctx `taoensso.telemere/*ctx*)
middleware-form (get opts :middleware `taoensso.telemere/*middleware*)
ctx-form
(if-let [ctx+ (get opts :ctx+)]
`(taoensso.encore.signals/update-ctx taoensso.telemere/*ctx* ~ctx+)
(get opts :ctx `taoensso.telemere/*ctx*))
middleware-form
(if-let [middleware+ (get opts :middleware+)]
`(taoensso.telemere/comp-middleware taoensso.telemere/*middleware* ~middleware+)
(get opts :middleware `taoensso.telemere/*middleware*))
kvs-form
(not-empty
(dissoc opts
:elidable? :location :location* :inst :uid :middleware,
:elidable? :location :location* :inst :uid :middleware :middleware+,
:sample-rate :ns :kind :id :level :filter :when #_:rate-limit #_:rate-limit-by,
:ctx :parent #_:trace?, :do :let :data :msg :error :run,
:ctx :ctx+ :parent #_:trace?, :do :let :data :msg :error :run,
:elide? :allow? #_:expansion-id :otel/context))
_ ; Compile-time validation

View file

@ -232,39 +232,51 @@
(is (= @c 16) "6x run + 6x let (0x suppressed) + 4x data (2x suppressed)")]))))
(testing "Dynamic bindings, etc."
[(binding[#?@(:clj [impl/*sig-spy-off-thread?* true])
*dynamic-var* "foo"
tel/*ctx* "bar"]
(let [sv (with-sig (sig! {:level :info, :data {:*dynamic-var* *dynamic-var*, :*ctx* tel/*ctx*}}))]
(is (sm? sv {:data {:*dynamic-var* "foo", :*ctx* "bar"}})
"Retain dynamic bindings in place at time of signal call")))
[(let [sv
(binding[#?@(:clj [impl/*sig-spy-off-thread?* true])
*dynamic-var* "dynamic-val"
tel/*ctx* "ctx-val"]
(with-sig (sig! {:level :info, :data {:*dynamic-var* *dynamic-var*, :*ctx* tel/*ctx*}})))]
(is (sm? sv {:data {:*dynamic-var* "dynamic-val", :*ctx* "ctx-val"}})
"Retain dynamic bindings in place at time of signal call"))
(let [sv (with-sig (sig! {:level :info, :ctx "my-ctx"}))]
(is (sm? sv {:ctx "my-ctx"}) "`*ctx*` can be overridden via call opt"))])
(is (sm? sv {:ctx "my-ctx"}) "`*ctx*` can be overridden via call opt"))
(testing "Dynamic middleware (`*middleware*`)"
[(is (sm? (tel/with-middleware nil (with-sig (sig! {:level :info }))) {:level :info }) "nil middleware ~ identity")
(is (sm? (tel/with-middleware identity (with-sig (sig! {:level :info }))) {:level :info }) "nil middleware ~ identity")
(is (sm? (tel/with-middleware #(assoc % :foo 1) (with-sig (sig! {:level :info }))) {:level :info, :foo 1 }))
(is (sm? (tel/with-middleware #(assoc % :foo 1) (with-sig (sig! {:level :info, :middleware #(assoc % :foo 2)}))) {:level :info, :foo 2 }) "call > dynamic")
(is (sm? (tel/with-middleware #(assoc % :foo 1) (with-sig (sig! {:level :info, :middleware nil}))) {:level :info, :foo :submap/nx}) "call > dynamic")
(is (= (tel/with-middleware #(do nil) (with-sig (sig! {:level :info }))) nil) "return nil => suppress")
(is (sm? (tel/with-middleware #(do nil) (with-sig (sig! {:level :info, :middleware nil}))) {:level :info}) "call > dynamic")])
(let [sv (binding [tel/*ctx* {:foo :bar}]
(with-sig (sig! {:level :info, :ctx+ {:baz :qux}})))]
(is (sm? sv {:ctx {:foo :bar, :baz :qux}}) "`*ctx*` can be updated via call opt"))])
(testing "Call middleware"
(let [c (enc/counter)
[[rv1 _] [sv1]] (with-sigs :raw nil (sig! {:level :info, :run (c), :middleware (tel/comp-middleware #(assoc % :m1 (c)) #(assoc % :m2 (c)))}))
[[rv2 _] [sv2]] (with-sigs :raw nil (sig! {:level :info, :run (c), :middleware (tel/comp-middleware #(assoc % :m1 (c)) #(assoc % :m2 (c))), :allow? false}))
[[rv3 _] [sv3]] (with-sigs :raw nil (sig! {:level :info, :run (c), :middleware (tel/comp-middleware #(assoc % :m1 (c)) #(assoc % :m2 (c)))}))
[[rv4 _] [sv4]] (with-sigs :raw nil (sig! {:level :info, :middleware (fn [_] "signal-value")}))
[[rv5 _] [sv5]] (with-sigs :raw nil (sig! {:level :info, :middleware (fn [_] nil)}))]
(testing "Middleware"
[(testing "Dynamic middleware (`*middleware*`)"
[(is (sm? (tel/with-middleware nil (with-sig (sig! {:level :info }))) {:level :info }) "nil middleware ~ identity")
(is (sm? (tel/with-middleware identity (with-sig (sig! {:level :info }))) {:level :info }) "nil middleware ~ identity")
(is (sm? (tel/with-middleware #(assoc % :foo 1) (with-sig (sig! {:level :info }))) {:level :info, :foo 1 }))
(is (sm? (tel/with-middleware #(assoc % :foo 1) (with-sig (sig! {:level :info, :middleware #(assoc % :foo 2)}))) {:level :info, :foo 2 }) "call > dynamic")
(is (sm? (tel/with-middleware #(assoc % :foo 1) (with-sig (sig! {:level :info, :middleware nil}))) {:level :info, :foo :submap/nx}) "call > dynamic")
(is (= (tel/with-middleware #(do nil) (with-sig (sig! {:level :info }))) nil) "return nil => suppress")
(is (sm? (tel/with-middleware #(do nil) (with-sig (sig! {:level :info, :middleware nil}))) {:level :info}) "call > dynamic")])
[(is (= rv1 0)) (is (sm? sv1 {:m1 1 :m2 2}))
(is (= rv2 3)) (is (nil? sv2))
(is (= rv3 4)) (is (sm? sv3 {:m1 5 :m2 6}))
(is (= rv4 true)) (is (= sv4 "signal-value"))
(is (= rv5 true)) (is (nil? sv5))
(is (= @c 7) "3x run + 4x middleware")]))
(testing "Call middleware"
(let [c (enc/counter)
[[rv1 _] [sv1]] (with-sigs :raw nil (sig! {:level :info, :run (c), :middleware (tel/comp-middleware #(assoc % :m1 (c)) #(assoc % :m2 (c)))}))
[[rv2 _] [sv2]] (with-sigs :raw nil (sig! {:level :info, :run (c), :middleware (tel/comp-middleware #(assoc % :m1 (c)) #(assoc % :m2 (c))), :allow? false}))
[[rv3 _] [sv3]] (with-sigs :raw nil (sig! {:level :info, :run (c), :middleware (tel/comp-middleware #(assoc % :m1 (c)) #(assoc % :m2 (c)))}))
[[rv4 _] [sv4]] (with-sigs :raw nil (sig! {:level :info, :middleware (fn [_] "signal-value")}))
[[rv5 _] [sv5]] (with-sigs :raw nil (sig! {:level :info, :middleware (fn [_] nil)}))]
[(is (= rv1 0)) (is (sm? sv1 {:m1 1 :m2 2}))
(is (= rv2 3)) (is (nil? sv2))
(is (= rv3 4)) (is (sm? sv3 {:m1 5 :m2 6}))
(is (= rv4 true)) (is (= sv4 "signal-value"))
(is (= rv5 true)) (is (nil? sv5))
(is (= @c 7) "3x run + 4x middleware")]))
(testing "Mixed middleware"
[(let [sv
(binding [tel/*middleware* #(assoc % :foo true)]
(with-sig (sig! {:level :info, :middleware+ #(assoc % :bar true)})))]
(is (sm? sv {:foo true, :bar true})))])])
#?(:clj
(testing "Printing"

View file

@ -132,9 +132,9 @@
:keys
[fallback, ; Unique to shell
#_defaults #_elide? #_allow? #_expansion-id, ; Undocumented
elidable? location #_location* inst uid middleware,
elidable? location #_location* inst uid middleware middleware+,
sample-rate kind ns id level when rate-limit rate-limit-by,
ctx parent root trace?, do let data msg error run & kvs]}])}
ctx ctx+ parent root trace?, do let data msg error run & kvs]}])}
[opts]
(if telemere-present?
@ -171,9 +171,9 @@
'([{:as opts :keys
[#_fallback, ; Unique to shell
#_defaults #_elide? #_allow? #_expansion-id, ; Undocumented
elidable? location #_location* #_inst #_uid #_middleware,
elidable? location #_location* #_inst #_uid #_middleware #_middleware+,
sample-rate kind ns id level when rate-limit rate-limit-by,
#_ctx #_parent #_root #_trace?, #_do #_let #_data #_msg #_error #_run #_& #_kvs]}])}
#_ctx #_ctx+ #_parent #_root #_trace?, #_do #_let #_data #_msg #_error #_run #_& #_kvs]}])}
[opts]
(if telemere-present?