[new] Add experimental :thread key to Clj signals

Only downside/hesitation is that this info *must* be collected at the callsite,
which means that it affects the performance of *all* created signals.

Adds ~30-50 nsecs per signal.
This commit is contained in:
Peter Taoussanis 2024-04-29 19:58:28 +02:00
parent 839143167b
commit ebe8a957f5
3 changed files with 39 additions and 20 deletions

View file

@ -26,6 +26,7 @@ Default signal keys:
`: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)
`:thread` ------ (Clj only) {:keys [group name id]} thread info for thread that called signal creator
`:sample-rate` - ?rate ∈ℝ[0,1] for combined signal AND handler sampling (0.75 => allow 75% of signals, nil => allow all)
<kvs> ---------- Other arb user-level ?kvs given to signal creator. Typically NOT included

View file

@ -215,7 +215,7 @@
(defrecord Signal
;; Telemere's main public data type, we avoid nesting and duplication
[^long schema inst uid,
location ns line column file,
location ns line column file #?(:clj thread),
sample-rate, kind id level, ctx parent,
data msg_ error run-form run-val,
end-inst run-nsecs kvs]
@ -351,7 +351,7 @@
^Signal
;; Note all dynamic vals passed as explicit args for better control
[inst uid,
location ns line column file,
location ns line column file #?(:clj thread :cljs _thread),
sample-rate, kind id level, ctx parent,
kvs data msg_,
run-form run-result error]
@ -371,14 +371,14 @@
msg_)]
(Signal. 1 inst uid,
location ns line column file,
location ns line column file #?(:clj thread),
sample-rate, kind id level, ctx parent,
data msg_,
run-err run-form run-val,
end-inst run-nsecs kvs))
(Signal. 1 inst uid,
location ns line column file,
location ns line column file #?(:clj thread),
sample-rate, kind id level, ctx parent,
data msg_, error nil nil nil nil kvs))]
@ -387,10 +387,10 @@
(do signal))))
(comment
(enc/qb 1e6 ; 55.67
(enc/qb 1e6 ; 66.8
(new-signal
nil nil nil nil nil nil nil nil nil nil
nil nil nil nil nil nil nil nil nil)))
nil nil nil nil nil nil nil nil nil nil)))
;;;; Signal API helpers
@ -540,6 +540,17 @@
;;;; Signal macro
#?(:clj
(defn thread-info
"Returns {:keys [group name id]} for current thread."
[]
(when-let [t (Thread/currentThread)]
{:group (when-let [g (.getThreadGroup t)] (.getName g))
:name (.getName t)
:id (.getId t)})))
(comment (enc/qb 1e6 (thread-info))) ; 44.49
#?(:clj
(defmacro ^:public signal!
"Generic low-level signal call, also aliased in Encore."
@ -549,6 +560,7 @@
(have? map? opts) ; We require const map keys, but vals may require eval
(let [defaults (get opts :defaults)
opts (merge defaults (dissoc opts :defaults))
clj? (not (:ns &env))
{run-form :run} opts
{:keys [#_expansion-id location elide? allow?]}
@ -587,6 +599,8 @@
uid-form (get opts :uid (when trace? :auto/uuid))
uid-form (parse-uid-form uid-form)
thread-form (if clj? `(thread-info) nil)
signal-delay-form
(let [{do-form :do
let-form :let
@ -626,7 +640,7 @@
(let [~@let-form ; Allow to throw, eval BEFORE data, msg, etc.
~'__signal
(new-signal ~'__inst ~'__uid
~location ~'__ns ~line-form ~column-form ~file-form,
~location ~'__ns ~line-form ~column-form ~file-form ~'__thread,
~sample-rate-form, ~'__kind ~'__id ~'__level, ~ctx-form ~parent-form,
~kvs-form ~data-form ~msg-form,
'~run-form ~'__run-result ~error-form)]
@ -651,6 +665,7 @@
~'__id ~id-form ; ''
~'__uid ~uid-form ; ''
~'__ns ~ns-form ; ''
~'__thread ~thread-form ; ''
~'__run-result ; Non-throwing (traps)
~(when run-form

View file

@ -4,7 +4,8 @@
(:require
[clojure.string :as str]
#?(:clj [clojure.java.io :as jio])
[taoensso.encore :as enc :refer [have have?]]))
[taoensso.encore :as enc :refer [have have?]]
[taoensso.telemere.impl :as impl]))
(comment
(require '[taoensso.telemere :as tel])
@ -52,7 +53,7 @@
;;;; Public misc
(enc/defaliases enc/newline enc/pr-edn #?(:cljs enc/pr-json))
(enc/defaliases enc/newline enc/pr-edn #?(:cljs enc/pr-json) #?(:clj impl/thread-info))
#?(:clj (defn thread-name "Returns string name of current thread." ^String [] (.getName (Thread/currentThread))))
#?(:clj (defn thread-id "Returns long id of current thread." ^long [] (.getId (Thread/currentThread))))
@ -375,10 +376,12 @@
err-stop (str newline ">>> error >>>")]
(fn a-signal-content-handler [signal hf vf]
(let [{:keys [uid parent data #_kvs ctx sample-rate]} signal]
(let [{:keys [uid parent data #_kvs ctx #?(:clj thread) sample-rate]} signal]
(when sample-rate (hf "sample: " (vf sample-rate)))
(when uid (hf " uid: " (vf uid)))
(when parent (hf "parent: " (vf parent)))
#?(:clj
(when thread (hf "thread: " (vf thread))))
(when data (hf " data: " (vf data)))
#_(when kvs (hf " kvs: " (vf kvs))) ; Don't auto include in output
(when ctx (hf " ctx: " (vf ctx))))