diff --git a/README.md b/README.md index a8a5afe..b7f0601 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ Taoensso open source -[**Documentation**](#documentation) | [Latest releases](#latest-releases) | [Slack channel][] +[**API**][cljdoc docs] | [**Wiki**][GitHub wiki] | [Latest releases](#latest-releases) | [Slack channel][] # Telemere logo @@ -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: - -Default ClojureScript console handler output - -#### Cljs raw console handler - -Chrome console, with [cljs-devtools](https://github.com/binaryage/cljs-devtools): - -Raw ClojureScript console handler output - -#### Clj file handler - -MacOS terminal: - -Default Clojure file handler output +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