clojure:向命名空间中的每个函数添加调试跟踪?

clojure:向命名空间中的每个函数添加调试跟踪?,clojure,Clojure,我刚开始在我的一个家庭项目中使用log4j,我正要打开鼠标,将(trace(str“entering:”function name))剪切并粘贴到一个大模块中的每个函数中。然后,理性的声音突然响起,说“必须有更好的方法”。。。我可以考虑制作一个宏来包装整个函数块,并向它们添加跟踪或类似的东西?智者们有什么建议吗 不需要宏: (defn trace-ns "ns should be a namespace object or a symbol." [ns] (doseq [s (key

我刚开始在我的一个家庭项目中使用log4j,我正要打开鼠标,将
(trace(str“entering:”function name))
剪切并粘贴到一个大模块中的每个函数中。然后,理性的声音突然响起,说“必须有更好的方法”。。。我可以考虑制作一个宏来包装整个函数块,并向它们添加跟踪或类似的东西?智者们有什么建议吗

不需要宏:

(defn trace-ns
  "ns should be a namespace object or a symbol."
  [ns]
  (doseq [s (keys (ns-interns ns))
          :let [v (ns-resolve ns s)]
          :when (and (ifn? @v) (-> v meta :macro not))]
    (intern ns
            (with-meta s {:traced true :untraced @v})
            (let [f @v] (fn [& args]
                          (clojure.contrib.trace/trace (str "entering: " s))
                          (apply f args))))))

(defn untrace-ns [ns]
  (doseq [s (keys (ns-interns ns))
          :let [v (ns-resolve ns s)]
          :when (:traced (meta v))]
    (alter-meta! (intern ns s (:untraced (meta v)))
                 #(dissoc % :traced :untraced))))
…或类似的东西。最可能的额外要求是使用
filter
,这样就不会对不属于
ifn?
s的东西调用
trace
。更新:在解决方案中编辑(也处理宏)。更新2:修复了一些主要错误。更新4:添加了取消跟踪功能

更新3:以下是我的REPL中的一个示例:

user> (ns foo)
nil
foo> (defn foo [x] x)
#'foo/foo
foo> (defmacro bar [x] x)
#'foo/bar
foo> (ns user)
nil
user> (trace-ns 'foo)
nil
user> (foo/foo :foo)
TRACE: "entering: foo"
:foo
user> (foo/bar :foo)
:foo
user> (untrace-ns 'foo)
nil
user> (foo/foo :foo)
:foo

你简直太棒了!您可以解释一下ns resolve部分吗?:-)
ns resolve
接受一个名称空间或名称空间命名符号和一个符号,并尝试在(第二个)符号给出的名称下查找给定名称空间中的变量。这里重要的一点是:(1)可以更改Var的根绑定(有很多方法可以更改,但是
intern
在这里特别方便,因为它还可以处理额外的元数据;
trace ns
使用重新绑定来替代原始的包装函数)和(2)可以更改Var的元数据(因此可以使用
未跟踪的ns
)。(事实上,它已于去年2月合并,但我现在才记得在这里添加一条评论。)