"Spy" signal creator, emphasizing form + level.

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:

  - 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.
     So no lazy seqs, async calls, or inversion of flow control (IoC) macros like
     core.async `go` blocks, etc.

  2. Tracing call (`spy!`) is usually expected to occur *within* normally flowing code.
     IoC macros can arbitrarily (and often opaquely) alter program flow and tracing
     across flow boundaries can be fragile or even fundamentally illogical.

     So use within IoC macro bodies might not make conceptual sense, or could produce
     errors or unreliable/confusing results.

     Basically- if possible, prefer tracing normal Clojure fns running within normal
     Clojure fns unless you deeply understand what your IoC macros are up to.

Examples:

  (spy! (+ 1 2))         ; %> {:kind :trace, :level :info, :run-form '(+ 1 2),
                         ;     :run-val 3, :run-nsecs <int>, :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-signal`: (with-signal (spy! ...)).
  - Supports the same options [2] as other signals [1].

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

  - Useful for debugging/monitoring forms, and tracing (nested) execution flow.
  - Execution of `form` arg 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
    actually realized. Compare:
      (spy!  (delay (my-slow-code))) ; Doesn't measure slow code
      (spy! @(delay (my-slow-code))) ; Does    measure slow code

  - See also Tufte (https://www.taoensso.com/tufte) for a complementary/partner
    Clj/s library that offers more advanced performance measurment and shares
    the same signal engine (filtering and handler API) as Telemere.

----------------------------------------------------------------------
[1] See `help:signal-creators` - (`signal!`, `log!`, `event!`, ...)
[2] See `help:signal-options`  - {:keys [kind level id data ...]}
[3] See `help:signal-content`  - {:keys [kind level id data ...]}
[4] See `help:signal-filters`  - (by ns/kind/id/level, sampling, etc.)
