Reputation: 1841
I'm using Clojure and I want to get my hands on a stack trace that I can log (ideally, i would like to get it as a String).
I see that (.getStackTrace e)
returns a StackTraceElement[]
but I don't know how to print something meaningful out of it. My second approach was (.printStackTrace e)
with a PrintWriter as a parameter (because I know this is possible in Java), but I don't seem to get the correct syntax.
Thanks.
Upvotes: 13
Views: 5501
Reputation: 788
You can just use the very useful pr-str
function from clojure.core
:
(catch Exception e
(l/error "Ho no, an exception:" (pr-str e)))
#error {
:cause nil
:via
[{:type java.lang.NullPointerException
:message nil
:at [my_app$fn__47429$fn__47430 invoke "my_app.clj" 30]}]
:trace
[[my_app$fn__47429$fn__47430 invoke "my_app.clj" 30]
[my_app$my_func invokeStatic "my_app.clj" 13]
[my_app$my_func invoke "my_app.clj" 10]
[my_app$other_func$fn__29431 invoke "my_app.clj" 19]
[my_app$other_func_BANG_ invokeStatic "my_app.clj" 28]
[my_app$other_func_BANG_ invoke "my_app.clj" 27]
[my_app$yet_another_func invokeStatic "my_app.clj" 40]
[my_app$yet_another_func invoke "my_app.clj" 37]
[clojure.core$fn__8072$fn__8074 invoke "core.clj" 6760]
[clojure.core.protocols$iter_reduce invokeStatic "protocols.clj" 49]
[clojure.core.protocols$fn__7839 invokeStatic "protocols.clj" 75]
[clojure.core.protocols$fn__7839 invoke "protocols.clj" 75]
[clojure.core.protocols$fn__7781$G__7776__7794 invoke "protocols.clj" 13]
[clojure.core$reduce invokeStatic "core.clj" 6748]
[clojure.core$fn__8072 invokeStatic "core.clj" 6750]
[clojure.core$fn__8072 invoke "core.clj" 6750]
[clojure.core.protocols$fn__7860$G__7855__7869 invoke "protocols.clj" 175]
[clojure.core$reduce_kv invokeStatic "core.clj" 6776]
[clojure.core$reduce_kv invoke "core.clj" 6767]
[my_app$yet_another_func invokeStatic "data_streamer.clj" 48]
[my_app$yet_another_func invoke "data_streamer.clj" 47]
[my_app$other_func invokeStatic "data_streamer.clj" 66]
[my_app$other_func invoke "data_streamer.clj" 58]
[my_app$other_func$fn__48385 invoke "my_app.clj" 73]
[clojure.core.async$thread_call$fn__6553 invoke "async.clj" 442]
[clojure.lang.AFn run "AFn.java" 22]
[java.util.concurrent.ThreadPoolExecutor runWorker "ThreadPoolExecutor.java" 1135]
[java.util.concurrent.ThreadPoolExecutor$Worker run "ThreadPoolExecutor.java" 635]
[java.lang.Thread run "Thread.java" 844]]}
Upvotes: 4
Reputation: 11
you can use with-out-str
(try
(name nil)
(catch Exception e
(with-out-str (println e))))
Upvotes: 1
Reputation: 549
There is also clojure.stacktrace which has print-stack-trace
, print-trace-element
and some other helpful functions.
Upvotes: 2
Reputation: 91
Here's a slight improvement over noisesmith's answer. It doesn't leave a lazy seq and has a beautification feature:
(apply str (interpose "\n" (.getStackTrace t)))
Upvotes: 7
Reputation: 20194
if number23_cn's solution is a bit much, this is how you can use the result of .getStackTrace as a string (which can then be printed, put in a log, whatever)
(try (/ 1 0)
(catch Throwable t
(map str (.getStackTrace t))))
Upvotes: 20
Reputation: 4629
use clojure.repl.pst
get StackTrace, and binding *err*
to java.io.StringWriter
:
(use '[clojure.repl :only (pst)])
(defmacro with-err-str
"Evaluates exprs in a context in which *err* is bound to a fresh
StringWriter. Returns the string created by any nested printing
calls."
[& body]
`(let [s# (new java.io.StringWriter)]
(binding [*err* s#]
~@body
(str s#))))
(try
(/ 1 0)
(catch Exception e
(let [s (with-err-str (pst e 36))]
(println "Error log:")
(println s))))
Upvotes: 8