diff --git a/README.md b/README.md
index a8a5afe..b7f0601 100644
--- a/README.md
+++ b/README.md
@@ -1,5 +1,5 @@
-[**Documentation**](#documentation) | [Latest releases](#latest-releases) | [Slack channel][]
+[**API**][cljdoc docs] | [**Wiki**][GitHub wiki] | [Latest releases](#latest-releases) | [Slack channel][]
#
@@ -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, sockets, and more.
+- Extensive set of [handlers](../../wiki/4-Handlers#included-handlers) included out-the-box.
#### Scaling
@@ -61,7 +61,11 @@ See for intro and usage:
```clojure
(require '[taoensso.telemere :as t])
-;; Start simple
+(t/log! {:id ::my-id, :data {:x1 :x2}} "My message") %>
+
+;; 2024-04-11T10:54:57.202869Z INFO LOG Schrebermann.local examples(56,1) ::my-id - My message
+;; data: {:x1 :x2}
+
(t/log! "This will send a `:log` signal to the Clj/s console")
(t/log! :info "This will do the same, but only when the current level is >= `:info`")
@@ -142,48 +146,30 @@ See relevant docstrings (links below) for usage info-
| [`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 |
-### Example handler output
+### Included handlers
-```clojure
-(t/log! {:id ::my-id, :data {:x1 :x2}} "My message") =>
-```
+See linked docstrings below for features and usage:
-#### Clj console handler
+| 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*` | [edn/JSON](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#pr-signal-fn) or [human-readable](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#format-signal-fn) |
+| [`handler:console`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#handler:console) | Cljs | Browser console | [edn/JSON](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#pr-signal-fn) or [human-readable](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#format-signal-fn) |
+| [`handler:console-raw`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#handler:console-raw) | Cljs | Browser console | Raw signals 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 | [edn/JSON](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#pr-signal-fn) or [human-readable](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#format-signal-fn) |
+| [`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/) |
+| [`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)) | [edn/JSON](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#pr-signal-fn) or [human-readable](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#format-signal-fn) |
+| [`handler:slack`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere.slack#handler:slack) | Clj | [Slack](https://slack.com/) (via [clj-slack](https://github.com/julienXX/clj-slack)) | [edn/JSON](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#pr-signal-fn) or [human-readable](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#format-signal-fn) |
+| [`handler:tcp-socket`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere.sockets#handler:tcp-socket) | Clj | TCP socket | [edn/JSON](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#pr-signal-fn) or [human-readable](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#format-signal-fn) |
+| [`handler:udp-socket`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere.sockets#handler:udp-socket) | Clj | UDP socket | [edn/JSON](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#pr-signal-fn) or [human-readable](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#format-signal-fn) |
-String output:
-
-```
-2024-04-11T10:54:57.202869Z INFO LOG Schrebermann.local examples(56,1) ::my-id - My message
- data: {:x1 :x2}
-```
-
-#### Cljs console handler
-
-Chrome console:
-
-
-
-#### Cljs raw console handler
-
-Chrome console, with [cljs-devtools](https://github.com/binaryage/cljs-devtools):
-
-
-
-#### Clj file handler
-
-MacOS terminal:
-
-
+See [here](../../wiki/4-Handlers) for more/upcoming handlers, community handlers, info on **writing your own handlers**, etc.
## Documentation
- [Wiki][GitHub wiki] (getting started, usage, etc.)
- API reference: [cljdoc][cljdoc docs] or [Codox][Codox docs]
- Support: [Slack channel][] or [GitHub issues][]
-
-## Observability tips
-
-See [here](../../wiki/7-Tips) for general advice re: building and maintaining observable Clojure/Script systems.
+- [General observability tips](../../wiki/7-Tips) (advice on building and maintaining observable Clojure/Script systems, and getting the most out of Telemere)
## Benchmarks
diff --git a/project.clj b/project.clj
index 7bb6725..f9b7afd 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.108.0"]]
+ [[com.taoensso/encore "3.109.0"]]
:test-paths ["test" #_"src"]
diff --git a/shadow-cljs.edn b/shadow-cljs.edn
index 99f6265..fe40890 100644
--- a/shadow-cljs.edn
+++ b/shadow-cljs.edn
@@ -1,7 +1,7 @@
{;;:lein true
:source-paths ["src" "test"]
:dependencies
- [[com.taoensso/encore "3.108.0"]
+ [[com.taoensso/encore "3.109.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 5b83061..b9cc9e0 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 108 0])
+(enc/assert-min-encore-version [3 109 0])
;;;; TODO
;; - Add handlers: Logstash, Carmine, Datadog, Kafka
diff --git a/src/taoensso/telemere/utils.cljc b/src/taoensso/telemere/utils.cljc
index 555992b..2f8edbc 100644
--- a/src/taoensso/telemere/utils.cljc
+++ b/src/taoensso/telemere/utils.cljc
@@ -112,58 +112,40 @@
(comment (error-signal? {:level :fatal}))
-(defn error-in-signal->maps
- "Experimental, subject to change.
- Returns given signal with possible `:error` replaced by
- [{:keys [type msg data]} ...] cause chain.
-
- Useful when serializing signals to edn/JSON/etc."
- [signal]
- (enc/if-let [error (get signal :error)
- chain (enc/ex-chain :as-map error)]
- (assoc signal :error chain)
- (do signal)))
-
-(comment (error-in-signal->maps {:level :info :error (ex-info "Ex" {})}))
-
-(defn remove-kvs
- "Returns given signal without user-level kvs."
+(defn ^:no-doc remove-signal-kvs
+ "Private, don't use.
+ Returns given signal without user-level kvs or `:kvs` key."
[signal]
(if-let [kvs (get signal :kvs)]
(reduce-kv (fn [m k _v] (dissoc m k)) (dissoc signal :kvs) kvs)
signal))
-(comment (remove-kvs {:a :A, :b :B, :kvs {:a :A}}))
-
-(defn minify-signal
- "Experimental, subject to change.
- Returns minimal signal, removing:
- - Keys with nil values, and
- - Keys with redundant values (`:kvs`, `:location`, `:file`).
-
- Useful when serializing signals to edn/JSON/etc."
-
- ;; Note that while handlers typically don't include user-level kvs, we
- ;; DO retain these here since signal serialization often implies transit
- ;; to some other system that may still need/want this info before final
- ;; processing/storage/etc.
-
+(defn ^:no-doc remove-signal-nils
+ "Private, don't use.
+ Returns given signal with nil-valued keys removed."
[signal]
- (reduce-kv
- (fn [m k v]
- (if (nil? v)
- m
- (case k
- (:kvs :location :file) m
- (assoc m k v))))
- nil signal))
-
-(comment
- (minify-signal (tel/with-signal (tel/event! ::ev-id1)))
- (let [s (tel/with-signal (tel/event! ::ev-id1))]
- (enc/qb 1e6 ; 683
- (minify-signal s))))
-
+ (if (enc/editable? signal)
+ (persistent! (reduce-kv (fn [m k v] (if (nil? v) (dissoc! m k) m)) (transient signal) signal))
+ (persistent! (reduce-kv (fn [m k v] (if (nil? v) m (assoc! m k v))) (transient {}) signal))))
+
+(defn ^:no-doc force-signal-msg
+ "Private, don't use.
+ Returns given signal with possible `:msg_` value forced (realized when a delay)."
+ [signal]
+ (if-let [msg_ (get signal :msg_)]
+ (assoc signal :msg_ (force msg_))
+ (do signal)))
+
+(defn ^:no-doc expand-signal-error
+ "Private, don't use.
+ Returns given signal with possible `:error` replaced by
+ [{:keys [type msg data]} ...] cause chain."
+ [signal]
+ (enc/if-let [error (get signal :error)
+ chain (enc/ex-chain :as-map error)]
+ (assoc signal :error chain)
+ (do signal)))
+
;;;; Files
#?(:clj (defn ^:no-doc as-file ^java.io.File [file] (jio/as-file file)))
@@ -604,8 +586,8 @@
{incl-newline? true
pr-fn :edn
prep-fn
- (comp error-in-signal->maps
- minify-signal)}}]
+ (comp expand-signal-error
+ remove-signal-nils)}}]
(let [nl newline
pr-fn
diff --git a/test/taoensso/telemere_tests.cljc b/test/taoensso/telemere_tests.cljc
index 9ed4056..a15133f 100644
--- a/test/taoensso/telemere_tests.cljc
+++ b/test/taoensso/telemere_tests.cljc
@@ -641,6 +641,14 @@
(is (= (utils/error-signal? {:level :fatal}) true))
(is (= (utils/error-signal? {:error? true}) true))])
+ (testing "Misc utils"
+ [(is (= (utils/remove-signal-kvs {:a :A, :b :B, :kvs {:b :B}}) {:a :A}))
+ (is (= (utils/remove-signal-nils {:a :A, :b nil}) {:a :A}))
+ (is (= (utils/force-signal-msg {:a :A, :msg_ (delay "msg")}) {:a :A, :msg_ "msg"}))
+ (is (= (utils/expand-signal-error {:level :info, :error ex2})
+ {:level :info, :error [{:type ex-info-type, :msg "Ex2", :data {:k2 "v2"}}
+ {:type ex-info-type, :msg "Ex1", :data {:k1 "v1"}}]}))])
+
#?(:clj
(testing "File writer"
(let [f (java.io.File/createTempFile "file-writer-test" ".txt")
@@ -662,12 +670,7 @@
(is (true? (.delete f)))])))
(testing "Formatters, etc."
- [(is (= (utils/error-in-signal->maps {:level :info, :error ex2})
- {:level :info, :error [{:type ex-info-type, :msg "Ex2", :data {:k2 "v2"}}
- {:type ex-info-type, :msg "Ex1", :data {:k1 "v1"}}]}))
-
- (is (= (utils/minify-signal {:level :info, :location {:ns "ns"}, :file "file"}) {:level :info}))
- (is (= ((utils/format-nsecs-fn) 1.5e9) "1.50s")) ; More tests in Encore
+ [(is (= ((utils/format-nsecs-fn) 1.5e9) "1.50s")) ; More tests in Encore
(is (= ((utils/format-inst-fn) t0) "2024-06-09T21:15:20.170Z"))
(testing "format-error-fn"
@@ -680,47 +683,47 @@
(is (enc/str-contains? ex2-str "invoke") "Root stack trace includes content")]))
(testing "signal-preamble-fn"
- (let [sig (with-sig (tel/event! ::ev-id {:inst t0}))
+ (let [sig (with-sig :raw :trap (tel/event! ::ev-id {:inst t0, :msg ["a" "b"]}))
preamble ((utils/signal-preamble-fn) sig)] ; "2024-06-09T21:15:20.170Z INFO EVENT taoensso.telemere-tests(592,35) ::ev-id"
[(is (enc/str-starts-with? preamble "2024-06-09T21:15:20.170Z INFO EVENT"))
- (is (enc/str-ends-with? preamble "::ev-id"))
+ (is (enc/str-ends-with? preamble "::ev-id - a b"))
(is (string? (re-find #"taoensso.telemere-tests\(\d+,\d+\)" preamble)))]))
(testing "pr-signal-fn"
(let [sig (with-sig (tel/event! ::ev-id {:inst t0}))]
- [(testing ":edn"
- (let [sig (update sig :inst enc/inst->udt)
- sig*1 (enc/read-edn ((tel/pr-signal-fn {:pr-fn :edn}) sig))
- sig*2 (enc/read-edn ((tel/pr-signal-fn) sig))]
+ [(testing ":edn"
+ (let [sig (update sig :inst enc/inst->udt)
+ sig*1 (enc/read-edn ((tel/pr-signal-fn {:pr-fn :edn}) sig))
+ sig*2 (enc/read-edn ((tel/pr-signal-fn) sig))]
- [(is (= sig*1 sig*2) "Default :pr-fn is :edn")
- (is
- (enc/submap? sig*1
- {:schema 1, :kind :event, :id ::ev-id, :level :info,
- :ns "taoensso.telemere-tests"
- :inst udt0
- :line pnat-int?
- :column pnat-int?}))]))
+ [(is (= sig*1 sig*2) "Default :pr-fn is :edn")
+ (is
+ (enc/submap? sig*1
+ {:schema 1, :kind :event, :id ::ev-id, :level :info,
+ :ns "taoensso.telemere-tests"
+ :inst udt0
+ :line pnat-int?
+ :column pnat-int?}))]))
- #?(:cljs
- (testing ":json"
- (let [sig* (enc/read-json ((tel/pr-signal-fn {:pr-fn :json}) sig))]
- (is
- (enc/submap? sig*
- {"schema" 1, "kind" "event", "id" "taoensso.telemere-tests/ev-id",
- "level" "info", "ns" "taoensso.telemere-tests",
- "inst" t0s
- "line" pnat-int?
- "column" pnat-int?})))))
+ #?(:cljs
+ (testing ":json"
+ (let [sig* (enc/read-json ((tel/pr-signal-fn {:pr-fn :json}) sig))]
+ (is
+ (enc/submap? sig*
+ {"schema" 1, "kind" "event", "id" "taoensso.telemere-tests/ev-id",
+ "level" "info", "ns" "taoensso.telemere-tests"
+ "inst" t0s
+ "line" pnat-int?
+ "column" pnat-int?})))))
- (testing "user fn"
- (is (= ((tel/pr-signal-fn {:pr-fn (fn [_] "str")}) sig) (str "str" utils/newline))))]))
+ (testing "user fn"
+ (is (= ((tel/pr-signal-fn {:pr-fn (fn [_] "str")}) sig) (str "str" utils/newline))))]))
(testing "format-signal-fn"
- (let [sig (with-sig (tel/event! ::ev-id {:inst t0}))]
- (is (enc/str-starts-with? ((tel/format-signal-fn) sig)
- "2024-06-09T21:15:20.170Z INFO EVENT"))))])])
+ (let [sig (with-sig :raw :trap (tel/event! ::ev-id {:inst t0, :msg ["a" "b"]}))]
+ (is (enc/str-starts-with? ((tel/format-signal-fn) sig) "2024-06-09T21:15:20.170Z INFO EVENT"))
+ (is (enc/str-ends-with? ((tel/format-signal-fn) sig) "::ev-id - a b\n"))))])])
;;;; File handler
diff --git a/wiki/4-Handlers.md b/wiki/4-Handlers.md
index 897d73a..9d52619 100644
--- a/wiki/4-Handlers.md
+++ b/wiki/4-Handlers.md
@@ -2,29 +2,32 @@ Signal handlers process created signals to **do something with them** (analyse t
# Included handlers
-A number of signal handlers are included out-the box. Alphabetically:
+Telemere includes a number of signal handlers out-the-box.
-| Name | Platform | Output target | Output format |
-| :------------------------------------------------------------------------------------------------------------------------------------------------------- | :------- | :------------------------------------------------------------------------------------------------------------- | :--------------------------------------------------------------------- |
-| [`handler:carmine`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere.carmine#handler:carmine) [0] | Clj | [Redis](https://redis.io/) (via [Carmine](https://www.taoensso.com/carmine)) | Serialized signals [1] |
-| [`handler:console`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#handler:console) | Clj | `*out*` or `*err*` | String [2] |
-| [`handler:console`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#handler:console) | Cljs | Browser console | String [2] |
-| [`handler:console-raw`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#handler:console-raw) | Cljs | Browser console | Raw signals [3] |
-| [`handler:file`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#handler:file) | Clj | File/s on disk | String [2] |
-| [`handler:logstash`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere.logstash#handler:logstash) [0] | Clj | [Logstash](https://www.elastic.co/logstash) | TODO |
-| [`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/) |
-| [`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)) | String [2] |
-| [`handler:slack`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere.slack#handler:slack) | Clj | [Slack](https://slack.com/) (via [clj-slack](https://github.com/julienXX/clj-slack)) | String [2] |
-| [`handler:tcp-socket`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere.sockets#handler:tcp-socket) | Clj | TCP socket | String [2] |
-| [`handler:udp-socket`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere.sockets#handler:udp-socket) | Clj | UDP socket | String [2] |
+[Writing your own handlers](#writing-handlers) is also often straight-forward, and [PRs](https://github.com/taoensso/telemere/pulls) are **very welcome** for additions to Telemere's included handlers, or to Telemere's [community resources](./8-Community).
-- \[0] Coming soon
-- \[1] Uses [Nippy](https://taoensso.com/nippy) to support all Clojure's rich data types
-- \[2] [Human-readable](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#format-signal-fn) (default), or [machine-readable](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#pr-signal-fn) ([edn](https://github.com/edn-format/edn), [JSON](https://www.json.org/), etc.).
-- \[3] 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!
+It helps to know what people need! You can [vote on](https://www.taoensso.com/roadmap/vote) additional handlers to add, [ping me](https://github.com/taoensso/telemere/issues), or ask on the [`#telemere` Slack channel](https://www.taoensso.com/telemere/slack).
+
+Current handlers, alphabetically (see linked docstrings below for features and usage):
+
+| 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*` | [edn/JSON](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#pr-signal-fn) or [human-readable](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#format-signal-fn) |
+| [`handler:console`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#handler:console) | Cljs | Browser console | [edn/JSON](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#pr-signal-fn) or [human-readable](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#format-signal-fn) |
+| [`handler:console-raw`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#handler:console-raw) | Cljs | Browser console | Raw signals 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 | [edn/JSON](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#pr-signal-fn) or [human-readable](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#format-signal-fn) |
+| [`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/) |
+| [`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)) | [edn/JSON](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#pr-signal-fn) or [human-readable](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#format-signal-fn) |
+| [`handler:slack`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere.slack#handler:slack) | Clj | [Slack](https://slack.com/) (via [clj-slack](https://github.com/julienXX/clj-slack)) | [edn/JSON](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#pr-signal-fn) or [human-readable](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#format-signal-fn) |
+| [`handler:tcp-socket`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere.sockets#handler:tcp-socket) | Clj | TCP socket | [edn/JSON](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#pr-signal-fn) or [human-readable](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#format-signal-fn) |
+| [`handler:udp-socket`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere.sockets#handler:udp-socket) | Clj | UDP socket | [edn/JSON](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#pr-signal-fn) or [human-readable](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#format-signal-fn) |
+
+Planned (upcoming) handlers:
+
+| Name | Platform | Output target | Output format |
+| :----------------------------------------------------------------------------------------------------------------------- | :------- | :--------------------------------------------------------------------------- | :----------------------------------------------- |
+| [`handler:carmine`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere.carmine#handler:carmine) | Clj | [Redis](https://redis.io/) (via [Carmine](https://www.taoensso.com/carmine)) | [Serialized](https://taoensso.com/nippy) signals |
+| [`handler:logstash`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere.logstash#handler:logstash) | Clj | [Logstash](https://www.elastic.co/logstash) | TODO |
# Configuring handlers
@@ -35,7 +38,7 @@ There's two kinds of config relevant to all signal handlers:
## Dispatch opts
-Dispatch opts includes dispatch priority, handler filtering, handler middleware, queue semantics, back-pressure opts, etc.
+Handler dispatch opts includes dispatch priority, handler filtering, handler middleware, 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.
@@ -201,7 +204,7 @@ For more complex cases, or for handlers that you want to make available for use
- See [`help:signal-content`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#help:signal-content) for signal map content.
- See the [utils namespace](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere.utils) for tools useful for customizing and writing signal handlers.
-- See section [8-Community](8-Community.md) for PRs to link to community-authored handlers.
+- [PRs](https://github.com/taoensso/telemere/pulls) are **very welcome** for additions to Telemere's included handlers, or to Telemere's [community resources](./8-Community)
# Example output