Skip to content

Commit

Permalink
[new] Add signal-allowed?
Browse files Browse the repository at this point in the history
Useful for using Telemere's filtering features without generating
any signals, etc.
  • Loading branch information
ptaoussanis committed Sep 13, 2024
1 parent da53018 commit 3279210
Show file tree
Hide file tree
Showing 4 changed files with 108 additions and 31 deletions.
1 change: 1 addition & 0 deletions projects/main/src/taoensso/telemere.cljc
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@
#?(:clj impl/with-signal)
#?(:clj impl/with-signals)
#?(:clj impl/signal!)
#?(:clj impl/signal-allowed?)

;; Utils
utils/format-signal-fn
Expand Down
25 changes: 20 additions & 5 deletions projects/main/src/taoensso/telemere/impl.cljc
Original file line number Diff line number Diff line change
Expand Up @@ -381,6 +381,13 @@
sample-rate kind ns id level when rate-limit,
ctx parent root trace?, do let data msg error run & kvs]}])

:signal-allowed?
'([{:as opts :keys
[#_defaults #_elide? #_allow? #_expansion-id, ; Undocumented
elidable? location #_location* #_inst #_uid #_middleware,
sample-rate kind ns id level when rate-limit,
#_ctx #_parent #_root #_trace?, #_do #_let #_data #_msg #_error #_run #_& #_kvs]}])

:event! ; [id] [id level-or-opts] => allowed?
'([id ]
[id level]
Expand Down Expand Up @@ -762,19 +769,27 @@
(signal! {:level :info, :run "run"}))))

#?(:clj
(defmacro signal-allowed?
"Used only for interop (tools.logging, SLF4J, etc.)."
{:arglists (signal-arglists :signal!)}
(defmacro ^:public signal-allowed?
"Returns true iff signal with given opts would meet filtering conditions:
(when (signal-allowed? {:level :warn}) (my-custom-code))"
;; Used also for interop (tools.logging, SLF4J), etc.
{:arglists (signal-arglists :signal-allowed?)}
[opts]
(let [{:keys [#_expansion-id #_location elide? allow?]}
(have? map? opts)
(let [defaults (get opts :defaults)
opts (merge defaults (dissoc opts :defaults))

{:keys [#_expansion-id #_location elide? allow?]}
(sigs/filterable-expansion
{:sf-arity 4
:ct-sig-filter ct-sig-filter
:*rt-sig-filter* `*rt-sig-filter*}
(assoc opts :location*
(get opts :location* (enc/get-source &form &env))))]

(and (not elide?) allow?))))
(if elide? false `(if ~allow? true false)))))

(comment (macroexpand '(signal-allowed? {:level :info})))

;;;; Interop

Expand Down
5 changes: 4 additions & 1 deletion projects/main/test/taoensso/telemere_tests.cljc
Original file line number Diff line number Diff line change
Expand Up @@ -275,7 +275,10 @@

[(is (= sv1 (read-string (pr-str sv1))))])))

(is (sm? (with-sig (shell/signal! {:level :info})) {:level :info, :ns "taoensso.telemere-tests", :line :submap/some}) "Shell API")])
(testing "Shell API"
[(is (sm? (with-sig (shell/signal! {:level :info})) {:level :info, :ns "taoensso.telemere-tests", :line :submap/some}))
(is (true? (tel/with-min-level :debug (shell/signal-allowed? {:level :debug}))))
(is (false? (tel/with-min-level :debug (shell/signal-allowed? {:level :trace}))))])])

(deftest _handlers
;; Basic handler tests are in Encore
Expand Down
108 changes: 83 additions & 25 deletions projects/shell/src/taoensso/telemere/shell.cljc
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,58 @@
(remove-ns 'taoensso.telemere.shell)
(:api (enc/interns-overview)))

;;;; Private

#?(:clj
(defmacro ^:private compile-if [test then else]
(if (try (eval test) (catch Throwable _ false)) then else)))

(def ^:private telemere-present?
"Is Telemere present (not necessarily loaded)?"
(compile-if (jio/resource "taoensso/telemere.cljc") true false))
#?(:clj
(def ^:private telemere-present?
"Is Telemere present (not necessarily loaded)?"
(compile-if (jio/resource "taoensso/telemere.cljc") true false)))

#?(:clj
(defn- require-telemere! []
(try
(require 'taoensso.telemere) ; For macro expansion
(catch Exception e
(throw
(ex-info "Failed to require `taoensso.telemere` - `(require-telemere-if-present)` call missing?"
{} e))))))

#?(:clj
(defn- get-source "From Encore" [macro-form macro-env]
(let [{:keys [line column file]} (meta macro-form)
file
(if-not (:ns macro-env)
*file* ; Compiling Clj
(or ; Compiling Cljs
(when-let [url (and file (try (jio/resource file) (catch Exception _)))]
(try (.getPath (jio/file url)) (catch Exception _))
(do (str url)))
file))

file
(when (string? file)
(when-not (contains? #{"NO_SOURCE_PATH" "NO_SOURCE_FILE" ""} file)
file))

m {:ns (str *ns*)}
m (if line (assoc m :line line) m)
m (if column (assoc m :column column) m)
m (if file (assoc m :file file) m)]
m)))

#?(:clj
(defn- signal-opts [macro-form macro-env opts]
(if (map? opts)
(conj {:location* (get-source macro-form macro-env)} (dissoc opts :fallback))
(throw
(ex-info "Signal opts must be a map"
{:given {:value opts, :type (type opts)}})))))

;;;; Public

#?(:clj
(defmacro if-telemere
Expand Down Expand Up @@ -92,28 +137,12 @@
ctx parent root trace?, do let data msg error run & kvs]}])}

[opts]
(if (map? opts)
(if telemere-present?
(do
(try
(require 'taoensso.telemere) ; For macro expansion
(catch Exception e
(throw
(ex-info "Failed to require `taoensso.telemere` - `(require-telemere-if-present)` call missing?"
{} e))))

(with-meta ; Keep callsite
`(taoensso.telemere/signal! ~(dissoc opts :fallback))
(meta &form)))

(let [fb-form (get opts :fallback)]
(if-let [run-form (get opts :run)]
`(let [run-result# ~run-form] ~fb-form run-result#)
(do fb-form))))

(throw
(ex-info "`signal!` expects map opts"
{:given {:value opts, :type (type opts)}})))))
(if telemere-present?
(do (require-telemere!) `(taoensso.telemere/signal! ~(signal-opts &form &env opts)))
(let [fb-form (get opts :fallback)]
(if-let [run-form (get opts :run)]
`(let [run-result# ~run-form] ~fb-form run-result#)
(do fb-form))))))

(comment
(macroexpand
Expand All @@ -123,3 +152,32 @@
:msg ["Hello" "world" x]
:data {:a :A :x x}
:fallback (println (str "Hello world " x))})))

#?(:clj
(defmacro signal-allowed?
"Experimental, subject to change.
Returns true iff Telemere is present and signal with given opts would meet
filtering conditions.
MUST be used with `require-telemere-if-present`, example:
(ns my-lib (:require [taoensso.telemere.shell :as t]))
(t/require-telemere-if-present) ; Just below `ns` form!
(when (t/signal-allowed? {:level :warn})
(my-custom-code))"

{:arglists
'([{:as opts :keys
[#_fallback, ; Unique to shell
#_defaults #_elide? #_allow? #_expansion-id, ; Undocumented
elidable? location #_location* #_inst #_uid #_middleware,
sample-rate kind ns id level when rate-limit,
#_ctx #_parent #_root #_trace?, #_do #_let #_data #_msg #_error #_run #_& #_kvs]}])}

[opts]
(if telemere-present?
(do (require-telemere!) `(taoensso.telemere/signal-allowed? ~(signal-opts &form &env opts)))
(get opts :fallback nil))))

(comment (macroexpand '(signal-allowed? {:level :warn})))

0 comments on commit 3279210

Please sign in to comment.