[new] Updates for latest Encore signal toolkit changes

This commit is contained in:
Peter Taoussanis 2024-05-14 13:48:35 +02:00
parent 2810ed79a1
commit ca9b27f895
30 changed files with 135 additions and 207 deletions

View file

@ -30,6 +30,7 @@ Big thanks to those that have patiently helped report and debug issues, especial
* \[new] Ongoing [API](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere) and [wiki](https://github.com/taoensso/telemere/wiki) doc improvements * \[new] Ongoing [API](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere) and [wiki](https://github.com/taoensso/telemere/wiki) doc improvements
* \[new] [`add-handler!`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#add-handler!) can now specify per-handler `:max-shutdown-msecs` (beta12) * \[new] [`add-handler!`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#add-handler!) can now specify per-handler `:max-shutdown-msecs` (beta12)
* \[new] [`with-handler`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#with-handler) and [`with-handler+`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#with-handler+) now auto shutdown handlers after use (beta12)
* \[new] (Advanced) Handler fns can now include `:dispatch-opts` metadata, useful for handler authors that want to set defaults for use by [`add-handler!`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#add-handler!) (beta8) * \[new] (Advanced) Handler fns can now include `:dispatch-opts` metadata, useful for handler authors that want to set defaults for use by [`add-handler!`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#add-handler!) (beta8)
* \[new] Added [Slack handler](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere.slack#handler:slack) (beta8) * \[new] Added [Slack handler](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere.slack#handler:slack) (beta8)
* \[new] Added [TCP](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere.sockets#handler:tcp-socket) and [UDP](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere.sockets#handler:udp-socket) socket handlers (beta7) * \[new] Added [TCP](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere.sockets#handler:tcp-socket) and [UDP](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere.sockets#handler:udp-socket) socket handlers (beta7)

View file

@ -98,7 +98,7 @@ See for intro and usage:
;;; A quick taste of filtering... ;;; A quick taste of filtering...
(t/set-ns-filter! {:deny "taoensso.*" :allow "taoensso.sente.*"}) ; Set namespace filter (t/set-ns-filter! {:disallow "taoensso.*" :allow "taoensso.sente.*"}) ; Set namespace filter
(t/set-id-filter! {:allow #{::my-particular-id "my-app/*"}}) ; Set id filter (t/set-id-filter! {:allow #{::my-particular-id "my-app/*"}}) ; Set id filter
(t/set-min-level! :warn) ; Set minimum level (t/set-min-level! :warn) ; Set minimum level
@ -114,7 +114,7 @@ See [examples.cljc](https://github.com/taoensso/telemere/blob/master/examples.cl
See relevant docstrings (links below) for usage info- See relevant docstrings (links below) for usage info-
### Signal creators ### Creating signals
| Name | Signal kind | Main arg | Optional arg | Returns | | Name | Signal kind | Main arg | Optional arg | Returns |
| :---------------------------------------------------------------------------------------------------------- | :---------- | :------- | :------------- | :--------------------------- | | :---------------------------------------------------------------------------------------------------------- | :---------- | :------- | :------------- | :--------------------------- |
@ -126,25 +126,19 @@ See relevant docstrings (links below) for usage info-
| [`catch->error!`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#catch-%3Eerror!) | `:error` | `form` | `opts`/`id` | Form value or given fallback | | [`catch->error!`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#catch-%3Eerror!) | `:error` | `form` | `opts`/`id` | Form value or given fallback |
| [`signal!`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#signal!) | `<arb>` | `opts` | - | Depends on opts | | [`signal!`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#signal!) | `<arb>` | `opts` | - | Depends on opts |
### Signal filters
| Global | Dynamic | Filters by |
| :-------------------------------------------------------------------------------------------------------------- | :-------------------------------------------------------------------------------------------------------------- | :-------------------------------------------------------- |
| [`set-kind-filter!`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#set-kind-filter!) | [`with-kind-filter`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#with-kind-filter) | Signal kind (`:log`, `:event`, etc.) |
| [`set-ns-filter!`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#set-ns-filter!) | [`with-ns-filter`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#with-ns-filter) | Signal namespace |
| [`set-id-filter!`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#set-id-filter!) | [`with-id-filter`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#with-id-filter) | Signal id |
| [`set-min-level`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#set-min-level) | [`with-min-level`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#with-min-level) | Signal level (minimum can be specified by kind and/or ns) |
### Internal help ### Internal help
Help is available without leaving your IDE:
| Var | Help with | | Var | Help with |
| :---------------------------------------------------------------------------------------------------------------------- | :-------------------------------------------- | | :---------------------------------------------------------------------------------------------------------------------------------------- | :------------------------------------------------------------------------ |
| [`help:signal-creators`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#help:signal-creators) | List of signal creators | | [`help:signal-creators`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#help:signal-creators) | Creating signals |
| [`help:signal-options`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#help:signal-options) | Options for signal creators | | [`help:signal-options`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#help:signal-options) | Signal options |
| [`help:signal-content`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#help:signal-content) | Signal map content | | [`help:signal-content`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#help:signal-content) | Signal content (map given to middleware/handlers) |
| [`help:signal-flow`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#help:signal-flow) | Ordered flow from signal creation to handling | | [`help:filters`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#help:filters) | Signal and handler filters |
| [`help:signal-filters`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#help:signal-filters) | API for configuring signal filters | | [`help:handlers`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#help:handlers) | Signal handlers |
| [`help:signal-handlers`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#help:signal-handlers) | API for configuring signal handlers | | [`help:handler-dispatch-options`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#help:handler-dispatch-options) | Signal handler dispatch options |
| [`help:environmental-config`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#help:environmental-config) | Config via JVM properties, environment variables, or classpath resources. |
### Included handlers ### Included handlers

View file

@ -39,7 +39,7 @@
;;; A quick taste of filtering... ;;; A quick taste of filtering...
(t/set-ns-filter! {:deny "taoensso.*" :allow "taoensso.sente.*"}) ; Set namespace filter (t/set-ns-filter! {:disallow "taoensso.*" :allow "taoensso.sente.*"}) ; Set namespace filter
(t/set-id-filter! {:allow #{::my-particular-id "my-app/*"}}) ; Set id filter (t/set-id-filter! {:allow #{::my-particular-id "my-app/*"}}) ; Set id filter
(t/set-min-level! :warn) ; Set minimum level (t/set-min-level! :warn) ; Set minimum level
@ -185,17 +185,18 @@
(let [handler-fn (let [handler-fn
(fn a-handler:my-handler ; Note naming convention (fn a-handler:my-handler ; Note naming convention
;; Shutdown arity - called by Telemere exactly once when the handler ;; Main arity, called by Telemere when handler should process given signal
;; is to be shut down.
([]
;; Can no-op, or finalize/free resources as necessary.
)
;; Main arity - called by Telemere whenever the handler should handle
;; the given signal. Never called after shutdown.
([signal] ([signal]
;; Do something with given signal (write to console/file/queue/db, etc.). ;; Do something with given signal (write to console/file/queue/db, etc.).
;; Return value is ignored. ;; Return value is ignored.
)
;; Optional stop arity for handlers that need to close/release resources or
;; otherwise finalize themselves during system shutdown, etc. Called by
;; Telemere when appropriate, but ONLY IF the handler's dispatch options
;; include a truthy `:needs-stopping?` value (false by default).
([]
;; Close/release resources, etc.
)) ))
;; (Advanced) optional default handler dispatch opts, ;; (Advanced) optional default handler dispatch opts,

View file

@ -8,7 +8,7 @@
:url "https://www.eclipse.org/legal/epl-v10.html"} :url "https://www.eclipse.org/legal/epl-v10.html"}
:dependencies :dependencies
[[com.taoensso/encore "3.110.0"]] [[com.taoensso/encore "3.112.0"]]
:test-paths ["test" #_"src"] :test-paths ["test" #_"src"]

View file

@ -31,8 +31,8 @@ Tips:
See also `error!`. See also `error!`.
------------------------------------------------------------------- ----------------------------------------------------------------------
[1] See `help:signal-creators` - (`signal!`, `log!`, `event!`, ...) [1] See `help:signal-creators` - (`signal!`, `log!`, `event!`, ...)
[2] See `help:signal-options` - {:keys [kind level id data ...]} [2] See `help:signal-options` - {:keys [kind level id data ...]}
[3] See `help:signal-content` - {:keys [kind level id data ...]} [3] See `help:signal-content` - {:keys [kind level id data ...]}
[4] See `help:signal-flow` - (filters, handling, etc.) [4] See `help:signal-filters` - (by ns/kind/id/level, sampling, etc.)

View file

@ -1,3 +1,6 @@
Telemere supports extensive environmental config via JVM properties,
environment variables, or classpath resources.
Environmental filter config includes: Environmental filter config includes:
Kind filter: Kind filter:
@ -23,10 +26,12 @@ Environmental filter config includes:
Examples: Examples:
`taoensso.telemere.rt-min-level.edn` -> ":info" `taoensso.telemere.rt-min-level.edn` -> ":info"
`TAOENSSO_TELEMERE_RT_NS_FILTER_EDN` -> "{:deny \"taoensso.*\"}" `TAOENSSO_TELEMERE_RT_NS_FILTER_EDN` -> "{:disallow \"taoensso.*\"}"
`taoensso.telemere.rt-id-filter.cljs.edn` -> "#{:my-id1 :my-id2}" `taoensso.telemere.rt-id-filter.cljs.edn` -> "#{:my-id1 :my-id2}"
`TAOENSSO_TELEMERE_RT_KIND_FILTER_CLJ_EDN` -> "nil" `TAOENSSO_TELEMERE_RT_KIND_FILTER_CLJ_EDN` -> "nil"
For other (non-filter) environmental config, see the relevant docstrings.
Tips: Tips:
- The above ids are for runtime filters (the most common). - The above ids are for runtime filters (the most common).

View file

@ -24,8 +24,8 @@ Tips:
- `error` arg is a platform error (`java.lang.Throwable` or `js/Error`). - `error` arg is a platform error (`java.lang.Throwable` or `js/Error`).
- Can conveniently be wrapped by `throw`: (throw (error! ...)). - Can conveniently be wrapped by `throw`: (throw (error! ...)).
------------------------------------------------------------------- ----------------------------------------------------------------------
[1] See `help:signal-creators` - (`signal!`, `log!`, `event!`, ...) [1] See `help:signal-creators` - (`signal!`, `log!`, `event!`, ...)
[2] See `help:signal-options` - {:keys [kind level id data ...]} [2] See `help:signal-options` - {:keys [kind level id data ...]}
[3] See `help:signal-content` - {:keys [kind level id data ...]} [3] See `help:signal-content` - {:keys [kind level id data ...]}
[4] See `help:signal-flow` - (filters, handling, etc.) [4] See `help:signal-filters` - (by ns/kind/id/level, sampling, etc.)

View file

@ -29,8 +29,8 @@ Tips:
Mnemonic: the arg that's typically larger is *always* in the rightmost Mnemonic: the arg that's typically larger is *always* in the rightmost
position, and for `event!` that's the `level-or-opts` arg. position, and for `event!` that's the `level-or-opts` arg.
------------------------------------------------------------------- ----------------------------------------------------------------------
[1] See `help:signal-creators` - (`signal!`, `log!`, `event!`, ...) [1] See `help:signal-creators` - (`signal!`, `log!`, `event!`, ...)
[2] See `help:signal-options` - {:keys [kind level id data ...]} [2] See `help:signal-options` - {:keys [kind level id data ...]}
[3] See `help:signal-content` - {:keys [kind level id data ...]} [3] See `help:signal-content` - {:keys [kind level id data ...]}
[4] See `help:signal-flow` - (filters, handling, etc.) [4] See `help:signal-filters` - (by ns/kind/id/level, sampling, etc.)

View file

@ -29,8 +29,8 @@ Tips:
- `msg` arg may be a string, or vector of strings to join with `\space`. - `msg` arg may be a string, or vector of strings to join with `\space`.
- See also `msg-splice`, `msg-skip` utils. - See also `msg-splice`, `msg-skip` utils.
------------------------------------------------------------------- ----------------------------------------------------------------------
[1] See `help:signal-creators` - (`signal!`, `log!`, `event!`, ...) [1] See `help:signal-creators` - (`signal!`, `log!`, `event!`, ...)
[2] See `help:signal-options` - {:keys [kind level id data ...]} [2] See `help:signal-options` - {:keys [kind level id data ...]}
[3] See `help:signal-content` - {:keys [kind level id data ...]} [3] See `help:signal-content` - {:keys [kind level id data ...]}
[4] See `help:signal-flow` - (filters, handling, etc.) [4] See `help:signal-filters` - (by ns/kind/id/level, sampling, etc.)

View file

@ -21,8 +21,8 @@ Tips:
- Test using `with-signal`: (with-signal (signal! ...)). - Test using `with-signal`: (with-signal (signal! ...)).
- Supports the same options [2] as other signals [1]. - Supports the same options [2] as other signals [1].
------------------------------------------------------------------- ----------------------------------------------------------------------
[1] See `help:signal-creators` - (`signal!`, `log!`, `event!`, ...) [1] See `help:signal-creators` - (`signal!`, `log!`, `event!`, ...)
[2] See `help:signal-options` - {:keys [kind level id data ...]} [2] See `help:signal-options` - {:keys [kind level id data ...]}
[3] See `help:signal-content` - {:keys [kind level id data ...]} [3] See `help:signal-content` - {:keys [kind level id data ...]}
[4] See `help:signal-flow` - (filters, handling, etc.) [4] See `help:signal-filters` - (by ns/kind/id/level, sampling, etc.)

View file

@ -26,7 +26,7 @@ and return values), making them more/less convenient for certain use cases:
- `log!` emphasizes messages, while `event!` emphasizes ids. - `log!` emphasizes messages, while `event!` emphasizes ids.
- `signal!` is the generic creator, and is used by all the others. - `signal!` is the generic creator, and is used by all the others.
------------------------------------------------------------------- ----------------------------------------------------------------------
[2] See `help:signal-options` - {:keys [kind level id data ...]} [2] See `help:signal-options` - {:keys [kind level id data ...]}
[3] See `help:signal-content` - {:keys [kind level id data ...]} [3] See `help:signal-content` - {:keys [kind level id data ...]}
[4] See `help:signal-flow` - (filters, handling, etc.) [4] See `help:signal-filters` - (by ns/kind/id/level, sampling, etc.)

View file

@ -1,49 +0,0 @@
A signal will be provided to a handler iff ALL of the following are true:
1. Signal (creation) is allowed by compile-time filters
2. Signal (creation) is allowed by runtime filters
3. Signal (handling) is allowed by handler filters
4. Signal middleware does not suppress the signal (return nil)
5. Handler middleware does not suppress the signal (return nil)
For 1-3, filtering may depend on (in order):
Sample rate → namespace → kind → id → level → when form/fn → rate limit
Compile-time vs runtime filtering:
Compile-time filtering is an advanced feature that can be tricky to set
and use correctly. Most folks will want ONLY runtime filtering.
Compile-time filtering works by eliding (completely removing the code for)
disallowed signals. This means zero performance cost for these signals,
but also means that compile-time filtering is PERMANENT once applied.
So if you set `:info` as the compile-time minimum level, that'll REMOVE
CODE for every signal call below `:info` level. To decrease that minimum
level, you'll need to rebuild.
Compile-time filtering can be set ONLY with environmental config
(JVM properties, environment variables, or classpath resources).
Signal and handler sampling is multiplicative:
Both signals and handlers can have independent sample rates, and these
MULTIPLY!
If a signal is created with 20% sampling and a handler handles 50%
of received signals, then 10% of possible signals will be handled
(50% of 20%).
The multiplicative rate is helpfully reflected in each signal's final
`:sample-rate` value.
For more info:
- Signal visual flowchart, Ref. <https://www.taoensso.com/telemere/flow>
- On signal filters, see: `help:signal-filters` docstring
- On handler filters, see: `help:signal-handlers` docstring
If anything is unclear, please ping me (@ptaoussanis) so that I can
improve these docs!

View file

@ -34,8 +34,8 @@ Tips:
- Can be useful to wrap with `catch->error!`: - Can be useful to wrap with `catch->error!`:
(catch->error! ::error-id (spy! ...)). (catch->error! ::error-id (spy! ...)).
------------------------------------------------------------------- ----------------------------------------------------------------------
[1] See `help:signal-creators` - (`signal!`, `log!`, `event!`, ...) [1] See `help:signal-creators` - (`signal!`, `log!`, `event!`, ...)
[2] See `help:signal-options` - {:keys [kind level id data ...]} [2] See `help:signal-options` - {:keys [kind level id data ...]}
[3] See `help:signal-content` - {:keys [kind level id data ...]} [3] See `help:signal-content` - {:keys [kind level id data ...]}
[4] See `help:signal-flow` - (filters, handling, etc.) [4] See `help:signal-filters` - (by ns/kind/id/level, sampling, etc.)

View file

@ -38,8 +38,8 @@ Tips:
refers to the general action of tracing program flow rather than to the refers to the general action of tracing program flow rather than to the
common logging level of the same name. common logging level of the same name.
------------------------------------------------------------------- ----------------------------------------------------------------------
[1] See `help:signal-creators` - (`signal!`, `log!`, `event!`, ...) [1] See `help:signal-creators` - (`signal!`, `log!`, `event!`, ...)
[2] See `help:signal-options` - {:keys [kind level id data ...]} [2] See `help:signal-options` - {:keys [kind level id data ...]}
[3] See `help:signal-content` - {:keys [kind level id data ...]} [3] See `help:signal-content` - {:keys [kind level id data ...]}
[4] See `help:signal-flow` - (filters, handling, etc.) [4] See `help:signal-filters` - (by ns/kind/id/level, sampling, etc.)

View file

@ -1,7 +1,7 @@
{;;:lein true {;;:lein true
:source-paths ["src" "test"] :source-paths ["src" "test"]
:dependencies :dependencies
[[com.taoensso/encore "3.110.0"] [[com.taoensso/encore "3.112.0"]
[cider/cider-nrepl "0.47.0"] [cider/cider-nrepl "0.47.0"]
[binaryage/devtools "1.0.7"]] [binaryage/devtools "1.0.7"]]

View file

@ -32,11 +32,12 @@
(remove-ns 'taoensso.telemere) (remove-ns 'taoensso.telemere)
(:api (enc/interns-overview))) (:api (enc/interns-overview)))
(enc/assert-min-encore-version [3 110 0]) (enc/assert-min-encore-version [3 112 0])
;;;; TODO ;;;; TODO
;; - Add handlers: Logstash, Carmine, Datadog, Kafka
;; - Native OpenTelemetry traces and spans ;; - Native OpenTelemetry traces and spans
;; - Solution and docs for lib authors
;; - Add handlers: Logstash, Carmine, Datadog, Kafka
;; - Update Tufte (signal API, config API, signal keys, etc.) ;; - Update Tufte (signal API, config API, signal keys, etc.)
;; - Update Timbre (signal API, config API, signal keys, backport improvements) ;; - Update Timbre (signal API, config API, signal keys, backport improvements)
@ -47,21 +48,7 @@
:sf-arity 4 :sf-arity 4
:ct-sig-filter impl/ct-sig-filter :ct-sig-filter impl/ct-sig-filter
:*rt-sig-filter* impl/*rt-sig-filter* :*rt-sig-filter* impl/*rt-sig-filter*
:*sig-handlers* impl/*sig-handlers* :*sig-handlers* impl/*sig-handlers*})
:sig-filter-env-config-help
(impl/signal-docstring :filter-env-config)})
(comment help:filters)
(comment
[level-aliases
help:handlers get-handlers add-handler! remove-handler!
with-handler with-handler+ shut-down-handlers!
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])
;;;; Aliases ;;;; Aliases
@ -90,12 +77,11 @@
;;;; Help ;;;; Help
(do
(impl/defhelp help:signal-creators :signal-creators) (impl/defhelp help:signal-creators :signal-creators)
(impl/defhelp help:signal-options :signal-options) (impl/defhelp help:signal-options :signal-options)
(impl/defhelp help:signal-flow :signal-flow)
(impl/defhelp help:signal-content :signal-content) (impl/defhelp help:signal-content :signal-content)
(enc/defalias help:signal-filters help:filters) ; Via Encore (impl/defhelp help:environmental-config :environmental-config))
(enc/defalias help:signal-handlers help:handlers) ; Via Encore
;;;; Context ;;;; Context

View file

@ -35,7 +35,7 @@
(let [error-signal? utils/error-signal?] (let [error-signal? utils/error-signal?]
(fn a-handler:console (fn a-handler:console
([]) ; Shut down (no-op) ([]) ; Shut down (noop)
([signal] ([signal]
(let [^java.io.Writer stream (let [^java.io.Writer stream
(case stream (case stream
@ -70,7 +70,7 @@
(let [js-console-logger utils/js-console-logger] (let [js-console-logger utils/js-console-logger]
(fn a-handler:console (fn a-handler:console
([]) ; Shut down (no-op) ([]) ; Shut down (noop)
([signal] ([signal]
(when-let [output (output-fn signal)] (when-let [output (output-fn signal)]
(let [logger (js-console-logger (get signal :level))] (let [logger (js-console-logger (get signal :level))]
@ -115,7 +115,7 @@
:raw-error? true})] :raw-error? true})]
(fn a-handler:console-raw (fn a-handler:console-raw
([]) ; Shut down (no-op) ([]) ; Shut down (noop)
([signal] ([signal]
(let [{:keys [level error]} signal (let [{:keys [level error]} signal
logger (js-console-logger level)] logger (js-console-logger level)]

View file

@ -106,7 +106,7 @@
(def ^:public msg-skip (def ^:public msg-skip
"For use within signal message vectors. "For use within signal message vectors.
Special value that will be ignored (no-op) when creating message. Special value that will be ignored (noop) when creating message.
Useful for conditionally skipping parts of message content, etc.: Useful for conditionally skipping parts of message content, etc.:
(signal! {:msg [\"Hello\" (if <cond> <then> msg-skip) \"world\"] <...>}) or (signal! {:msg [\"Hello\" (if <cond> <then> msg-skip) \"world\"] <...>}) or
@ -242,13 +242,10 @@
[ns kind id level signal-value_] [ns kind id level signal-value_]
sigs/IFilterableSignal sigs/IFilterableSignal
(allow-signal? [_ sig-filter] (sig-filter ns kind id level)) (allow-signal? [_ sig-filter] (sig-filter ns kind id level))
(signal-value [_ handler-context] (signal-value [_ handler-sample-rate]
(let [sig-val @signal-value_] (let [sig-val @signal-value_]
(or (or
(when-let [handler-sample-rate (when handler-sample-rate
(when-let [^taoensso.encore.signals.HandlerContext hc handler-context]
(.-sample-rate hc))]
(when (map? sig-val) (when (map? sig-val)
;; Replace call sample rate with combined (call * handler) sample rate ;; Replace call sample rate with combined (call * handler) sample rate
(assoc sig-val :sample-rate (assoc sig-val :sample-rate

View file

@ -212,7 +212,7 @@
(let [] (let []
(fn a-handler:open-telemetry-logger (fn a-handler:open-telemetry-logger
([]) ; Shut down (no-op) ([]) ; Shut down (noop)
([signal] ([signal]
(let [{:keys [ns inst level msg_]} signal (let [{:keys [ns inst level msg_]} signal
logger (.get logger-provider (or ns "default")) logger (.get logger-provider (or ns "default"))

View file

@ -107,7 +107,7 @@
(let [handler-fn (let [handler-fn
(fn a-handler:postal (fn a-handler:postal
([]) ; Shut down (no-op) ([]) ; Shut down (noop)
([signal] ([signal]
(enc/when-let [subject (subject-fn signal) (enc/when-let [subject (subject-fn signal)
body (body-fn signal)] body (body-fn signal)]

View file

@ -74,7 +74,7 @@
handler-fn handler-fn
(fn a-handler:slack (fn a-handler:slack
([]) ; Shut down (no-op) ([]) ; Shut down (noop)
([signal] ([signal]
(when-let [output (output-fn signal)] (when-let [output (output-fn signal)]
(slack.chat/post-message conn-opts channel-id (slack.chat/post-message conn-opts channel-id

View file

@ -159,5 +159,5 @@
#?(:clj (defmacro with-context+ "Prefer `telemere/with-ctx+`." [context & body] `(tel/with-ctx+ ~context (do ~@body)))) #?(:clj (defmacro with-context+ "Prefer `telemere/with-ctx+`." [context & body] `(tel/with-ctx+ ~context (do ~@body))))
(defn shutdown-appenders! (defn shutdown-appenders!
"Prefer `telemere/shut-down-handlers!`." "Prefer `telemere/stop-handlers!`."
[] (tel/shut-down-handlers!)) [] (tel/stop-handlers!))

View file

@ -176,7 +176,7 @@
(defn file-writer (defn file-writer
"Experimental, subject to change. "Experimental, subject to change.
Opens the specified file and returns a stateful fn of 2 arities: Opens the specified file and returns a stateful fn of 2 arities:
[content] => Writes given content to file, or no-ops if closed. [content] => Writes given content to file, or noops if closed.
[] => Closes the writer. [] => Closes the writer.
Useful for basic handlers that write to a file, etc. Useful for basic handlers that write to a file, etc.
@ -273,7 +273,7 @@
(defn tcp-socket-writer (defn tcp-socket-writer
"Experimental, subject to change. "Experimental, subject to change.
Connects to specified TCP socket and returns a stateful fn of 2 arities: Connects to specified TCP socket and returns a stateful fn of 2 arities:
[content] => Writes given content to socket, or no-ops if closed. [content] => Writes given content to socket, or noops if closed.
[] => Closes the writer. [] => Closes the writer.
Useful for basic handlers that write to a TCP socket, etc. Useful for basic handlers that write to a TCP socket, etc.

View file

@ -326,7 +326,7 @@
(tel/with-handler :hid1 (tel/with-handler :hid1
(fn ([_] (c5)) ([] (c6))) (fn ([_] (c5)) ([] (c6)))
dispatch-opts (assoc dispatch-opts :needs-stopping? true)
(do (do
(dotimes [_ n] (fp (fn [] (c1) (tel/event! ::ev-id1 {:run (c2), :do (c3)}) (c4)))) (dotimes [_ n] (fp (fn [] (c1) (tel/event! ::ev-id1 {:run (c2), :do (c3)}) (c4))))
(fp))) (fp)))

View file

@ -89,7 +89,7 @@ And setup your namespace imports:
Telemere is configured sensibly out-the-box. Telemere is configured sensibly out-the-box.
See section [3-Config](./3-Config) for customization. See section [3-Config](./3-Config) for customization.
**Default minimum level**: `:info` (signals with lower levels will no-op). **Default minimum level**: `:info` (signals with lower levels will noop).
**Default signal handlers**: **Default signal handlers**:
@ -122,7 +122,7 @@ Run [`check-intakes`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/tao
# Usage # Usage
## Create signals ## Creating signals
Use whichever signal creator is most convenient for your needs: Use whichever signal creator is most convenient for your needs:
@ -136,12 +136,12 @@ Use whichever signal creator is most convenient for your needs:
| [`catch->error!`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#catch-%3Eerror!) | `:error` | `form` | `opts`/`id` | Form value or given fallback | [`catch->error!`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#catch-%3Eerror!) | `:error` | `form` | `opts`/`id` | Form value or given fallback
| [`signal!`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#signal!) | `<arb>` | `opts` | - | Depends on opts | [`signal!`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#signal!) | `<arb>` | `opts` | - | Depends on opts
- See [`help:signal-creators`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#help:signal-creators) for more info on signal creators.
- See [`help:signal-options`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#help:signal-options) for signal options (shared by all creators).
- See relevant docstrings (links above) for usage info. - See relevant docstrings (links above) for usage info.
- See [`help:signal-creators`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#help:signal-creators) for more about signal creators.
- See [`help:signal-options`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#help:signal-options) for options shared by all signal creators.
- See [examples.cljc](https://github.com/taoensso/telemere/blob/master/examples.cljc) for REPL-ready examples. - See [examples.cljc](https://github.com/taoensso/telemere/blob/master/examples.cljc) for REPL-ready examples.
## Check signals ## Checking signals
Use the [`with-signal`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#with-signal) or (advanced) [`with-signals`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#with-signals) utils to help test/debug the signals that you're creating: Use the [`with-signal`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#with-signal) or (advanced) [`with-signals`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#with-signals) utils to help test/debug the signals that you're creating:
@ -160,17 +160,18 @@ Use the [`with-signal`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/t
Both have several options, see their docstrings (links above) for details. Both have several options, see their docstrings (links above) for details.
## Filter signals ## Filtering
A signal will be provided to a handler iff ALL of the following are true: A signal will be provided to a handler iff ALL of the following are true:
1. Signal **creation** is allowed by **compile-time** filter config 1. Signal **creation** is allowed by **compile-time** "signal filters"
2. Signal **creation** is allowed by **runtime** filter config 2. Signal **creation** is allowed by **runtime** "signal filters"
3. Signal **handling** is allowed by **handler** filter config 3. Signal **handling** is allowed by **runtime** "handler filters"
4. Signal **middleware** does not suppress the signal (return nil) 4. Signal **middleware** does not suppress the signal (return nil)
5. Handler **middleware** does not suppress the signal (return nil) 5. Handler **middleware** does not suppress the signal (return nil)
For 1-3, filtering may depend on (in order): All filters (1-3) may depend on (in order):
Sample rate → namespace → kind → id → level → when form/fn → rate limit Sample rate → namespace → kind → id → level → when form/fn → rate limit
Quick examples of some basic filtering: Quick examples of some basic filtering:
@ -183,36 +184,24 @@ Quick examples of some basic filtering:
(t/with-min-level :trace ; Override global minimum level (t/with-min-level :trace ; Override global minimum level
(t/with-signal (t/event! ::my-id1 :debug))) ; => {:keys [inst id ...]} (t/with-signal (t/event! ::my-id1 :debug))) ; => {:keys [inst id ...]}
;; Deny all signals in matching namespaces ;; Disallow all signals in matching namespaces
(t/set-ns-filter! {:deny "some.nosy.namespace.*"}) (t/set-ns-filter! {:disallow "some.nosy.namespace.*"})
``` ```
- Filtering is always O(1), except for rate limits which are O(n_windows). - Filtering is always O(1), except for rate limits which are O(n_windows).
- Signal and handler sampling is *multiplicative*: if a signal is created with *20%* sampling and a handler handles *50%* of received signals, then *10%* of possible signals will be handled. This multiplicative rate is helpfully reflected in each signal's final `:sample-rate` value. - See [`help:filters`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#help:filters) for more about filtering.
- See [`help:signal-flow`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#help:signal-flow) for internal docs on signal flow.
- See section [2-Architecture](./2-Architecture) for a flowchart / visual aid. - See section [2-Architecture](./2-Architecture) for a flowchart / visual aid.
Runtime signal filters can be set with:
| Global | Dynamic | Filters by |
| :-------------------------------------------------------------------------------------------------------------- | :-------------------------------------------------------------------------------------------------------------- | :-------------------------------------------------------- |
| [`set-kind-filter!`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#set-kind-filter!) | [`with-kind-filter`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#with-kind-filter) | Signal kind (`:log`, `:event`, etc.) |
| [`set-ns-filter!`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#set-ns-filter!) | [`with-ns-filter`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#with-ns-filter) | Signal namespace |
| [`set-id-filter!`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#set-id-filter!) | [`with-id-filter`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#with-id-filter) | Signal id |
| [`set-min-level`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#set-min-level) | [`with-min-level`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#with-min-level) | Signal level (minimum can be specified by kind and/or ns) |
- See relevant docstrings (links above) for usage info.
- Compile-time filters are set with environmental config, see section [3-Config](./3-Config).
# Internal help # Internal help
Telemere includes extensive internal help docstrings: Telemere includes extensive internal help docstrings:
| Var | Help with | | Var | Help with |
| :-------------------------------------------------------------------------------------------------------------------------- | :-------------------------------------------- | | :---------------------------------------------------------------------------------------------------------------------------------------- | :------------------------------------------------------------------------ |
| [`help:signal-creators`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#help:signal-creators) | List of signal creators | | [`help:signal-creators`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#help:signal-creators) | Creating signals |
| [`help:signal-options`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#help:signal-options) | Options for signal creators | | [`help:signal-options`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#help:signal-options) | Signal options |
| [`help:signal-content`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#help:signal-content) | Signal map content | | [`help:signal-content`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#help:signal-content) | Signal content (map given to middleware/handlers) |
| [`help:signal-flow`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#help:signal-flow) | Ordered flow from signal creation to handling | | [`help:filters`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#help:filters) | Signal and handler filters |
| [`help:signal-filters`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#help:signal-filters) | API for configuring signal filters | | [`help:handlers`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#help:handlers) | Signal handlers |
| [`help:signal-handlers`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#help:signal-handlers) | API for configuring signal handlers | | [`help:handler-dispatch-options`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#help:handler-dispatch-options) | Signal handler dispatch options |
| [`help:environmental-config`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#help:environmental-config) | Config via JVM properties, environment variables, or classpath resources.

View file

@ -11,20 +11,9 @@ console/file/queue/db, etc.).
So you *call* a *signal creator* to (conditionally) create a *signal* (map) which is then dispatched to registered _signal handlers_ for (conditional) handling. So you *call* a *signal creator* to (conditionally) create a *signal* (map) which is then dispatched to registered _signal handlers_ for (conditional) handling.
This flow is described by [`help:signal-flow`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#help:signal-flow), and is visualized below: This flow is visualized below:
<img src="https://raw.githubusercontent.com/taoensso/telemere/master/imgs/signal-flow.svg" alt="Telemere signal flowchart" width="640"/> <img src="https://raw.githubusercontent.com/taoensso/telemere/master/imgs/signal-flow.svg" alt="Telemere signal flowchart" width="640"/>
- `A/sync queue` semantics are configured per handler when calling [`add-handler!`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#add-handler!). Default semantics are: async with a dropping buffer, and 1 handler thread. - `A/sync queue` semantics are specified via [handler dispatch options](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#help:handler-dispatch-options).
- The shared **signal middleware cache** is super useful when doing signal transformations that are expensive and/or involve side effects (like syncing with another service/db to get a unique tx id, etc.). - The shared **signal middleware cache** is super useful when doing signal transformations that are expensive and/or involve side effects (like syncing with another service/db to get a unique tx id, etc.).
For more info see:
| Var | Help with |
| :-------------------------------------------------------------------------------------------------------------------------- | :-------------------------------------------- |
| [`help:signal-creators`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#help:signal-creators) | List of signal creators |
| [`help:signal-options`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#help:signal-options) | Options for signal creators |
| [`help:signal-content`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#help:signal-content) | Signal map content |
| [`help:signal-flow`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#help:signal-flow) | Ordered flow from signal creation to handling |
| [`help:signal-filters`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#help:signal-filters) | API for configuring signal filters |
| [`help:signal-handlers`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#help:signal-handlers) | API for configuring signal handlers |

View file

@ -1,20 +1,20 @@
See below for config by topic- See below for config by topic-
# Signal filtering # Filtering
A signal will be provided to a handler iff ALL of the following are true: A signal will be provided to a handler iff ALL of the following are true:
1. Signal **creation** is allowed by **compile-time** filter config 1. Signal **creation** is allowed by **compile-time** "signal filters"
2. Signal **creation** is allowed by **runtime** filter config 2. Signal **creation** is allowed by **runtime** "signal filters"
3. Signal **handling** is allowed by **handler** filter config 3. Signal **handling** is allowed by **runtime** "handler filters"
4. Signal **middleware** does not suppress the signal (return nil) 4. Signal **middleware** does not suppress the signal (return nil)
5. Handler **middleware** does not suppress the signal (return nil) 5. Handler **middleware** does not suppress the signal (return nil)
For 1-3, filtering may depend on (in order): All filters (1-3) may depend on (in order):
Sample rate → namespace → kind → id → level → when form/fn → rate limit Sample rate → namespace → kind → id → level → when form/fn → rate limit
- See [`help:signal-filters`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#help:signal-filters) for info on signal creation filters, **environmental config**, etc. See [`help:filters`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#help:filters) for more about filtering.
- See [`add-handler!`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#add-handler!) for info on signal handler filters.
# Signal handlers # Signal handlers

View file

@ -38,9 +38,9 @@ There's two kinds of config relevant to all signal handlers:
## Dispatch opts ## Dispatch opts
Handler dispatch opts includes dispatch priority, handler filtering, handler middleware, queue semantics, back-pressure opts, etc. Handler dispatch opts includes dispatch priority (determines order in which handlers are called), handler filtering, handler middleware, a/sync queue semantics, back-pressure opts, etc.
This is all specified when calling [`add-handler!`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#add-handler!) - and documented there. See [`help:handler-dispatch-options`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#help:handler-dispatch-options) for full info, and [`default-handler-dispatch-opts`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#default-handler-dispatch-opts) for defaults.
Note that handler middleware in particular is an often overlooked but powerful feature, allowing you to arbitrarily transform and/or filter every [signal map](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#help:signal-content) before it is given to the handler. Note that handler middleware in particular is an often overlooked but powerful feature, allowing you to arbitrarily transform and/or filter every [signal map](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#help:signal-content) before it is given to the handler.
@ -127,7 +127,7 @@ These user-level data/opts are typically NOT included by default in handler outp
# Managing handlers # Managing handlers
See [`help:signal-handlers`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#help:signal-handlers) for info on handler management. See [`help:handlers`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#help:signal-handlers) for info on handler management.
## Managing handlers on startup ## Managing handlers on startup
@ -141,6 +141,10 @@ If you want to manage handlers **conditionally** based on **environmental config
Use this to easily define your own arbitrary cross-platform config, and make whatever conditional handler management decisions you'd like. Use this to easily define your own arbitrary cross-platform config, and make whatever conditional handler management decisions you'd like.
## Handler stats
By default, Telemere handlers maintain comprehensive internal info about their handling times and outcomes. See [`get-handlers-stats`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#get-handlers-stats) for more.
# Writing handlers # Writing handlers
Writing your own signal handlers for Telemere is straightforward, and a reasonable choice if you prefer customizing behaviour that way, or want to write signals to a DB/format/service for which a ready-made handler isn't available. Writing your own signal handlers for Telemere is straightforward, and a reasonable choice if you prefer customizing behaviour that way, or want to write signals to a DB/format/service for which a ready-made handler isn't available.
@ -180,17 +184,18 @@ For more complex cases, or for handlers that you want to make available for use
(let [handler-fn (let [handler-fn
(fn a-handler:my-handler ; Note naming convention (fn a-handler:my-handler ; Note naming convention
;; Shutdown arity - called by Telemere exactly once when the handler ;; Main arity, called by Telemere when handler should process given signal
;; is to be shut down.
([]
;; Can no-op, or finalize/free resources as necessary.
)
;; Main arity - called by Telemere whenever the handler should handle
;; the given signal. Never called after shutdown.
([signal] ([signal]
;; Do something with given signal (write to console/file/queue/db, etc.). ;; Do something with given signal (write to console/file/queue/db, etc.).
;; Return value is ignored. ;; Return value is ignored.
)
;; Optional stop arity for handlers that need to close/release resources or
;; otherwise finalize themselves during system shutdown, etc. Called by
;; Telemere when appropriate, but ONLY IF the handler's dispatch options
;; include a truthy `:needs-stopping?` value (false by default).
([]
;; Close/release resources, etc.
)) ))
;; (Advanced) optional default handler dispatch opts, ;; (Advanced) optional default handler dispatch opts,

View file

@ -97,6 +97,16 @@ Note that you can even use `format` or any other formatter/s of your choice. You
See also [`msg-skip`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#msg-skip) and [`msg-splice`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#msg-splice) for some handy utils. See also [`msg-skip`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#msg-skip) and [`msg-splice`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#msg-splice) for some handy utils.
# How does Telemere compare to Mulog?
> [Mulog](https://github.com/BrunoBonacci/mulog) is an excellent "micro-logging library" for Clojure that shares many of the same capabilities and objectives as Telemere!
TODO - will add a comparison here before Telemere's final release.
# How to use Telemere from a library?
TODO - will add advice here before Telemere's final release.
# Other questions? # Other questions?
Please [open a Github issue](https://github.com/taoensso/telemere/issues). I'll regularly update the FAQ to add common questions. Please [open a Github issue](https://github.com/taoensso/telemere/issues) or ping on Telemere's [Slack channel](https://www.taoensso.com/telemere/slack). I'll regularly update the FAQ to add common questions.

View file

@ -54,7 +54,7 @@ Consider the **quantities** of data that'd best suit your needs *for that data*:
<img src="https://raw.githubusercontent.com/taoensso/telemere/master/imgs/signal-sampling.svg" alt="Telemere sampling" width="640"/> <img src="https://raw.githubusercontent.com/taoensso/telemere/master/imgs/signal-sampling.svg" alt="Telemere sampling" width="640"/>
Telemere offers [extensive filtering](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#help:signal-flow) capabilities that help you easily express the **conditions** and **quantities** that make sense for your needs. *Use these* both for their effects and as a *form of documentation*. Telemere offers [extensive filtering](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#help:filters) capabilities that help you easily express the **conditions** and **quantities** that make sense for your needs. *Use these* both for their effects and as a *form of documentation*.
## Consider evolution ## Consider evolution