[nop] Housekeeping

This commit is contained in:
Peter Taoussanis 2024-05-05 14:15:09 +02:00
parent 19d447c44c
commit 0ff8dafaf3
13 changed files with 195 additions and 141 deletions

View file

@ -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

View file

@ -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. <https://github.com/example/some-lib>.
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

View file

@ -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"]

View file

@ -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"]]

View file

@ -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!`."

View file

@ -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. <https://github.com/binaryage/cljs-devtools>."
Ref. <https://github.com/binaryage/cljs-devtools>.
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

View file

@ -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`)

View file

@ -263,7 +263,7 @@
(enc/defonce ^:dynamic *sig-handlers* "?[<wrapped-handler-fn>]" 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.

View file

@ -191,9 +191,9 @@
Ref. <https://github.com/open-telemetry/opentelemetry-java>.
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`

View file

@ -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. <https://github.com/drewr/postal>.
Needs `postal`, Ref. <https://github.com/drewr/postal>.
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 <foo@example.com\", :to \"Bob <bar@example.com>\"},
@ -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. <https://github.com/drewr/postal> 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

View file

@ -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!

View file

@ -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)))
;; "<ns>:(<line>,<column>)"
;; "<ns>(<line>,<column>)"
(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` ∈ #{<unary-fn> :edn :json (Cljs only)}
See arglists for more.
Options:
`pr-fn` - ∈ #{<unary-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 {<opts>})
@ -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))

View file

@ -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. <https://github.com/example/some-lib>.
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.