Skip to content

Commit

Permalink
[new] Refactor impln of common signal creators
Browse files Browse the repository at this point in the history
Objectives:

  - Support single map opts arg in all cases.

  - Make it easier for folks to inspect the source to understand how
    the common creators use/wrap underlying `signal!`.

Also updated relevant docstrings, etc.
  • Loading branch information
ptaoussanis committed Dec 23, 2024
1 parent ace6e2d commit d2386d6
Show file tree
Hide file tree
Showing 12 changed files with 264 additions and 375 deletions.
7 changes: 3 additions & 4 deletions projects/main/resources/signal-docstrings/catch-to-error!.txt
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
Unconditionally executes given form and-
If form succeeds: return the form's result.
If form throws:
ALWAYS (unconditionally) executes given `run` form and:
If `run` form succeeds: return the form's result.
If `run` form throws:
Call `error!` with the thrown error and the given signal options [2],
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`

Expand Down
6 changes: 3 additions & 3 deletions projects/main/resources/signal-docstrings/error!.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"Error" signal creator, emphasizing error + id.
"Error" signal creator, emphasizing (optional id) + error (Exception, etc.).
ALWAYS (unconditionally) returns the given error, so can conveniently be wrapped
by `throw`: (throw (error! (ex-info ...)), etc.

API: [error] [id-or-opts error] => given error (unconditional)
Default kind: `:error`
Default level: `:error`

Expand All @@ -22,7 +23,6 @@ Tips:
- Supports the same options [2] as other signals [1].

- `error` arg is a platform error (`java.lang.Throwable` or `js/Error`).
- Can conveniently be wrapped by `throw`: (throw (error! ...)).

----------------------------------------------------------------------
[1] See `help:signal-creators` - (`signal!`, `log!`, `event!`, ...)
Expand Down
4 changes: 2 additions & 2 deletions projects/main/resources/signal-docstrings/event!.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"Event" signal creator, emphasizing id + level.
"Event" signal creator, emphasizing id + (optional level).
Returns true iff signal was created (allowed by filtering).

API: [id] [id level-or-opts] => true iff signal was allowed
Default kind: `:event`
Default level: `:info`

Expand Down
4 changes: 2 additions & 2 deletions projects/main/resources/signal-docstrings/log!.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"Log" signal creator, emphasizing message + level.
"Log" signal creator, emphasizing (optional level) + message.
Returns true iff signal was created (allowed by filtering).

API: [msg] [level-or-opts msg] => true iff signal was allowed.
Default kind: `:log`
Default level: `:info`

Expand Down
13 changes: 7 additions & 6 deletions projects/main/resources/signal-docstrings/signal!.txt
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
Low-level generic signal creator.
Low-level "generic" signal creator for creating signals of any "kind".
Takes a single map of options [2] with compile-time keys.

API: [opts] => depends on options [2]
Default kind: `:generic`
Return value depends on options:
- If given `:run` form: unconditionally returns run value, or rethrows run error.
- Otherwise: returns true iff signal was created (allowed by filtering).

Default kind: `:generic` (feel free to change!)
Default level: `:info`

When filtering conditions are met [4], creates a Telemere signal [3] and
dispatches it to registered handlers for processing (e.g. writing to
console/file/queue/db, etc.).

If `:run` option is provided: returns value of given run form, or throws.
Otherwise: returns true iff signal was created (allowed).

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 higher-level signal creators optimized for ease-of-use in
Expand Down
14 changes: 7 additions & 7 deletions projects/main/resources/signal-docstrings/signal-creators.txt
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,13 @@ various keys:
Creators vary only in in their default options and call APIs (expected args
and return values), making them more/less convenient for certain use cases:

`event!` -------- [id ] or [id opts/level] => true iff signal was created (allowed)
`log!` ---------- [msg ] or [opts/level msg] => true iff signal was created (allowed)
`error!` -------- [error] or [opts/id error] => given error (unconditional)
`trace!` -------- [form ] or [opts/id form] => form result (value/throw) (unconditional)
`spy!` ---------- [form ] or [opts/level form] => form result (value/throw) (unconditional)
`catch->error!` - [form ] or [opts/id form] => form value, or given fallback
`signal!` ------- [opts ] => depends on options
`signal!` ------- opts => allowed? / unconditional run result (value or throw)
`event!` -------- id + ?level => allowed?
`log!` ---------- ?level + msg => allowed?
`trace!` -------- ?id + run => unconditional run result (value or throw)
`spy!` ---------- ?level + run => unconditional run result (value or throw)
`error!` -------- ?id + error => unconditional given error
`catch->error!` - ?id + run => unconditional run value or ?catch-val

- `log!` and `event!` are both good default/general-purpose signal creators.
- `log!` emphasizes messages, while `event!` emphasizes ids.
Expand Down
18 changes: 9 additions & 9 deletions projects/main/resources/signal-docstrings/spy!.txt
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
"Spy" signal creator, emphasizing form + level.
"Spy" signal creator, emphasizing (optional level) + form to run.
ALWAYS (unconditionally) returns run value, or rethrows run error.

API: [form] [level-or-opts form] => form's result (value/throw) (unconditional)
Default kind: `:spy`
Default level: `:info`

When filtering conditions are met [4], creates a Telemere signal [3] and
dispatches it to registered handlers for processing (e.g. writing to
console/file/queue/db, etc.).

Enables tracing of given `form` arg:
Enables tracing of given `run` form:

- Resulting signal will include {:keys [run-form run-val run-nsecs]}.
- Nested signals will include this signal's id and uid under `:parent`.

Limitations:

1. Traced code (`form` arg) is usually expected to be synchronous and eager.
1. Traced `run` form is usually expected to be synchronous and eager.
So no lazy seqs, async calls, or inversion of flow control (IoC) macros like
core.async `go` blocks, etc.

Expand Down Expand Up @@ -47,18 +47,18 @@ Tips:
- Test using `with-signal`: (with-signal (spy! ...)).
- Supports the same options [2] as other signals [1].

- Identical to `trace!`, but emphasizes form + level rather than form + id.
- Like `trace!`, but takes optional level rather than optional id.

- Useful for debugging/monitoring forms, and tracing (nested) execution flow.
- Execution of `form` arg may create additional (nested) signals.
- Execution of `run` form may create additional (nested) signals.
Each signal's `:parent` key will indicate its immediate parent.

- Can be useful to wrap with `catch->error!`:
(catch->error! ::error-id (spy! ...)).

- Runtime of async or lazy code in `form` will intentionally NOT be included
in resulting signal's `:run-nsecs` value. If you want to measure such
runtimes, make sure that your form wraps where the relevant costs are
- Runtime of async or lazy code in `run` form will intentionally NOT be
included in resulting signal's `:run-nsecs` value. If you want to measure
such runtimes, make sure that your form wraps where the relevant costs are
actually realized. Compare:
(spy! (delay (my-slow-code))) ; Doesn't measure slow code
(spy! @(delay (my-slow-code))) ; Does measure slow code
Expand Down
18 changes: 9 additions & 9 deletions projects/main/resources/signal-docstrings/trace!.txt
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
"Trace" signal creator, emphasizing form + id.
"Trace" signal creator, emphasizing (optional id) + form to run.
ALWAYS (unconditionally) returns run value, or rethrows run error.

API: [form] [id-or-opts form] => form's result (value/throw) (unconditional)
Default kind: `:trace`
Default level: `:info` (intentionally NOT `:trace`!)

When filtering conditions are met [4], creates a Telemere signal [3] and
dispatches it to registered handlers for processing (e.g. writing to
console/file/queue/db, etc.).

Enables tracing of given `form` arg:
Enables tracing of given `run` form:

- Resulting signal will include {:keys [run-form run-val run-nsecs]}.
- Nested signals will include this signal's id and uid under `:parent`.

Limitations:

1. Traced code (`form` arg) is usually expected to be synchronous and eager.
1. Traced `run` form is usually expected to be synchronous and eager.
So no lazy seqs, async calls, or inversion of flow control (IoC) macros like
core.async `go` blocks, etc.

Expand Down Expand Up @@ -47,10 +47,10 @@ Tips:
- Test using `with-signal`: (with-signal (trace! ...)).
- Supports the same options [2] as other signals [1].

- Identical to `spy!`, but emphasizes form + id rather than form + level.
- Like `spy!`, but takes optional id rather than optional level.

- Useful for debugging/monitoring forms, and tracing (nested) execution flow.
- Execution of `form` arg may create additional (nested) signals.
- Execution of `run` form may create additional (nested) signals.
Each signal's `:parent` key will indicate its immediate parent.

- Can be useful to wrap with `catch->error!`:
Expand All @@ -60,9 +60,9 @@ Tips:
refers to the general action of tracing program flow rather than to the
common logging level of the same name.

- Runtime of async or lazy code in `form` will intentionally NOT be included
in resulting signal's `:run-nsecs` value. If you want to measure such
runtimes, make sure that your form wraps where the relevant costs are
- Runtime of async or lazy code in `run` form will intentionally NOT be
included in resulting signal's `:run-nsecs` value. If you want to measure
such runtimes, make sure that your form wraps where the relevant costs are
actually realized. Compare:
(trace! (delay (my-slow-code))) ; Doesn't measure slow code
(trace! @(delay (my-slow-code))) ; Does measure slow code
Expand Down
Loading

0 comments on commit d2386d6

Please sign in to comment.