Structured telemetry for Clojure/Script applications. See the GitHub page (esp. Wiki) for info on motivation and design: <https://www.taoensso.com/telemere>
Optional context (state) attached to all signals. Value may be any type, but is usually nil or a map. Default (root) value is nil. Useful for dynamically attaching arbitrary app-level state to signals. Re/bind dynamic value using `with-ctx`, `with-ctx+`, or `binding`. Modify root (default) value using `set-ctx!`. As with all dynamic Clojure vars, "binding conveyance" applies when using futures, agents, etc. Tips: - Value may be (or may contain) an atom if you want mutable semantics. - Value may be of form {<scope-id> <data>} for custom scoping, etc. - Use `get-env` to set default (root) value based on environmental config.
Optional (fn [signal]) => ?modified-signal to apply to all signals. When middleware returns nil, skips all handlers. Default (root) value is nil. Useful for dynamically transforming signals and/or filtering signals by signal data/content/etc. Re/bind dynamic value using `with-middleware`, `binding`. Modify root (default) value using `set-middleware!`. As with all dynamic Clojure vars, "binding conveyance" applies when using futures, agents, etc. Tips: - Compose multiple middleware fns together with `comp-middleware`. - Use `get-env` to set default (root) value based on environmental config.
Experimental, subject to change. (fn [root?]) used to generate signal `:uid` values when tracing. These are basically unique signal instance identifiers. `root?` argument is true iff signal is a top-level trace (i.e. form being traced is unnested = has no parent form). Root uids typically have ~128 bits of entropy to ensure uniqueness. Child uids are typically used only with respect to a parent/root, and so can often make do with ~64 bits of entropy or less. Smaller uids are generally cheaper to generate, and use less space when serializing/transmitting/storing/etc. By default generates nano-style uids like "r76-B8LoIPs5lBG1_Uhdy" (root) and "tMEYoZH0K-" (non-root). For plain fixed-length UUIDs use: (fn [_root?] (utils/uuid)) For plain fixed-length UUID strings use: (fn [_root?] (utils/uuid-str)) See also `utils/nano-uid-fn`, `utils/hex-id-fn`, etc.
(add-handler! handler-id handler-fn)
(add-handler! handler-id handler-fn dispatch-opts)
Registers given signal handler and returns {<handler-id> {:keys [dispatch-opts handler-fn]}} for all handlers now registered. `handler-fn` should be a fn of exactly 2 arities: [signal] ; Single argument Called asynchronously or synchronously (depending on dispatch options) to do something useful with the given signal. Example actions: Save data to disk or db, `tap>`, log, `put!` to an appropriate `core.async` channel, filter, aggregate, use for a realtime analytics dashboard, examine for outliers or unexpected data, etc. [] ; No arguments Called exactly once when stopping handler to provide an opportunity for handler to flush buffers, close files, etc. May just noop. NB you should always call `stop-handlers!` somewhere appropriate - usually near the end of your `-main` or shutdown procedure, AFTER all other code has completed that could create signals. See `help:handler-dispatch-options` for handler filters, etc.
(call-on-shutdown! f)
Registers given nullary fn as a JVM shutdown hook. (f) will be called sometime during shutdown. While running, it will attempt to block shutdown.
(catch->error! form)
(catch->error! id form)
(catch->error! {:as opts
:keys [rethrow? catch-val elidable? location inst uid middleware
sample-rate kind ns id level when rate-limit ctx parent
root trace? do let data msg error & kvs]}
form)
Unconditionally executes given form and- If form succeeds: return the form's result. If form throws: Call `error!` with the thrown error and the given signal options [2], then return (:catch-val opts) if it exists, or rethrow the error. API: [form] [id-or-opts form] => form's result (value/throw) (unconditional), or (:catch-val opts) Default kind: `:error` Default level: `:error` Examples: (catch->error! (/ 1 0)) ; %> {:kind :error, :level :error, :error <caught> ...} (catch->error! ::my-id (/ 1 0)) ; %> {... :id ::my-id ...} (catch->error! {:let [x "x"] ; Available to `:data` and `:msg` :data {:x x} :msg ["My msg:" x my-error] :catch-val "Return value when form throws" :catch-sym my-error ; Sym of caught error, available to `:data` and `:msg` } (/ 1 0)) ; %> {... :data {x "x"}, :msg_ "My msg: x <caught>" ...} Tips: - Test using `with-signal`: (with-signal (catch->error! ...)). - Supports the same options [2] as other signals [1]. - Useful for recording errors in forms, futures, callbacks, etc. See also `error!`. ---------------------------------------------------------------------- [1] See `help:signal-creators` - (`signal!`, `log!`, `event!`, ...) [2] See `help:signal-options` - {:keys [kind level id data ...]} [3] See `help:signal-content` - {:keys [kind level id data ...]} [4] See `help:signal-filters` - (by ns/kind/id/level, sampling, etc.)
(check-intakes)
Experimental, subject to change. Runs Telemere's registered intake checks and returns {<source-id> {:keys [sending->telemere? telemere-receiving? ...]}}. Useful for tests/debugging.
(comp-middleware fs)
(comp-middleware f1 f2)
(comp-middleware f1 f2 f3)
(comp-middleware f1 f2 f3 & fs)
Returns a single (composite) unary fn that applies all given unary fns sequentially (left->right!: f1, f2, ...). If any given fn returns nil, the returned composite fn immediately returns nil: ((comp-middleware inc #(* % 2) inc) 1) => 5 ; (inc (* (inc 1) 2)) ((comp-middleware inc (fn [_] nil) (fn [_] (throw (Exception. "Never thrown!")))) 1) => nil Useful for composing Ring-style middleware fns.
Default handler dispatch options, see `help:handler-dispatch-options` for details.
(error! error)
(error! id error)
(error! {:as opts
:keys [elidable? location inst uid middleware sample-rate kind ns id
level when rate-limit ctx parent root trace? do let data msg
error & kvs]}
error)
"Error" signal creator, emphasizing error + id. API: [error] [id-or-opts error] => given error (unconditional) Default kind: `:error` Default level: `:error` Examples: (throw (error! (ex-info "MyEx" {}))) ; %> {:kind :error, :level :error, :error <MyEx> ...} (throw (error! ::my-id (ex-info "MyEx" {}))) ; %> {... :id ::my-id ...} (throw (error! {:let [x "x"] ; Available to `:data` and `:msg` :data {:x x} :msg ["My message:" x]} (ex-info "MyEx" {}))) ; %> {... :data {x "x"}, :msg_ "My msg: x" ...} Tips: - Test using `with-signal`: (with-signal (error! ...)). - Supports the same options [2] as other signals [1]. - `error` arg is a platform error (`java.lang.Throwable` or `js/Error`). - Can conveniently be wrapped by `throw`: (throw (error! ...)). ---------------------------------------------------------------------- [1] See `help:signal-creators` - (`signal!`, `log!`, `event!`, ...) [2] See `help:signal-options` - {:keys [kind level id data ...]} [3] See `help:signal-content` - {:keys [kind level id data ...]} [4] See `help:signal-filters` - (by ns/kind/id/level, sampling, etc.)
(error-signal? signal)
Experimental, subject to change. Returns true iff given signal has an `:error` value, or a `:kind` or `:level` that indicates that it's an error.
(event! id)
(event! id level)
(event! id
{:as opts
:keys [elidable? location inst uid middleware sample-rate kind ns id
level when rate-limit ctx parent root trace? do let data msg
error & kvs]})
"Event" signal creator, emphasizing id + level. API: [id] [id level-or-opts] => true iff signal was allowed Default kind: `:event` Default level: `:info` When filtering conditions are met [4], creates a Telemere signal [3] and dispatches it to registered handlers for processing (e.g. writing to console/file/queue/db, etc.). Examples: (event! ::my-id) ; %> {:kind :event, :level :info, :id ::my-id ...} (event! ::my-id :warn) ; %> {... :level :warn ...} (event! ::my-id {:let [x "x"] ; Available to `:data` and `:msg` :data {:x x} :msg ["My msg:" x]}) ; %> {... :data {x "x"}, :msg_ "My msg: x" ...} Tips: - Test using `with-signal`: (with-signal (event! ...)). - Supports the same options [2] as other signals [1]. - `log!` and `event!` are both good default/general-purpose signal creators. - `log!` emphasizes messages, while `event!` emphasizes ids. - Has a different 2-arity arg order to all other signals! Mnemonic: the arg that's typically larger is *always* in the rightmost position, and for `event!` that's the `level-or-opts` arg. ---------------------------------------------------------------------- [1] See `help:signal-creators` - (`signal!`, `log!`, `event!`, ...) [2] See `help:signal-options` - {:keys [kind level id data ...]} [3] See `help:signal-content` - {:keys [kind level id data ...]} [4] See `help:signal-filters` - (by ns/kind/id/level, sampling, etc.)
(format-signal-fn)
(format-signal-fn {:keys [incl-newline? preamble-fn content-fn]
:or {incl-newline? true
preamble-fn (signal-preamble-fn)
content-fn (signal-content-fn)}})
Experimental, subject to change. Returns a (fn format [signal]) that: - 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.
(get-env {:keys [as default return] :or {as :str return :value}} spec)
Flexible cross-platform util for embedding an environmental config value during macro expansion. Used by other Taoensso libraries. Given a const kw/string id or vector of desc-priority alternative ids, parse and return the first of the following that exists: - JVM property value for id - Environment variable value for id - Classpath resource content for id Ids may include optional segment in `<>` tag (e.g. `<.edn>`). Ids may include `<.?platform.?>` tag for auto replacement, useful for supporting platform-specific config. Search order: desc by combined [alt-index platform(y/n) optional(y/n)]. So (get-env {:as :edn} [:my-app/alt1<.platform><.edn> :my-app/alt2]) will parse and return the first of the following that exists: 1. Alt1 +platform +optional (.edn suffix) 1a. `my-app.alt1.clj.edn` JVM property value 1b. `MY_APP_ALT1_CLJ_EDN` environment variable value 1c. `my-app.alt1.clj.edn` classpath resource content 2. Alt1 +platform -optional (.edn suffix) 2a. `my-app.alt1.clj` JVM property value 2b. `MY_APP_ALT1_CLJ` environment variable value 2c. `my-app.alt1.clj` classpath resource content 3. Alt1 -platform +optional (.edn suffix) 3a. `my-app.alt1.edn` JVM property value 3b. `MY_APP_ALT1_EDN` environment variable value 3c. `my-app.alt1.edn` classpath resource content 4. Alt1 -platform -optional (.edn suffix) 4a. `my-app.alt1` JVM property value 4b. `MY_APP_ALT1` environment variable value 4c. `my-app.alt1` classpath resource content 5. Alt2 5a. `my-app.alt2` JVM property value 5b. `MY_APP_ALT2` environment variable value 5c. `my-app.alt2` classpath resource content Options: `:as` - Parse found value as given type ∈ #{:str :bool :edn} (default `:str`). `:default` - Fallback to return unparsed if no value found during search (default `nil`). `:return` - Return type ∈ #{:value :map :explain} (default `:value`). Resulting config value must be something that can be safely embedded in code during macro-expansion. Symbols in edn will be evaluated during expansion. TIP!: Use the {:return :explain} option in tests or at the REPL to verify/inspect resulting config value, config source, and specific search order of prop/env/res ids.
(get-handlers)
Returns ?{<handler-id> {:keys [dispatch-opts handler-fn handler-stats_]}} for all registered signal handlers.
(get-handlers-stats)
Alpha, subject to change. Returns ?{<handler-id> {:keys [handling-nsecs counts]}} for all registered signal handlers that have the `:track-stats?` dispatch option enabled (it is by default). Stats include: `:handling-nsecs` - Summary stats of nanosecond handling times, keys: `:min` - Minimum handling time `:max` - Maximum handling time `:mean` - Arithmetic mean handling time `:mad` - Mean absolute deviation of handling time (measure of dispersion) `:var` - Variance of handling time (measure of dispersion) `:p50` - 50th percentile of handling time (50% of times <= this) `:p90` - 90th percentile of handling time (90% of times <= this) `:p99` - 99th percentile of handling time `:last` - Most recent handling time ... `:counts` - Integer counts for handler outcomes, keys (chronologically): `:dropped` - Noop handler calls due to stopped handler `:back-pressure` - Handler calls that experienced (async) back-pressure (possible noop, depending on back-pressure mode) `:sampled` - Noop handler calls due to sample rate `:filtered` - Noop handler calls due to kind/ns/id/level/when filtering `:rate-limited` - Noop handler calls due to rate limit `:disallowed` - Noop handler calls due to sampling/filtering/rate-limiting `:allowed` - Other handler calls (no sampling/filtering/rate-limiting) `:suppressed` - Noop handler calls due to nil middleware result `:handled` - Handler calls that completed successfully `:errors` - Handler calls that threw an error Note that for performance reasons returned counts are not mutually atomic, e.g. `:sampled` count may be incremented before `:disallowed` count is. Useful for understanding/debugging how your handlers behave in practice, especially when they're under stress (high-volumes, etc.). Handler stats are tracked from the time each handler is last registered (e.g. with an `add-handler!` call).
(get-min-levels)
(get-min-levels kind)
(get-min-levels kind ns)
Returns current ?{:keys [compile-time runtime]} minimum signal levels.
(handler:console)
(handler:console {:keys [stream output-fn]
:or {stream :auto output-fn (utils/format-signal-fn)}})
Experimental, subject to change. Returns a signal handler that: - 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 as human or machine-readable (edn, JSON) strings. Options: `: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.
(handler:console)
(handler:console {:keys [output-fn] :or {output-fn (utils/format-signal-fn)}})
Experimental, subject to change. If `js/console` exists, returns a signal handler that: - 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 as human or machine-readable (edn, JSON) strings. Options: `:output-fn` - (fn [signal]) => string, see `format-signal-fn` or `pr-signal-fn`
(handler:console-raw)
(handler:console-raw {:keys [preamble-fn format-nsecs-fn]
:as opts
:or {preamble-fn (utils/signal-preamble-fn)
format-nsecs-fn (utils/format-nsecs-fn)}})
Experimental, subject to change. If `js/console` exists, returns a signal handler that: - 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>. Options: `:preamble-fn` - (fn [signal]) => string. `:format-nsecs-fn` - (fn [nanosecs]) => string.
(handler:file)
(handler:file {:keys [output-fn path interval max-file-size max-num-parts
max-num-intervals gzip-archives?]
:or {output-fn (utils/format-signal-fn)
path "logs/telemere.log"
interval :monthly
max-file-size (* 1024 1024 4)
max-num-parts 8
max-num-intervals 6
gzip-archives? true}})
Experimental, subject to change. Returns a signal handler that: - Takes a Telemere signal (map). - Writes (appends) the signal as a string 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) ... `/logs/telemere.log-2020-01-01m.8.gz` ; Archive for Jan 2020, part 8 (oldest entries) Options: `: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`) When non-nil, causes interval-based archives to be maintained. `:max-file-size` ∈ #{nil <pos-int>} (default 4MB) When `path` file size > ~this many bytes, rotates old content to numbered archives. `:max-num-parts` ∈ #{nil <pos-int>} (default 8) Maximum number of numbered archives to retain for any particular interval. `:max-num-intervals` ∈ #{nil <pos-int>} (default 6) Maximum number of intervals (days/weeks/months) to retain.
Telemere supports extensive environmental config via JVM properties, environment variables, or classpath resources. Environmental filter config includes: Kind filter: JVM property: `taoensso.telemere.rt-kind-filter.edn` Env variable: `TAOENSSO_TELEMERE_RT_KIND_FILTER_EDN` Classpath resource: `taoensso.telemere.rt-kind-filter.edn` Namespace filter: JVM property: `taoensso.telemere.rt-ns-filter.edn` Env variable: `TAOENSSO_TELEMERE_RT_NS_FILTER_EDN` Classpath resource: `taoensso.telemere.rt-ns-filter.edn` Id filter: JVM property: `taoensso.telemere.rt-id-filter.edn` Env variable: `TAOENSSO_TELEMERE_RT_ID_FILTER_EDN` Classpath resource: `taoensso.telemere.rt-id-filter.edn` Minimum level: JVM property: `taoensso.telemere.rt-min-level.edn` Env variable: `TAOENSSO_TELEMERE_RT_MIN_LEVEL_EDN` Classpath resource: `taoensso.telemere.rt-min-level.edn` Examples: `taoensso.telemere.rt-min-level.edn` -> ":info" `TAOENSSO_TELEMERE_RT_NS_FILTER_EDN` -> "{:disallow \"taoensso.*\"}" `taoensso.telemere.rt-id-filter.cljs.edn` -> "#{:my-id1 :my-id2}" `TAOENSSO_TELEMERE_RT_KIND_FILTER_CLJ_EDN` -> "nil" For other (non-filter) environmental config, see the relevant docstrings. Tips: - The above ids are for runtime filters (the most common). For compile-time filters, change `rt`->`ct` / `RT`->`CT`. - The above ids will affect both Clj AND Cljs. For platform-specific filters, use ".clj.edn" / "_CLJ_EDN" or ".cljs.edn" / "_CLJS_EDN" suffixes instead. - ".edn" / "_EDN" suffixes are optional. - Config values should be edn. To get the right syntax, first set your runtime filters using the standard utils (`set-min-level!`, etc.). Then call `get-filters` and serialize the relevant parts to edn with `pr-str`. - All environmental config uses `get-env` underneath. See the `get-env` docstring for more/advanced details. - Classpath resources are files accessible on your project's classpath. This usually includes files in your project's `resources/` dir.
A signal will be provided to a handler iff ALL of the following are true: 1. Signal creation is allowed by "signal filters": a. Compile-time: sample rate, kind, ns, id, level, when form, rate limit b. Runtime: sample rate, kind, ns, id, level, when form, rate limit 2. Signal handling is allowed by "handler filters": a. Compile-time: not applicable b. Runtime: sample rate, kind, ns, id, level, when fn, rate limit 3. Signal middleware (fn [signal]) => ?modified-signal does not return nil 4. Handler middleware (fn [signal]) => ?modified-signal does not return nil Note that middleware provides a flexible way to filter signals by arbitrary signal data/content conditions (return nil to suppress signal). Config: To set signal filters (1a, 1b): Use: `set-kind-filter!`, `with-kind-filter` `set-ns-filter!`, `with-ns-filter` `set-id-filter!`, `with-id-filter` `set-min-level!`, `with-min-level` or see `help:environmental-config`. To set handler filters (2b) or handler middleware (4): Provide relevant opts when calling `add-handler!` or `with-handler/+`. See `help:handler-dispatch-options` for details. Note: signal filters (1a, 1b) should generally be AT LEAST as permissive as handler filters (2b), otherwise signals will be suppressed before reaching handlers. To set signal middleware (3): use `set-middleware!`, `with-middleware` Compile-time vs runtime filters: Compile-time filters are an advanced feature that can be tricky to set and use correctly. Most folks will want ONLY runtime filters. Compile-time filters works by eliding (completely removing the code for) disallowed signals. This means zero performance cost for these signals, but also means that compile-time filters are PERMANENT once applied. So if you set `:info` as the compile-time minimum level, that'll REMOVE CODE for every signal below `:info` level. To decrease that minimum level, you'll need to rebuild. Compile-time filters can be set ONLY with environmental config (see `help:environmental-config` for details). Signal and handler sampling is multiplicative: Both signals and handlers can have independent sample rates, and these MULTIPLY! If a signal is created with 20% sampling and a handler handles 50% of received signals, then 10% of possible signals will be handled (50% of 20%). The final (multiplicative) rate is helpfully reflected in each signal's `:sample-rate` value. For more info: - On signal filters, see: `help:filters` - On handler filters, see: `help:handler-dispatch-options` If anything is unclear, please ping me (@ptaoussanis) so that I can improve these docs!
Dispatch options can be provided for each signal handler when calling `add-handler!` or `with-handler/+`. These options will be merged over the defaults specified by `default-handler-dispatch-opts`. All handlers support the same dispatch options, including: `:async` (Clj only) options include: `:buffer-size` (default 1024) Size of request buffer, and the max number of pending requests before configured back-pressure behaviour is triggered (see `:mode`). `:mode` (default `:blocking`) Back-pressure mode ∈ #{:blocking :dropping :sliding}. Controls what happens when a new request is made while request buffer is full: `:blocking` => Blocks caller until buffer space is available `:dropping` => Drops the newest request (noop) `:sliding` => Drops the oldest request `:n-threads` (default 1) Number of threads to use for executing fns (servicing request buffer). NB execution order may be non-sequential when n > 1. `:drain-msecs` (default 6000 msecs) Maximum time (in milliseconds) to try allow pending execution requests to complete when stopping handler. nil => no maximum. `:priority` (default 100) Optional handler priority ∈ℤ. Handlers will be called in descending priority order (larger ints first). `:sample-rate` (default nil => no sampling) Optional sample rate ∈ℝ[0,1], or (fn dyamic-sample-rate []) => ℝ[0,1]. When present, handle only this (random) proportion of args: 1.0 => handle every arg (same as nil rate, default) 0.0 => noop every arg 0.5 => handle random 50% of args `:kind-filter` - Kind filter as in `set-kind-filter!` (when relevant) `:ns-filter` - Namespace filter as in `set-ns-filter!` `:id-filter` - Id filter as in `set-id-filter!` (when relevant) `:min-level` - Minimum level as in `set-min-level!` `:when-fn` (default nil => always allow) Optional nullary (fn allow? []) that must return truthy for handler to be called. When present, called *after* sampling and other filters, but before rate limiting. Useful for filtering based on external state/context. See `:middleware` for an alternative that takes a signal argument. `:rate-limit` (default nil => no rate limit) Optional rate limit spec as provided to `taoensso.encore/rate-limiter`, {<limit-id> [<n-max-calls> <msecs-window>]}. Examples: {"1/sec" [1 1000]} => Max 1 call per 1000 msecs {"1/sec" [1 1000] "10/min" [10 60000]} => Max 1 call per 1000 msecs, and 10 calls per 60 secs `:middleware` (default nil => no middleware) Optional (fn [signal]) => ?modified-signal to apply before handling signal. When middleware returns nil, skips handler. Compose multiple middleware fns together with `comp-middleware`. `:error-fn` - (fn [{:keys [handler-id signal error]}]) to call on handler error. `:backp-fn` - (fn [{:keys [handler-id ]}]) to call on handler back-pressure. If anything is unclear, please ping me (@ptaoussanis) so that I can improve these docs!
Signal handlers process created signals to do something with them (analyse them, write them to console/file/queue/db, etc.). Manage handlers with: `get-handlers` - Returns info on registered handlers (dispatch options, etc.) `get-handlers-stats` - Returns stats for registered handlers (handling times, etc.) `add-handler!` - Registers given handler `remove-handler!` - Unregisters given handler `with-handler` - Executes form with ONLY the given handler registered `with-handler+` - Executes form with the given handler (also) registered `stop-handlers!` - Stops registered handlers NB you should always call `stop-handlers!` somewhere appropriate - usually near the end of your `-main` or shutdown procedure, AFTER all other code has completed that could create signals. See the relevant docstrings for details. See `help:handler-dispatch-options` for handler filters, etc. If anything is unclear, please ping me (@ptaoussanis) so that I can improve these docs!
Signals are maps with {:keys [inst id ns level data msg_ ...]}, though they can be modified by signal and/or handler middleware. Default signal keys: `:schema` ------ Int version of signal schema (current: 1) `:inst` -------- Platform instant [1] when signal was created `:level` ------- Signal level ∈ #{<int> :trace :debug :info :warn :error :fatal :report ...} `:kind` -------- Signal ?kind ∈ #{nil :event :error :log :trace :spy :slf4j :tools-logging <app-val> ...} `:id` ---------- ?id of signal (common to all signals created at callsite, contrast with `:uid`) `:uid` --------- ?id of signal instance (unique to each signal created at callsite when tracing, contrast with `:id`) `:msg` --------- Arb app-level message ?str given to signal creator `:data` -------- Arb app-level data ?val (usu. a map) given to signal creator `:error` ------- Arb app-level platform ?error [2] given to signal creator `:run-form` ---- Unevaluated ?form given to signal creator as `:run` `:run-val` ----- Successful return ?val of `:run` ?form `:run-nsecs` --- ?int nanosecs runtime of `:run` ?form `:end-inst` ---- Platform ?instant [1] when `:run` ?form completed `:ctx` --------- ?val of `*ctx*` (arb app-level state) when signal was created `:parent` ------ ?{:keys [id uid]} of parent signal, present in nested signals when tracing `:root` -------- ?{:keys [id uid]} of root signal, present in nested signals when tracing `:location` ---- ?{:keys [ns file line column]} signal creator callsite `:ns` ---------- ?str namespace of signal creator callsite, same as (:ns location) `:line` -------- ?int line of signal creator callsite, same as (:line location) `:column` ------ ?int column of signal creator callsite, same as (:column location) `:file` -------- ?str filename of signal creator callsite, same as (:file location) `:host` -------- (Clj only) {:keys [name ip]} info for network host `:thread` ------ (Clj only) {:keys [name id group]} info for thread that created signal `:sample-rate` - ?rate ∈ℝ[0,1] for combined signal AND handler sampling (0.75 => allow 75% of signals, nil => allow all) <kvs> ---------- Other arb app-level ?kvs given to signal creator. Typically NOT included in handler output, so a great way to provide custom data/opts for use (only) by custom middleware/handlers. If anything is unclear, please ping me (@ptaoussanis) so that I can improve these docs! [1] `java.time.Instant` or `js/Date` [2] `java.lang.Throwable` or `js/Error`
Call a Telemere signal creator to conditionally create a signal at that callsite. When filtering conditions are met [4], the call creates a Telemere signal [3] and dispatches it to registered handlers for processing (e.g. writing to console/file/queue/db, etc.). Telemere doesn't make a hard distinction between different kinds of signals (log, event, error, etc.) - they're all just plain Clojure/Script maps with 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: `event!` -------- [id ] or [id opts/level] => true iff signal was created (allowed) `log!` ---------- [msg ] or [opts/level msg] => true iff signal was created (allowed) `error!` -------- [error] or [opts/id error] => given error (unconditional) `trace!` -------- [form ] or [opts/id form] => form result (value/throw) (unconditional) `spy!` ---------- [form ] or [opts/level form] => form result (value/throw) (unconditional) `catch->error!` - [form ] or [opts/id form] => form value, or given fallback `signal!` ------- [opts ] => depends on options - `log!` and `event!` are both good default/general-purpose signal creators. - `log!` emphasizes messages, while `event!` emphasizes ids. - `signal!` is the generic creator, and is used by all the others. ---------------------------------------------------------------------- [2] See `help:signal-options` - {:keys [kind level id data ...]} [3] See `help:signal-content` - {:keys [kind level id data ...]} [4] See `help:signal-filters` - (by ns/kind/id/level, sampling, etc.)
Signal options (shared by all signal creators): `:inst` -------- Platform instant [1] when signal was created, ∈ #{nil :auto <[1]>} `:level` ------- Signal level ∈ #{<int> :trace :debug :info :warn :error :fatal :report ...} `:kind` -------- Signal ?kind ∈ #{nil :event :error :log :trace :spy <app-val> ...} `:id` ---------- ?id of signal (common to all signals created at callsite, contrast with `:uid`) `:uid` --------- ?id of signal instance (unique to each signal created at callsite, contrast with `:id`) `:msg` --------- Arb app-level ?message to incl. in signal: str or vec of strs to join (with `\space`) `:data` -------- Arb app-level ?data to incl. in signal: usu. a map `:error` ------- Arb app-level ?error to incl. in signal: platform error [2] `:run` --------- ?form to execute UNCONDITIONALLY; will incl. `:run-value` in signal `:do` ---------- ?form to execute conditionally (iff signal allowed), before establishing `:let` ?binding `:let` --------- ?bindings to establish conditionally (iff signal allowed), BEFORE evaluating `:data` and `:msg` (useful!) `:ctx` --------- Custom ?val to override auto (dynamic `*ctx*`) in signal `:parent` ------ Custom ?{:keys [id uid]} to override auto (dynamic) parent signal tracing info `:root` -------- Custom ?{:keys [id uid]} to override auto (dynamic) root signal tracing info `:location` ---- Custom ?{:keys [ns line column file]} to override auto signal creator callsite location `:elidable?` --- Should signal be subject to compile-time elision? (Default: true) `:sample-rate` - ?rate ∈ℝ[0,1] for signal sampling (0.75 => allow 75% of signals, nil => allow all) `:when` -------- Arb ?form; when present, form must return truthy to allow signal `:rate-limit` -- ?spec as given to `taoensso.telemere/rate-limiter`, see its docstring for details `:middleware` -- Optional (fn [signal]) => ?modified-signal to apply when signal is created `:trace?` ------ Should tracing be enabled for `:run` form? <kvs> ---------- Other arb app-level ?kvs to incl. in signal. Typically NOT included in handler output, so a great way to provide custom data/opts for use (only) by custom middleware/handlers. handler-specific data that can just be ignored by other handlers If anything is unclear, please ping me (@ptaoussanis) so that I can improve these docs! [1] `java.time.Instant` or `js/Date` [2] `java.lang.Throwable` or `js/Error`
(log! msg)
(log! level msg)
(log! {:as opts
:keys [elidable? location inst uid middleware sample-rate kind ns id
level when rate-limit ctx parent root trace? do let data msg error
& kvs]}
msg)
"Log" signal creator, emphasizing message + level. API: [msg] [level-or-opts msg] => true iff signal was allowed. Default kind: `:log` Default level: `:info` When filtering conditions are met [4], creates a Telemere signal [3] and dispatches it to registered handlers for processing (e.g. writing to console/file/queue/db, etc.). Examples: (log! "My msg") ; %> {:kind :log, :level :info, :id ::my-id ...} (log! :warn "My msg") ; %> {... :level :warn ...} (log! {:let [x "x"] ; Available to `:data` and `:msg` :data {:x x}} ["My msg:" x]) ; %> {... :data {x "x"}, :msg_ "My msg: x" ...} Tips: - Test using `with-signal`: (with-signal (log! ...)). - Supports the same options [2] as other signals [1]. - `log!` and `event!` are both good default/general-purpose signal creators. - `log!` emphasizes messages, while `event!` emphasizes ids. - `msg` arg may be a string, or vector of strings to join with `\space`. - See also `msg-splice`, `msg-skip` utils. ---------------------------------------------------------------------- [1] See `help:signal-creators` - (`signal!`, `log!`, `event!`, ...) [2] See `help:signal-options` - {:keys [kind level id data ...]} [3] See `help:signal-content` - {:keys [kind level id data ...]} [4] See `help:signal-filters` - (by ns/kind/id/level, sampling, etc.)
For use within signal message vectors. Special value that will be ignored (noop) when creating message. Useful for conditionally skipping parts of message content, etc.: (signal! {:msg ["Hello" (if <cond> <then> msg-skip) "world"] <...>}) or (log! ["Hello" (if <cond> <then> msg-skip) "world"]), etc. %> {:msg_ "Hello world" <...>}
(msg-splice args)
For use within signal message vectors. Wraps given arguments so that they're spliced when creating message. Useful for conditionally splicing in extra message content, etc.: (signal! {:msg [(when <cond> (msg-splice ["Username:" "Steve"])) <...>]}) or (log! [(when <cond> (msg-splice ["Username:" "Steve"]))]) %> {:msg_ "Username: Steve"}
(pr-signal-fn)
(pr-signal-fn {:keys [pr-fn incl-kvs? incl-nils? incl-newline? incl-keys]
:as opts
:or {pr-fn :edn incl-newline? true}})
Experimental, subject to change. Returns a (fn pr [signal]) that: - Takes a Telemere signal (map). - Returns a machine-readable signal ?string. Options: `:pr-fn` - ∈ #{<unary-fn> :edn (default) :json (Cljs only)} `:incl-kvs?` - Include signal's app-level kvs? (default false) `:incl-nils?` - Include signal's keys with nil values? (default false) `:incl-newline?` - Include terminating system newline? (default true) `:incl-keys` - Subset of signal keys to retain from those otherwise excluded by default: #{:location :kvs :file :thread} Examples: (pr-signal-fn {:pr-fn :edn ...}) ; Outputs edn (pr-signal-fn {:pr-fn :json ...}) ; Outputs JSON (Cljs only) To output JSON for Clj, you must provide an appropriate `:pr-fn`. `jsonista` offers one good option, Ref. <https://github.com/metosin/jsonista>: (require '[jsonista.core :as jsonista]) (pr-signal-fn {:pr-fn jsonista/write-value-as-string ...}) See also `format-signal-fn` for human-readable output.
(rate-limiter spec)
(rate-limiter opts spec)
Takes a spec of form [ [<n-max-reqs> <msecs-window>] ...] or {<limit-id> [<n-max-reqs> <msecs-window>]}, and returns a basic stateful (fn a-rate-limiter [req-id] [command req-id]). Call the limiter fn with a request id (e.g. username) by which to count/limit. Will return: - nil when allowed (all limits pass for given req-id), or - [<worst-limit-id> <worst-backoff-msecs> {<limit-id> <backoff-msecs>}] when denied (any limits fail for given req-id). Or call the limiter fn with an additional command argument: `:rl/peek` <req-id> - Check limits w/o incrementing count. `:rl/reset` <req-id> - Reset all limits for given req-id. Example: (defonce my-rate-limiter (rate-limiter {"1 per sec" [1 1000] "10 per min" [10 60000]})) (defn send-message! [username msg-content] (if-let [fail (my-rate-limiter username)] (throw (ex-info "Sorry, rate limited!" {:fail fail})) <send message>))
(remove-handler! handler-id)
Stops and deregisters signal handler with given id, and returns ?{<handler-id> {:keys [dispatch-opts handler-fn]}} for all handlers still registered.
(set-ctx! root-ctx-val)
Set `*ctx*` var's default (root) value. See `*ctx*` for details.
(set-id-filter! id-filter)
Sets signal id filter based on given `id-filter` spec. `id-filter` may be: - A str/kw/sym to allow, in which "*"s act as wildcards. - A regex pattern of id/s to allow. - A vector or set of regex patterns or strs/kws/syms. - {:allow <spec> :disallow <spec>} with specs as above. If present, `:allow` spec MUST match, AND If present, `:disallow` spec MUST NOT match.
(set-kind-filter! kind-filter)
Sets signal kind filter based on given `kind-filter` spec. `kind-filter` may be: - A str/kw/sym to allow, in which "*"s act as wildcards. - A regex pattern of kind/s to allow. - A vector or set of regex patterns or strs/kws/syms. - {:allow <spec> :disallow <spec>} with specs as above. If present, `:allow` spec MUST match, AND If present, `:disallow` spec MUST NOT match.
(set-middleware! ?root-middleware-fn)
Set `*middleware*` var's default (root) value. See `*middleware*` for details.
(set-min-level! min-level)
(set-min-level! kind min-level)
(set-min-level! kind ns-filter min-level)
Sets minimum signal level based on given `min-level` spec. `min-level` may be: - nil (=> no minimum level). - A level keyword (see `level-aliases` var for details). - An integer. If `ns-filter` is provided, then the given minimum level will apply only for the namespace/s that match `ns-filter`. See `set-ns-filter!` for details. If non-nil `kind` is provided, then the given minimum level will apply only for that signal kind. Examples: (set-min-level! nil) ; Disable minimum level (set-min-level! :info) ; Set `:info` as minimum level (set-min-level! 100) ; Set 100 as minimum level ;; Set `:debug` as minimum level for current namespace ;; (nil `kind` => all kinds) (set-min-level! nil *ns* :debug)
(set-ns-filter! ns-filter)
Sets signal namespace filter based on given `ns-filter` spec. `ns-filter` may be: - A namespace. - A str/kw/sym to allow, in which "*"s act as wildcards. - A regex pattern of namespace/s to allow. - A vector or set of regex patterns or strs/kws/syms. - {:allow <spec> :disallow <spec>} with specs as above. If present, `:allow` spec MUST match, AND If present, `:disallow` spec MUST NOT match.
(set-var-root! var-sym root-val)
Sets root binding (value) of the var identified by given symbol, and returns the new value. Cross-platform. See also `update-var-root!`.
(signal! {:as opts
:keys [elidable? location inst uid middleware sample-rate kind ns id
level when rate-limit ctx parent root trace? do let data msg
error run & kvs]})
Low-level generic signal creator. API: [opts] => depends on options [2] Default kind: none (optional) Default level: none (must be provided) When filtering conditions are met [4], creates a Telemere signal [3] and dispatches it to registered handlers for processing (e.g. writing to console/file/queue/db, etc.). If `:run` option is provided: returns value of given run form, or throws. Otherwise: returns true iff signal was created (allowed). Generic signals are fairly low-level and useful mostly for library authors or advanced users writing their own wrapper macros. Regular users will typically prefer one of the higher-level signal creators optimized for ease-of-use in common cases [1]. Tips: - Test using `with-signal`: (with-signal (signal! ...)). - Supports the same options [2] as other signals [1]. ---------------------------------------------------------------------- [1] See `help:signal-creators` - (`signal!`, `log!`, `event!`, ...) [2] See `help:signal-options` - {:keys [kind level id data ...]} [3] See `help:signal-content` - {:keys [kind level id data ...]} [4] See `help:signal-filters` - (by ns/kind/id/level, sampling, etc.)
(spy! form)
(spy! id form)
(spy! {:as opts
:keys [elidable? location inst uid middleware sample-rate kind ns id
level when rate-limit ctx parent root trace? do let data msg error
run & kvs]}
form)
"Spy" signal creator, emphasizing form + level. API: [form] [level-or-opts form] => form's result (value/throw) (unconditional) Default kind: `:spy` Default level: `:info` When filtering conditions are met [4], creates a Telemere signal [3] and dispatches it to registered handlers for processing (e.g. writing to console/file/queue/db, etc.). Examples: (spy! (+ 1 2)) ; %> {:kind :trace, :level :info, :run-form '(+ 1 2), ; :run-val 3, :run-nsecs <int>, :parent {:keys [id uid]} ; :msg "(+ 1 2) => 3" ...} (spy! ::my-id (+ 1 2)) ; %> {... :id ::my-id ...} (spy! {:let [x "x"] ; Available to `:data` and `:msg` :data {:x x}} (+ 1 2)) ; %> {... :data {x "x"}, :msg_ "My msg: x" ...} Tips: - Test using `with-signal`: (with-signal (spy! ...)). - Supports the same options [2] as other signals [1]. - Identical to `trace!`, but emphasizes form + level rather than form + id. - Useful for debugging/monitoring forms, and tracing (nested) execution flow. - Execution of `form` arg may create additional (nested) signals. Each signal's `:parent` key will indicate its immediate parent. - Can be useful to wrap with `catch->error!`: (catch->error! ::error-id (spy! ...)). ---------------------------------------------------------------------- [1] See `help:signal-creators` - (`signal!`, `log!`, `event!`, ...) [2] See `help:signal-options` - {:keys [kind level id data ...]} [3] See `help:signal-content` - {:keys [kind level id data ...]} [4] See `help:signal-filters` - (by ns/kind/id/level, sampling, etc.)
(stop-handlers!)
Stops registered signal handlers in parallel by calling each handler-fn with no arguments. This gives each handler the opportunity to flush buffers, close files, etc. Each handler will immediately stop accepting new signals, nooping if called. Blocks to return ?{<handler-id> {:keys [okay error]}}, honouring each handler's `:drain-msecs` value (see `help:handler-dispatch-options`). NB you should always call `stop-handlers!` somewhere appropriate - usually near the end of your `-main` or shutdown procedure, AFTER all other code has completed that could create signals.
(streams->reset!)
Experimental, subject to change. Resets `System/out` and `System/err` to their original value (prior to any `streams->telemere!` call).
(streams->telemere!)
(streams->telemere! {:keys [out err]
:or {out default-out-opts err default-err-opts}})
Experimental, subject to change. When given `out`, sets JVM's `System/out` to flush to Telemere signals with those opts. When given `err`, sets JVM's `System/err` to flush to Telemere signals with those opts. Note that setting `System/out` won't necessarily affect Clojure's `*out*`, and setting `System/err` won't necessarily affect Clojure's `*err*`. See also: `with-out->telemere`, `with-err->telemere`, `with-streams->telemere`.
(trace! form)
(trace! id form)
(trace! {:as opts
:keys [elidable? location inst uid middleware sample-rate kind ns id
level when rate-limit ctx parent root trace? do let data msg
error run & kvs]}
form)
"Trace" signal creator, emphasizing form + id. API: [form] [id-or-opts form] => form's result (value/throw) (unconditional) Default kind: `:trace` Default level: `:info` (intentionally NOT `:trace`!) When filtering conditions are met [4], creates a Telemere signal [3] and dispatches it to registered handlers for processing (e.g. writing to console/file/queue/db, etc.). Examples: (trace! (+ 1 2)) ; %> {:kind :trace, :level :info, :run-form '(+ 1 2), ; :run-val 3, :run-nsecs <int>, :parent {:keys [id uid]} ... ; :msg "(+ 1 2) => 3" ...} (trace! ::my-id (+ 1 2)) ; %> {... :id ::my-id ...} (trace! {:let [x "x"] ; Available to `:data` and `:msg` :data {:x x}} (+ 1 2)) ; %> {... :data {x "x"}, :msg_ "My msg: x" ...} Tips: - Test using `with-signal`: (with-signal (trace! ...)). - Supports the same options [2] as other signals [1]. - Identical to `spy!`, but emphasizes form + id rather than form + level. - Useful for debugging/monitoring forms, and tracing (nested) execution flow. - Execution of `form` arg may create additional (nested) signals. Each signal's `:parent` key will indicate its immediate parent. - Can be useful to wrap with `catch->error!`: (catch->error! ::error-id (trace! ...)). - Default level is `:info`, not `:trace`! The name "trace" in "trace signal" refers to the general action of tracing program flow rather than to the common logging level of the same name. ---------------------------------------------------------------------- [1] See `help:signal-creators` - (`signal!`, `log!`, `event!`, ...) [2] See `help:signal-options` - {:keys [kind level id data ...]} [3] See `help:signal-content` - {:keys [kind level id data ...]} [4] See `help:signal-filters` - (by ns/kind/id/level, sampling, etc.)
(uncaught->error!)
(uncaught->error! id)
(uncaught->error! {:as opts
:keys [elidable? location inst uid middleware sample-rate
kind ns id level when rate-limit ctx parent root
trace? do let data msg error & kvs]})
Uses `uncaught->handler!` so that `error!` will be called for uncaught JVM errors. See `uncaught->handler!` and `error!` for details.
(uncaught->handler! handler)
Sets JVM's global `DefaultUncaughtExceptionHandler` to given (fn handler [`<java.lang.Thread>` `<java.lang.Throwable>`]). See also `uncaught->error!`.
(update-var-root! var-sym update-fn)
Updates root binding (value) of the var identified by given symbol, and returns the new value: (update-var-root! my-var (fn [old-root-val] <new-root-val>)) => <new-root-val> Similar to `alter-var-root` but cross-platform and takes a symbol rather than a var. See also `set-var-root!`.
(with-ctx ctx-val form)
Evaluates given form with given `*ctx*` value. See `*ctx*` for details.
(with-ctx+ update-map-or-fn form)
Evaluates given form with updated `*ctx*` value. `update-map-or-fn` may be: - A map to merge with current `*ctx*` value, or - A unary fn to apply to current `*ctx*` value See `*ctx*` for details.
(with-err->telemere form)
(with-err->telemere opts form)
Executes form with `*err*` bound to flush to Telemere signals with given opts.
(with-handler handler-id handler-fn form)
(with-handler handler-id handler-fn dispatch-opts form)
Executes form with ONLY the given signal handler registered. Stops handler after use. Useful for tests/debugging. See `help:handler-dispatch-options` for handler filters, etc. See also `with-handler+`.
(with-handler+ handler-id handler-fn form)
(with-handler+ handler-id handler-fn dispatch-opts form)
Executes form with the given signal handler (also) registered. Stops handler after use. Useful for tests/debugging. See `help:handler-dispatch-options` for handler filters, etc. See also `with-handler`.
(with-id-filter id-filter form)
Executes form with given signal id filter in effect. See `set-id-filter!` for details.
(with-kind-filter kind-filter form)
Executes form with given signal kind filter in effect. See `set-kind-filter!` for details.
(with-middleware ?middleware-fn form)
Evaluates given form with given `*middleware*` value. See `*middleware*` for details.
(with-min-level min-level form)
(with-min-level kind min-level form)
(with-min-level kind ns-filter min-level form)
Executes form with given minimum signal level in effect. See `set-min-level!` for details.
(with-ns-filter ns-filter form)
Executes form with given signal namespace filter in effect. See `set-ns-filter!` for details.
(with-out->telemere form)
(with-out->telemere opts form)
Executes form with `*out*` bound to flush to Telemere signals with given opts.
(with-signal form)
(with-signal trap-signals? form)
(with-signal raw-msg? trap-signals? form)
Experimental, subject to change. Executes given form, trapping errors. Returns the LAST signal created by form. Useful for tests/debugging. Options: `trap-signals?` (default false) Should ALL signals created by form be trapped to prevent normal dispatch to registered handlers? `raw-msg?` (default false) Should delayed `:msg_` in returned signal be retained as-is? Delay is otherwise replaced by realized string. See also `with-signals`.
(with-signals form)
(with-signals trap-signals? form)
(with-signals raw-msgs? trap-signals? form)
Experimental, subject to change. Like `with-signal` but returns [[<form-value> <form-error>] [<signal1> ...]]. Useful for tests/debugging.
(with-streams->telemere form)
(with-streams->telemere {:keys [out err]
:or {out default-out-opts err default-err-opts}}
form)
Executes form with `*out*` and/or `*err*` bound to flush to Telemere signals with given opts.
(without-filters form)
Executes form without any runtime signal filters.
cljdoc is a website building & hosting documentation for Clojure/Script libraries
× close