mirror of
https://github.com/taoensso/telemere.git
synced 2025-12-17 01:51:10 +00:00
[new] Misc API polish, first signal docstrings
This commit is contained in:
parent
ef79a57e48
commit
5a0d9d8241
13 changed files with 570 additions and 163 deletions
30
resources/signal-docstrings/catch-to-error!.txt
Normal file
30
resources/signal-docstrings/catch-to-error!.txt
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
Unconditionally executes given form and-
|
||||
If form succeeds: return the form's result.
|
||||
If form throws:
|
||||
Call `error!` with the thrown error and the given signal options [1],
|
||||
then return (:catch-val opts) if it exists, or rethrow the error.
|
||||
|
||||
API: [form] [id-or-opts form] => form's result (value/throw) (unconditional), or (:catch-val opts)
|
||||
Default kind: `:error`
|
||||
Default level: `:error`
|
||||
|
||||
Examples:
|
||||
|
||||
(catch->error! (/ 1 0)) ; %> {:kind :error, :level :error, :error <caught> ...}
|
||||
(catch->error! {:id ::my-id, :catch-val "threw"} (/ 1 0)) ; %> {... :id ::my-id ...}
|
||||
(catch->error!
|
||||
{:let [x "x"] ; Available to `:data` and `:msg`
|
||||
:data {:x x}
|
||||
:msg_ ["My msg:" x]}
|
||||
(/ 1 0)) ; %> {... :data {x "x"}, :msg_ "My msg: x" ...}
|
||||
|
||||
Tips:
|
||||
|
||||
- Test using `with-signals`: (with-signals (catch->error! ...)).
|
||||
- Supports the same options as other signals [1].
|
||||
|
||||
- Useful for recording errors in forms, futures, callbacks, etc.
|
||||
|
||||
See also `error!`.
|
||||
|
||||
[1] See `help:signal-options` docstring
|
||||
29
resources/signal-docstrings/error!.txt
Normal file
29
resources/signal-docstrings/error!.txt
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
"Error" signal call, focused on error + id.
|
||||
|
||||
API: [error] [id-or-opts error] => given error (unconditional)
|
||||
Default kind: `:error`
|
||||
Default level: `:error`
|
||||
|
||||
Examples:
|
||||
|
||||
(throw (error! (ex-info "MyEx" {}))) ; %> {:kind :error, :level :error, :error <MyEx> ...}
|
||||
(throw (error! ::my-id (ex-info "MyEx" {}))) ; %> {... :id ::my-id ...}
|
||||
(throw
|
||||
(error!
|
||||
{:let [x "x"] ; Available to `:data` and `:msg`
|
||||
:data {:x x}
|
||||
:msg ["My message:" x]}
|
||||
|
||||
(ex-info "MyEx" {}))) ; %> {... :data {x "x"}, :msg_ "My msg: x" ...}
|
||||
|
||||
Tips:
|
||||
|
||||
- Test using `with-signals`: (with-signals (error! ...)).
|
||||
- Supports the same options as other signals [3].
|
||||
|
||||
- `error` arg is a platform error (`java.lang.Throwable` or `js/Error`).
|
||||
- Can conveniently be wrapped by `throw`: (throw (error! ...)).
|
||||
|
||||
[1] See `help:signal-handling` docstring
|
||||
[2] See `help:signal-content` docstring
|
||||
[3] See `help:signal-options` docstring
|
||||
34
resources/signal-docstrings/event!.txt
Normal file
34
resources/signal-docstrings/event!.txt
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
"Event" signal call, focused on id + level.
|
||||
|
||||
API: [id] [id level-or-opts] => true iff signal call was allowed
|
||||
Default kind: `:event`
|
||||
Default level: `:info`
|
||||
|
||||
When conditions are met [1], creates a Telemere signal [2] and dispatches it to
|
||||
registered handlers for processing (writing to console/disk/db, etc.).
|
||||
|
||||
Examples:
|
||||
|
||||
(event! ::my-id) ; %> {:kind :event, :level :info, :id ::my-id ...}
|
||||
(event! ::my-id :warn) ; %> {... :level :warn ...}
|
||||
(event! ::my-id
|
||||
{:let [x "x"] ; Available to `:data` and `:msg`
|
||||
:data {:x x}
|
||||
:msg ["My msg:" x]}) ; %> {... :data {x "x"}, :msg_ "My msg: x" ...}
|
||||
|
||||
Tips:
|
||||
|
||||
- Test using `with-signals`: (with-signals (error! ...)).
|
||||
- Supports the same options as other signals [3].
|
||||
|
||||
- A good general-purpose signal, prefer to `log!` by default, since it
|
||||
better encourages structured data over unstructured messages.
|
||||
|
||||
- Has a different 2-arity arg order to all other signals!
|
||||
Mnemonic: the arg that's typically larger is *always* in the rightmost
|
||||
position, and for `event!` that's the `level-or-opts` arg.
|
||||
|
||||
----------------------------------------
|
||||
[1] See `help:signal-handling` docstring
|
||||
[2] See `help:signal-content` docstring
|
||||
[3] See `help:signal-options` docstring
|
||||
34
resources/signal-docstrings/log!.txt
Normal file
34
resources/signal-docstrings/log!.txt
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
"Log" signal call, focused on message + level.
|
||||
|
||||
API: [msg] [level-or-opts msg] => true iff signal call was allowed.
|
||||
Default kind: `:log`
|
||||
Default level: `:info`
|
||||
|
||||
When conditions are met [1], creates a Telemere signal [2] and dispatches it to
|
||||
registered handlers for processing (writing to console/disk/db, etc.).
|
||||
|
||||
Examples:
|
||||
|
||||
(log! "My msg") ; %> {:kind :log, :level :info, :id ::my-id ...}
|
||||
(log! :warn "My msg") ; %> {... :level :warn ...}
|
||||
(log!
|
||||
{:let [x "x"] ; Available to `:data` and `:msg`
|
||||
:data {:x x}}
|
||||
|
||||
["My msg:" x]) ; %> {... :data {x "x"}, :msg_ "My msg: x" ...}
|
||||
|
||||
Tips:
|
||||
|
||||
- Test using `with-signals`: (with-signals (log! ...)).
|
||||
- Supports the same options as other signals [3].
|
||||
|
||||
- Prefer `event!` to `log!` by default, since it better encourages structured
|
||||
data over unstructured messages.
|
||||
|
||||
- `msg` arg may be a string, or vector of strings to join with `\space`.
|
||||
- See also `msg-splice`, `msg-skip` utils.
|
||||
|
||||
----------------------------------------
|
||||
[1] See `help:signal-handling` docstring
|
||||
[2] See `help:signal-content` docstring
|
||||
[3] See `help:signal-options` docstring
|
||||
35
resources/signal-docstrings/signal!.txt
Normal file
35
resources/signal-docstrings/signal!.txt
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
Low-level generic signal call.
|
||||
|
||||
API: [opts] => depends on options [3]
|
||||
Default kind: none (optional)
|
||||
Default level: none (must be provided)
|
||||
|
||||
When conditions are met [1], creates a Telemere signal [2] and dispatches it to
|
||||
registered handlers for processing (writing to console/disk/db, etc.).
|
||||
|
||||
If `:run` option is provided: returns value of given run form, or throws.
|
||||
Otherwise: returns true iff call conditions were met.
|
||||
|
||||
Generic signals are fairly low-level and useful mostly for library authors or
|
||||
advanced users writing their own wrapper macros. Regular users will typically
|
||||
prefer one of the provided wrapper macros optimized for ease-of-use in
|
||||
common cases.
|
||||
|
||||
These all use `signal!` underneath and offer the same options, but vary in
|
||||
their defaults and the focus of their call APIs (args and return values):
|
||||
|
||||
`event!` - (id + opts/level) => true iff signal call was allowed
|
||||
`log!` - (message + opts/level) => true iff signal call was allowed
|
||||
`error!` - (error + opts/id) => given error (unconditional)
|
||||
`trace!` - (form + opts/id) => form's result (value/throw) (unconditional)
|
||||
`spy!` - (form + opts/level) => form's result (value/throw) (unconditional)
|
||||
|
||||
Tips:
|
||||
|
||||
- Test using `with-signals`: (with-signals (signal! ...)).
|
||||
- Supports the same options as other signals [3].
|
||||
|
||||
----------------------------------------
|
||||
[1] See `help:signal-handling` docstring
|
||||
[2] See `help:signal-content` docstring
|
||||
[3] See `help:signal-options` docstring
|
||||
36
resources/signal-docstrings/signal-content.txt
Normal file
36
resources/signal-docstrings/signal-content.txt
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
Signals are initially maps with {:keys [instant id ns level data msg_ ...]},
|
||||
though they can be modified by call and/or handler middleware.
|
||||
|
||||
Default keys:
|
||||
|
||||
`:schema-version` - Int version of signal schema (current: 1)
|
||||
|
||||
`:instant` - Platform instant [1] when signal was created
|
||||
`:level` - Signal level ∈ #{<int> :trace :debug :info :warn :error :fatal :report ...}
|
||||
`:kind` - Signal ?kind ∈ #{nil :event :error :log :trace :spy <user-val> ...}
|
||||
`:id` - ?id of signal call (common to all signals created by signal call, contrast with `:uid`)
|
||||
`:uid` - ?id of signal instance (unique to each signal created by signal call, contrast with `:id`)
|
||||
|
||||
`:data` - Arb user-level data ?val (usu. a map) given to signal call
|
||||
`:msg` - Arb user-level message ?str given to signal call
|
||||
`:error` - Arb user-level platform ?error [2] given to signal call
|
||||
|
||||
`:run-form` - Unevaluated ?form given to signal macro as `:run`
|
||||
`:run-value` - Successful return ?val of `:run` ?form
|
||||
`:end-instant` - Platform ?instant [1] when `:run` ?form completed
|
||||
`:runtime-nsecs`- ?int nanosecs runtime of `:run` ?form
|
||||
|
||||
`:ctx` - ?val of `*ctx*` (arb user-level state) when signal was created
|
||||
`:parent` - ?{:keys [id uid]} of parent signal, present in nested signals when tracing
|
||||
`:location` - ?{:keys [ns file line column]} signal call location
|
||||
`:ns` - ?str namespace of signal call, same as (:ns location)
|
||||
`:file` - ?str filename of signal call, same as (:file location)
|
||||
`:line` - ?int line of signal call, same as (:line location)
|
||||
`:column` - ?int column of signal call, same as (:column location)
|
||||
|
||||
`:sample-rate` - ?rate ∈ℝ[0,1] for combined call AND handler sampling (0.75 => allow 75% of signals, nil => allow all)
|
||||
|
||||
If anything is unclear, please ping me (@ptaoussanis) so that I can improve these docs!
|
||||
|
||||
[1] Clj: `java.time.Instant`, Cljs: `js/Date`
|
||||
[2] Clj: `java.lang.Throwable`, Cljs: `js/Error`
|
||||
17
resources/signal-docstrings/signal-handling.txt
Normal file
17
resources/signal-docstrings/signal-handling.txt
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
A signal will be provided to a handler iff ALL of the following are true:
|
||||
|
||||
1. Signal call is allowed by compile-time filters
|
||||
2. Signal call is allowed by runtime filters
|
||||
3. Handler is allowed by runtime filters
|
||||
|
||||
4. Signal call middleware does not suppress the signal (return nil)
|
||||
5. Handler middleware does not suppress the signal (return nil)
|
||||
|
||||
For more info:
|
||||
|
||||
- On call filters, see: `help:filters` docstring
|
||||
- On handler filters, see: `help:handlers` docstring
|
||||
- On signal flow, see: Ref. <https://tinyurl.com/telemere-signal-flowchart>
|
||||
|
||||
If anything is unclear, please ping me (@ptaoussanis) so that I can
|
||||
improve these docs!
|
||||
33
resources/signal-docstrings/signal-options.txt
Normal file
33
resources/signal-docstrings/signal-options.txt
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
Signal options (shared by `signal!`, `event!`, ...):
|
||||
|
||||
`:instant` - Platform instant [1] when signal was created, ∈ #{nil :auto <user-val>}
|
||||
`:level` - Signal level ∈ #{<int> :trace :debug :info :warn :error :fatal :report ...}
|
||||
`:kind` - Signal ?kind ∈ #{nil :event :error :log :trace :spy <user-val> ...}
|
||||
`:id` - ?id of signal call (common to all signals created by signal call, contrast with `:uid`)
|
||||
`:uid` - ?id of signal instance (unique to each signal created by signal call, contrast with `:id`)
|
||||
|
||||
`:data` - Arb user-level ?data to incl. in signal: usu. a map
|
||||
`:msg` - Arb user-level ?message to incl. in signal: str or vec of strs to join (with `\space`)
|
||||
`:error` - Arb user-level ?error to incl. in signal: platform error [2]
|
||||
|
||||
`:run` - ?form to execute UNCONDITIONALLY; will incl. `:run-value` in signal
|
||||
`:do` - ?form to execute conditionally (iff signal allowed), before establishing `:let` ?binding
|
||||
`:let` - ?binding 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 info in signal
|
||||
`:location` - Custom ?{:keys [ns line column file]} to override auto signal call location
|
||||
|
||||
`:elidable?` - Should signal call be subject to compile-time elision? (Default: true)
|
||||
`:sample-rate` - ?rate ∈ℝ[0,1] for call 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 `telemere/rate-limiter`, see its docstring for details
|
||||
`:middleware` - ?[(fn [signal])=>modified-signal ...] call middleware
|
||||
`:trace?` - Should tracing be enabled for `:run` form?
|
||||
|
||||
<user-opts> - Arb user-level ?kvs to incl. in signal
|
||||
|
||||
If anything is unclear, please ping me (@ptaoussanis) so that I can improve these docs!
|
||||
|
||||
[1] Clj: `java.time.Instant`, Cljs: `js/Date`
|
||||
[2] Clj: `java.lang.Throwable`, Cljs: `js/Error`
|
||||
36
resources/signal-docstrings/spy!.txt
Normal file
36
resources/signal-docstrings/spy!.txt
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
"Spy" signal call, focused on form + level.
|
||||
|
||||
API: [form] [level-or-opts form] => form's result (value/throw) (unconditional)
|
||||
Default kind: `:spy`
|
||||
Default level: `:info`
|
||||
|
||||
When conditions are met [1], creates a Telemere signal [2] and dispatches it to
|
||||
registered handlers for processing (writing to console/disk/db, etc.).
|
||||
|
||||
Examples:
|
||||
|
||||
(spy! (+ 1 2)) ; %> {:kind :trace, :level :info, :run-form '(+ 1 2),
|
||||
; :run-value 3, :parent {:keys [id uid]}
|
||||
; :msg "(+ 1 2) => 3" ...}
|
||||
(spy! ::my-id (+ 1 2)) ; %> {... :id ::my-id ...}
|
||||
(spy!
|
||||
{:let [x "x"] ; Available to `:data` and `:msg`
|
||||
:data {:x x}}
|
||||
|
||||
(+ 1 2)) ; %> {... :data {x "x"}, :msg_ "My msg: x" ...}
|
||||
|
||||
Tips:
|
||||
|
||||
- Test using `with-signals`: (with-signals (spy! ...)).
|
||||
- Supports the same options as other signals [3].
|
||||
|
||||
- Identical to `trace!`, but focused on form + level rather than form + id.
|
||||
|
||||
- Useful for debugging/monitoring forms, and tracing (nested) execution flow.
|
||||
- Execution of `form` arg may trigger additional (nested) signals.
|
||||
Each signal's `:parent` key will indicate its immediate parent.
|
||||
|
||||
----------------------------------------
|
||||
[1] See `help:signal-handling` docstring
|
||||
[2] See `help:signal-content` docstring
|
||||
[3] See `help:signal-options` docstring
|
||||
40
resources/signal-docstrings/trace!.txt
Normal file
40
resources/signal-docstrings/trace!.txt
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
"Trace" signal call, focused on form + id.
|
||||
|
||||
API: [form] [id-or-opts form] => form's result (value/throw) (unconditional)
|
||||
Default kind: `:trace`
|
||||
Default level: `:info` (intentionally NOT `:trace`!)
|
||||
|
||||
When conditions are met [1], creates a Telemere signal [2] and dispatches it to
|
||||
registered handlers for processing (writing to console/disk/db, etc.).
|
||||
|
||||
Examples:
|
||||
|
||||
(trace! (+ 1 2)) ; %> {:kind :trace, :level :info, :run-form '(+ 1 2),
|
||||
; :run-value 3, :parent {:keys [id uid]} ...
|
||||
; :msg "(+ 1 2) => 3" ...}
|
||||
(trace! ::my-id (+ 1 2)) ; %> {... :id ::my-id ...}
|
||||
(trace!
|
||||
{:let [x "x"] ; Available to `:data` and `:msg`
|
||||
:data {:x x}}
|
||||
|
||||
(+ 1 2)) ; %> {... :data {x "x"}, :msg_ "My msg: x" ...}
|
||||
|
||||
Tips:
|
||||
|
||||
- Test using `with-signals`: (with-signals (trace! ...)).
|
||||
- Supports the same options as other signals [3].
|
||||
|
||||
- Identical to `spy!`, but focused on form + id rather than form + level.
|
||||
|
||||
- Useful for debugging/monitoring forms, and tracing (nested) execution flow.
|
||||
- Execution of `form` arg may trigger additional (nested) signals.
|
||||
Each signal's `:parent` key will indicate its immediate parent.
|
||||
|
||||
- Default level is `:info`, not `:trace`! The name "trace" in "trace signal"
|
||||
refers to the general action of tracing program flow rather than to the
|
||||
common logging level of the same name.
|
||||
|
||||
----------------------------------------
|
||||
[1] See `help:signal-handling` docstring
|
||||
[2] See `help:signal-content` docstring
|
||||
[3] See `help:signal-options` docstring
|
||||
|
|
@ -58,8 +58,8 @@
|
|||
|
||||
(comment
|
||||
[level-aliases]
|
||||
[handlers-help get-handlers add-handler! remove-handler! with-handler with-handler+]
|
||||
[filtering-help get-filters get-min-level
|
||||
[help:handlers get-handlers add-handler! remove-handler! with-handler with-handler+]
|
||||
[help:filtering get-filters get-min-level
|
||||
set-kind-filter! set-ns-filter! set-id-filter! set-min-level!
|
||||
with-kind-filter with-ns-filter with-id-filter with-min-level])
|
||||
|
||||
|
|
@ -78,6 +78,14 @@
|
|||
#?(:clj impl/with-signals)
|
||||
#?(:clj impl/signal!))
|
||||
|
||||
;;;; Signal help
|
||||
|
||||
(comment help:filters help:handlers) ; Via Encore
|
||||
|
||||
(impl/defhelp help:signal-handling :signal-handling)
|
||||
(impl/defhelp help:signal-content :signal-content)
|
||||
(impl/defhelp help:signal-options :signal-options)
|
||||
|
||||
;;;; Context
|
||||
|
||||
(enc/defonce default-ctx
|
||||
|
|
@ -88,7 +96,7 @@
|
|||
(enc/get-env {:as :edn} :taoensso.telemere/default-ctx<.platform><.edn>))
|
||||
|
||||
(enc/def* ^:dynamic *ctx*
|
||||
"Dynamic context: arbitrary app-level state attached as `:ctx` to all signals.
|
||||
"Dynamic context: arbitrary user-level state attached as `:ctx` to all signals.
|
||||
Value may be any type, but is usually nil or a map.
|
||||
|
||||
Re/bind dynamic value using `with-ctx`, `with-ctx+`, or `binding`.
|
||||
|
|
@ -179,68 +187,120 @@
|
|||
:data data}))))
|
||||
|
||||
;;;; Common signals
|
||||
;; - log! [msg] [level-or-opts msg] ; msg + ?level => allowed?
|
||||
;; - event! [id] [level-or-opts id] ; id + ?level => allowed?
|
||||
;; - error! [error] [id-or-opts error] ; error + ?id => error
|
||||
;; - trace! [form] [id-or-opts form] ; run + ?id => run result (value or throw)
|
||||
;; - spy! [form] [level-or-opts form] ; run + ?level => run result (value or throw)
|
||||
;; - catch->error! [form] [id-or-opts form] ; run + ?id => run value or ?return
|
||||
;; - uncaught->error! [] [id-or-opts ] ; ?id => nil
|
||||
|
||||
#?(:clj
|
||||
(defmacro log!
|
||||
"TODO Docstring [msg] [level-or-opts msg] => allowed?"
|
||||
{:arglists (impl/signal-arglists :log!)}
|
||||
[& args]
|
||||
(let [opts (apply impl/signal-opts :msg, :level, {:kind :log, :level :info} args)]
|
||||
(enc/keep-callsite `(impl/signal! ~opts)))))
|
||||
;; - signal! [ opts] ; => allowed? / run result (value or throw)
|
||||
;; - event! [id ] [id level-or-opts] ; id + ?level => allowed? ; Sole signal with descending main arg!
|
||||
;; - log! [msg ] [level-or-opts msg] ; msg + ?level => allowed?
|
||||
;; - error! [error] [id-or-opts error] ; error + ?id => given error
|
||||
;; - trace! [form ] [id-or-opts form] ; run + ?id => run result (value or throw)
|
||||
;; - spy! [form ] [level-or-opts form] ; run + ?level => run result (value or throw)
|
||||
;; - catch->error! [form ] [id-or-opts form] ; run + ?id => run value or ?return
|
||||
;; - uncaught->error! [ ] [id-or-opts ] ; ?id => nil
|
||||
|
||||
#?(:clj
|
||||
(defmacro event!
|
||||
"TODO Docstring [id] [level-or-opts id] => allowed?"
|
||||
{:arglists (impl/signal-arglists :event!)}
|
||||
"[id] [id level-or-opts] => allowed?"
|
||||
{:doc (impl/signal-docstring :event!)
|
||||
:arglists (impl/signal-arglists :event!)}
|
||||
[& args]
|
||||
(let [opts (apply impl/signal-opts :id, :level, {:kind :event, :level :info} args)]
|
||||
(let [opts (impl/signal-opts `event! {:kind :event, :level :info} :id :level :dsc args)]
|
||||
(enc/keep-callsite `(impl/signal! ~opts)))))
|
||||
|
||||
(comment
|
||||
(with-signal (event! ::my-id))
|
||||
(with-signal (event! ::my-id :warn))
|
||||
(with-signal
|
||||
(event! ::my-id
|
||||
{:let [x "x"] ; Available to `:data` and `:msg`
|
||||
:data {:x x}
|
||||
:msg ["My msg:" x]})))
|
||||
|
||||
#?(:clj
|
||||
(defmacro log!
|
||||
"[msg] [level-or-opts msg] => allowed?"
|
||||
{:doc (impl/signal-docstring :log!)
|
||||
:arglists (impl/signal-arglists :log!)}
|
||||
[& args]
|
||||
(let [opts (impl/signal-opts `log! {:kind :log, :level :info} :msg :level :asc args)]
|
||||
(enc/keep-callsite `(impl/signal! ~opts)))))
|
||||
|
||||
(comment
|
||||
(with-signal (log! "My msg"))
|
||||
(with-signal (log! :warn "My msg"))
|
||||
(with-signal
|
||||
(log!
|
||||
{:let [x "x"] ; Available to `:data` and `:msg`
|
||||
:data {:x x}}
|
||||
["My msg:" x])))
|
||||
|
||||
#?(:clj
|
||||
(defmacro error!
|
||||
"TODO Docstring [error] [id-or-opts error] => error
|
||||
(throw (error! <error>)) example."
|
||||
{:arglists (impl/signal-arglists :error!)}
|
||||
"[error] [error id-or-opts] => error"
|
||||
{:doc (impl/signal-docstring :error!)
|
||||
:arglists (impl/signal-arglists :error!)}
|
||||
[& args]
|
||||
(let [opts (apply impl/signal-opts :error, :id, {:kind :error, :level :error} args)
|
||||
(let [opts (impl/signal-opts `error! {:kind :error, :level :error} :error :id :asc args)
|
||||
error-form (get opts :error)]
|
||||
;; (enc/keep-callsite `(impl/signal! ~opts)) ; => allowed?
|
||||
|
||||
(enc/keep-callsite
|
||||
`(let [~'__error ~error-form]
|
||||
(impl/signal! ~(assoc opts :error '__error))
|
||||
~'__error)))))
|
||||
~'__error ; Unconditional!
|
||||
)))))
|
||||
|
||||
(comment (throw (error! (Exception. "hello"))))
|
||||
(comment
|
||||
(with-signal (throw (error! (ex-info "MyEx" {}))))
|
||||
(with-signal (throw (error! ::my-id (ex-info "MyEx" {}))))
|
||||
(with-signal
|
||||
(throw
|
||||
(error!
|
||||
{:let [x "x"] ; Available to `:data` and `:msg`
|
||||
:data {:x x}
|
||||
:msg ["My msg:" x]}
|
||||
(ex-info "MyEx" {})))))
|
||||
|
||||
#?(:clj
|
||||
(defmacro trace!
|
||||
"TODO Docstring [form] [id-or-opts form] => run result (value or throw)"
|
||||
{:arglists (impl/signal-arglists :trace!)}
|
||||
"[form] [id-or-opts form] => run result (value or throw)"
|
||||
{:doc (impl/signal-docstring :trace!)
|
||||
:arglists (impl/signal-arglists :trace!)}
|
||||
[& args]
|
||||
(let [opts (apply impl/signal-opts :run, :id, {:kind :trace, :level :info} args)]
|
||||
(let [opts (impl/signal-opts `trace! {:kind :trace, :level :info, :msg ::impl/spy} :run :id :asc args)]
|
||||
(enc/keep-callsite `(impl/signal! ~opts)))))
|
||||
|
||||
(comment
|
||||
(with-signal (trace! (+ 1 2)))
|
||||
(with-signal (trace! ::my-id (+ 1 2)))
|
||||
(with-signal
|
||||
(trace!
|
||||
{:let [x "x"] ; Available to `:data` and `:msg`
|
||||
:data {:x x}}
|
||||
(+ 1 2))))
|
||||
|
||||
#?(:clj
|
||||
(defmacro spy!
|
||||
"TODO Docstring [form] [level-or-opts form] => run result (value or throw)"
|
||||
{:arglists (impl/signal-arglists :spy!)}
|
||||
"[form] [level-or-opts form] => run result (value or throw)"
|
||||
{:doc (impl/signal-docstring :spy!)
|
||||
:arglists (impl/signal-arglists :spy!)}
|
||||
[& args]
|
||||
(let [opts (apply impl/signal-opts :run, :level, {:kind :spy, :level :info, :msg ::impl/spy} args)]
|
||||
(let [opts (impl/signal-opts `spy! {:kind :spy, :level :info, :msg ::impl/spy} :run :level :asc args)]
|
||||
(enc/keep-callsite `(impl/signal! ~opts)))))
|
||||
|
||||
(comment
|
||||
(with-signal (spy! (+ 1 2)))
|
||||
(with-signal (spy! ::my-id (+ 1 2)))
|
||||
(with-signal
|
||||
(spy!
|
||||
{:let [x "x"] ; Available to `:data` and `:msg`
|
||||
:data {:x x}}
|
||||
(+ 1 2))))
|
||||
|
||||
#?(:clj
|
||||
(defmacro catch->error!
|
||||
"TODO Docstring [form] [id-or-opts form] => run value or ?catch-val"
|
||||
{:arglists (impl/signal-arglists :catch->error!)}
|
||||
"[form] [id-or-opts form] => run value or ?catch-val"
|
||||
{:doc (impl/signal-docstring :catch-to-error!)
|
||||
:arglists (impl/signal-arglists :catch->error!)}
|
||||
[& args]
|
||||
(let [opts (apply impl/signal-opts ::__form, :id, {:kind :error, :level :error} args)
|
||||
(let [opts (impl/signal-opts `catch->error! {:kind :error, :level :error} ::__form :id :asc args)
|
||||
rethrow? (if (contains? opts :catch-val) false (get opts :rethrow?))
|
||||
catch-val (get opts :catch-val)
|
||||
form (get opts ::__form)
|
||||
|
|
@ -248,26 +308,38 @@
|
|||
|
||||
(enc/keep-callsite
|
||||
`(enc/try* ~form
|
||||
(catch :any ~'__t
|
||||
(impl/signal! ~(assoc opts :error '__t))
|
||||
(if ~rethrow? (throw ~'__t) ~catch-val)))))))
|
||||
(catch :any ~'__caught-error
|
||||
(impl/signal! ~(assoc opts :error '__caught-error))
|
||||
(if ~rethrow? (throw ~'__caught-error) ~catch-val)))))))
|
||||
|
||||
(comment (catch->error! {:id :id1, :catch-val "threw"} (/ 1 0)))
|
||||
(comment
|
||||
(with-signal (catch->error! (/ 1 0)))
|
||||
(with-signal (catch->error! {:id ::my-id, :catch-val "threw"} (/ 1 0)))
|
||||
(with-signal
|
||||
(catch->error!
|
||||
{:let [x "x"] ; Available to `:data` and `:msg`
|
||||
:data {:x x}
|
||||
:msg_ ["My msg:" x __caught-error]}
|
||||
(/ 1 0))))
|
||||
|
||||
#?(:clj
|
||||
(defmacro uncaught->error!
|
||||
"TODO Docstring
|
||||
See also `uncaught->handler!`."
|
||||
{:arglists (impl/signal-arglists :uncaught->error!)}
|
||||
([ ] (enc/keep-callsite `(uncaught->error! nil)))
|
||||
([id-or-opts]
|
||||
(let [msg-form ["Uncaught Throwable on thread: " `(.getName ~(with-meta '__thread {:tag 'java.lang.Thread}))]
|
||||
opts (impl/signal-opts :error, :id, {:kind :error, :level :error, :msg msg-form} id-or-opts '__throwable)]
|
||||
"Uses `uncaught->handler!` so that `error!` will be called for
|
||||
uncaught JVM errors.
|
||||
|
||||
(enc/keep-callsite
|
||||
`(uncaught->handler!
|
||||
(fn [~'__thread ~'__throwable]
|
||||
(impl/signal! ~opts))))))))
|
||||
See `uncaught->handler!` and `error!` for details."
|
||||
{:arglists (impl/signal-arglists :uncaught->error!)}
|
||||
[& args]
|
||||
(let [msg-form ["Uncaught Throwable on thread: " `(.getName ~(with-meta '__thread {:tag 'java.lang.Thread}))]
|
||||
opts
|
||||
(impl/signal-opts `uncaught->error!
|
||||
{:kind :error, :level :error, :msg msg-form}
|
||||
:error :id :dsc (into ['__throwable] args))]
|
||||
|
||||
(enc/keep-callsite
|
||||
`(uncaught->handler!
|
||||
(fn [~'__thread ~'__throwable]
|
||||
(impl/signal! ~opts)))))))
|
||||
|
||||
(comment (macroexpand '(uncaught->error! :id1)))
|
||||
|
||||
|
|
@ -277,12 +349,14 @@
|
|||
(defn uncaught->handler!
|
||||
"Sets JVM's global `DefaultUncaughtExceptionHandler` to given
|
||||
(fn handler [`<java.lang.Thread>` `<java.lang.Throwable>`]).
|
||||
|
||||
See also `uncaught->error!`."
|
||||
[handler]
|
||||
(Thread/setDefaultUncaughtExceptionHandler
|
||||
(reify Thread$UncaughtExceptionHandler
|
||||
(uncaughtException [_ thread throwable]
|
||||
(handler thread throwable))))))
|
||||
(handler thread throwable))))
|
||||
nil))
|
||||
|
||||
#?(:clj
|
||||
(defn hostname
|
||||
|
|
|
|||
|
|
@ -194,7 +194,7 @@
|
|||
(defrecord Signal
|
||||
;; Telemere's main public data type, we avoid nesting and duplication
|
||||
[^long schema-version instant uid,
|
||||
callsite-id location ns line column file,
|
||||
location ns line column file,
|
||||
sample-rate, kind id level, ctx parent,
|
||||
data msg_ error run-form run-value,
|
||||
end-instant runtime-nsecs])
|
||||
|
|
@ -256,7 +256,7 @@
|
|||
#?(:clj
|
||||
(defmacro ^:public with-signals
|
||||
"Executes given form and records any signals triggered by it.
|
||||
Return value depends on options. Useful for tests/debugging.
|
||||
Return value depends on given options. Useful for tests/debugging.
|
||||
|
||||
Options:
|
||||
|
||||
|
|
@ -301,7 +301,7 @@
|
|||
^Signal
|
||||
;; Note all dynamic vals passed as explicit args for better control
|
||||
[instant uid,
|
||||
callsite-id location ns line column file,
|
||||
location ns line column file,
|
||||
sample-rate, kind id level, ctx parent,
|
||||
user-opts data msg_,
|
||||
run-form run-result error]
|
||||
|
|
@ -321,14 +321,14 @@
|
|||
msg_)]
|
||||
|
||||
(Signal. 1 instant uid,
|
||||
callsite-id location ns line column file,
|
||||
location ns line column file,
|
||||
sample-rate, kind id level, ctx parent,
|
||||
data msg_,
|
||||
run-error run-form run-value,
|
||||
end-instant runtime-nsecs))
|
||||
|
||||
(Signal. 1 instant uid,
|
||||
callsite-id location ns line column file,
|
||||
location ns line column file,
|
||||
sample-rate, kind id level, ctx parent,
|
||||
data msg_, error nil nil instant nil))]
|
||||
|
||||
|
|
@ -340,66 +340,69 @@
|
|||
(enc/qb 1e6 ; 55.67
|
||||
(new-signal
|
||||
nil nil nil nil nil nil nil nil nil nil
|
||||
nil nil nil nil nil nil nil nil nil nil)))
|
||||
nil nil nil nil nil nil nil nil nil)))
|
||||
|
||||
;;;; Signal API helpers
|
||||
|
||||
#?(:clj (defmacro signal-docstring [rname] (enc/slurp-resource (str "signal-docstrings/" (name rname) ".txt"))))
|
||||
#?(:clj (defmacro defhelp [sym rname] `(enc/def* ~sym {:doc ~(eval `(signal-docstring ~rname))} "See docstring")))
|
||||
|
||||
#?(:clj
|
||||
(defn signal-arglists [macro-id]
|
||||
(case macro-id
|
||||
|
||||
:signal! ; [opts] => <run result> or <allowed?>
|
||||
:signal! ; [opts] => allowed? / run result (value or throw)
|
||||
'([{:as opts :keys
|
||||
[#_defaults #_elide? #_allow? #_callsite-id,
|
||||
[#_defaults #_elide? #_allow? #_expansion-id, ; Undocumented
|
||||
elidable? location instant uid middleware,
|
||||
sample-rate ns kind id level when rate-limit,
|
||||
ctx parent trace?, do let data msg error run & user-opts]}])
|
||||
|
||||
:log! ; [msg] [level-or-opts msg] => <allowed?>
|
||||
:event! ; [id] [id level-or-opts] => allowed?
|
||||
'([id ]
|
||||
[id level]
|
||||
[id
|
||||
{:as opts :keys
|
||||
[#_defaults #_elide? #_allow? #_expansion-id,
|
||||
elidable? location instant uid middleware,
|
||||
sample-rate ns kind id level when rate-limit,
|
||||
ctx parent trace?, do let data msg error #_run & user-opts]}])
|
||||
|
||||
:log! ; [msg] [level-or-opts msg] => allowed?
|
||||
'([ msg]
|
||||
[level msg]
|
||||
[{:as opts :keys
|
||||
[#_defaults #_elide? #_allow? #_callsite-id,
|
||||
[#_defaults #_elide? #_allow? #_expansion-id,
|
||||
elidable? location instant uid middleware,
|
||||
sample-rate ns kind id level when rate-limit,
|
||||
ctx parent trace?, do let data msg error #_run & user-opts]}
|
||||
msg])
|
||||
|
||||
:event! ; [id] [level-or-opts id] => <allowed?>
|
||||
'([ id]
|
||||
[level id]
|
||||
[{:as opts :keys
|
||||
[#_defaults #_elide? #_allow? #_callsite-id,
|
||||
elidable? location instant uid middleware,
|
||||
sample-rate ns kind id level when rate-limit,
|
||||
ctx parent trace?, do let data msg error #_run & user-opts]}
|
||||
id])
|
||||
|
||||
:error! ; [error] [id-or-opts error] => <error>
|
||||
:error! ; [error] [id-or-opts error] => given error
|
||||
'([ error]
|
||||
[id error]
|
||||
[{:as opts :keys
|
||||
[#_defaults #_elide? #_allow? #_callsite-id,
|
||||
[#_defaults #_elide? #_allow? #_expansion-id,
|
||||
elidable? location instant uid middleware,
|
||||
sample-rate ns kind id level when rate-limit,
|
||||
ctx parent trace?, do let data msg error #_run & user-opts]}
|
||||
error])
|
||||
|
||||
(:trace! :spy!) ; [form] [id-or-opts form] => <run result> (value or throw)
|
||||
(:trace! :spy!) ; [form] [id-or-opts form] => run result (value or throw)
|
||||
'([ form]
|
||||
[id form]
|
||||
[{:as opts :keys
|
||||
[#_defaults #_elide? #_allow? #_callsite-id,
|
||||
[#_defaults #_elide? #_allow? #_expansion-id,
|
||||
elidable? location instant uid middleware,
|
||||
sample-rate ns kind id level when rate-limit,
|
||||
ctx parent trace?, do let data msg error run & user-opts]}
|
||||
form])
|
||||
|
||||
:catch->error! ; [form] [level-or-opts form] => <run result> (value or throw)
|
||||
'([ form]
|
||||
[level form]
|
||||
:catch->error! ; [form] [id-or-opts form] => run result (value or throw)
|
||||
'([ form]
|
||||
[id form]
|
||||
[{:as opts :keys
|
||||
[#_defaults #_elide? #_allow? #_callsite-id, rethrow? catch-val,
|
||||
[#_defaults #_elide? #_allow? #_expansion-id, rethrow? catch-val,
|
||||
elidable? location instant uid middleware,
|
||||
sample-rate ns kind id level when rate-limit,
|
||||
ctx parent trace?, do let data msg error #_run & user-opts]}
|
||||
|
|
@ -409,7 +412,7 @@
|
|||
'([ ]
|
||||
[id]
|
||||
[{:as opts :keys
|
||||
[#_defaults #_elide? #_allow? #_callsite-id,
|
||||
[#_defaults #_elide? #_allow? #_expansion-id,
|
||||
elidable? location instant uid middleware,
|
||||
sample-rate ns kind id level when rate-limit,
|
||||
ctx parent trace?, do let data msg error #_run & user-opts]}])
|
||||
|
|
@ -418,48 +421,46 @@
|
|||
|
||||
#?(:clj
|
||||
(defn signal-opts
|
||||
"Util to help write common signal wrapper macros:
|
||||
[[<config>] val-y] => signal-opts
|
||||
[[<config>] opts-or-val-x val-y] => signal-opts"
|
||||
([arg-key or-key defaults arg-val] {:defaults defaults, arg-key arg-val})
|
||||
([arg-key or-key defaults opts-or-key arg-val]
|
||||
(if (map? opts-or-key)
|
||||
(let [opts opts-or-key] (conj {:defaults defaults, arg-key arg-val} opts))
|
||||
(let [or-val opts-or-key] {:defaults defaults, arg-key arg-val, or-key or-val})))))
|
||||
"Util to help write common signal wrapper macros."
|
||||
[context defaults main-key extra-key arg-order args]
|
||||
|
||||
(comment
|
||||
[(signal-opts :msg :level {:level :info} "foo")
|
||||
(signal-opts :msg :level {:level :info} {:level :warn} "foo")
|
||||
(signal-opts :msg :level {:level :info} :warn "foo")])
|
||||
(enc/cond
|
||||
:let [num-args (count args)]
|
||||
|
||||
(not (#{1 2} num-args))
|
||||
(throw
|
||||
(ex-info (str "Wrong number of args (" num-args ") passed to: " context)
|
||||
{:context context
|
||||
:num-args {:actual num-args, :expected #{1 2}}
|
||||
:args args}))
|
||||
|
||||
:let [[main-val extra-val-or-opts]
|
||||
(case arg-order
|
||||
:dsc args, ; [main ...]
|
||||
:asc (reverse args) ; [... main]
|
||||
(enc/unexpected-arg!
|
||||
arg-order))]
|
||||
|
||||
(if (or (= num-args 1) (map? extra-val-or-opts))
|
||||
(let [opts extra-val-or-opts] (conj {:defaults defaults, main-key main-val } opts))
|
||||
(let [extra-val extra-val-or-opts] {:defaults defaults, main-key main-val, extra-key extra-val})))))
|
||||
|
||||
(comment (signal-opts `signal! {:level :info} :id :level :dsc [::my-id {:level :warn}]))
|
||||
|
||||
;;;; Signal macro
|
||||
|
||||
#?(:clj
|
||||
(defmacro ^:public signal!
|
||||
"Expands to a low-level signal call.
|
||||
|
||||
TODO Docstring
|
||||
- How low-level is this? Should location, ctx, etc. be in public arglists?
|
||||
- Describe
|
||||
- Reference diagram link [1]
|
||||
- Mention ability to delay-wrap :data
|
||||
- Mention combo `:sample-rate` stuff (call * handler)
|
||||
|
||||
- Document Signal fields
|
||||
- Link to signal-flow diagram
|
||||
|
||||
- If :run => returns body run-result (re-throwing)
|
||||
Otherwise returns true iff call allowed
|
||||
|
||||
[1] Ref. <https://tinyurl.com/telemere-signal-flow>"
|
||||
{:arglists (signal-arglists :signal!)}
|
||||
"Generic low-level signal call, also aliased in Encore."
|
||||
{:doc (signal-docstring :signal!)
|
||||
:arglists (signal-arglists :signal!)}
|
||||
[opts]
|
||||
(have? map? opts) ; We require const map keys, but vals may require eval
|
||||
(let [defaults (get opts :defaults)
|
||||
opts (merge defaults (dissoc opts :defaults))
|
||||
{run-form :run} opts
|
||||
|
||||
{:keys [callsite-id location elide? allow?]}
|
||||
{:keys [#_expansion-id location elide? allow?]}
|
||||
(sigs/filterable-expansion
|
||||
{:macro-form &form
|
||||
:macro-env &env
|
||||
|
|
@ -510,14 +511,14 @@
|
|||
:elidable? :location :instant :uid :middleware,
|
||||
:sample-rate :ns :kind :id :level :filter :when #_:rate-limit,
|
||||
:ctx :parent #_:trace?, :do :let :data :msg :error :run
|
||||
:elide? :allow? :callsite-id))]
|
||||
:elide? :allow? #_:expansion-id))]
|
||||
|
||||
;; Eval let bindings AFTER call filtering but BEFORE data, msg
|
||||
`(do
|
||||
~do-form
|
||||
(let ~let-form ; Allow to throw during `signal-value_` deref
|
||||
(new-signal ~'__instant ~'__uid
|
||||
~callsite-id ~location ~ns ~line ~column ~file,
|
||||
~location ~ns ~line ~column ~file,
|
||||
~sample-rate-form, ~kind-form ~'__id ~level-form, ~ctx-form ~parent-form,
|
||||
~user-opts-form ~data-form ~msg-form,
|
||||
'~run-form ~'__run-result ~error-form))))]
|
||||
|
|
@ -572,7 +573,7 @@
|
|||
"Used only for interop (SLF4J, `clojure.tools.logging`, etc.)."
|
||||
{:arglists (signal-arglists :signal!)}
|
||||
[opts]
|
||||
(let [{:keys [#_callsite-id #_location elide? allow?]}
|
||||
(let [{:keys [#_expansion-id #_location elide? allow?]}
|
||||
(sigs/filterable-expansion
|
||||
{:macro-form &form
|
||||
:macro-env &env
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@
|
|||
|
||||
#?(:cljs
|
||||
(:require-macros
|
||||
[taoensso.telemere-tests :refer [sig! ws ws! ws1]])))
|
||||
[taoensso.telemere-tests :refer [sig! ws wsf wst ws1]])))
|
||||
|
||||
(comment
|
||||
(remove-ns 'taoensso.telemere-tests)
|
||||
|
|
@ -25,12 +25,14 @@
|
|||
#?(:clj
|
||||
(do
|
||||
(defmacro ws [form] `(impl/-with-signals (fn [] ~form) {}))
|
||||
(defmacro ws! [form] `(impl/-with-signals (fn [] ~form) {:trap-errors? true}))
|
||||
(defmacro wsf [form] `(impl/-with-signals (fn [] ~form) {:force-msg? true}))
|
||||
(defmacro wst [form] `(impl/-with-signals (fn [] ~form) {:trap-errors? true}))
|
||||
(defmacro ws1 [form] `(let [[_# [s1#]] (impl/-with-signals (fn [] ~form) {:force-msg? true})] s1#))))
|
||||
|
||||
(do
|
||||
(def ex1 (ex-info "TestEx" {}))
|
||||
(def ex1-pred (enc/pred #(= % ex1))))
|
||||
(def ex1-pred (enc/pred #(= % ex1)))
|
||||
(defn ex1! [] (throw ex1)))
|
||||
|
||||
(def ^:dynamic *dynamic-var* nil)
|
||||
|
||||
|
|
@ -59,8 +61,8 @@
|
|||
(is (= (ws (sig! {:level :info, :allow? false })) [nil nil]) "With runtime suppression")
|
||||
(is (= (ws (sig! {:level :info, :allow? false, :run (+ 1 2)})) [3 nil]) "With runtime suppression, run-form")
|
||||
|
||||
(is (->> (sig! {:level :info, :elide? true, :run (throw ex1)}) (throws? :ex-info "TestEx")) "With compile-time elision, throwing run-form")
|
||||
(is (->> (sig! {:level :info, :allow? false, :run (throw ex1)}) (throws? :ex-info "TestEx")) "With runtime suppression, throwing run-form")
|
||||
(is (->> (sig! {:level :info, :elide? true, :run (ex1!)}) (throws? :ex-info "TestEx")) "With compile-time elision, throwing run-form")
|
||||
(is (->> (sig! {:level :info, :allow? false, :run (ex1!)}) (throws? :ex-info "TestEx")) "With runtime suppression, throwing run-form")
|
||||
|
||||
(let [[rv1 [sv1]] (ws (sig! {:level :info }))
|
||||
[rv2 [sv2]] (ws (sig! {:level :info, :run (+ 1 2)}))]
|
||||
|
|
@ -281,25 +283,25 @@
|
|||
(tel/with-handler :hid1
|
||||
(fn [sv] (force (:data sv)) (reset! sv_ sv))
|
||||
{:async nil, :error-fn (fn [x] (reset! error_ x)), :rl-error nil,
|
||||
:middleware [(fn [sv] (if *throwing-handler-middleware?* (throw ex1) sv))]}
|
||||
:middleware [(fn [sv] (if *throwing-handler-middleware?* (ex1!) sv))]}
|
||||
|
||||
[(is (->> (sig! {:level :info, :when (throw ex1)}) (throws? :ex-info "TestEx")) "`~filterable-expansion/allow` throws at call")
|
||||
(is (->> (sig! {:level :info, :instant (throw ex1)}) (throws? :ex-info "TestEx")) "`~instant-form` throws at call")
|
||||
(is (->> (sig! {:level :info, :id (throw ex1)}) (throws? :ex-info "TestEx")) "`~id-form` throws at call")
|
||||
(is (->> (sig! {:level :info, :uid (throw ex1)}) (throws? :ex-info "TestEx")) "`~uid-form` throws at call")
|
||||
(is (->> (sig! {:level :info, :run (throw ex1)}) (throws? :ex-info "TestEx")) "`~run-form` rethrows at call")
|
||||
[(is (->> (sig! {:level :info, :when (ex1!)}) (throws? :ex-info "TestEx")) "`~filterable-expansion/allow` throws at call")
|
||||
(is (->> (sig! {:level :info, :instant (ex1!)}) (throws? :ex-info "TestEx")) "`~instant-form` throws at call")
|
||||
(is (->> (sig! {:level :info, :id (ex1!)}) (throws? :ex-info "TestEx")) "`~id-form` throws at call")
|
||||
(is (->> (sig! {:level :info, :uid (ex1!)}) (throws? :ex-info "TestEx")) "`~uid-form` throws at call")
|
||||
(is (->> (sig! {:level :info, :run (ex1!)}) (throws? :ex-info "TestEx")) "`~run-form` rethrows at call")
|
||||
(is (sm? @sv_ {:level :info, :error ex1-pred}) "`~run-form` rethrows at call *after* dispatch")
|
||||
|
||||
(testing "`@signal-value_`: trap with wrapped handler"
|
||||
[(testing "Throwing `~let-form`"
|
||||
(reset-state!)
|
||||
[(is (true? (sig! {:level :info, :let [_ (throw ex1)]})))
|
||||
[(is (true? (sig! {:level :info, :let [_ (ex1!)]})))
|
||||
(is (= @sv_ :nx))
|
||||
(is (sm? @error_ {:handler-id :hid1, :error ex1-pred}))])
|
||||
|
||||
(testing "Throwing call middleware"
|
||||
(reset-state!)
|
||||
[(is (true? (sig! {:level :info, :middleware [(fn [_] (throw ex1))]})))
|
||||
[(is (true? (sig! {:level :info, :middleware [(fn [_] (ex1!))]})))
|
||||
(is (= @sv_ :nx))
|
||||
(is (sm? @error_ {:handler-id :hid1, :error ex1-pred}))])
|
||||
|
||||
|
|
@ -312,13 +314,13 @@
|
|||
|
||||
(testing "Throwing `@data_`"
|
||||
(reset-state!)
|
||||
[(is (true? (sig! {:level :info, :data (delay (throw ex1))})))
|
||||
[(is (true? (sig! {:level :info, :data (delay (ex1!))})))
|
||||
(is (= @sv_ :nx))
|
||||
(is (sm? @error_ {:handler-id :hid1, :error ex1-pred}))])
|
||||
|
||||
(testing "Throwing user opt"
|
||||
(reset-state!)
|
||||
[(is (true? (sig! {:level :info, :my-opt (throw ex1)})))
|
||||
[(is (true? (sig! {:level :info, :my-opt (ex1!)})))
|
||||
(is (= @sv_ :nx))
|
||||
(is (sm? @error_ {:handler-id :hid1, :error ex1-pred}))])])])))
|
||||
|
||||
|
|
@ -400,21 +402,19 @@
|
|||
(deftest _common-signals
|
||||
[#?(:clj
|
||||
(testing "signal-opts"
|
||||
[(is (= (impl/signal-opts :msg, :level, {:level :info} "msg") {:defaults {:level :info}, :msg "msg"}))
|
||||
(is (= (impl/signal-opts :msg, :level, {:level :info} {:level :warn} "msg") {:defaults {:level :info}, :msg "msg", :level :warn}))
|
||||
(is (= (impl/signal-opts :msg, :level, {:level :info} :warn "msg") {:defaults {:level :info}, :msg "msg", :level :warn}))]))
|
||||
[(is (= (impl/signal-opts `signal! {:level :info} :id :level :dsc [::my-id ]) {:defaults {:level :info}, :id ::my-id}))
|
||||
(is (= (impl/signal-opts `signal! {:level :info} :id :level :dsc [::my-id :warn ]) {:defaults {:level :info}, :id ::my-id, :level :warn}))
|
||||
(is (= (impl/signal-opts `signal! {:level :info} :id :level :dsc [::my-id {:level :warn}]) {:defaults {:level :info}, :id ::my-id, :level :warn}))
|
||||
|
||||
(testing "log!" ; msg + ?level => allowed?
|
||||
[(let [[rv [sv]] (ws (tel/log! "msg"))] [(is (= rv true)) (is (sm? sv {:kind :log, :line :submap/ex, :msg_ "msg", :level :info}))])
|
||||
(let [[rv [sv]] (ws (tel/log! :warn "msg"))] [(is (= rv true)) (is (sm? sv {:kind :log, :line :submap/ex, :msg_ "msg", :level :warn}))])
|
||||
(let [[rv [sv]] (ws (tel/log! {:level :warn} "msg"))] [(is (= rv true)) (is (sm? sv {:kind :log, :line :submap/ex, :msg_ "msg", :level :warn}))])
|
||||
(let [[rv [sv]] (ws (tel/log! {:allow? false} "msg"))] [(is (= rv nil)) (is (nil? sv))])])
|
||||
(is (= (impl/signal-opts `signal! {:level :info} :id :level :asc [ ::my-id]) {:defaults {:level :info}, :id ::my-id}))
|
||||
(is (= (impl/signal-opts `signal! {:level :info} :id :level :asc [:warn ::my-id]) {:defaults {:level :info}, :id ::my-id, :level :warn}))
|
||||
(is (= (impl/signal-opts `signal! {:level :info} :id :level :asc [{:level :warn} ::my-id]) {:defaults {:level :info}, :id ::my-id, :level :warn}))]))
|
||||
|
||||
(testing "event!" ; id + ?level => allowed?
|
||||
[(let [[rv [sv]] (ws (tel/event! :id1))] [(is (= rv true)) (is (sm? sv {:kind :event, :line :submap/ex, :level :info, :id :id1}))])
|
||||
(let [[rv [sv]] (ws (tel/event! :warn :id1))] [(is (= rv true)) (is (sm? sv {:kind :event, :line :submap/ex, :level :warn, :id :id1}))])
|
||||
(let [[rv [sv]] (ws (tel/event! {:level :warn} :id1))] [(is (= rv true)) (is (sm? sv {:kind :event, :line :submap/ex, :level :warn, :id :id1}))])
|
||||
(let [[rv [sv]] (ws (tel/event! {:allow? false} :id1))] [(is (= rv nil)) (is (nil? sv))])])
|
||||
[(let [[rv [sv]] (ws (tel/event! :id1 ))] [(is (= rv true)) (is (sm? sv {:kind :event, :line :submap/ex, :level :info, :id :id1}))])
|
||||
(let [[rv [sv]] (ws (tel/event! :id1 :warn ))] [(is (= rv true)) (is (sm? sv {:kind :event, :line :submap/ex, :level :warn, :id :id1}))])
|
||||
(let [[rv [sv]] (ws (tel/event! :id1 {:level :warn}))] [(is (= rv true)) (is (sm? sv {:kind :event, :line :submap/ex, :level :warn, :id :id1}))])
|
||||
(let [[rv [sv]] (ws (tel/event! :id1 {:allow? false}))] [(is (= rv nil)) (is (nil? sv))])])
|
||||
|
||||
(testing "error!" ; error + ?id => error
|
||||
[(let [[rv [sv]] (ws (tel/error! ex1))] [(is (= rv ex1)) (is (sm? sv {:kind :error, :line :submap/ex, :level :error, :error ex1-pred, :id nil}))])
|
||||
|
|
@ -422,30 +422,38 @@
|
|||
(let [[rv [sv]] (ws (tel/error! {:id :id1} ex1))] [(is (= rv ex1)) (is (sm? sv {:kind :error, :line :submap/ex, :level :error, :error ex1-pred, :id :id1}))])
|
||||
(let [[rv [sv]] (ws (tel/error! {:allow? false} ex1))] [(is (= rv ex1)) (is (nil? sv))])])
|
||||
|
||||
(testing "log!" ; msg + ?level => allowed?
|
||||
[(let [[rv [sv]] (ws (tel/log! "msg"))] [(is (= rv true)) (is (sm? sv {:kind :log, :line :submap/ex, :msg_ "msg", :level :info}))])
|
||||
(let [[rv [sv]] (ws (tel/log! :warn "msg"))] [(is (= rv true)) (is (sm? sv {:kind :log, :line :submap/ex, :msg_ "msg", :level :warn}))])
|
||||
(let [[rv [sv]] (ws (tel/log! {:level :warn} "msg"))] [(is (= rv true)) (is (sm? sv {:kind :log, :line :submap/ex, :msg_ "msg", :level :warn}))])
|
||||
(let [[rv [sv]] (ws (tel/log! {:allow? false} "msg"))] [(is (= rv nil)) (is (nil? sv))])])
|
||||
|
||||
(testing "trace!" ; run + ?id => run result (value or throw)
|
||||
[(let [[rv [sv]] (ws (tel/trace! (+ 1 2)))] [(is (= rv 3)) (is (sm? sv {:kind :trace, :line :submap/ex, :level :info, :id nil}))])
|
||||
(let [[rv [sv]] (ws (tel/trace! :id1 (+ 1 2)))] [(is (= rv 3)) (is (sm? sv {:kind :trace, :line :submap/ex, :level :info, :id :id1}))])
|
||||
(let [[rv [sv]] (ws (tel/trace! {:id :id1} (+ 1 2)))] [(is (= rv 3)) (is (sm? sv {:kind :trace, :line :submap/ex, :level :info, :id :id1}))])
|
||||
(let [[[_ re] [sv]] (ws! (tel/trace! :id1 (throw ex1)))] [(is (= re ex1)) (is (sm? sv {:kind :trace, :line :submap/ex, :level :info, :id :id1, :error ex1-pred}))])
|
||||
(let [[rv [sv]] (ws (tel/trace! {:allow? false} (+ 1 2)))] [(is (= rv 3)) (is (nil? sv))])])
|
||||
[(let [[rv [sv]] (wsf (tel/trace! (+ 1 2)))] [(is (= rv 3)) (is (sm? sv {:kind :trace, :line :submap/ex, :level :info, :id nil, :msg_ "(+ 1 2) => 3"}))])
|
||||
(let [[rv [sv]] (ws (tel/trace! {:msg nil} (+ 1 2)))] [(is (= rv 3)) (is (sm? sv {:kind :trace, :line :submap/ex, :level :info, :id nil, :msg_ nil}))])
|
||||
(let [[rv [sv]] (ws (tel/trace! :id1 (+ 1 2)))] [(is (= rv 3)) (is (sm? sv {:kind :trace, :line :submap/ex, :level :info, :id :id1}))])
|
||||
(let [[rv [sv]] (ws (tel/trace! {:id :id1} (+ 1 2)))] [(is (= rv 3)) (is (sm? sv {:kind :trace, :line :submap/ex, :level :info, :id :id1}))])
|
||||
(let [[[_ re] [sv]] (wst (tel/trace! :id1 (ex1!)))] [(is (= re ex1)) (is (sm? sv {:kind :trace, :line :submap/ex, :level :info, :id :id1, :error ex1-pred}))])
|
||||
(let [[rv [sv]] (ws (tel/trace! {:allow? false} (+ 1 2)))] [(is (= rv 3)) (is (nil? sv))])])
|
||||
|
||||
(testing "spy" ; run + ?level => run result (value or throw)
|
||||
[(let [[rv [sv]] (ws (tel/spy! (+ 1 2)))] [(is (= rv 3)) (is (sm? sv {:kind :spy, :line :submap/ex, :level :info}))])
|
||||
(let [[rv [sv]] (ws (tel/spy! :warn (+ 1 2)))] [(is (= rv 3)) (is (sm? sv {:kind :spy, :line :submap/ex, :level :warn}))])
|
||||
(let [[rv [sv]] (ws (tel/spy! {:level :warn} (+ 1 2)))] [(is (= rv 3)) (is (sm? sv {:kind :spy, :line :submap/ex, :level :warn}))])
|
||||
(let [[[_ re] [sv]] (ws! (tel/spy! :warn (throw ex1)))] [(is (= re ex1)) (is (sm? sv {:kind :spy, :line :submap/ex, :level :warn, :error ex1-pred}))])
|
||||
(let [[rv [sv]] (ws (tel/spy! {:allow? false} (+ 1 2)))] [(is (= rv 3)) (is (nil? sv))])])
|
||||
[(let [[rv [sv]] (wsf (tel/spy! (+ 1 2)))] [(is (= rv 3)) (is (sm? sv {:kind :spy, :line :submap/ex, :level :info, :msg_ "(+ 1 2) => 3"}))])
|
||||
(let [[rv [sv]] (wsf (tel/spy! {:msg nil} (+ 1 2)))] [(is (= rv 3)) (is (sm? sv {:kind :spy, :line :submap/ex, :level :info, :msg_ nil}))])
|
||||
(let [[rv [sv]] (ws (tel/spy! :warn (+ 1 2)))] [(is (= rv 3)) (is (sm? sv {:kind :spy, :line :submap/ex, :level :warn}))])
|
||||
(let [[rv [sv]] (ws (tel/spy! {:level :warn} (+ 1 2)))] [(is (= rv 3)) (is (sm? sv {:kind :spy, :line :submap/ex, :level :warn}))])
|
||||
(let [[[_ re] [sv]] (wst (tel/spy! :warn (ex1!)))] [(is (= re ex1)) (is (sm? sv {:kind :spy, :line :submap/ex, :level :warn, :error ex1-pred}))])
|
||||
(let [[rv [sv]] (ws (tel/spy! {:allow? false} (+ 1 2)))] [(is (= rv 3)) (is (nil? sv))])])
|
||||
|
||||
(testing "catch->error!" ; form + ?id => run value or ?return
|
||||
[(let [[rv [sv]] (ws (tel/catch->error! (+ 1 2)))] [(is (= rv 3)) (is (nil? sv))])
|
||||
(let [[rv [sv]] (ws (tel/catch->error! (throw ex1)))] [(is (= rv nil)) (is (sm? sv {:kind :error, :line :submap/ex, :level :error, :error ex1-pred, :id nil}))])
|
||||
(let [[rv [sv]] (ws (tel/catch->error! :id1 (throw ex1)))] [(is (= rv nil)) (is (sm? sv {:kind :error, :line :submap/ex, :level :error, :error ex1-pred, :id :id1}))])
|
||||
(let [[rv [sv]] (ws (tel/catch->error! {:id :id1} (throw ex1)))] [(is (= rv nil)) (is (sm? sv {:kind :error, :line :submap/ex, :level :error, :error ex1-pred, :id :id1}))])
|
||||
(let [[[_ re] [sv]] (ws! (tel/catch->error! {:rethrow? true} (throw ex1)))] [(is (= re ex1)) (is (sm? sv {:kind :error, :line :submap/ex, :level :error, :error ex1-pred, :id nil}))])
|
||||
(let [[rv [sv]] (ws (tel/catch->error! {:catch-val :foo} (throw ex1)))] [(is (= rv :foo)) (is (sm? sv {:kind :error, :line :submap/ex, :level :error, :error ex1-pred, :id nil}))])
|
||||
(let [[rv [sv]] (ws (tel/catch->error! {:catch-val :foo} (+ 1 2)))] [(is (= rv 3)) (is (nil? sv))])
|
||||
[(let [[rv [sv]] (ws (tel/catch->error! (+ 1 2)))] [(is (= rv 3)) (is (nil? sv))])
|
||||
(let [[rv [sv]] (ws (tel/catch->error! (ex1!)))] [(is (= rv nil)) (is (sm? sv {:kind :error, :line :submap/ex, :level :error, :error ex1-pred, :id nil}))])
|
||||
(let [[rv [sv]] (ws (tel/catch->error! :id1 (ex1!)))] [(is (= rv nil)) (is (sm? sv {:kind :error, :line :submap/ex, :level :error, :error ex1-pred, :id :id1}))])
|
||||
(let [[rv [sv]] (ws (tel/catch->error! {:id :id1} (ex1!)))] [(is (= rv nil)) (is (sm? sv {:kind :error, :line :submap/ex, :level :error, :error ex1-pred, :id :id1}))])
|
||||
(let [[[_ re] [sv]] (wst (tel/catch->error! {:rethrow? true} (ex1!)))] [(is (= re ex1)) (is (sm? sv {:kind :error, :line :submap/ex, :level :error, :error ex1-pred, :id nil}))])
|
||||
(let [[rv [sv]] (ws (tel/catch->error! {:catch-val :foo} (ex1!)))] [(is (= rv :foo)) (is (sm? sv {:kind :error, :line :submap/ex, :level :error, :error ex1-pred, :id nil}))])
|
||||
(let [[rv [sv]] (ws (tel/catch->error! {:catch-val :foo} (+ 1 2)))] [(is (= rv 3)) (is (nil? sv))])
|
||||
(let [[rv [sv]] (ws (tel/catch->error! {:catch-val :foo ; Overrides `:rethrow?`
|
||||
:rethrow? true} (+ 1 2)))] [(is (= rv 3)) (is (nil? sv))])])
|
||||
:rethrow? true} (+ 1 2)))] [(is (= rv 3)) (is (nil? sv))])])
|
||||
|
||||
#?(:clj
|
||||
(testing "uncaught->error!"
|
||||
|
|
@ -453,13 +461,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 (impl/threaded (throw ex1))) (sm? @sv_ {:kind :error, :line :submap/ex, :level :error, :error ex1-pred, :id nil})))
|
||||
(is (do (.join (impl/threaded (ex1!))) (sm? @sv_ {:kind :error, :line :submap/ex, :level :error, :error ex1-pred, :id nil})))
|
||||
;;
|
||||
(is (nil? (tel/uncaught->error! :id1)))
|
||||
(is (do (.join (impl/threaded (throw ex1))) (sm? @sv_ {:kind :error, :line :submap/ex, :level :error, :error ex1-pred, :id :id1})))
|
||||
(is (do (.join (impl/threaded (ex1!))) (sm? @sv_ {:kind :error, :line :submap/ex, :level :error, :error ex1-pred, :id :id1})))
|
||||
;;
|
||||
(is (nil? (tel/uncaught->error! {:id :id1})))
|
||||
(is (do (.join (impl/threaded (throw ex1))) (sm? @sv_ {:kind :error, :line :submap/ex, :level :error, :error ex1-pred, :id :id1})))
|
||||
(is (do (.join (impl/threaded (ex1!))) (sm? @sv_ {:kind :error, :line :submap/ex, :level :error, :error ex1-pred, :id :id1})))
|
||||
;;
|
||||
(do (enc/set-var-root! impl/*sig-handlers* nil) :unset-handler)])))])
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue