From 12f4b35d713783511e1910df46b8f97926238a93 Mon Sep 17 00:00:00 2001 From: Peter Taoussanis Date: Thu, 25 Apr 2024 09:37:55 +0200 Subject: [PATCH] [doc] Documentation improvements --- README.md | 2 +- examples.cljc | 8 +-- .../signal-docstrings/filter-env-config.txt | 52 +++++++++++++++++++ .../signal-docstrings/filter-system-vals.txt | 15 ------ .../signal-docstrings/signal-content.txt | 4 +- resources/signal-docstrings/signal-flow.txt | 35 ++++++++++--- .../signal-docstrings/signal-options.txt | 8 ++- src/taoensso/telemere.cljc | 4 +- src/taoensso/telemere/impl.cljc | 34 +++++++----- src/taoensso/telemere/tools_logging.clj | 8 +-- wiki/1-Getting-started.md | 6 +-- wiki/3-Config.md | 4 +- wiki/4-Handlers.md | 40 ++++++++------ wiki/5-Migrating.md | 2 +- wiki/7-Tips.md | 12 +++-- wiki/8-Community.md | 14 ++--- 16 files changed, 165 insertions(+), 83 deletions(-) create mode 100644 resources/signal-docstrings/filter-env-config.txt delete mode 100644 resources/signal-docstrings/filter-system-vals.txt diff --git a/README.md b/README.md index 1aa4530..8c4df64 100644 --- a/README.md +++ b/README.md @@ -41,7 +41,7 @@ See [here][GitHub releases] for earlier releases. #### Flexibility - Config via plain **Clojure vals and fns** for easy customization, composition, and REPL debugging. -- Unmatched support for **system-level config** (JVM props, ENV vars, classpath resources). +- Unmatched **environmental config** support (JVM properties, environment variables, or classpath resources). - Expressive **per-call** and **per-handler** filtering at both **runtime** and **compile-time**. - Filter by namespace and id pattern, level, **level by namespace pattern**, etc. - **Sampling**, **rate-limiting**, and **back-pressure monitoring**. diff --git a/examples.cljc b/examples.cljc index d18f888..288d3e1 100644 --- a/examples.cljc +++ b/examples.cljc @@ -160,7 +160,8 @@ (defn handler:my-handler ; Note naming convention "Returns a (fn handler [signal] that: - - Does something. + - Takes a Telemere signal. + - Does something with it. Options: `:option1` - Description @@ -169,8 +170,9 @@ ([] (handler:my-handler nil)) ; Use default opts ([{:as constructor-opts}] - ;; Do expensive prep outside returned handler fn whenever possible - - ;; i.e. at (one-off) construction time rather than handling time. + ;; Do option validation and expensive prep *outside* returned handler + ;; fn whenever possible - i.e. at (one-off) construction time rather than + ;; at every handler call. (let [] (fn a-handler:my-handler ; Note naming convention diff --git a/resources/signal-docstrings/filter-env-config.txt b/resources/signal-docstrings/filter-env-config.txt new file mode 100644 index 0000000..864bf53 --- /dev/null +++ b/resources/signal-docstrings/filter-env-config.txt @@ -0,0 +1,52 @@ +Environmental filter config includes: + + Kind filter: + JVM property: `taoensso.telemere.rt-kind-filter.edn` + Env variable: `TAOENSSO_TELEMERE_RT_KIND_FILTER_EDN` + Classpath resource: `taoensso.telemere.rt-kind-filter.edn` + + Namespace filter: + JVM property: `taoensso.telemere.rt-ns-filter.edn` + Env variable: `TAOENSSO_TELEMERE_RT_NS_FILTER_EDN` + Classpath resource: `taoensso.telemere.rt-ns-filter.edn` + + Id filter: + JVM property: `taoensso.telemere.rt-id-filter.edn` + Env variable: `TAOENSSO_TELEMERE_RT_ID_FILTER_EDN` + Classpath resource: `taoensso.telemere.rt-id-filter.edn` + + Minimum level: + JVM property: `taoensso.telemere.rt-min-level.edn` + Env variable: `TAOENSSO_TELEMERE_RT_MIN_LEVEL_EDN` + Classpath resource: `taoensso.telemere.rt-min-level.edn` + +Examples: + + `taoensso.telemere.rt-min-level.edn` -> ":info" + `TAOENSSO_TELEMERE_RT_NS_FILTER_EDN` -> "{:deny \"taoensso.*\"}" + `taoensso.telemere.rt-id-filter.cljs.edn` -> "#{:my-id1 :my-id2}" + `TAOENSSO_TELEMERE_RT_KIND_FILTER_CLJ_EDN` -> "nil" + +Tips: + + - The above ids are for runtime filters (the most common). + For compile-time filters, change `rt`->`ct` / `RT`->`CT`. + + - The above ids will affect both Clj AND Cljs. + For platform-specific filters, use + ".clj.edn" / "_CLJ_EDN" or + ".cljs.edn" / "_CLJS_EDN" suffixes instead. + + - ".edn" / "_EDN" suffixes are optional. + + - Config values should be edn. To get the right syntax, first set + your runtime filters using the standard utils (`set-min-level!`, + etc.). Then call `get-filters` and serialize the relevant parts + to edn with `pr-str`. + + - All environmental config uses `get-env` underneath. + See the `get-env` docstring for more/advanced details. + + - Classpath resources are files accessible on your project's + classpath. This usually includes files in your project's + `resources/` dir. diff --git a/resources/signal-docstrings/filter-system-vals.txt b/resources/signal-docstrings/filter-system-vals.txt deleted file mode 100644 index 1f53380..0000000 --- a/resources/signal-docstrings/filter-system-vals.txt +++ /dev/null @@ -1,15 +0,0 @@ -These include: - - Compile-time: - - ns-filter: (get-env {:as :edn} :taoensso.telemere/ct-ns-filter<.platform><.edn>) - id-filter: (get-env {:as :edn} :taoensso.telemere/ct-id-filter<.platform><.edn>) - min-level: (get-env {:as :edn} :taoensso.telemere/ct-min-level<.platform><.edn>) - - Runtime: - - ns-filter: (get-env {:as :edn} :taoensso.telemere/rt-ns-filter<.platform><.edn>) - id-filter: (get-env {:as :edn} :taoensso.telemere/rt-id-filter<.platform><.edn>) - min-level: (get-env {:as :edn, :default :info} :taoensso.telemere/rt-min-level<.platform><.edn>) - - See `get-env` for details. diff --git a/resources/signal-docstrings/signal-content.txt b/resources/signal-docstrings/signal-content.txt index 2be21d0..6ea181d 100644 --- a/resources/signal-docstrings/signal-content.txt +++ b/resources/signal-docstrings/signal-content.txt @@ -28,7 +28,9 @@ Default signal keys: `:file` -------- ?str filename of signal creator callsite, same as (:file location) `:sample-rate` - ?rate ∈ℝ[0,1] for combined signal AND handler sampling (0.75 => allow 75% of signals, nil => allow all) - ---------- Arb other user-level ?kvs given to signal creator + ---------- Other arb user-level ?kvs given to signal creator. Typically NOT included + in handler output, so a great way to provide custom data/opts for use + (only) by custom middleware/handlers. If anything is unclear, please ping me (@ptaoussanis) so that I can improve these docs! diff --git a/resources/signal-docstrings/signal-flow.txt b/resources/signal-docstrings/signal-flow.txt index 867a73f..3f616a8 100644 --- a/resources/signal-docstrings/signal-flow.txt +++ b/resources/signal-docstrings/signal-flow.txt @@ -1,4 +1,5 @@ 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 @@ -7,18 +8,40 @@ A signal will be provided to a handler iff ALL of the following are true: 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 -Note that sample rates are multiplicative: - If a signal is created with 20% sampling and a handler handles 50% - of given signals, then 10% of possible signals will be handled. +Compile-time vs runtime filtering: - This multiplicative rate is helpfully reflected in each signal's final + 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 a visual flowchart, see: Ref. - For more info: + + - Signal visual flowchart, Ref. - On signal filters, see: `help:signal-filters` docstring - On handler filters, see: `help:signal-handlers` docstring diff --git a/resources/signal-docstrings/signal-options.txt b/resources/signal-docstrings/signal-options.txt index 1985dd4..ab74243 100644 --- a/resources/signal-docstrings/signal-options.txt +++ b/resources/signal-docstrings/signal-options.txt @@ -18,14 +18,18 @@ Signal options (shared by all signal creators): `: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 creator callsite location -`:elidable?` --- Should signal be subject to compile-time elision? (Default: true). +`:elidable?` --- Should signal be subject to compile-time elision? (Default: true) `:sample-rate` - ?rate ∈ℝ[0,1] for signal 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 `taoensso.telemere/rate-limiter`, see its docstring for details `:middleware` -- ?[(fn [signal])=>modified-signal ...] signal middleware `:trace?` ------ Should tracing be enabled for `:run` form? - ---------- Arb other user-level ?kvs to incl. in signal + ---------- Other arb user-level ?kvs to incl. in signal. Typically NOT included in + handler output, so a great way to provide custom data/opts for use + (only) by custom middleware/handlers. + +handler-specific data that can just be ignored by other handlers If anything is unclear, please ping me (@ptaoussanis) so that I can improve these docs! diff --git a/src/taoensso/telemere.cljc b/src/taoensso/telemere.cljc index 4259cfe..9148db1 100644 --- a/src/taoensso/telemere.cljc +++ b/src/taoensso/telemere.cljc @@ -47,8 +47,8 @@ :ct-sig-filter impl/ct-sig-filter :*rt-sig-filter* impl/*rt-sig-filter* :*sig-handlers* impl/*sig-handlers* - :sig-filter-system-vals-info - (impl/signal-docstring :filter-system-vals)}) + :sig-filter-env-config-help + (impl/signal-docstring :filter-env-config)}) (comment help:filters) diff --git a/src/taoensso/telemere/impl.cljc b/src/taoensso/telemere/impl.cljc index 0dd223b..e2d0b1d 100644 --- a/src/taoensso/telemere/impl.cljc +++ b/src/taoensso/telemere/impl.cljc @@ -34,29 +34,35 @@ ;;;; Config #?(:clj - (let [base (enc/get-env {:as :edn} :taoensso.telemere/ct-filters<.platform><.edn>) - ns-filter (enc/get-env {:as :edn} :taoensso.telemere/ct-ns-filter<.platform><.edn>) - id-filter (enc/get-env {:as :edn} :taoensso.telemere/ct-id-filter<.platform><.edn>) - min-level (enc/get-env {:as :edn} :taoensso.telemere/ct-min-level<.platform><.edn>)] + (let [base (enc/get-env {:as :edn} :taoensso.telemere/ct-filters<.platform><.edn>) + kind-filter (enc/get-env {:as :edn} :taoensso.telemere/ct-kind-filter<.platform><.edn>) + ns-filter (enc/get-env {:as :edn} :taoensso.telemere/ct-ns-filter<.platform><.edn>) + id-filter (enc/get-env {:as :edn} :taoensso.telemere/ct-id-filter<.platform><.edn>) + min-level (enc/get-env {:as :edn} :taoensso.telemere/ct-min-level<.platform><.edn>)] (enc/defonce ct-sig-filter "`SigFilter` used for compile-time elision, or nil." (sigs/sig-filter - {:ns-filter (or ns-filter (get base :ns-filter)) - :id-filter (or id-filter (get base :id-filter)) - :min-level (or min-level (get base :min-level))})))) + {:kind-filter (or kind-filter (get base :kind-filter)) + :ns-filter (or ns-filter (get base :ns-filter)) + :id-filter (or id-filter (get base :id-filter)) + :min-level (or min-level (get base :min-level))})))) -(let [base (enc/get-env {:as :edn} :taoensso.telemere/rt-filters<.platform><.edn>) - ns-filter (enc/get-env {:as :edn} :taoensso.telemere/rt-ns-filter<.platform><.edn>) - id-filter (enc/get-env {:as :edn} :taoensso.telemere/rt-id-filter<.platform><.edn>) - min-level (enc/get-env {:as :edn, :default :info} :taoensso.telemere/rt-min-level<.platform><.edn>)] +(let [base (enc/get-env {:as :edn} :taoensso.telemere/rt-filters<.platform><.edn>) + kind-filter (enc/get-env {:as :edn} :taoensso.telemere/rt-kind-filter<.platform><.edn>) + ns-filter (enc/get-env {:as :edn} :taoensso.telemere/rt-ns-filter<.platform><.edn>) + id-filter (enc/get-env {:as :edn} :taoensso.telemere/rt-id-filter<.platform><.edn>) + min-level (enc/get-env {:as :edn, :default :info} :taoensso.telemere/rt-min-level<.platform><.edn>)] (enc/defonce ^:dynamic *rt-sig-filter* "`SigFilter` used for runtime filtering, or nil." (sigs/sig-filter - {:ns-filter (or ns-filter (get base :ns-filter)) - :id-filter (or id-filter (get base :id-filter)) - :min-level (or min-level (get base :min-level))}))) + {:kind-filter (or kind-filter (get base :kind-filter)) + :ns-filter (or ns-filter (get base :ns-filter)) + :id-filter (or id-filter (get base :id-filter)) + :min-level (or min-level (get base :min-level))}))) + +(comment (enc/get-env {:as :edn, :return :explain} :taoensso.telemere/rt-filters<.platform><.edn>)) ;;;; Context (optional arb app-level state) ;; taoensso.telemere/*ctx* diff --git a/src/taoensso/telemere/tools_logging.clj b/src/taoensso/telemere/tools_logging.clj index f8a28cb..7a4bcd0 100644 --- a/src/taoensso/telemere/tools_logging.clj +++ b/src/taoensso/telemere/tools_logging.clj @@ -39,10 +39,10 @@ (defn tools-logging->telemere! "Configures `clojure.tools.logging` to use Telemere as its logging implementation. - Called automatically if the following is true: - (get-env {:as :bool} :clojure.tools.logging/to-telemere) - - See `get-env` for details." + Called automatically if one of the following is \"true\": + JVM property: `clojure.tools.logging.to-telemere` + Env variable: `CLOJURE_TOOLS_LOGGING_TO_TELEMERE` + Classpath resource: `clojure.tools.logging.to-telemere`" [] (impl/signal! {:kind :event diff --git a/wiki/1-Getting-started.md b/wiki/1-Getting-started.md index 1d3ca3d..036442b 100644 --- a/wiki/1-Getting-started.md +++ b/wiki/1-Getting-started.md @@ -188,11 +188,11 @@ Quick examples of some basic filtering: ``` - Filtering is always O(1), except for rate limits which are O(n_windows). -- Sample rates are *multiplicative*: if a signal is created with *20%* sampling and a handler handles *50%* of given signals, then *10%* of possible signals will be handled. This multiplicative rate is helpfully reflected in each signal's final `:sample-rate` value. +- 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: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. -Runtime signal filters can be configured with: +Runtime signal filters can be set with: | Global | Dynamic | Filters by | | :-------------------------------------------------------------------------------------------------------------- | :-------------------------------------------------------------------------------------------------------------- | :-------------------------------------------------------- | @@ -202,7 +202,7 @@ Runtime signal filters can be configured with: | [`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 controlled by system-level config, see section [3-Config](./3-Config). +- Compile-time filters are set with environmental config, see section [3-Config](./3-Config). # Internal help diff --git a/wiki/3-Config.md b/wiki/3-Config.md index 609372b..7dfa546 100644 --- a/wiki/3-Config.md +++ b/wiki/3-Config.md @@ -13,7 +13,7 @@ A signal will be provided to a handler iff ALL of the following are true: For 1-3, filtering may depend on (in order): 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. +- 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 [`add-handler!`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#add-handler!) for info on signal handler filters. # Signal handlers @@ -29,7 +29,7 @@ See section [4-Handlers](./4-Handlers). To do this: 1. Ensure that you have the `clojure.tools.logging` dependency, and -2. Call [`tools-logging->telemere!`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere.tools-logging#tools-logging-%3Etelemere!), or set the relevant system config as described in its docstring. +2. Call [`tools-logging->telemere!`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere.tools-logging#tools-logging-%3Etelemere!), or set the relevant environmental config as described in its docstring. Verify successful intake with [`check-intakes`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#check-intakes): diff --git a/wiki/4-Handlers.md b/wiki/4-Handlers.md index 0a0dfc5..f5ab65d 100644 --- a/wiki/4-Handlers.md +++ b/wiki/4-Handlers.md @@ -2,18 +2,22 @@ Signal handlers process created signals to *do something with them* (analyse the # Included handlers -The following handlers are included out-the-box: +The following signal handlers are currently included out-the-box: -| Name | Platform | Writes signals to | Writes signals as | -| :------------------------------------------------------------------------------------------------------------------------------------------------------- | :------- | :------------------------------------------------------------------------------------------------------------- | :------------------------------------------------------------------------------- | -| [`handler:console`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#handler:console) | Clj | `*out*` or `*err*` | String ([edn](https://github.com/edn-format/edn), JSON, formatted, etc.) | -| [`handler:console`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#handler:console) | Cljs | Browser console | String ([edn](https://github.com/edn-format/edn), JSON, formatted, etc.) | -| [`handler:console-raw`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#handler:console-raw) | Cljs | Browser console | Raw data (for [cljs-devtools](https://github.com/binaryage/cljs-devtools), etc.) | -| [`handler:file`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#handler:file) | Clj | File/s on disk | String ([edn](https://github.com/edn-format/edn), JSON, formatted, etc.) | -| [`handler:open-telemetry-logger`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere.open-telemetry#handler:open-telemetry-logger) | Clj | [OpenTelemetry](https://opentelemetry.io/) [Java client](https://github.com/open-telemetry/opentelemetry-java) | [LogRecord](https://opentelemetry.io/docs/specs/otel/logs/data-model/) | +| Name | Platform | Output target | Output format | +| :------------------------------------------------------------------------------------------------------------------------------------------------------- | :------- | :------------------------------------------------------------------------------------------------------------- | :--------------------------------------------------------------------- | +| [`handler:console`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#handler:console) | Clj | `*out*` or `*err*` | Formatted string [1] | +| [`handler:console`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#handler:console) | Cljs | Browser console | Formatted string [1] | +| [`handler:console-raw`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#handler:console-raw) | Cljs | Browser console | Raw signal data [2] | +| [`handler:file`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#handler:file) | Clj | File/s on disk | Formatted string [1] | +| [`handler:postal`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere.postal#handler:postal) | Clj | Email (via [postal](https://github.com/drewr/postal)) | Formatted string [1] | +| [`handler:open-telemetry-logger`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere.open-telemetry#handler:open-telemetry-logger) | Clj | [OpenTelemetry](https://opentelemetry.io/) [Java client](https://github.com/open-telemetry/opentelemetry-java) | [LogRecord](https://opentelemetry.io/docs/specs/otel/logs/data-model/) | -- See relevant docstrings (links above) for more info. -- See section [8-Community](8-Community.md) for additional handlers. +- \[1] [Configurable](https://cljdoc.org/d/com.taoensso/telemere/1.0.0-beta3/api/taoensso.telemere#help:signal-formatters): human-readable (default), [edn](https://github.com/edn-format/edn), [JSON](https://www.json.org/), etc. +- \[2] For use with browser formatting tools like [cljs-devtools](https://github.com/binaryage/cljs-devtools). +- See relevant docstrings (links above) for features, usage, etc. +- See section [8-Community](8-Community.md) for more (community-supported) handlers. +- If there's other handlers you'd like to see, feel free to [ping me](https://github.com/taoensso/telemere/issues), or ask on the [`#telemere` Slack channel](https://www.taoensso.com/telemere/slack). It helps to know what people most need! # Configuring handlers @@ -97,11 +101,11 @@ Want to add or remove a particular handler when your application starts? Just make an appropriate call to [`add-handler!`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#add-handler!) or [`remove-handler!`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#remove-handler!). -## System-level config +## Environmental config -If you want to manage handlers **conditionally** based on **system-level config** (e.g. JVM prop, ENV var, or classpath resource) - Telemere provides the highly flexible [`get-env`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#get-env) util. +If you want to manage handlers **conditionally** based on **environmental config** (JVM properties, environment variables, or classpath resources) - Telemere provides the highly flexible [`get-env`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#get-env) util. -Use this to easily check your own cross-platform system 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. # Writing handlers @@ -120,7 +124,8 @@ For more complex cases, or for handlers that you want to make available for use ```clojure (defn handler:my-handler ; Note naming convention "Returns a (fn handler [signal] that: - - Does something. + - Takes a Telemere signal. + - Does something with it. Options: `:option1` - Description @@ -129,8 +134,9 @@ For more complex cases, or for handlers that you want to make available for use ([] (handler:my-handler nil)) ; Use default opts ([{:as constructor-opts}] - ;; Do expensive prep outside returned handler fn whenever possible - - ;; i.e. at (one-off) construction time rather than handling time. + ;; Do option validation and expensive prep *outside* returned handler + ;; fn whenever possible - i.e. at (one-off) construction time rather than + ;; at every handler call. (let [] (fn a-handler:my-handler ; Note naming convention @@ -181,4 +187,4 @@ Chrome console, with [cljs-devtools](https://github.com/binaryage/cljs-devtools) MacOS terminal: -Default Clojure file handler output \ No newline at end of file +Default Clojure file handler output diff --git a/wiki/5-Migrating.md b/wiki/5-Migrating.md index 6026487..f3f265e 100644 --- a/wiki/5-Migrating.md +++ b/wiki/5-Migrating.md @@ -26,7 +26,7 @@ If not, you may need to [write something yourself](./4-Handlers#writing-handlers This may be easier than it sounds. Remember that signals are just plain Clojure/Script [maps](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#help:signal-content), and handlers just plain Clojure/Script functions that do something with those maps. -Feel free to [ping me](https://github.com/taoensso/telemere/issues) for assistance, or ask on the [`#telemere` Slack channel](https://clojurians.slack.com/archives/C06ALA6EEUA). +Feel free to [ping me](https://github.com/taoensso/telemere/issues) for assistance, or ask on the [`#telemere` Slack channel](https://www.taoensso.com/telemere/slack). ### 2. Imports diff --git a/wiki/7-Tips.md b/wiki/7-Tips.md index 8f32e7a..a856f15 100644 --- a/wiki/7-Tips.md +++ b/wiki/7-Tips.md @@ -72,7 +72,7 @@ Consider the [differences](https://www.youtube.com/watch?v=oyLBGkS5ICk) between - [`log!`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#log!) and [`event!`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#event!) are both **good general-purpose** signal creators. -- Try **always provide an id** for all signals you create. +- **Provide an id** for all signals you create. Qualified keywords are perfect! Downstream behaviour (e.g. alerts) can then look for these ids rather than messages (which are harder to match and more likely to change). @@ -84,11 +84,13 @@ Consider the [differences](https://www.youtube.com/watch?v=oyLBGkS5ICk) between The result of signal middleware is cached and *shared between all handlers* making it an efficient place to transform signals. For this reason - prefer signal middleware to handler middleware when possible/convenient. -- **Signal sampling** and **handler sampling** are **multiplicative**. +- Signal and handler **sampling is multiplicative**. - If a signal is created with *20%* sampling and a handler handles *50%* of given signals, then *10%* of possible signals will be handled. + Both signals and handlers can have independent sample rates, and these MULTIPLY! - This multiplicative rate is helpfully reflected in each signal's final `:sample-rate` value, making it possible to estimate unsampled cardinalities in relevant cases. + 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%). + + This multiplicative rate is helpfully reflected in each signal's final `:sample-rate` value, making it possible to estimate *unsampled* cardinalities in relevant cases. So for `n` randomly sampled signals matching some criteria, you'd have seen an estimated `Σ(1.0/sample-rate_i)` such signals _without_ sampling, etc. @@ -117,7 +119,7 @@ Consider the [differences](https://www.youtube.com/watch?v=oyLBGkS5ICk) between Note that all user kvs will *also* be available *together* under the signal's `:kvs` key. - User kvs are a great way of controlling the per-signal behaviour of custom/advanced handlers. + User kvs are typically *not* included in handler output, so are a great way of providing custom data/opts for use (only) by custom middleware or handlers. - Signal `kind` can be useful in advanced cases. diff --git a/wiki/8-Community.md b/wiki/8-Community.md index b44b738..85cd696 100644 --- a/wiki/8-Community.md +++ b/wiki/8-Community.md @@ -4,7 +4,7 @@ If there's demand, additional stuff can then be authored by Telemere's *communit **PRs very welcome** to add links to this page for: -- Handlers (see [Writing handlers](./4-Handlers#writing-handlers)) +- Handler libraries or examples (see [Writing handlers](./4-Handlers#writing-handlers)) - Handler utils (formatters, etc.) - Middleware - Tutorials / demos / etc. @@ -12,9 +12,9 @@ If there's demand, additional stuff can then be authored by Telemere's *communit If you spot issues with any linked resources, please **contact the relevant authors** to let them know! Thank you! 🙏 -| Contributor | Link | Description | -| :--------------------------------------------- | :-------------------------------------------------------------------------- | :------------------------------------------------------------ | -| [@ptaoussanis](https://github.com/ptaoussanis) | [Official Slack channel](https://clojurians.slack.com/archives/C06ALA6EEUA) | For questions, support, etc. | -| [@ptaoussanis](https://github.com/ptaoussanis) | [GitHub issues](https://github.com/taoensso/telemere/issues) | For questions, support, bug reports, PRs, etc. | -| _ | _ | Your link here? [PRs](../wiki#contributions-welcome) welcome! | -| [@username](https://github.com/username) | [Project](https://github.com/username/project) | Short description of resource | +| Contributor | Link | Description | +| :--------------------------------------------- | :---------------------------------------------------------------- | :------------------------------------------------------------ | +| [@ptaoussanis](https://github.com/ptaoussanis) | [Official Slack channel](https://www.taoensso.com/telemere/slack) | For questions, support, etc. | +| [@ptaoussanis](https://github.com/ptaoussanis) | [GitHub issues](https://github.com/taoensso/telemere/issues) | For questions, support, bug reports, PRs, etc. | +| _ | _ | Your link here? [PRs](../wiki#contributions-welcome) welcome! | +| [@username](https://github.com/username) | [Project](https://github.com/username/project) | Short description of resource |