如何放入 clojure 函数内的 repl 并打印堆栈跟踪
How to drop into a repl inside a clojure function and print the stack traces
给定以下函数
(defn func []
(break!))
我要休息!启动 repl 的函数,在该 repl 中我可以打印调用 func
.
的调用堆栈
该功能类似于 Python 中的 ipdb
,当我们想要在某个函数的运行时内部进行交互式调查时,它会非常方便。
一个非常基本的版本可以是:
(defn break! [] (clojure.main/repl))
这将启动一个新的嵌套 REPL,当您退出它时(在 Windows 上使用 ^D -- 或 ^Z),它将继续。
你不能评估局部变量,但是如果你把 break!
写成一个宏,你至少可以 显示 在启动 REPL 之前激活的局部变量:
user=> (defmacro break! []
(let [locals (into {} (map (juxt keyword identity)) (keys &env))]
(prn locals)
(clojure.main/repl :prompt #(print "nested> "))))
#'user/break!
user=> (defn foo "Using the break! function." [a b] (break!))
#'user/foo
user=> (foo 13 42)
{:a 13, :b 42}
nested> (doc foo)
-------------------------
user/foo
([a b])
Using the break! function.
nil
nested> ^D
nil
user=>
如果您希望堆栈跟踪作为嵌套 REPL 中的数据,您可以评估 (:trace (Throwable->map (Throwable.)))
给定以下函数
(defn func []
(break!))
我要休息!启动 repl 的函数,在该 repl 中我可以打印调用 func
.
该功能类似于 Python 中的 ipdb
,当我们想要在某个函数的运行时内部进行交互式调查时,它会非常方便。
一个非常基本的版本可以是:
(defn break! [] (clojure.main/repl))
这将启动一个新的嵌套 REPL,当您退出它时(在 Windows 上使用 ^D -- 或 ^Z),它将继续。
你不能评估局部变量,但是如果你把 break!
写成一个宏,你至少可以 显示 在启动 REPL 之前激活的局部变量:
user=> (defmacro break! []
(let [locals (into {} (map (juxt keyword identity)) (keys &env))]
(prn locals)
(clojure.main/repl :prompt #(print "nested> "))))
#'user/break!
user=> (defn foo "Using the break! function." [a b] (break!))
#'user/foo
user=> (foo 13 42)
{:a 13, :b 42}
nested> (doc foo)
-------------------------
user/foo
([a b])
Using the break! function.
nil
nested> ^D
nil
user=>
如果您希望堆栈跟踪作为嵌套 REPL 中的数据,您可以评估 (:trace (Throwable->map (Throwable.)))