mirror of
https://github.com/taoensso/telemere.git
synced 2025-12-16 17:41:12 +00:00
[doc] Updates for Trove, simplify examples
This commit is contained in:
parent
070fe88abb
commit
b7b3a25a82
10 changed files with 157 additions and 116 deletions
106
README.md
106
README.md
|
|
@ -16,11 +16,18 @@
|
|||
|
||||
It's small, super fast, easy to learn, easy to use, and **absurdly flexible**.
|
||||
|
||||
An example call:
|
||||
|
||||
```clojure
|
||||
(tel/log! {:level :info, :id :auth/login, :data {:user-id 1234}, :msg "User logged in!"})
|
||||
```
|
||||
|
||||
Use it alone, or as part of a suite of complementary **observability tools** for modern Clojure/Script applications:
|
||||
|
||||
- [Telemere](https://www.taoensso.com/telemere) for logging, tracing, and general telemetry
|
||||
- [Tufte](https://www.taoensso.com/tufte) for performance monitoring
|
||||
- [Truss](https://www.taoensso.com/truss) for assertions and error handling
|
||||
- [Trove](https://www.taoensso.com/trove) for library authors that want to do structured logging
|
||||
|
||||
Together these help enable Clojure/Script systems that are **robust**, **fast**, and **easily debugged**.
|
||||
|
||||
|
|
@ -56,29 +63,30 @@ It enables you to write code that is **information-verbose by default**.
|
|||
<details open><summary>Create signals</summary><br/>
|
||||
|
||||
```clojure
|
||||
(require '[taoensso.telemere :as t])
|
||||
(require '[taoensso.telemere :as tel])
|
||||
|
||||
;; No config needed for typical use cases!!
|
||||
;; Signals print to console by default for both Clj and Cljs
|
||||
|
||||
;; Without structured data
|
||||
(t/log! :info "Hello world!") ; %> Basic log signal (has message)
|
||||
(t/event! ::my-id :debug) ; %> Basic event signal (just id)
|
||||
;; Traditional style logging (data formatted into message string):
|
||||
(tel/log! {:level :info, :msg (str "User " 1234 " logged in!")})
|
||||
|
||||
;; With structured data
|
||||
(t/log! {:level :info, :data {...}} "Hello again!")
|
||||
(t/event! ::my-id {:level :debug, :data {...}})
|
||||
;; Modern/structured style logging (explicit id and data)
|
||||
(tel/log! {:level :info, :id :auth/login, :data {:user-id 1234}})
|
||||
|
||||
;; Mixed style (explicit id and data, with message string)
|
||||
(tel/log! {:level :info, :id :auth/login, :data {:user-id 1234}, :msg "User logged in!"})
|
||||
|
||||
;; Trace (can interop with OpenTelemetry)
|
||||
;; Tracks form runtime, return value, and (nested) parent tree
|
||||
(t/trace! {:id ::my-id :data {...}}
|
||||
(tel/trace! {:id ::my-id :data {...}}
|
||||
(do-some-work))
|
||||
|
||||
;; Check resulting signal content for debug/tests
|
||||
(t/with-signal (t/event! ::my-id)) ; => {:keys [ns level id data msg_ ...]}
|
||||
(tel/with-signal (tel/log! {...})) ; => {:keys [ns level id data msg_ ...]}
|
||||
|
||||
;; Getting fancy (all costs are conditional!)
|
||||
(t/log!
|
||||
(tel/log!
|
||||
{:level :debug
|
||||
:sample 0.75 ; 75% sampling (noop 25% of the time)
|
||||
:when (my-conditional)
|
||||
|
|
@ -106,33 +114,33 @@ It enables you to write code that is **information-verbose by default**.
|
|||
|
||||
```clojure
|
||||
;; Set minimum level
|
||||
(t/set-min-level! :warn) ; For all signals
|
||||
(t/set-min-level! :log :debug) ; For `log!` signals only
|
||||
(tel/set-min-level! :warn) ; For all signals
|
||||
(tel/set-min-level! :log :debug) ; For `log!` signals specifically
|
||||
|
||||
;; Set id and namespace filters
|
||||
(t/set-id-filter! {:allow #{::my-particular-id "my-app/*"}})
|
||||
(t/set-ns-filter! {:disallow "taoensso.*" :allow "taoensso.sente.*"})
|
||||
(tel/set-id-filter! {:allow #{::my-particular-id "my-app/*"}})
|
||||
(tel/set-ns-filter! {:disallow "taoensso.*" :allow "taoensso.sente.*"})
|
||||
|
||||
;; SLF4J signals will have their `:ns` key set to the logger's name
|
||||
;; (typically a source class)
|
||||
(t/set-ns-filter! {:disallow "com.noisy.java.package.*"})
|
||||
(tel/set-ns-filter! {:disallow "com.noisy.java.package.*"})
|
||||
|
||||
;; Set minimum level for `event!` signals for particular ns pattern
|
||||
(t/set-min-level! :event "taoensso.sente.*" :warn)
|
||||
;; Set minimum level for `log!` signals for particular ns pattern
|
||||
(tel/set-min-level! :log "taoensso.sente.*" :warn)
|
||||
|
||||
;; Use transforms (xfns) to filter and/or arbitrarily modify signals
|
||||
;; by signal data/content/etc.
|
||||
|
||||
(t/set-xfn!
|
||||
(tel/set-xfn!
|
||||
(fn [signal]
|
||||
(if (-> signal :data :skip-me?)
|
||||
nil ; Filter signal (don't handle)
|
||||
(assoc signal :transformed? true))))
|
||||
|
||||
(t/with-signal (t/event! ::my-id {:data {:skip-me? true}})) ; => nil
|
||||
(t/with-signal (t/event! ::my-id {:data {:skip-me? false}})) ; => {...}
|
||||
(tel/with-signal (tel/log! {... :data {:skip-me? true}})) ; => nil
|
||||
(tel/with-signal (tel/log! {... :data {:skip-me? false}})) ; => {...}
|
||||
|
||||
;; See `t/help:filters` docstring for more filtering options
|
||||
;; See `tel/help:filters` docstring for more filtering options
|
||||
```
|
||||
|
||||
</details>
|
||||
|
|
@ -141,13 +149,13 @@ It enables you to write code that is **information-verbose by default**.
|
|||
|
||||
```clojure
|
||||
;; Add your own signal handler
|
||||
(t/add-handler! :my-handler
|
||||
(tel/add-handler! :my-handler
|
||||
(fn
|
||||
([signal] (println signal))
|
||||
([] (println "Handler has shut down"))))
|
||||
|
||||
;; Use `add-handler!` to set handler-level filtering and back-pressure
|
||||
(t/add-handler! :my-handler
|
||||
(tel/add-handler! :my-handler
|
||||
(fn
|
||||
([signal] (println signal))
|
||||
([] (println "Handler has shut down")))
|
||||
|
|
@ -158,27 +166,27 @@ It enables you to write code that is **information-verbose by default**.
|
|||
:min-level :info
|
||||
:ns-filter {:disallow "taoensso.*"}
|
||||
:limit {"1 per sec" [1 1000]}
|
||||
;; See `t/help:handler-dispatch-options` for more
|
||||
;; See `tel/help:handler-dispatch-options` for more
|
||||
})
|
||||
|
||||
;; See current handlers
|
||||
(t/get-handlers) ; => {<handler-id> {:keys [handler-fn handler-stats_ dispatch-opts]}}
|
||||
(tel/get-handlers) ; => {<handler-id> {:keys [handler-fn handler-stats_ dispatch-opts]}}
|
||||
|
||||
;; Add console handler to print signals as human-readable text
|
||||
(t/add-handler! :my-handler
|
||||
(t/handler:console
|
||||
{:output-fn (t/format-signal-fn {})}))
|
||||
(tel/add-handler! :my-handler
|
||||
(tel/handler:console
|
||||
{:output-fn (tel/format-signal-fn {})}))
|
||||
|
||||
;; Add console handler to print signals as edn
|
||||
(t/add-handler! :my-handler
|
||||
(t/handler:console
|
||||
{:output-fn (t/pr-signal-fn {:pr-fn :edn})}))
|
||||
(tel/add-handler! :my-handler
|
||||
(tel/handler:console
|
||||
{:output-fn (tel/pr-signal-fn {:pr-fn :edn})}))
|
||||
|
||||
;; Add console handler to print signals as JSON
|
||||
;; Ref. <https://github.com/metosin/jsonista> (or any alt JSON lib)
|
||||
#?(:clj (require '[jsonista.core :as jsonista]))
|
||||
(t/add-handler! :my-handler
|
||||
(t/handler:console
|
||||
(tel/add-handler! :my-handler
|
||||
(tel/handler:console
|
||||
{:output-fn
|
||||
#?(:cljs :json ; Use js/JSON.stringify
|
||||
:clj jsonista/write-value-as-string)}))
|
||||
|
|
@ -235,19 +243,29 @@ It enables you to write code that is **information-verbose by default**.
|
|||
|
||||
## API overview
|
||||
|
||||
See relevant docstrings (links below) for usage info-
|
||||
|
||||
### Creating signals
|
||||
|
||||
| Name | Kind | Args | Returns |
|
||||
| :---------------------------------------------------------------------------------------------------------- | :--------- | :--------------- | :--------------------------- |
|
||||
| [`log!`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#log!) | `:log` | `?level` + `msg` | nil |
|
||||
| [`event!`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#event!) | `:event` | `id` + `?level` | nil |
|
||||
| [`trace!`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#trace!) | `:trace` | `?id` + `run` | Form result |
|
||||
| [`spy!`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#spy!) | `:spy` | `?level` + `run` | Form result |
|
||||
| [`error!`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#error!) | `:error` | `?id` + `error` | Given error |
|
||||
| [`catch->error!`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#catch-%3Eerror!) | `:error` | `?id` | Form value or given fallback |
|
||||
| [`signal!`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#signal!) | `:generic` | `opts` | Depends on opts |
|
||||
Telemere's signals are all created using the low-level `signal!` macro. You can use that directly, or one of the wrapper macros like `log!`.
|
||||
|
||||
Several different wrapper macros are provided. The only difference between them:
|
||||
|
||||
1. They create signals with a different `:kind` value (which can be handy for filtering, etc.).
|
||||
2. They have different positional arguments and/or return values optimised for concise calling in different use cases.
|
||||
|
||||
**NB:** ALL wrapper macros can also just be called with a single [opts](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#help:signal-options) map!
|
||||
|
||||
See the linked docstrings below for more info:
|
||||
|
||||
|
||||
| Name | Args | Returns |
|
||||
| :---------------------------------------------------------------------------------------------------------- | :------------------------- | :--------------------------- |
|
||||
| [`log!`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#log!) | `[opts]` or `[?level msg]` | nil |
|
||||
| [`event!`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#event!) | `[opts]` or `[id ?level]` | nil |
|
||||
| [`trace!`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#trace!) | `[opts]` or `[?id run]` | Form result |
|
||||
| [`spy!`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#spy!) | `[opts]` or `[?level run]` | Form result |
|
||||
| [`error!`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#error!) | `[opts]` or `[?id error]` | Given error |
|
||||
| [`catch->error!`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#catch-%3Eerror!) | `[opts]` or `[?id error]` | Form value or given fallback |
|
||||
| [`signal!`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#signal!) | `[opts]` | Depends on opts |
|
||||
|
||||
### Internal help
|
||||
|
||||
|
|
|
|||
|
|
@ -10,4 +10,4 @@ Please report possible security vulnerabilities [via GitHub](https://github.com/
|
|||
|
||||
Thank you!
|
||||
|
||||
\- [Peter Taoussanis](https://www.taoensso.com)
|
||||
\- [Peter Taoussanis](https://www.taoensso.com)
|
||||
|
|
@ -8,23 +8,25 @@
|
|||
|
||||
(require '[taoensso.telemere :as tel])
|
||||
|
||||
;; (Just works / no config necessary for typical use cases)
|
||||
;; No config needed for typical use cases!!
|
||||
;; Signals print to console by default for both Clj and Cljs
|
||||
|
||||
;; Without structured data
|
||||
(tel/log! :info "Hello world!") ; %> Basic log signal (has message)
|
||||
(tel/event! ::my-id :debug) ; %> Basic event signal (just id)
|
||||
;; Traditional style logging (data formatted into message string):
|
||||
(tel/log! {:level :info, :msg (str "User " 1234 " logged in!")})
|
||||
|
||||
;; With structured data
|
||||
(tel/log! {:level :info, :data {}} "Hello again!")
|
||||
(tel/event! ::my-id {:level :debug, :data {}})
|
||||
;; Modern/structured style logging (explicit id and data)
|
||||
(tel/log! {:level :info, :id :auth/login, :data {:user-id 1234}})
|
||||
|
||||
;; Trace (auto interops with OpenTelemetry)
|
||||
;; Mixed style (explicit id and data, with message string)
|
||||
(tel/log! {:level :info, :id :auth/login, :data {:user-id 1234}, :msg "User logged in!"})
|
||||
|
||||
;; Trace (can interop with OpenTelemetry)
|
||||
;; Tracks form runtime, return value, and (nested) parent tree
|
||||
(tel/trace! {:id ::my-id :data {}}
|
||||
(tel/trace! {:id ::my-id :data {...}}
|
||||
(do-some-work))
|
||||
|
||||
;; Check resulting signal content for debug/tests
|
||||
(tel/with-signal (tel/event! ::my-id)) ; => {:keys [ns level id data msg_ ...]}
|
||||
(tel/with-signal (tel/log! {...})) ; => {:keys [ns level id data msg_ ...]}
|
||||
|
||||
;; Getting fancy (all costs are conditional!)
|
||||
(tel/log!
|
||||
|
|
@ -47,20 +49,25 @@
|
|||
|
||||
;; Message string or vector to join as string
|
||||
["Something interesting happened!" formatted])
|
||||
)
|
||||
|
||||
;; Set minimum level
|
||||
(tel/set-min-level! :warn) ; For all signals
|
||||
(tel/set-min-level! :log :debug) ; For `log!` signals only
|
||||
(tel/set-min-level! :log :debug) ; For `log!` signals specifically
|
||||
|
||||
;; Set namespace and id filters
|
||||
(tel/set-ns-filter! {:disallow "taoensso.*" :allow "taoensso.sente.*"})
|
||||
;; Set id and namespace filters
|
||||
(tel/set-id-filter! {:allow #{::my-particular-id "my-app/*"}})
|
||||
(tel/set-ns-filter! {:disallow "taoensso.*" :allow "taoensso.sente.*"})
|
||||
|
||||
;; Set minimum level for `event!` signals for particular ns pattern
|
||||
(tel/set-min-level! :event "taoensso.sente.*" :warn)
|
||||
;; SLF4J signals will have their `:ns` key set to the logger's name
|
||||
;; (typically a source class)
|
||||
(tel/set-ns-filter! {:disallow "com.noisy.java.package.*"})
|
||||
|
||||
;; Set minimum level for `log!` signals for particular ns pattern
|
||||
(tel/set-min-level! :log "taoensso.sente.*" :warn)
|
||||
|
||||
;; Use transforms (xfns) to filter and/or arbitrarily modify signals
|
||||
;; by signal data/contentel/etc.
|
||||
;; by signal data/content/etc.
|
||||
|
||||
(tel/set-xfn!
|
||||
(fn [signal]
|
||||
|
|
@ -68,13 +75,11 @@
|
|||
nil ; Filter signal (don't handle)
|
||||
(assoc signal :transformed? true))))
|
||||
|
||||
(tel/with-signal (tel/event! ::my-id {:data {:skip-me? true}})) ; => nil
|
||||
(tel/with-signal (tel/event! ::my-id {:data {:skip-me? false}})) ; => {...}
|
||||
(tel/with-signal (tel/log! {... :data {:skip-me? true}})) ; => nil
|
||||
(tel/with-signal (tel/log! {... :data {:skip-me? false}})) ; => {...}
|
||||
|
||||
;; See `tel/help:filters` docstring for more filtering options
|
||||
|
||||
;;;; README "More examples"
|
||||
|
||||
;; Add your own signal handler
|
||||
(tel/add-handler! :my-handler
|
||||
(fn
|
||||
|
|
|
|||
|
|
@ -11,8 +11,8 @@ various keys:
|
|||
- All signal creators offer the same options [2], and
|
||||
- All signal kinds can contain the same content [3]
|
||||
|
||||
Creators vary only in in their default options and call APIs (expected args
|
||||
and return values), making them more/less convenient for certain use cases:
|
||||
Creators vary only in in their default `:kind` value and call APIs (expected
|
||||
args and return values), making them more/less convenient for certain use cases:
|
||||
|
||||
`log!` ------------- ?level + msg => nil
|
||||
`event!` ----------- id + ?level => nil
|
||||
|
|
|
|||
|
|
@ -83,7 +83,7 @@ deps.edn: com.taoensso/telemere {:mvn/version "x-y-z"}
|
|||
And setup your namespace imports:
|
||||
|
||||
```clojure
|
||||
(ns my-app (:require [taoensso.telemere :as t]))
|
||||
(ns my-app (:require [taoensso.telemere :as tel]))
|
||||
```
|
||||
|
||||
# Default config
|
||||
|
|
@ -127,30 +127,34 @@ Interop can be tough to get configured correctly so the [`check-interop`](https:
|
|||
|
||||
## Creating signals
|
||||
|
||||
Use whichever signal creator is most convenient for your needs:
|
||||
Telemere's signals are all created using the low-level `signal!` macro. You can use that directly, or one of the wrapper macros like `log!`.
|
||||
|
||||
| Name | Kind | Args | Returns |
|
||||
| :---------------------------------------------------------------------------------------------------------- | :--------- | :--------------- | :--------------------------- |
|
||||
| [`log!`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#log!) | `:log` | `?level` + `msg` | nil |
|
||||
| [`event!`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#event!) | `:event` | `id` + `?level` | nil |
|
||||
| [`trace!`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#trace!) | `:trace` | `?id` + `run` | Form result |
|
||||
| [`spy!`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#spy!) | `:spy` | `?level` + `run` | Form result |
|
||||
| [`error!`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#error!) | `:error` | `?id` + `error` | Given error |
|
||||
| [`catch->error!`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#catch-%3Eerror!) | `:error` | `?id` | Form value or given fallback |
|
||||
| [`signal!`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#signal!) | `:generic` | `opts` | Depends on opts |
|
||||
|
||||
- See relevant docstrings (links above) for usage info.
|
||||
- See [`help:signal-creators`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#help:signal-creators) for more about signal creators.
|
||||
- See [`help:signal-options`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#help:signal-options) for options shared by all signal creators.
|
||||
- See [examples.cljc](https://github.com/taoensso/telemere/blob/master/examples.cljc) for REPL-ready examples.
|
||||
Several different wrapper macros are provided. The only difference between them:
|
||||
|
||||
1. They create signals with a different `:kind` value (which can be handy for filtering, etc.).
|
||||
2. They have different positional arguments and/or return values optimised for concise calling in different use cases.
|
||||
|
||||
**NB:** ALL wrapper macros can also just be called with a single [opts](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#help:signal-options) map!
|
||||
|
||||
See the linked docstrings below for more info:
|
||||
|
||||
| Name | Args | Returns |
|
||||
| :---------------------------------------------------------------------------------------------------------- | :------------------------- | :--------------------------- |
|
||||
| [`log!`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#log!) | `[opts]` or `[?level msg]` | nil |
|
||||
| [`event!`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#event!) | `[opts]` or `[id ?level]` | nil |
|
||||
| [`trace!`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#trace!) | `[opts]` or `[?id run]` | Form result |
|
||||
| [`spy!`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#spy!) | `[opts]` or `[?level run]` | Form result |
|
||||
| [`error!`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#error!) | `[opts]` or `[?id error]` | Given error |
|
||||
| [`catch->error!`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#catch-%3Eerror!) | `[opts]` or `[?id error]` | Form value or given fallback |
|
||||
| [`signal!`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#signal!) | `[opts]` | Depends on opts |
|
||||
|
||||
## Checking signals
|
||||
|
||||
Use the [`with-signal`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#with-signal) or (advanced) [`with-signals`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#with-signals) utils to help test/debug the signals that you're creating:
|
||||
|
||||
```clojure
|
||||
(t/with-signal
|
||||
(t/log!
|
||||
(tel/with-signal
|
||||
(tel/log!
|
||||
{:let [x "x"]
|
||||
:data {:x x}}
|
||||
["My msg:" x]))
|
||||
|
|
@ -185,15 +189,15 @@ A signal will be provided to a handler iff **ALL** of the following are true:
|
|||
Quick examples of some basic filtering:
|
||||
|
||||
```clojure
|
||||
(t/set-min-level! :info) ; Set global minimum level
|
||||
(t/with-signal (t/event! ::my-id1 :info)) ; => {:keys [inst id ...]}
|
||||
(t/with-signal (t/event! ::my-id1 :debug)) ; => nil (signal not allowed)
|
||||
(tel/set-min-level! :info) ; Set global minimum level
|
||||
(tel/with-signal (tel/log! {:level :info ...})) ; => {:keys [inst id ...]}
|
||||
(tel/with-signal (tel/log! {:level :debug ...})) ; => nil (signal not allowed)
|
||||
|
||||
(t/with-min-level :trace ; Override global minimum level
|
||||
(t/with-signal (t/event! ::my-id1 :debug))) ; => {:keys [inst id ...]}
|
||||
(tel/with-min-level :trace ; Override global minimum level
|
||||
(tel/with-signal (tel/log! {:level :debug ...})) ; => {:keys [inst id ...]}
|
||||
|
||||
;; Disallow all signals in matching namespaces
|
||||
(t/set-ns-filter! {:disallow "some.nosy.namespace.*"})
|
||||
(tel/set-ns-filter! {:disallow "some.nosy.namespace.*"})
|
||||
```
|
||||
|
||||
- Filtering is always O(1), except for rate limits which are O(n_windows).
|
||||
|
|
|
|||
|
|
@ -132,7 +132,7 @@ Telemere can easily incorporate Tufte performance data in its signals, just like
|
|||
|
||||
```clojure
|
||||
(let [[_ perf-data] (tufte/profiled <opts> <form>)]
|
||||
(t/log! {:perf-data perf-data} "Performance data"))
|
||||
(tel/log! {:perf-data perf-data} "Performance data"))
|
||||
```
|
||||
|
||||
Telemere and Tufte work great together:
|
||||
|
|
@ -149,7 +149,7 @@ Telemere can easily incorporate Truss assertion failure information in its signa
|
|||
The [`catch->error!`](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#catch-%3Eerror!) signal creator can be particularly convenient for this:
|
||||
|
||||
```clojure
|
||||
(t/catch->error! <form-with-truss-assertion/s>)
|
||||
(tel/catch->error! <form-with-truss-assertion/s>)
|
||||
```
|
||||
|
||||
Telemere also uses [Truss contextual exceptions](https://cljdoc.org/d/com.taoensso/truss/CURRENT/api/taoensso.truss#ex-info) when relevant.
|
||||
|
|
@ -71,11 +71,11 @@ By default it writes formatted strings intended for human consumption:
|
|||
```clojure
|
||||
;; Create a test signal
|
||||
(def my-signal
|
||||
(t/with-signal
|
||||
(t/log! {:id ::my-id, :data {:x1 :x2}} "My message")))
|
||||
(tel/with-signal
|
||||
(tel/log! {:id ::my-id, :data {:x1 :x2}} "My message")))
|
||||
|
||||
;; Create console handler with default opts (writes formatted string)
|
||||
(def my-handler (t/handler:console {}))
|
||||
(def my-handler (tel/handler:console {}))
|
||||
|
||||
;; Test handler, remember it's just a (fn [signal])
|
||||
(my-handler my-signal) ; %>
|
||||
|
|
@ -90,8 +90,8 @@ To instead writes signals as [edn](https://github.com/edn-format/edn):
|
|||
```clojure
|
||||
;; Create console handler which writes signals as edn
|
||||
(def my-handler
|
||||
(t/handler:console
|
||||
{:output-fn (t/pr-signal-fn {:pr-fn :edn})}))
|
||||
(tel/handler:console
|
||||
{:output-fn (tel/pr-signal-fn {:pr-fn :edn})}))
|
||||
|
||||
(my-handler my-signal) ; %>
|
||||
;; {:inst #inst "2024-04-11T10:54:57.202869Z", :msg_ "My message", :ns "examples", ...}
|
||||
|
|
@ -105,9 +105,9 @@ To instead writes signals as JSON:
|
|||
;; Ref. <https://github.com/metosin/jsonista> (or any alt JSON lib)
|
||||
#?(:clj (require '[jsonista.core :as jsonista]))
|
||||
(def my-handler
|
||||
(t/handler:console
|
||||
(tel/handler:console
|
||||
{:output-fn
|
||||
(t/pr-signal-fn
|
||||
(tel/pr-signal-fn
|
||||
{:pr-fn
|
||||
#?(:cljs :json ; Use js/JSON.stringify
|
||||
:clj jsonista/write-value-as-string)})}))
|
||||
|
|
@ -125,9 +125,10 @@ Telemere includes a handy mechanism for including arbitrary app-level data/opts
|
|||
Any *non-standard* (app-level) keys you include in your signal constructor opts will automatically be included in created signals, e.g.:
|
||||
|
||||
```clojure
|
||||
(t/with-signal
|
||||
(t/event! ::my-id
|
||||
{:my-data-for-xfn "foo"
|
||||
(tel/with-signal
|
||||
(tel/log!
|
||||
{...
|
||||
:my-data-for-xfn "foo"
|
||||
:my-data-for-handler "bar"}))
|
||||
|
||||
;; %>
|
||||
|
|
@ -250,7 +251,7 @@ If you're making a customizable handler for use by others, it's often handy to d
|
|||
# Example output
|
||||
|
||||
```clojure
|
||||
(t/log! {:id ::my-id, :data {:x1 :x2}} "My message") =>
|
||||
(tel/log! {:id ::my-id, :data {:x1 :x2}} "My message") =>
|
||||
```
|
||||
|
||||
## Clj console handler
|
||||
|
|
|
|||
|
|
@ -76,18 +76,18 @@ Examples:
|
|||
|
||||
```clojure
|
||||
;; A fixed message (string arg)
|
||||
(t/log! "A fixed message") ; %> {:msg "A fixed message"}
|
||||
(tel/log! "A fixed message") ; %> {:msg "A fixed message"}
|
||||
|
||||
;; A joined message (vector arg)
|
||||
(let [user-arg "Bob"]
|
||||
(t/log! ["User" (str "`" user-arg "`") "just logged in!"]))
|
||||
(tel/log! ["User" (str "`" user-arg "`") "just logged in!"]))
|
||||
;; %> {:msg_ "User `Bob` just logged in!` ...}
|
||||
|
||||
;; With arg prep
|
||||
(let [user-arg "Bob"
|
||||
usd-balance-str "22.4821"]
|
||||
|
||||
(t/log!
|
||||
(tel/log!
|
||||
{:let
|
||||
[username (clojure.string/upper-case user-arg)
|
||||
usd-balance (parse-double usd-balance-str)]
|
||||
|
|
@ -100,10 +100,10 @@ Examples:
|
|||
|
||||
;; %> {:msg "User BOB has balance: $22" ...}
|
||||
|
||||
(t/log! (str "This message " "was built " "by `str`"))
|
||||
(tel/log! (str "This message " "was built " "by `str`"))
|
||||
;; %> {:msg "This message was built by `str`"}
|
||||
|
||||
(t/log! (format "This message was built by `%s`" "format"))
|
||||
(tel/log! (format "This message was built by `%s`" "format"))
|
||||
;; %> {:msg "This message was built by `format`"}
|
||||
```
|
||||
|
||||
|
|
|
|||
|
|
@ -114,7 +114,7 @@ Consider the [differences](https://www.youtube.com/watch?v=oyLBGkS5ICk) between
|
|||
Any non-standard [options](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#help:signal-options) you give to a signal creator call will be added to the signal it creates:
|
||||
|
||||
```clojure
|
||||
(t/with-signal (t/log! {:my-key "foo"} "My message")))
|
||||
(tel/with-signal (tel/log! {:my-key "foo"} "My message")))
|
||||
;; => {:my-key "foo", :kvs {:my-key "foo", ...}, ...}
|
||||
```
|
||||
|
||||
|
|
|
|||
|
|
@ -1,17 +1,30 @@
|
|||
Are you a library author/maintainer that's considering **using Telemere in your library**?
|
||||
|
||||
You have **two options** below-
|
||||
You have **a few options** below-
|
||||
|
||||
# Options
|
||||
## 1. Common logging facade (basic logging only)
|
||||
|
||||
Many libraries need only basic logging. In these cases it can be beneficial to do your logging through a common logging facade like [tools.logging](https://github.com/clojure/tools.logging) or [SLF4J](https://www.slf4j.org/).
|
||||
## Modern logging facade
|
||||
|
||||
This'll limit you to basic features (e.g. no structured logging or [rich filtering](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#get-filters)) - but your users will have the freedom to choose and configure their **preferred backend** ([incl. Telemere if they like](./3-Config#interop)).
|
||||
[Trove](https://www.taoensso.com/trove) is a minimal, modern alternative to [tools.logging](https://github.com/clojure/tools.logging) that supports all of Telemere's structured logging and rich filtering features.
|
||||
|
||||
## 2. Telemere as a transitive dependency
|
||||
Basically:
|
||||
|
||||
Include [Telemere](https://clojars.org/com.taoensso/telemere) in your **library's dependencies**. Your library (and users) will then have access to the full Telemere API.
|
||||
1. You include the (very small) Trove dependency with your library
|
||||
2. Your library logs using the [Trove API](https://github.com/taoensso/trove#to-choose-a-backend)
|
||||
3. Your users then [choose](https://github.com/taoensso/trove#to-choose-a-backend) their preferred backend (Telemere, etc.)
|
||||
|
||||
This would be my first recommendation, and is what I'm planning to use for future updates to [Sente](https://www.taoensso.com/sente), [Carmine](https://www.taoensso.com/carmine), etc.
|
||||
|
||||
## Traditional logging facade (basic logging only)
|
||||
|
||||
Many libraries need only basic logging. In these cases it can be beneficial to do your logging through a common traditional logging facade like [tools.logging](https://github.com/clojure/tools.logging) or [SLF4J](https://www.slf4j.org/).
|
||||
|
||||
Though these'll limit you to basic features (e.g. no structured logging or [rich filtering](https://cljdoc.org/d/com.taoensso/telemere/CURRENT/api/taoensso.telemere#get-filters)).
|
||||
|
||||
## Telemere as a transitive dependency
|
||||
|
||||
You could just include [Telemere](https://clojars.org/com.taoensso/telemere) in your **library's dependencies**. Your library (and users) will then have access to the full Telemere API.
|
||||
|
||||
Telemere's [default config](./1-Getting-started#default-config) is sensible (with println-like console output), so your users are unlikely to need to configure or interact with Telemere much unless they choose to.
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue