From 0ff8dafaf3e37a17c5b0481c69dc48cca94abe84 Mon Sep 17 00:00:00 2001 From: Peter Taoussanis Date: Sun, 5 May 2024 14:15:09 +0200 Subject: [PATCH] [nop] Housekeeping --- README.md | 4 +- examples.cljc | 54 +++++++++----- project.clj | 2 +- shadow-cljs.edn | 2 +- src/taoensso/telemere.cljc | 24 ++++--- src/taoensso/telemere/consoles.cljc | 35 ++++----- src/taoensso/telemere/files.clj | 13 ++-- src/taoensso/telemere/impl.cljc | 6 +- src/taoensso/telemere/open_telemetry.clj | 6 +- src/taoensso/telemere/postal.clj | 28 ++++---- src/taoensso/telemere/sockets.clj | 18 +++-- src/taoensso/telemere/utils.cljc | 90 ++++++++++++++---------- wiki/4-Handlers.md | 54 +++++++++----- 13 files changed, 195 insertions(+), 141 deletions(-) diff --git a/README.md b/README.md index 734adf6..6323942 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ It helps enable Clojure/Script systems that are **observable**, **robust**, and ## Latest release/s -- `v1.0.0-beta7`: [release info](../../releases/tag/v1.0.0-beta7) +- `v1.0.0-beta7`: [release info](../../releases/tag/v1.0.0-beta7) (for early adopters) [![Main tests][Main tests SVG]][Main tests URL] [![Graal tests][Graal tests SVG]][Graal tests URL] @@ -32,7 +32,7 @@ See [here][GitHub releases] for earlier releases. - 1st-class **out-the-box interop** with [SLF4J v2](https://www.slf4j.org/), [clojure.tools.logging](https://github.com/clojure/tools.logging), [OpenTelemetry](https://opentelemetry.io/), and [Tufte](https://www.taoensso.com/tufte). - Included [shim](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere.timbre) for easy/gradual [migration from Timbre](../../wiki/5-Migrating). -- Included [handlers](../../wiki/4-Handlers#included-handlers) for consoles, files, email, Redis, Slack, TCP/UDP sockets, Logstash, etc. +- Included [handlers](../../wiki/4-Handlers#included-handlers) for consoles, files, email, Redis, Slack, sockets, and more. #### Scaling diff --git a/examples.cljc b/examples.cljc index 6fd3cb2..d442496 100644 --- a/examples.cljc +++ b/examples.cljc @@ -161,33 +161,49 @@ ;;; Writing handlers (defn handler:my-handler ; Note naming convention - "Returns a (fn handler [signal] that: - - Takes a Telemere signal. - - Does something with it. + "Needs `some-lib`, Ref. . + + Returns a (fn handler [signal] that: + - Takes a Telemere signal (map). + - Does something with the signal. Options: - `:option1` - Description - `:option2` - Description" + `:option1` - Option description + `:option2` - Option description - ([] (handler:my-handler nil)) ; Use default opts + Tips: + - Tip 1 + - Tip 2" + + ([] (handler:my-handler nil)) ; Use default opts (when defaults viable) ([{:as constructor-opts}] - ;; 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 [] + ;; Do option validation and other prep here, i.e. try to keep expensive work + ;; outside handler function when possible. - (fn a-handler:my-handler ; Note naming convention + (let [handler-fn + (fn a-handler:my-handler ; Note naming convention - ;; Shutdown arity - called by Telemere exactly once when the handler is - ;; to be shut down. This is your opportunity to finalize/free resources, etc. - ([]) + ;; Shutdown arity - called by Telemere exactly once when the handler + ;; 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] - ;; TODO Do something with given signal - ))))) + ;; Main arity - called by Telemere whenever the handler should handle + ;; the given signal. Never called after shutdown. + ([signal] + ;; Do something with given signal (write to console/file/queue/db, etc.). + ;; Return value is ignored. + )) + + ;; (Advanced) optional default handler dispatch opts, + ;; see `add-handler!` for full list of possible opts + default-dispatch-opts + {:min-level :info + :rate-limit [[1 (enc/msecs :min 1)]]}] + + (with-meta handler-fn default-dispatch-opts)))) ;;; Message building diff --git a/project.clj b/project.clj index 4b921db..b69f4c6 100644 --- a/project.clj +++ b/project.clj @@ -8,7 +8,7 @@ :url "https://www.eclipse.org/legal/epl-v10.html"} :dependencies - [[com.taoensso/encore "3.107.0"]] + [[com.taoensso/encore "3.108.0"]] :test-paths ["test" #_"src"] diff --git a/shadow-cljs.edn b/shadow-cljs.edn index 6c2ee88..99f6265 100644 --- a/shadow-cljs.edn +++ b/shadow-cljs.edn @@ -1,7 +1,7 @@ {;;:lein true :source-paths ["src" "test"] :dependencies - [[com.taoensso/encore "3.107.0"] + [[com.taoensso/encore "3.108.0"] [cider/cider-nrepl "0.47.0"] [binaryage/devtools "1.0.7"]] diff --git a/src/taoensso/telemere.cljc b/src/taoensso/telemere.cljc index d81d2a0..d9dea29 100644 --- a/src/taoensso/telemere.cljc +++ b/src/taoensso/telemere.cljc @@ -32,7 +32,7 @@ (remove-ns 'taoensso.telemere) (:api (enc/interns-overview))) -(enc/assert-min-encore-version [3 107 0]) +(enc/assert-min-encore-version [3 108 0]) ;;;; TODO ;; - Add handlers: Logstash, Slack, Carmine, Datadog, Kafka @@ -66,6 +66,7 @@ ;;;; Aliases (enc/defaliases + ;; Encore #?(:clj enc/set-var-root!) #?(:clj enc/update-var-root!) #?(:clj enc/get-env) @@ -74,23 +75,26 @@ enc/newline enc/comp-middleware + ;; Impl impl/msg-splice impl/msg-skip #?(:clj impl/with-signal) #?(:clj impl/with-signals) #?(:clj impl/signal!) - utils/error-signal? + + ;; Utils + utils/format-signal-fn utils/pr-signal-fn - utils/format-signal-fn) + utils/error-signal?) ;;;; Help -(impl/defhelp help:signal-creators :signal-creators) -(impl/defhelp help:signal-options :signal-options) -(impl/defhelp help:signal-flow :signal-flow) -(impl/defhelp help:signal-content :signal-content) -(enc/defalias help:signal-filters help:filters) ; Via Encore -(enc/defalias help:signal-handlers help:handlers) ; Via Encore +(impl/defhelp help:signal-creators :signal-creators) +(impl/defhelp help:signal-options :signal-options) +(impl/defhelp help:signal-flow :signal-flow) +(impl/defhelp help:signal-content :signal-content) +(enc/defalias help:signal-filters help:filters) ; Via Encore +(enc/defalias help:signal-handlers help:handlers) ; Via Encore ;;;; Context @@ -151,7 +155,7 @@ "Optional (fn [signal]) => ?modified-signal to apply (once) when signal is created. When middleware returns nil, skips all handlers. - Compose multiple middleware fns together with `comp-middleware. + Compose multiple middleware fns together with `comp-middleware`. Re/bind dynamic value using `with-middleware`, `binding`. Modify root (base) value using `set-middleware!`." diff --git a/src/taoensso/telemere/consoles.cljc b/src/taoensso/telemere/consoles.cljc index 6ef76dd..bf29895 100644 --- a/src/taoensso/telemere/consoles.cljc +++ b/src/taoensso/telemere/consoles.cljc @@ -14,17 +14,17 @@ #?(:clj (defn ^:public handler:console - "Experimental, subject to change. Feedback welcome! + "Experimental, subject to change. Returns a (fn handler [signal]) that: - - Takes a Telemere signal. - - Writes formatted signal string to stream. + - Takes a Telemere signal (map). + - Writes the signal as a string to specified stream. A general-purpose `println`-style handler that's well suited for outputting - signals formatted as edn, JSON, or human-readable strings. + signals as human or machine-readable (edn, JSON) strings. Options: - `:output-fn` - (fn [signal]) => output string, see `format-signal-fn` or `pr-signal-fn` + `:output-fn` - (fn [signal]) => string, see `format-signal-fn` or `pr-signal-fn` `:stream` - `java.io.writer` Defaults to `*err*` if `utils/error-signal?` is true, and `*out*` otherwise." @@ -46,17 +46,17 @@ :cljs (defn ^:public handler:console - "Experimental, subject to change. Feedback welcome! + "Experimental, subject to change. If `js/console` exists, returns a (fn handler [signal]) that: - - Takes a Telemere signal. - - Writes formatted signal string to JavaScript console. + - Takes a Telemere signal (map). + - Writes the signal as a string to JavaScript console. A general-purpose `println`-style handler that's well suited for outputting - signals formatted as edn, JSON, or human-readable strings. + signals as human or machine-readable (edn, JSON) strings. Options: - `:output-fn` - (fn [signal]) => output string, see `format-signal-fn` or `pr-signal-fn`" + `:output-fn` - (fn [signal]) => string, see `format-signal-fn` or `pr-signal-fn`" ([] (handler:console nil)) ([{:keys [output-fn] @@ -83,21 +83,24 @@ #?(:cljs (defn ^:public handler:console-raw - "Experimental, subject to change. Feedback welcome! + "Experimental, subject to change. If `js/console` exists, returns a (fn handler [signal]) that: - - Takes a Telemere signal. - - Writes raw signal data to JavaScript console. + - Takes a Telemere signal (map). + - Writes the raw signal to JavaScript console. Intended for use with browser formatting tools like `binaryage/devtools`, - Ref. ." + Ref. . + + Options: + `:preamble-fn` - (fn [signal]) => string. + `:format-nsecs-fn` - (fn [nanosecs]) => string." ([] (handler:console-raw nil)) ([{:keys [preamble-fn format-nsecs-fn] :as opts :or {preamble-fn (utils/signal-preamble-fn) - format-nsecs-fn (utils/format-nsecs-fn) ; (fn [nanosecs]) - }}] + format-nsecs-fn (utils/format-nsecs-fn)}}] (when (and (exists? js/console) (exists? js/console.group)) (let [js-console-logger utils/js-console-logger diff --git a/src/taoensso/telemere/files.clj b/src/taoensso/telemere/files.clj index 9c39125..770c45d 100644 --- a/src/taoensso/telemere/files.clj +++ b/src/taoensso/telemere/files.clj @@ -266,17 +266,18 @@ ;;;; Handler (defn ^:public handler:file - "Experimental, subject to change. Feedback welcome! + "Experimental, subject to change. - Returns a (fn handler [signal]) that: - - Takes a Telemere signal. - - Writes formatted signal string to file. + Returns a (fn handler [signal]) that: + - Takes a Telemere signal (map). + - Writes (appends) the signal as a string to file specified by `path`. - Signals will be appended to file specified by `path`. Depending on options, archives may be maintained: - `logs/app.log.n.gz` (for nil `:interval`, non-nil `:max-file-size`) - `logs/app.log-YYYY-MM-DDd.n.gz` (for non-nil `:interval`) ; d=daily/w=weekly/m=monthly + Can output signals as human or machine-readable (edn, JSON) strings. + Example files with default options: `/logs/telemere.log` ; Current file `/logs/telemere.log-2020-01-01m.1.gz` ; Archive for Jan 2020, part 1 (newest entries) @@ -284,7 +285,7 @@ `/logs/telemere.log-2020-01-01m.8.gz` ; Archive for Jan 2020, part 8 (oldest entries) Options: - `:output-fn`- (fn [signal]) => output string, see `format-signal-fn` or `pr-signal-fn` + `:output-fn`- (fn [signal]) => string, see `format-signal-fn` or `pr-signal-fn` `:path` - Path string of the target output file (default `logs/telemere.log`) `:interval` - ∈ #{nil :daily :weekly :monthly} (default `:monthly`) diff --git a/src/taoensso/telemere/impl.cljc b/src/taoensso/telemere/impl.cljc index 60b3cb0..30159b7 100644 --- a/src/taoensso/telemere/impl.cljc +++ b/src/taoensso/telemere/impl.cljc @@ -263,7 +263,7 @@ (enc/defonce ^:dynamic *sig-handlers* "?[]" nil) (defn force-msg-in-sig [sig] - (if-not (map? sig) + (if-not (map? sig) sig (if-let [e (find sig :msg_)] (assoc sig :msg_ (force (val e))) @@ -276,11 +276,11 @@ Useful for tests/debugging. Options: - `trap-signals?` (default: false) + `trap-signals?` (default false) Should ALL signals created by form be trapped to prevent normal dispatch to registered handlers? - `raw-msg?` (default: false) + `raw-msg?` (default false) Should delayed `:msg_` in returned signal be retained as-is? Delay is otherwise replaced by realized string. diff --git a/src/taoensso/telemere/open_telemetry.clj b/src/taoensso/telemere/open_telemetry.clj index b614307..b5e0bb8 100644 --- a/src/taoensso/telemere/open_telemetry.clj +++ b/src/taoensso/telemere/open_telemetry.clj @@ -191,9 +191,9 @@ Ref. . Returns a (fn handler [signal]) that: - - Takes a Telemere signal. - - Emits signal content to the `io.opentelemetry.api.logs.Logger` - returned by given `io.opentelemetry.api.logs.LoggerProvider`. + - Takes a Telemere signal (map). + - Emits the signal to `io.opentelemetry.api.logs.Logger` returned + by given `io.opentelemetry.api.logs.LoggerProvider`. Options: `:logger-provider` - `io.opentelemetry.api.logs.LoggerProvider` diff --git a/src/taoensso/telemere/postal.clj b/src/taoensso/telemere/postal.clj index f7398c7..b5c0173 100644 --- a/src/taoensso/telemere/postal.clj +++ b/src/taoensso/telemere/postal.clj @@ -16,8 +16,8 @@ (defn signal-subject-fn "Experimental, subject to change. Returns a (fn format [signal]) that: - - Takes a Telemere signal. - - Returns a formatted email subject like: + - Takes a Telemere signal (map). + - Returns an email subject string like: \"INFO EVENT :taoensso.telemere.postal/ev-id1 - msg\"" ([] (signal-subject-fn nil)) ([{:keys [max-len subject-signal-key] @@ -46,14 +46,13 @@ ;;;; Handler (defn handler:postal - "Experimental, subject to change. Feedback welcome! + "Experimental, subject to change. - Needs `postal`, - Ref. . + Needs `postal`, Ref. . Returns a (fn handler [signal]) that: - - Takes a Telemere signal. - - Sends formatted signal string as email to specified recipient. + - Takes a Telemere signal (map). + - Sends the signal as an email to specified recipient. Useful for emailing important alerts to admins, etc. @@ -61,15 +60,14 @@ See tips section re: protecting against unexpected costs. Options: - - `:postal/conn-opts` - Map of connection opts provided to `postal` + `:postal/conn-opts` - Map of connection opts given to `postal/send-message` Examples: {:host \"mail.isp.net\", :user \"jsmith\", :pass \"a-secret\"}, {:host \"smtp.gmail.com\", :user \"jsmith@gmail.com\", :pass \"a-secret\" :port 587 :tls true}, {:host \"email-smtp.us-east-1.amazonaws.com\", :port 587, :tls true :user \"AKIAIDTP........\" :pass \"AikCFhx1P.......\"} - `:postal/msg-opts` - Map of message options + `:postal/msg-opts` - Map of message options given to `postal/send-message` Examples: {:from \"foo@example.com\", :to \"bar@example.com\"}, {:from \"Alice \"}, @@ -79,10 +77,10 @@ :X-MyHeader \"A custom header\"} `:subject-fn` - (fn [signal]) => email subject string - `:body-fn` - (fn [signal]) => email body content string, see `format-signal-fn` or `pr-signal-fn` + `:body-fn` - (fn [signal]) => email body content string, + see `format-signal-fn` or `pr-signal-fn` Tips: - - Sending emails can incur financial costs! Use appropriate dispatch filtering options when calling `add-handler!` to prevent handler from sending unnecessary emails! @@ -101,7 +99,7 @@ - Ref. for more info on `postal` options." - ([] (handler:postal nil)) + ;; ([] (handler:postal nil)) ([{:keys [postal/conn-opts postal/msg-opts @@ -112,8 +110,8 @@ {subject-fn (signal-subject-fn) body-fn (utils/format-signal-fn)}}] - (when-not conn-opts (throw (ex-info "No `:postal/conn-opts` was provided" {}))) - (when-not msg-opts (throw (ex-info "No `:postal/msg-opts` was provided" {}))) + (when-not conn-opts (throw (ex-info "No `:postal/conn-opts` was given" {}))) + (when-not msg-opts (throw (ex-info "No `:postal/msg-opts` was given" {}))) (let [] (defn a-handler:postal diff --git a/src/taoensso/telemere/sockets.clj b/src/taoensso/telemere/sockets.clj index feaedaf..e8328b9 100644 --- a/src/taoensso/telemere/sockets.clj +++ b/src/taoensso/telemere/sockets.clj @@ -19,18 +19,20 @@ ;;;; Handlers (defn handler:tcp-socket - "Experimental, subject to change. Feedback welcome! + "Experimental, subject to change. Returns a (fn handler [signal]) that: - - Takes a Telemere signal. - - Sends formatted signal string to specified TCP socket. + - Takes a Telemere signal (map). + - Sends the signal as a string to specified TCP socket. + + Can output signals as human or machine-readable (edn, JSON) strings. Options: `host` - Destination TCP socket hostname string `port` - Destination TCP socket port int `:socket-opts` - {:keys [ssl? connect-timeout-msecs]} - `:output-fn` - (fn [signal]) => output string, see `format-signal-fn` or `pr-signal-fn` + `:output-fn` - (fn [signal]) => string, see `format-signal-fn` or `pr-signal-fn` Limitations: - Failed writes will be retried only once. @@ -53,14 +55,16 @@ "Experimental, subject to change. Feedback welcome! Returns a (fn handler [signal]) that: - - Takes a Telemere signal. - - Sends formatted signal string to specified UDP socket. + - Takes a Telemere signal (map). + - Sends the signal as a string to specified UDP socket. + + Can output signals as human or machine-readable (edn, JSON) strings. Options: `host` - Destination UDP socket hostname string `port` - Destination UDP socket port int - `:output-fn` - (fn [signal]) => output string, see `format-signal-fn` or `pr-signal-fn` + `:output-fn` - (fn [signal]) => string, see `format-signal-fn` or `pr-signal-fn` `:max-packet-bytes` - Max packet size (in bytes) before truncating output (default 512) `:truncation-warning-fn` - Optional (fn [{:keys [max actual signal]}]) to call whenever output is truncated. Should be appropriately rate-limited! diff --git a/src/taoensso/telemere/utils.cljc b/src/taoensso/telemere/utils.cljc index 4e2c125..fe30473 100644 --- a/src/taoensso/telemere/utils.cljc +++ b/src/taoensso/telemere/utils.cljc @@ -127,7 +127,7 @@ (comment (error-in-signal->maps {:level :info :error (ex-info "Ex" {})})) (defn remove-kvs - "Returns the given signal without user-level kvs." + "Returns given signal without user-level kvs." [signal] (if-let [kvs (get signal :kvs)] (reduce-kv (fn [m k _v] (dissoc m k)) (dissoc signal :kvs) kvs) @@ -137,7 +137,7 @@ (defn minify-signal "Experimental, subject to change. - Returns minimal signal map, removing: + Returns minimal signal, removing: - Keys with nil values, and - Keys with redundant values (`:kvs`, `:location`, `:file`). @@ -186,14 +186,13 @@ #?(:clj (defn ^:no-doc file-stream "Private, don't use. - Returns a new `java.io.FileOutputStream` for given `java.io.File`, etc." + Returns new `java.io.FileOutputStream` for given `java.io.File`." ^java.io.FileOutputStream [file append?] (java.io.FileOutputStream. (as-file file) (boolean append?)))) #?(:clj (defn file-writer - "Experimental, subject to change. Feedback welcome! - + "Experimental, subject to change. Opens the specified file and returns a stateful fn of 2 arities: [content] => Writes given content to file, or no-ops if closed. [] => Closes the writer. @@ -286,27 +285,26 @@ #?(:clj (defn tcp-socket-writer - "Experimental, subject to change. Feedback welcome! + "Experimental, subject to change. + Connects to specified TCP socket and returns a stateful fn of 2 arities: + [content] => Writes given content to socket, or no-ops if closed. + [] => Closes the writer. - Connects to specified TCP socket and returns a stateful fn of 2 arities: - [content] => Writes given content to socket, or no-ops if closed. - [] => 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. + Options: + `:ssl?` - Use SSL/TLS? + `:connect-timeout-msecs` - Connection timeout (default 3000 msecs) + `:socket-fn` - (fn [host port timeout]) => `java.net.Socket` + `:ssl-socket-fn` - (fn [socket host port]) => `java.net.Socket` - Options: - `:ssl?` - Use SSL/TLS? - `:connect-timeout-msecs` - Connection timeout (default 3000 msecs) - `:socket-fn` - (fn [host port timeout]) => `java.net.Socket` - `:ssl-socket-fn` - (fn [socket host port]) => `java.net.Socket` - - Notes: - - Writer should be manually closed after use (with zero-arity call). - - Flushes after every write. - - Will retry failed writes once, then drop. - - Thread safe, locks on single socket stream. - - Advanced users may want a custom implementation using a connection - pool and/or more sophisticated retry semantics, etc." + Notes: + - Writer should be manually closed after use (with zero-arity call). + - Flushes after every write. + - Will retry failed writes once, then drop. + - Thread safe, locks on single socket stream. + - Advanced users may want a custom implementation using a connection + pool and/or more sophisticated retry semantics, etc." [host port {:keys @@ -394,7 +392,7 @@ "Experimental, subject to change. Returns a (fn format [nanosecs]) that: - Takes a long nanoseconds (e.g. runtime). - - Returns a formatted human-readable string like: + - Returns a human-readable string like: \"1.00m\", \"4.20s\", \"340ms\", \"822μs\", etc." ([] (format-nsecs-fn nil)) ([{:as _opts}] (fn format-nsecs [nanosecs] (enc/format-nsecs nanosecs)))) @@ -421,7 +419,7 @@ "Experimental, subject to change. Returns a (fn format [error]) that: - Takes a platform error (`Throwable` or `js/Error`). - - Returns a formatted human-readable string" + - Returns a human-readable error string." ([] (format-error-fn nil)) ([{:as _opts}] (let [nl enc/newline @@ -457,11 +455,12 @@ (defn signal-preamble-fn "Experimental, subject to change. Returns a (fn preamble [signal]) that: - - Takes a Telemere signal. + - Takes a Telemere signal (map). - Returns a signal preamble ?string like: \"2024-03-26T11:14:51.806Z INFO EVENT Hostname taoensso.telemere(2,21) ::ev-id - msg\" - See arglists for options." + Options: + `:format-inst-fn` - (fn format [instant]) => string." ([] (signal-preamble-fn nil)) ([{:keys [format-inst-fn] :or {format-inst-fn (format-inst-fn)}}] @@ -477,7 +476,7 @@ (if kind (s+spc (upper-qn kind)) (s+spc "DEFAULT")) #?(:clj (s+spc (hostname))) - ;; ":(,)" + ;; "(,)" (when-let [base (or ns (get signal :file))] (let [s+ (partial enc/sb-append sb)] ; Without separator (s+ " " base) @@ -497,10 +496,16 @@ (defn signal-content-fn "Experimental, subject to change. Returns a (fn content [signal]) that: - - Takes a Telemere signal. - - Returns a signal content ?string (incl. data, ctx, etc.) + - Takes a Telemere signal (map). + - Returns a signal content ?string (incl. data, ctx, etc.). + + Options: + `:incl-thread?` - Include signal `:thread` info? (default false) + `:incl-kvs?` - Include signal `:kvs` info? (default false) + `:raw-error?` - Retain unformatted error? (default false) + `:format-nsecs-fn` - (fn [nanosecs]) => string. + `:format-error-fn` - (fn [error]) => string." - See arglists for options." ([] (signal-content-fn nil)) ([{:keys [incl-thread? incl-kvs? raw-error?, @@ -566,13 +571,15 @@ (defn pr-signal-fn "Experimental, subject to change. - Returns a (fn pr-signal [signal]) that: - - Takes a Telemere signal. - - Returns machine-readable serialized string of the (minified) signal. + Returns a (fn pr [signal]) that: + - Takes a Telemere signal (map). + - Returns a machine-readable (minified) signal string. - Options include: - `pr-fn` ∈ #{ :edn :json (Cljs only)} - See arglists for more. + Options: + `pr-fn` - ∈ #{ :edn :json (Cljs only)} + `:incl-thread?` - Include signal `:thread` info? (default false) + `:incl-kvs?` - Include signal `:kvs` info? (default false) + `:incl-newline?` - Include terminating system newline? (default true) Examples: (pr-signal-fn :edn {}) @@ -627,8 +634,13 @@ (defn format-signal-fn "Experimental, subject to change. Returns a (fn format [signal]) that: - - Takes a Telemere signal. - - Returns human-readable formatted string. + - Takes a Telemere signal (map). + - Returns a human-readable signal string. + + Options: + `:incl-newline?` - Include terminating system newline? (default true) + `:preamble-fn` - (fn [signal]) => signal preamble string. + `:content-fn` - (fn [signal]) => signal content string. See also `pr-signal-fn` for machine-readable output." ([] (format-signal-fn nil)) diff --git a/wiki/4-Handlers.md b/wiki/4-Handlers.md index 14afd27..9434445 100644 --- a/wiki/4-Handlers.md +++ b/wiki/4-Handlers.md @@ -153,33 +153,49 @@ 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: - - Takes a Telemere signal. - - Does something with it. + "Needs `some-lib`, Ref. . + + Returns a (fn handler [signal] that: + - Takes a Telemere signal (map). + - Does something with the signal. Options: - `:option1` - Description - `:option2` - Description" + `:option1` - Option description + `:option2` - Option description - ([] (handler:my-handler nil)) ; Use default opts + Tips: + - Tip 1 + - Tip 2" + + ([] (handler:my-handler nil)) ; Use default opts (when defaults viable) ([{:as constructor-opts}] - ;; 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 [] + ;; Do option validation and other prep here, i.e. try to keep expensive work + ;; outside handler function when possible. - (fn a-handler:my-handler ; Note naming convention + (let [handler-fn + (fn a-handler:my-handler ; Note naming convention - ;; Shutdown arity - called by Telemere exactly once when the handler is - ;; to be shut down. This is your opportunity to finalize/free resources, etc. - ([]) + ;; Shutdown arity - called by Telemere exactly once when the handler + ;; 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] - ;; TODO Do something with given signal - ))))) + ;; Main arity - called by Telemere whenever the handler should handle + ;; the given signal. Never called after shutdown. + ([signal] + ;; Do something with given signal (write to console/file/queue/db, etc.). + ;; Return value is ignored. + )) + + ;; (Advanced) optional default handler dispatch opts, + ;; see `add-handler!` for full list of possible opts + default-dispatch-opts + {:min-level :info + :rate-limit [[1 (enc/msecs :min 1)]]}] + + (with-meta handler-fn default-dispatch-opts)))) ``` - See [`help:signal-content`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#help:signal-content) for signal map content.