Skip to content

Commit f2545a1

Browse files
author
Lukas Domagala
committed
added run macro for easier deep trace usage
1 parent a45d403 commit f2545a1

File tree

11 files changed

+136
-81
lines changed

11 files changed

+136
-81
lines changed

README.md

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
# omni-trace
22
Omnipotent/omniscient tracing core for debugging clojure(script)
33

4-
alpha, api is still unstable but its only for dev time so there shouldn't be any problems.
5-
4+
beta, api is still unstable but its only for dev time so there shouldn't be any problems.
65

76
[![Clojars Project](https://img.shields.io/clojars/v/org.clojars.cyrik/omni-trace.svg)](https://clojars.org/org.clojars.cyrik/omni-trace)
87

@@ -56,15 +55,15 @@ or just through github source:
5655

5756
[Example "real world" usage story](https://cyrik.github.io/day1.html) (Spoilers for Advent of Code 2021 Day1)
5857

59-
## experimental deeptrace
58+
## Deeptrace
6059

6160
```clojure
6261
(require '[cyrik.omni-trace :as o])
6362

6463
;; uncomment to also trace clojure.core, tested with testing-ns only
6564
;; (require '[cyrik.omni-trace.instrument :as i])
6665
;; (reset! i/ns-blacklist [])
67-
(o/run-traced 'cyrik.omni-trace.testing-ns/run-machine)
66+
(o/run (cyrik.omni-trace.testing-ns/run-machine))
6867

6968
;; run this for cljs
7069
;; (o/run-traced-cljs 'cyrik.omni-trace.testing-ns/run-machine)
@@ -73,14 +72,14 @@ or just through github source:
7372

7473
This uses [clj-kondo](https://github.com/clj-kondo/clj-kondo) to find all transitive calls from the provided symbol.
7574
It then runs the function with any supplied args and untraces everything.
76-
This reaches all the way down into clojure.core.
75+
This reaches all the way down into clojure.core if you remove the blacklist.
7776

7877
![Screenshot](docs/deep-trace.png)
7978

8079
If your deeptraced function only traced itself make sure it's namespace is required somewhere inside "src" or "dev".
8180
I will add more options for choosing namespaces later.
8281
Currently there are still a few problems with recursion, will have to rewrite the deps graph for it.
83-
I'm guessing a lot of code will stil explode when allowing clojure.core trace, since the tracing code itself uses those.
82+
I'm guessing a lot of code will still explode when allowing clojure.core trace, since the tracing code itself, uses those.
8483
Will probably cleanup the blacklist and try to use local function copies for tracing.
8584

8685
## experimental inner-trace
@@ -188,7 +187,6 @@ works pretty well already, but:
188187

189188
## In the works
190189

191-
- loads of cleanup of api and code
192190
- better trace output to the REPL
193191
- performance
194192
- callbacks from Portal so you can rerun an updated function with the old params by clicking on it in the Flamegraph

deps.edn

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
:main-opts ["-m" "kaocha.runner" "unit" "features"]}
1515
:test-kaocha-debux {:extra-paths ["test"]
1616
:main-opts ["-m" "kaocha.runner" "unit-debux"]}
17-
:test-cljs {:extra-paths ["test/unit"]
17+
:test-cljs {:extra-paths ["test/unit" "test/features"]
1818
:main-opts ["-m" "kaocha.runner" "unit-cljs"]}
1919
:build {:deps {io.github.seancorfield/build-clj
2020
{:git/tag "v0.5.4" :git/sha "bc9c0cc"}}

dev/user.clj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@
5757

5858
;; run-traced
5959
(o/reset-workspace!)
60-
(o/run-traced 'cyrik.omni-trace.testing-ns/run-machine)
60+
(o/run (cyrik.omni-trace.testing-ns/run-machine))
6161
(tap> (o/flamegraph))
6262
(o/reset-workspace!)
6363

@@ -72,7 +72,7 @@
7272

7373
;; deep into core
7474
(reset! i/ns-blacklist [])
75-
(o/run-traced 'cyrik.omni-trace.testing-ns/run-machine)
75+
(o/run (cyrik.omni-trace.testing-ns/run-machine))
7676
(tap> (o/flamegraph))
7777
(o/reset-workspace!)
7878
(reset! i/ns-blacklist ['cljs.core 'clojure.core])

dev/user.cljs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@
4848
(tap> ^{:portal.viewer/default :portal.viewer/hiccup} [:button {:onclick (str "alert('123')")} (str "alert('123')")])
4949
[:button {:onclick "alert('123')"} "Test it!"]
5050
;remove tracing from a namesapce
51-
(o/uninstrument-ns 'omni-trace.testing-ns)
51+
(o/uninstrument-ns 'cyrik.omni-trace.testing-ns)
5252
(o/reset-workspace!)
5353
i/instrumented-vars
5454
(macroexpand '(o/instrument-ns 'cyrik.omni-trace.testing-ns))
@@ -57,7 +57,7 @@
5757
(macro/cljs-macroexpand-all '(o/instrument-fn 'cyrik.omni-trace.testing-ns/insert-coin))
5858
(macro/cljs-macroexpand-all '(o/instrument 'cyrik.omni-trace.testing-ns/insert-coin))
5959
(macro/cljs-macroexpand-all '(i/uninstrument))
60-
(i/uninstrument)
60+
(o/untrace)
6161
(alter-meta! (var cyrik.omni-trace.testing-ns/insert-coin) assoc-in [:stuffs] "yeah123")
6262
(.log js/console (meta (var cyrik.omni-trace.testing-ns/insert-coin)))
6363

src/cyrik/omni_trace.cljc

Lines changed: 44 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,15 @@
11
(ns cyrik.omni-trace
22
(:require
33
#?(:clj [cyrik.omni-trace.deep-trace :as deep])
4+
#?(:clj [cyrik.omni-trace.util :as util])
45
[cyrik.omni-trace.instrument :as i]
56
[cyrik.omni-trace.graph :as flame]
7+
[cljs.test]
8+
#?(:clj [cljs.analyzer.api :as ana-api])
69
[net.cgrand.macrovich :as macros])
7-
810
#?(:cljs (:require-macros
9-
[cyrik.omni-trace :refer [instrument-fn uninstrument-fn instrument-ns uninstrument-ns]])))
11+
[cyrik.omni-trace :refer [instrument-fn uninstrument-fn instrument-ns uninstrument-ns
12+
run]])))
1013

1114
(defmacro instrument-fn
1215
"Instruments a function.
@@ -87,33 +90,56 @@
8790
#?(:clj
8891
(defn run-traced [s & args]
8992
(apply #'deep/run-traced (into [s] args))))
93+
(macros/deftime
94+
#?(:clj
95+
(defmacro run [form]
96+
(macros/case :clj `(deep/run-traced (~util/->sym ~(first form)) ~@(rest form))
97+
:cljs `(do
98+
~(let [fun (ana-api/resolve &env (first form))
99+
args (rest form)
100+
n (:ns fun)
101+
f (-> fun
102+
:name
103+
name
104+
symbol)
105+
dep-list (deep/transitive-deps (deep/deps (deep/analysis ["dev" "src"]) :cljs)
106+
n f)
107+
sym-list (mapv #(symbol (name (first %)) (name (second %))) (filter first dep-list)) ;;fix nil namespaces
108+
instrumenters (mapv (fn [sym] `#(cyrik.omni-trace.instrument.cljs/cljs-instrument-fn '~sym {:cyrik.omni-trace/workspace cyrik.omni-trace.instrument/workspace} cyrik.omni-trace.instrument/instrumented)) sym-list)
109+
deinstrumenters (mapv (fn [sym] `#(cyrik.omni-trace.instrument.cljs/cljs-instrument-fn '~sym {:cyrik.omni-trace/workspace cyrik.omni-trace.instrument/workspace} cyrik.omni-trace.instrument/uninstrumented)) sym-list)
110+
]
111+
`(let [_# (doseq [f# ~instrumenters]
112+
(f#))
113+
result# (apply ~(symbol (name n) (name f)) (list ~@args))
114+
_# (doseq [g# ~deinstrumenters]
115+
(g#))]
116+
result#)))))))
90117

91-
#?(:clj
92-
(defmacro run-traced-cljs [ns f & args]
93-
(let [ns (symbol (name ns))
94-
f (symbol (name f))
95-
dep-list (deep/transitive-deps (deep/deps (deep/analysis ["dev" "src"]) :cljs)
96-
ns f)
97-
sym-list (mapv #(symbol (name (first %)) (name (second %))) (filter first dep-list)) ;;fix nil namespaces
98-
instrumenters (mapv (fn [sym] `#(cyrik.omni-trace.instrument.cljs/cljs-instrument-fn '~sym {:cyrik.omni-trace/workspace cyrik.omni-trace.instrument/workspace} cyrik.omni-trace.instrument/instrumented)) sym-list)
99-
deinstrumenters (mapv (fn [sym] `#(cyrik.omni-trace.instrument.cljs/cljs-instrument-fn '~sym {:cyrik.omni-trace/workspace cyrik.omni-trace.instrument/workspace} cyrik.omni-trace.instrument/uninstrumented)) sym-list)
100-
runner `#(~(symbol (name ns) (name f)))
101-
merged (into [] (concat instrumenters [runner] deinstrumenters))]
102-
`(doseq [f# ~merged]
103-
(f#)))))
104118

105119
(comment
106120
(require '[portal.api :as p])
107121
(def portal (p/open))
108122
(add-tap #'p/submit)
109123

110124

111-
112-
113-
(filter #(and (= (:lang %) :cljs) (= (:from %) 'cyrik.omni-trace.testing-ns))(:var-usages(deep/analysis ["dev" "src"])))
114125

126+
(filter #(and (= (:lang %) :cljs) (= (:from %) 'cyrik.omni-trace.testing-ns)) (:var-usages (deep/analysis ["dev" "src"])))
115127

116128

117129

130+
(require '[cyrik.cljs-macroexpand :as macro])
131+
(clojure.walk/macroexpand-all '(run (+ 1 2)))
132+
(macro/cljs-macroexpand-all '(run `(+ 1 2)))
133+
(macroexpand '(run `(+ 1 2)))
134+
(defn thing [a]
135+
(inc a))
136+
(defn thing2 [a b]
137+
(+ a b))
138+
(run `(thing (inc (inc 1))))
139+
(macroexpand '(run `(thing (inc (inc 1)))))
140+
(macro/cljs-macroexpand-all '(run `(thing (inc (inc 1)))))
141+
(cyrik.omni-trace/run (thing2 1 2))
142+
(macroexpand '(cyrik.omni-trace/run (thing2 1 2)))
143+
(macro/cljs-macroexpand-all '(cyrik.omni-trace/run (thing2 1 2)))
118144
.
119145
)

src/cyrik/omni_trace/instrument/clj.clj

Lines changed: 9 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
[clojure.tools.reader.reader-types :as rts]
44
[clojure.string :as string]
55
[clojure.java.io :as io]
6+
[cyrik.omni-trace.util :as u]
67
[borkdude.dynaload :as dynaload]
78
clojure.repl))
89

@@ -55,44 +56,19 @@
5556
(use 'clojure.core)
5657
(eval form)))
5758

58-
(defn var->sym [v]
59-
(let [m (meta v)]
60-
(symbol (name (ns-name (:ns m))) (name (:name m)))))
61-
62-
(defn ->var [something]
63-
(cond
64-
(var? something) something
65-
(symbol? something) (resolve something)
66-
(string? something) (resolve (symbol something))
67-
:else nil))
68-
69-
(defn ->sym [something]
70-
(cond
71-
(symbol? something) something
72-
(var? something) (var->sym something)
73-
(string? something) (symbol something)
74-
:else nil))
75-
76-
(defn ->ns [something]
77-
(cond
78-
(instance? clojure.lang.Namespace something) something
79-
(symbol? something) (find-ns something)
80-
(string? something) (find-ns (symbol something))
81-
:else nil))
82-
8359
(defn fully-qualified [s]
84-
(var->sym (resolve s)))
60+
(u/var->sym (resolve s)))
8561

8662
(defn vars-in-ns-clj [sym]
8763
(if (find-ns sym)
8864
(for [[_ v] (ns-interns sym)
8965
:when (not (:macro (meta v)))]
90-
(var->sym v))
66+
(u/var->sym v))
9167
(throw (Exception. (str "ns " sym " does not exist.")))))
9268

9369
(defn clj-instrument-fn [f opts instrumenter]
94-
(when-let [v (->var f)]
95-
(let [var-name (var->sym v)
70+
(when-let [v (u/->var f)]
71+
(let [var-name (u/var->sym v)
9672
original @v
9773
meta* (update (meta v) :file #(if-let [classpath-file (io/resource %)]
9874
(.getPath classpath-file)
@@ -115,7 +91,7 @@
11591

11692
(defn clj-instrument-ns [ns-sym opts instrumenter]
11793
(->> ns-sym
118-
->sym
94+
u/->sym
11995
vars-in-ns-clj
12096
(filter symbol?)
12197
(distinct)
@@ -124,16 +100,16 @@
124100

125101
(defn instrument [s opts instrumenter]
126102
(let [xs (if (coll? s) s [s])
127-
syms (map #(->sym %) xs)]
103+
syms (map #(u/->sym %) xs)]
128104
(mapcat #(if (string/includes? (name %) ".")
129105
(clj-instrument-ns % opts instrumenter)
130106
(instrument-syms [%] opts instrumenter))
131107
syms)))
132108

133109
(comment
134110
(-> #'cyrik.omni-trace.instrument.clj/fully-qualified-sym str symbol)
135-
(instance? clojure.lang.Namespace (->ns "cyrik.omni-trace.testing-ns"))
136-
(->var "cyrik.omni-trace.testing-ns/insert-coin")
111+
(instance? clojure.lang.Namespace (u/->ns "cyrik.omni-trace.testing-ns"))
112+
(u/->var "cyrik.omni-trace.testing-ns/insert-coin")
137113

138114
(type cyrik.omni-trace.testing-ns/insert-coin)
139115
)

src/cyrik/omni_trace/instrument/cljs.cljc

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@
5353
(let [var-name (:name v)
5454
file (get-file &env (or (:file (:meta v))
5555
(:file v)));;incase of jar?
56-
meta* (assoc (:meta v) :file file)]
56+
meta* (select-keys (assoc (:meta v) :file file) [:column :line :file])]
5757
(when-not (:macro v)
5858
(swap! instrumented-var-names conj var-name)
5959
`(when-let [instrumented# (~instrumenter '~sym (var ~sym) ~meta* nil ~opts)]
@@ -65,7 +65,7 @@
6565
(let [var-name (:name v)
6666
file (get-file &env (or (:file (:meta v))
6767
(:file v)));;incase of jar?
68-
meta* (assoc (:meta v) :file file)]
68+
meta* (select-keys (assoc (:meta v) :file file) [:column :line :file])]
6969
(when-not (:macro v)
7070
(swap! instrumented-var-names disj var-name)
7171
`(when-let [instrumented# (~instrumenter '~sym (var ~sym) ~meta* nil ~opts)]
@@ -120,6 +120,7 @@
120120

121121
(comment
122122
(require '[cyrik.cljs-macroexpand :as macro])
123+
(reset! instrumented-var-names #{})
123124
(cyrik.omni-trace.instrument.cljs/sym-test "cljs.core/inc")
124125
(macro/cljs-macroexpand-all '(cyrik.omni-trace.instrument.cljs/instrument ["cyrik.omni-trace.testing-ns" #'cljs.core/inc] {} #()))
125126
(instrument "cyrik.omni-trace.testing-ns" {} #())

src/cyrik/omni_trace/testing_ns.cljc

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -110,8 +110,18 @@
110110
(throw #?(:cljs (js/Error. "Oops") :clj (Exception. "Oops")))
111111
(dissoc machine :change-returned)])
112112

113-
(defn run-machine []
114-
(-> machine-init
113+
(defn run-machine
114+
([]
115+
(-> machine-init
116+
(insert-coin :quarter)
117+
(insert-coin :dime)
118+
(insert-coin :nickel)
119+
(insert-coin :penny)
120+
(press-button :a1)))
121+
)
122+
(defn run-machine-with
123+
[start]
124+
(-> start
115125
(insert-coin :quarter)
116126
(insert-coin :dime)
117127
(insert-coin :nickel)

src/cyrik/omni_trace/util.clj

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
(ns cyrik.omni-trace.util
2+
(:require [clojure.repl :as repl]
3+
))
4+
5+
(defn var->sym [v]
6+
(let [m (meta v)]
7+
(symbol (name (ns-name (:ns m))) (name (:name m)))))
8+
9+
(defn ->var [something]
10+
(cond
11+
(var? something) something
12+
(symbol? something) (resolve something)
13+
(string? something) (resolve (symbol something))
14+
:else nil))
15+
16+
(defn ->sym [something]
17+
(cond
18+
(fn? something) (-> something .getClass .getName repl/demunge symbol)
19+
(symbol? something) something
20+
(var? something) (var->sym something)
21+
(string? something) (symbol something)
22+
:else nil))
23+
24+
(defn ->ns [something]
25+
(cond
26+
(instance? clojure.lang.Namespace something) something
27+
(symbol? something) (find-ns something)
28+
(string? something) (find-ns (symbol something))
29+
:else nil))
30+
31+
(defn fully-qualified [s]
32+
(var->sym (resolve s)))

0 commit comments

Comments
 (0)