在 Clojure 中获取调用堆栈
Posted
技术标签:
【中文标题】在 Clojure 中获取调用堆栈【英文标题】:Obtain a callstack in Clojure 【发布时间】:2011-05-03 04:17:04 【问题描述】:当我运行 Clojure 程序并在执行过程中遇到错误时,我注意到 REPL 打印的消息仅包含我执行的脚本的***行号。我可以让它转储一个调用堆栈(它引用了 Clojure 代码的各种行号)吗?
例如:
user=> (load-file "test.clj")
java.lang.IllegalArgumentException: Wrong number of args (1) passed to: user$eval134$fn (test.clj:206)
user=>
如果我知道的不仅仅是***调用(第 206 行),那就更好了。
【问题讨论】:
【参考方案1】:最后一次抛出的异常在 *e
变量中可用。您可以通过在 Exception 上调用 .printStackTrace
来打印堆栈跟踪。如果您的异常是由文件中的源代码抛出的,它将打印行号,如果它来自 REPL,它会打印 NO_SOURCE_FILE,如下面的示例所示。
Clojure 1.2.0
user=> (throw (Exception. "FOO"))
java.lang.Exception: FOO (NO_SOURCE_FILE:0)
user=> *e
#<CompilerException java.lang.Exception: FOO (NO_SOURCE_FILE:0)>
user=> (.printStackTrace *e)
java.lang.Exception: FOO (NO_SOURCE_FILE:0)
at clojure.lang.Compiler.eval(Compiler.java:5440)
at clojure.lang.Compiler.eval(Compiler.java:5391)
at clojure.core$eval.invoke(core.clj:2382)
at clojure.main$repl$read_eval_print__5624.invoke(main.clj:183)
at clojure.main$repl$fn__5629.invoke(main.clj:204)
at clojure.main$repl.doInvoke(main.clj:204)
at clojure.lang.RestFn.invoke(RestFn.java:422)
at clojure.main$repl_opt.invoke(main.clj:262)
at clojure.main$main.doInvoke(main.clj:355)
at clojure.lang.RestFn.invoke(RestFn.java:398)
at clojure.lang.Var.invoke(Var.java:361)
at clojure.lang.AFn.applyToHelper(AFn.java:159)
at clojure.lang.Var.applyTo(Var.java:482)
at clojure.main.main(main.java:37)
Caused by: java.lang.Exception: FOO
at user$eval1.invoke(NO_SOURCE_FILE:1)
at clojure.lang.Compiler.eval(Compiler.java:5424)
... 13 more
nil
在 Clojure 1.3 (alpha) 中有一个名为 pst
的函数可以做同样的事情。这些堆栈跟踪更好一些,因为删除了一些无关的行。
Clojure 1.3.0-master-SNAPSHOT
user=> (throw (Exception. "FOO"))
Exception FOO user/eval1 (NO_SOURCE_FILE:1)
user=> (pst)
Exception FOO
user/eval1 (NO_SOURCE_FILE:1)
clojure.lang.Compiler.eval (Compiler.java:5998)
clojure.lang.Compiler.eval (Compiler.java:5965)
clojure.core/eval (core.clj:2652)
clojure.core/eval (core.clj:-1)
clojure.main/repl/read-eval-print--5575 (main.clj:178)
clojure.main/repl/fn--5580 (main.clj:199)
clojure.main/repl (main.clj:199)
clojure.main/repl-opt (main.clj:257)
clojure.main/main (main.clj:350)
clojure.lang.Var.invoke (Var.java:361)
clojure.lang.Var.applyTo (Var.java:482)
nil
某些 IDE(例如 Emacs 的 SLIME)会自动为您弹出堆栈跟踪。还有一些用于显示和操作堆栈跟踪的库,例如 clojure.stacktrace 和 clj-stacktrace。
堆栈跟踪处理似乎是 Clojure 的一个方面,仍在完善中。
【讨论】:
除了 *e 之外,有没有办法访问过去的异常?以上是关于在 Clojure 中获取调用堆栈的主要内容,如果未能解决你的问题,请参考以下文章
在 Clojure/Compojure 中转义/清理用户输入