[nop] Housekeeping

This commit is contained in:
Peter Taoussanis 2024-04-29 17:42:52 +02:00
parent 378465b373
commit 63f488082b
10 changed files with 64 additions and 62 deletions

View file

@ -8,7 +8,7 @@
:url "https://www.eclipse.org/legal/epl-v10.html"} :url "https://www.eclipse.org/legal/epl-v10.html"}
:dependencies :dependencies
[[com.taoensso/encore "3.105.1"]] [[com.taoensso/encore "3.107.0"]]
:test-paths ["test" #_"src"] :test-paths ["test" #_"src"]
@ -16,7 +16,7 @@
{;; :default [:base :system :user :provided :dev] {;; :default [:base :system :user :provided :dev]
:provided {:dependencies [[org.clojure/clojurescript "1.11.132"] :provided {:dependencies [[org.clojure/clojurescript "1.11.132"]
[org.clojure/clojure "1.11.3"]]} [org.clojure/clojure "1.11.3"]]}
:c1.12 {:dependencies [[org.clojure/clojure "1.12.0-alpha10"]]} :c1.12 {:dependencies [[org.clojure/clojure "1.12.0-alpha11"]]}
:c1.11 {:dependencies [[org.clojure/clojure "1.11.3"]]} :c1.11 {:dependencies [[org.clojure/clojure "1.11.3"]]}
:c1.10 {:dependencies [[org.clojure/clojure "1.10.1"]]} :c1.10 {:dependencies [[org.clojure/clojure "1.10.1"]]}
@ -48,10 +48,12 @@
[com.taoensso/slf4j-telemere "1.0.0-beta5"] [com.taoensso/slf4j-telemere "1.0.0-beta5"]
#_[org.slf4j/slf4j-simple "2.0.13"] #_[org.slf4j/slf4j-simple "2.0.13"]
#_[org.slf4j/slf4j-nop "2.0.13"] #_[org.slf4j/slf4j-nop "2.0.13"]
[com.draines/postal "2.0.5"]
;;; For optional handlers
[io.opentelemetry/opentelemetry-api "1.37.0"] [io.opentelemetry/opentelemetry-api "1.37.0"]
#_[io.opentelemetry/opentelemetry-sdk-extension-autoconfigure "1.37.0"] #_[io.opentelemetry/opentelemetry-sdk-extension-autoconfigure "1.37.0"]
#_[io.opentelemetry/opentelemetry-exporter-otlp "1.37.0"]] #_[io.opentelemetry/opentelemetry-exporter-otlp "1.37.0"]
[com.draines/postal "2.0.5"]]
:plugins :plugins
[[lein-pprint "1.3.2"] [[lein-pprint "1.3.2"]

View file

@ -1,5 +1,5 @@
Common signal formatters include: Common signal formatters include:
(utils/format-signal-str->fn) {<opts>}) ; For human-readable string output (default) (utils/format-signal->str-fn) {<opts>}) ; For human-readable string output (default)
(utils/format-signal->edn-fn) {<opts>}) ; For edn output (utils/format-signal->edn-fn) {<opts>}) ; For edn output
(utils/format-signal->json-fn {<opts>}) ; For JSON output (utils/format-signal->json-fn {<opts>}) ; For JSON output

View file

@ -1,7 +1,7 @@
{;;:lein true {;;:lein true
:source-paths ["src" "test"] :source-paths ["src" "test"]
:dependencies :dependencies
[[com.taoensso/encore "3.105.1"] [[com.taoensso/encore "3.107.0"]
[cider/cider-nrepl "0.47.0"] [cider/cider-nrepl "0.47.0"]
[binaryage/devtools "1.0.7"]] [binaryage/devtools "1.0.7"]]

View file

@ -32,9 +32,10 @@
(remove-ns 'taoensso.telemere) (remove-ns 'taoensso.telemere)
(:api (enc/interns-overview))) (:api (enc/interns-overview)))
(enc/assert-min-encore-version [3 105 1]) (enc/assert-min-encore-version [3 107 0])
;;;; TODO ;;;; TODO
;; - Add handlers: Logstash, Slack, Carmine, Datadog, Kafka
;; - Native OpenTelemetry traces and spans ;; - Native OpenTelemetry traces and spans
;; - Update Tufte (signal API, config API, signal keys, etc.) ;; - Update Tufte (signal API, config API, signal keys, etc.)
;; - Update Timbre (signal API, config API, signal keys, backport improvements) ;; - Update Timbre (signal API, config API, signal keys, backport improvements)
@ -118,12 +119,12 @@
#?(:clj #?(:clj
(defmacro set-ctx! (defmacro set-ctx!
"Set `*ctx*` var's root (base) value. See `*ctx*` for details." "Set `*ctx*` var's root (base) value. See `*ctx*` for details."
[root-val] `(enc/set-var-root! *ctx* ~root-val))) [root-ctx-val] `(enc/set-var-root! *ctx* ~root-ctx-val)))
#?(:clj #?(:clj
(defmacro with-ctx (defmacro with-ctx
"Evaluates given form with given `*ctx*` value. See `*ctx*` for details." "Evaluates given form with given `*ctx*` value. See `*ctx*` for details."
[init-val form] `(binding [*ctx* ~init-val] ~form))) [ctx-val form] `(binding [*ctx* ~ctx-val] ~form)))
(comment (with-ctx "my-ctx" *ctx*)) (comment (with-ctx "my-ctx" *ctx*))

View file

@ -18,7 +18,7 @@
Returns a (fn handler [signal]) that: Returns a (fn handler [signal]) that:
- Takes a Telemere signal. - Takes a Telemere signal.
- Writes a formatted signal string to stream. - Writes formatted signal string to stream.
A general-purpose `println`-style handler that's well suited for outputting A general-purpose `println`-style handler that's well suited for outputting
signals formatted as edn, JSON, or human-readable strings. signals formatted as edn, JSON, or human-readable strings.
@ -34,8 +34,7 @@
:or {format-signal-fn (utils/format-signal->str-fn)}}] :or {format-signal-fn (utils/format-signal->str-fn)}}]
(let [stream (case stream :*out* *out*, :*err* *err* stream) (let [stream (case stream :*out* *out*, :*err* *err* stream)
error-signal? utils/error-signal? error-signal? utils/error-signal?]
nl utils/newline]
(fn a-handler:console (fn a-handler:console
([]) ; Shut down (no-op) ([]) ; Shut down (no-op)
@ -52,7 +51,7 @@
If `js/console` exists, returns a (fn handler [signal]) that: If `js/console` exists, returns a (fn handler [signal]) that:
- Takes a Telemere signal. - Takes a Telemere signal.
- Writes a formatted signal string to JavaScript console. - Writes formatted signal string to JavaScript console.
A general-purpose `println`-style handler that's well suited for outputting A general-purpose `println`-style handler that's well suited for outputting
signals formatted as edn, JSON, or human-readable strings. signals formatted as edn, JSON, or human-readable strings.
@ -65,8 +64,7 @@
:or {format-signal-fn (utils/format-signal->str-fn)}}] :or {format-signal-fn (utils/format-signal->str-fn)}}]
(when (exists? js/console) (when (exists? js/console)
(let [js-console-logger utils/js-console-logger (let [js-console-logger utils/js-console-logger]
nl utils/newline]
(fn a-handler:console (fn a-handler:console
([]) ; Shut down (no-op) ([]) ; Shut down (no-op)

View file

@ -270,7 +270,7 @@
Returns a (fn handler [signal]) that: Returns a (fn handler [signal]) that:
- Takes a Telemere signal. - Takes a Telemere signal.
- Writes a formatted signal string to file. - Writes formatted signal string to file.
Signals will be appended to file specified by `path`. Signals will be appended to file specified by `path`.
Depending on options, archives may be maintained: Depending on options, archives may be maintained:

View file

@ -201,14 +201,6 @@
(defmacro with-tracing (defmacro with-tracing
"Wraps `form` with tracing iff const boolean `trace?` is true." "Wraps `form` with tracing iff const boolean `trace?` is true."
[trace? id uid form] [trace? id uid form]
;; Not much motivation to support runtime `trace?` form, but easy
;; to add support later if desired
(when-not (enc/const-form? trace?)
(enc/unexpected-arg! trace?
{:msg "Expected constant (compile-time) `:trace?` value"
:context `with-tracing}))
(if trace? (if trace?
`(binding [*trace-parent* (TraceParent. ~id ~uid)] ~form) `(binding [*trace-parent* (TraceParent. ~id ~uid)] ~form)
(do form)))) (do form))))
@ -581,6 +573,13 @@
id-form :id} opts id-form :id} opts
trace? (get opts :trace? (boolean run-form)) trace? (get opts :trace? (boolean run-form))
_
(when-not (contains? #{true false nil} trace?)
;; Not much motivation to support runtime `trace?` form, but easy
;; to add support later if desired
(enc/unexpected-arg! trace?
{:msg "Expected constant (compile-time) `:trace?` boolean"
:context `with-tracing}))
inst-form (get opts :inst :auto) inst-form (get opts :inst :auto)
inst-form (if (= inst-form :auto) `(enc/now-inst*) inst-form) inst-form (if (= inst-form :auto) `(enc/now-inst*) inst-form)
@ -588,7 +587,7 @@
uid-form (get opts :uid (when trace? :auto/uuid)) uid-form (get opts :uid (when trace? :auto/uuid))
uid-form (parse-uid-form uid-form) uid-form (parse-uid-form uid-form)
signal-form signal-delay-form
(let [{do-form :do (let [{do-form :do
let-form :let let-form :let
msg-form :msg msg-form :msg
@ -601,6 +600,7 @@
ctx-form (get opts :ctx `taoensso.telemere/*ctx*) ctx-form (get opts :ctx `taoensso.telemere/*ctx*)
parent-form (get opts :parent (when trace? `taoensso.telemere.impl/*trace-parent*)) parent-form (get opts :parent (when trace? `taoensso.telemere.impl/*trace-parent*))
middleware-form (get opts :middleware `taoensso.telemere/*middleware*)
kvs-form kvs-form
(not-empty (not-empty
@ -610,6 +610,7 @@
:ctx :parent #_:trace?, :do :let :data :msg :error :run :ctx :parent #_:trace?, :do :let :data :msg :error :run
:elide? :allow? #_:expansion-id))] :elide? :allow? #_:expansion-id))]
;; Compile-time validation
(when (and run-form error-form) (when (and run-form error-form)
(throw ; Prevent ambiguity re: source of error (throw ; Prevent ambiguity re: source of error
(ex-info "Signals cannot have both `:run` and `:error` opts at the same time" (ex-info "Signals cannot have both `:run` and `:error` opts at the same time"
@ -618,23 +619,29 @@
:location location :location location
:other-opts (dissoc opts :run :error)}))) :other-opts (dissoc opts :run :error)})))
;; Eval let bindings AFTER call filtering but BEFORE data, msg `(delay
`(do ;; Delay (cache) shared by all handlers. Covers signal `:let` eval, signal construction,
;; middleware (possibly expensive), etc. Throws here will be caught by handler.
~do-form ~do-form
(let ~let-form ; Allow to throw during `signal-value_` deref (let [~@let-form ; Allow to throw, eval BEFORE data, msg, etc.
~'__signal
(new-signal ~'__inst ~'__uid (new-signal ~'__inst ~'__uid
~location ~'__ns ~line-form ~column-form ~file-form, ~location ~'__ns ~line-form ~column-form ~file-form,
~sample-rate-form, ~'__kind ~'__id ~'__level, ~ctx-form ~parent-form, ~sample-rate-form, ~'__kind ~'__id ~'__level, ~ctx-form ~parent-form,
~kvs-form ~data-form ~msg-form, ~kvs-form ~data-form ~msg-form,
'~run-form ~'__run-result ~error-form)))) '~run-form ~'__run-result ~error-form)]
run-fn-form (when run-form `(fn [] (~run-form)))] ;; Final unwrapped signal value visible to users/handler-fns, allow to throw
(if-let [call-middleware# ~middleware-form]
((sigs/get-middleware-fn call-middleware#) ~'__signal) ; Can throw
(do ~'__signal)))))]
;; Could avoid double `run-form` expansion with a fn wrap (>0 cost) ;; Could avoid double `run-form` expansion with a fn wrap (>0 cost)
;; (let [run-fn-form (when run-form `(fn [] (~run-form)))]
;; `(let [~'run-fn-form ~run-fn-form] ;; `(let [~'run-fn-form ~run-fn-form]
;; (if-not ~allow? ;; (if-not ~allow?
;; (run-fn-form) ;; (run-fn-form)
;; (let [...]))) ;; (let [...]))))
`(enc/if-not ~allow? ; Allow to throw at call `(enc/if-not ~allow? ; Allow to throw at call
~run-form ~run-form
@ -645,33 +652,23 @@
~'__uid ~uid-form ; '' ~'__uid ~uid-form ; ''
~'__ns ~ns-form ; '' ~'__ns ~ns-form ; ''
~'__call-middleware ~(get opts :middleware `taoensso.telemere/*middleware*)
~'__run-result ; Non-throwing (traps) ~'__run-result ; Non-throwing (traps)
~(when run-form ~(when run-form
`(let [~'__t0 (enc/now-nano*)] `(let [t0# (enc/now-nano*)]
(with-tracing ~trace? ~'__id ~'__uid (with-tracing ~trace? ~'__id ~'__uid
(enc/try* (enc/try*
(do (RunResult. ~run-form nil (- (enc/now-nano*) ~'__t0))) (do (RunResult. ~run-form nil (- (enc/now-nano*) t0#)))
(catch :all ~'__t (RunResult. nil ~'__t (- (enc/now-nano*) ~'__t0))))))) (catch :all t# (RunResult. nil t# (- (enc/now-nano*) t0#)))))))
~'__signal_ signal_# ~signal-delay-form]
(delay
;; Cache shared by all handlers. Covers signal `:let` eval, signal construction,
;; middleware (possibly expensive), etc.
;; The unwrapped signal value actually visible to users/handler-fns, realized only (dispatch-signal! ; Runner preserves dynamic bindings when async.
;; AFTER handler filtering. Allowed to throw on deref (handler will catch). ;; Unconditionally send same wrapped signal to all handlers. Each handler will
(let [~'__signal ~signal-form] ; Can throw ;; use wrapper for handler filtering, unwrapping (realizing) only allowed signals.
(if ~'__call-middleware (WrappedSignal. ~'__ns ~'__kind ~'__id ~'__level signal_#))
((sigs/get-middleware-fn ~'__call-middleware) ~'__signal) ; Can throw
(do ~'__signal))))]
;; Unconditionally send same wrapped signal to all handlers.
;; Each handler will then use wrapper for filtering, unwrapping allowed signals.
(dispatch-signal! (WrappedSignal. ~'__ns ~'__kind ~'__id ~'__level ~'__signal_))
(if ~'__run-result (if ~'__run-result
(do (~'__run-result ~'__signal_)) (do (~'__run-result signal_#))
true)))))))) true))))))))
(comment (comment

View file

@ -55,7 +55,7 @@
Returns a (fn handler [signal]) that: Returns a (fn handler [signal]) that:
- Takes a Telemere signal. - Takes a Telemere signal.
- Sends an email with formatted signal content to the configured recipient. - Sends formatted signal string as email to specified recipient.
Useful for emailing important alerts to admins, etc. Useful for emailing important alerts to admins, etc.

View file

@ -249,7 +249,7 @@
:writer/state {:file file, :stream (.deref stream_)} :writer/state {:file file, :stream (.deref stream_)}
(when (open?_) (when (open?_)
(let [content content-or-action (let [content content-or-action
ba (.getBytes (str content) java.nio.charset.StandardCharsets/UTF_8)] ba (enc/str->utf8-ba (str content))]
(locking lock (locking lock
(try (try
(file-exists!) (file-exists!)

View file

@ -240,6 +240,10 @@
(is (= rv4 true)) (is (= sv4 "signal-value")) (is (= rv4 true)) (is (= sv4 "signal-value"))
(is (= @c 7) "3x run + 4x middleware")])) (is (= @c 7) "3x run + 4x middleware")]))
(testing "Binding conveyance"
(binding [*dynamic-var* :foo]
(is (sm? (with-sig (sig! {:level :info, :data {:dynamic-var *dynamic-var*}})) {:data {:dynamic-var :foo}}))))
#?(:clj #?(:clj
(testing "Printing" (testing "Printing"
(let [sv1 (with-sig (sig! {:level :info, :run (+ 1 2), :my-k1 :my-v1})) (let [sv1 (with-sig (sig! {:level :info, :run (+ 1 2), :my-k1 :my-v1}))