Question

It is known that you can use the command binding to temporarily attach a custom writer to global vars such as out. For example, this works:

(let [customWriter (StringWriter.)]
  (binding [*out* customWriter]
    (println "One line!")
    (.toUpperCase (.toString customWriter))))

It prints "ONE LINE!\r\n" as expected.

I captured the standard output in my customWriter. I would like to do the same thing with the standard error stream. So I did:

(let [customWriter (StringWriter.)]
  (binding [*err* customWriter]
    (try (/ 1 0)
      (catch Exception e
        (.printStackTrace e)
        (.toString customWriter)))))

But it returns an empty String and still prints the stack trace in the console. It is funny that if try err and System/err in the REPL they are diferent instances.

I know there is another way to do what I want which is to pass a custom PrintWriter to the method printStackTrace of the exception. But I think I misunderstood something related to err that I need to grasp.

Was it helpful?

Solution

Java's .printStackTrace method is agnostic to the existence of Clojure's *err* var, so binding it won't change Java's behavior.

Consider instead

(use 'clojure.stacktrace)

(try (/ 1 0) 
  (catch Exception e 
    (with-out-str (print-stack-trace))))

See source of print-stack-trace for details, but basically it is using the .getStackTrace method and then printing to *out*, which you can bind with with-out-str, for example.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top