mirror of
https://github.com/taoensso/telemere.git
synced 2025-12-24 20:38:25 +00:00
[mod] Rework (simplify) with-signal API
This commit is contained in:
parent
46e629504b
commit
dae36ef549
10 changed files with 63 additions and 80 deletions
|
|
@ -24,7 +24,7 @@ Examples:
|
|||
|
||||
Tips:
|
||||
|
||||
- Test using `with-signals`: (with-signals (catch->error! ...)).
|
||||
- Test using `with-signal`: (with-signal (catch->error! ...)).
|
||||
- Supports the same options as other signals [1].
|
||||
|
||||
- Useful for recording errors in forms, futures, callbacks, etc.
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ Examples:
|
|||
|
||||
Tips:
|
||||
|
||||
- Test using `with-signals`: (with-signals (error! ...)).
|
||||
- Test using `with-signal`: (with-signal (error! ...)).
|
||||
- Supports the same options as other signals [3].
|
||||
|
||||
- `error` arg is a platform error (`java.lang.Throwable` or `js/Error`).
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ Examples:
|
|||
|
||||
Tips:
|
||||
|
||||
- Test using `with-signals`: (with-signals (error! ...)).
|
||||
- Test using `with-signal`: (with-signal (event! ...)).
|
||||
- Supports the same options as other signals [3].
|
||||
|
||||
- A good general-purpose signal, prefer to `log!` by default, since it
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ Examples:
|
|||
|
||||
Tips:
|
||||
|
||||
- Test using `with-signals`: (with-signals (log! ...)).
|
||||
- Test using `with-signal`: (with-signal (log! ...)).
|
||||
- Supports the same options as other signals [3].
|
||||
|
||||
- Prefer `event!` to `log!` by default, since it better encourages structured
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ their defaults and the focus of their call APIs (args and return values):
|
|||
|
||||
Tips:
|
||||
|
||||
- Test using `with-signals`: (with-signals (signal! ...)).
|
||||
- Test using `with-signal`: (with-signal (signal! ...)).
|
||||
- Supports the same options as other signals [3].
|
||||
|
||||
----------------------------------------
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ Examples:
|
|||
|
||||
Tips:
|
||||
|
||||
- Test using `with-signals`: (with-signals (spy! ...)).
|
||||
- Test using `with-signal`: (with-signal (spy! ...)).
|
||||
- Supports the same options as other signals [3].
|
||||
|
||||
- Identical to `trace!`, but focused on form + level rather than form + id.
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@ Examples:
|
|||
|
||||
Tips:
|
||||
|
||||
- Test using `with-signals`: (with-signals (trace! ...)).
|
||||
- Test using `with-signal`: (with-signal (trace! ...)).
|
||||
- Supports the same options as other signals [3].
|
||||
|
||||
- Identical to `spy!`, but focused on form + id rather than form + level.
|
||||
|
|
|
|||
|
|
@ -20,7 +20,7 @@
|
|||
[set-ctx! with-ctx with-ctx+
|
||||
set-middleware! with-middleware
|
||||
|
||||
with-signals with-signal
|
||||
with-signal with-signals
|
||||
signal! event! log! trace! spy! catch->error!
|
||||
|
||||
;; Via `sigs/def-api`
|
||||
|
|
@ -72,8 +72,8 @@
|
|||
|
||||
impl/msg-splice
|
||||
impl/msg-skip
|
||||
#?(:clj impl/with-signals)
|
||||
#?(:clj impl/with-signal)
|
||||
#?(:clj impl/with-signals)
|
||||
#?(:clj impl/signal!))
|
||||
|
||||
;;;; Signal help
|
||||
|
|
|
|||
|
|
@ -5,7 +5,11 @@
|
|||
(:refer-clojure :exclude [binding])
|
||||
(:require
|
||||
[taoensso.encore :as enc :refer [binding have have?]]
|
||||
[taoensso.encore.signals :as sigs]))
|
||||
[taoensso.encore.signals :as sigs])
|
||||
|
||||
#?(:cljs
|
||||
(:require-macros
|
||||
[taoensso.telemere.impl :refer [with-signal]])))
|
||||
|
||||
(comment
|
||||
(remove-ns 'taoensso.telemere.impl)
|
||||
|
|
@ -243,92 +247,72 @@
|
|||
(enc/defonce ^:dynamic *sig-spy* "To support `with-signals`, etc." nil)
|
||||
(enc/defonce ^:dynamic *sig-handlers* "?[<wrapped-handler-fn>]" nil)
|
||||
|
||||
(defn- force-msg [sig]
|
||||
(if-not (map? sig)
|
||||
(defn force-msg-in-sig [sig]
|
||||
(if-not (map? sig)
|
||||
sig
|
||||
(if-let [e (find sig :msg_)]
|
||||
(assoc sig :msg_ (force (val e)))
|
||||
(do sig))))
|
||||
|
||||
(defn -with-signals
|
||||
"Private util to support `with-signals` macro."
|
||||
[form-fn
|
||||
{:keys [handle? trap-errors? force-msg?]
|
||||
:or {handle? true}}]
|
||||
#?(:clj
|
||||
(defmacro ^:public with-signal
|
||||
"Experimental.
|
||||
Executes given form, trapping errors. Returns the LAST signal triggered by form.
|
||||
Useful for tests/debugging.
|
||||
|
||||
(let [sigs_ (volatile! nil)]
|
||||
(binding [*sig-spy* [sigs_ (not :last-only?) handle?]]
|
||||
(let [form-result
|
||||
(if-not trap-errors?
|
||||
(form-fn)
|
||||
(enc/try*
|
||||
(do [(form-fn) nil])
|
||||
(catch :all t t [nil t])))]
|
||||
Options:
|
||||
`trap-signals?` (default: false)
|
||||
Should ALL signals triggered by form be trapped to prevent normal dispatch
|
||||
to registered handlers?
|
||||
|
||||
[form-result
|
||||
(when-let [sigs @sigs_]
|
||||
(if force-msg?
|
||||
(mapv force-msg sigs)
|
||||
(do sigs)))]))))
|
||||
`raw-msg?` (default: false)
|
||||
Should delayed `:msg_` in returned signal be retained as-is?
|
||||
Delay is otherwise replaced by realized string.
|
||||
|
||||
See also `with-signals`."
|
||||
([ form] `(with-signal false false ~form))
|
||||
([ trap-signals? form] `(with-signal false ~trap-signals? ~form))
|
||||
([raw-msg? trap-signals? form]
|
||||
`(let [sig_# (volatile! nil)]
|
||||
(binding [*sig-spy* [sig_# :last-only ~trap-signals?]]
|
||||
(enc/try* ~form (catch :all _#)))
|
||||
|
||||
(if ~raw-msg?
|
||||
(do @sig_#)
|
||||
(force-msg-in-sig @sig_#))))))
|
||||
|
||||
#?(:clj
|
||||
(defmacro ^:public with-signals
|
||||
"Experimental.
|
||||
Executes given form and records any signals triggered by it.
|
||||
Return value depends on given options. Useful for tests/debugging.
|
||||
Like `with-signal` but returns [[<form-value> <form-error>] [<signal1> ...]].
|
||||
Useful for tests/debugging."
|
||||
([ form] `(with-signals false false ~form))
|
||||
([ trap-signals? form] `(with-signals false ~trap-signals? ~form))
|
||||
([raw-msgs? trap-signals? form]
|
||||
`(let [sigs_# (volatile! nil)
|
||||
form-result#
|
||||
(binding [*sig-spy* [sigs_# (not :last-only) ~trap-signals?]]
|
||||
(enc/try*
|
||||
(do [~form nil])
|
||||
(catch :all t# [nil t#])))
|
||||
|
||||
Options:
|
||||
sigs#
|
||||
(if ~raw-msgs?
|
||||
(do @sigs_#)
|
||||
(mapv force-msg-in-sig @sigs_#))]
|
||||
|
||||
`handle?`
|
||||
Should registered handlers receive signals triggered by form, as usual?
|
||||
Default: true.
|
||||
|
||||
`trap-errors?`
|
||||
If true: returns [[form-value form-error] signals], trapping any form error.
|
||||
If false: returns [ form-value signals], throwing on form error.
|
||||
Default: false.
|
||||
|
||||
`force-msg?`
|
||||
Should delayed `:msg_` keys in signals be replaced with realized strings?
|
||||
Default: false.
|
||||
|
||||
See also `with-signal` for a simpler API."
|
||||
{:arglists
|
||||
'([form]
|
||||
[{:keys [handle? trap-errors? force-msg?]
|
||||
:or {handle? true}} form])}
|
||||
|
||||
([ form] `(-with-signals (fn [] ~form) nil))
|
||||
([opts form] `(-with-signals (fn [] ~form) ~opts))))
|
||||
|
||||
#?(:clj
|
||||
(defmacro ^:public with-signal
|
||||
"Experimental
|
||||
Minimal version of `with-signals`.
|
||||
Executes given form and returns the last signal triggered by it.
|
||||
Useful for tests/debugging.
|
||||
|
||||
- Always allows registered handlers to receive signals as usual.
|
||||
- Always traps form errors.
|
||||
- Never forces `:msg_` key.
|
||||
|
||||
See also `with-signals` for more options."
|
||||
[form]
|
||||
`(let [sig_# (volatile! nil)]
|
||||
(binding [*sig-spy* [sig_# :last-only :handle]]
|
||||
(enc/catching ~form))
|
||||
@sig_#)))
|
||||
[form-result# (not-empty sigs#)]))))
|
||||
|
||||
(defn dispatch-signal!
|
||||
"Dispatches given signal to registered handlers, supports `with-signals`."
|
||||
"Dispatches given signal to registered handlers, supports `with-signal/s`."
|
||||
[signal]
|
||||
(or
|
||||
(when-let [[v_ last-only? handle?] *sig-spy*]
|
||||
(when-let [[v_ last-only? trap-signals?] *sig-spy*]
|
||||
(let [sv (sigs/signal-value signal nil)]
|
||||
(if last-only?
|
||||
(vreset! v_ sv)
|
||||
(vswap! v_ #(conj (or % []) sv))))
|
||||
(when-not handle? :stop))
|
||||
(when trap-signals? :stop))
|
||||
|
||||
(sigs/call-handlers! *sig-handlers* signal)))
|
||||
|
||||
|
|
@ -618,7 +602,7 @@
|
|||
true))))))))
|
||||
|
||||
(comment
|
||||
(with-signals (signal! {:level :warn :let [x :x] :msg ["Test" "message" x] :data {:a :A :x x} :run (+ 1 2)}))
|
||||
(with-signal (signal! {:level :warn :let [x :x] :msg ["Test" "message" x] :data {:a :A :x x} :run (+ 1 2)}))
|
||||
(macroexpand '(signal! {:level :warn :let [x :x] :msg ["Test" "message" x] :data {:a :A :x x} :run (+ 1 2)}))
|
||||
|
||||
(do
|
||||
|
|
@ -664,9 +648,8 @@
|
|||
|
||||
(defn test-interop! [msg test-fn]
|
||||
(let [msg (str "Interop test: " msg " (" (enc/uuid-str) ")")
|
||||
[_ [signal]]
|
||||
signal
|
||||
(binding [*rt-sig-filter* nil] ; Without runtime filters
|
||||
(-with-signals (fn [] (test-fn msg))
|
||||
{:handle? false}))]
|
||||
(with-signal :raw :trap (test-fn msg)))]
|
||||
|
||||
(= (force (get signal :msg_)) msg)))
|
||||
|
|
|
|||
|
|
@ -72,7 +72,7 @@
|
|||
*err* (if-let [err# ~err] (osw (telemere-print-stream err#)) *err*)]
|
||||
~form)))
|
||||
|
||||
(comment (impl/with-signals (with-out->telemere (println "hello"))))
|
||||
(comment (impl/with-signal (with-out->telemere (println "hello"))))
|
||||
|
||||
(enc/defonce ^:private orig-out_ "Original `System/out`, or nil" (atom nil))
|
||||
(enc/defonce ^:private orig-err_ "Original `System/err`, or nil" (atom nil))
|
||||
|
|
|
|||
Loading…
Reference in a new issue