3

I want to use core.async as a logger that writes out to a file, so I created a test.txt file, stuck it in my resources folder and wrote this code:

(use 'clojure.java.io)
(use 'clojure.core.async)

(def print-chan (chan))

(go (loop []
      (when-let [v (<! print-chan)]
        (with-open [wrtr (writer "resources/test.txt" :append true)]
          (.write wrtr v))
        (recur)))) 

(>!! print-chan 42)

When I run this, however, I find that it will only replace what is in the file, and not append to it. Also, sometimes the output that is written to the file is odd. Once, I tried to put 42 and I got * instead. When I use the writer without the core.async functions, it works as expected. What is the idiomatic way to write to a log file in Clojure using core.async? Thanks in advance!

*I am using light table.

2 Answers 2

4

wrtr is a java.io.BufferedWriter.

When you send 42 (long) into the channel, you're calling (.write wrtr 42) which invokes this method:

write(int c)
Writes a single character.

42 represents the \* character on the ASCII table so that's what's being written.

Instead, you want to invoke this Writer method via (.write wrtr "42"):

write(String str)
Writes a string.

And you can do that by converting the values read from the channel into strings:

(.write wrtr (str v))
Sign up to request clarification or add additional context in comments.

3 Comments

Thanks for this super simple and helpful answer. The only problem I have now is getting it to print each item to a new line. Should I look in the Clojure or Java documentation to figure this out?
Just write a newline after your log line. Either include it in the message: (.write wrtr "42\n"), or write it explicitly: (.write wrtr "\n").
Exactly. Just change the line to (.write wrtr (str v "\n")).
3

You are opening the file anew in each loop/recur cycle, this is why it's not appending.

What you need to do is open the writer once for the life of the program.

(go
  (with-open [wrtr (writer "resources/test.txt" :append true)]
    (loop []
      (when-let [v (<! print-chan)]
        (.write wrtr (str v "\n"))
      (recur)))) 

I just had to write code like this today. What I found was that you have to call with-open inside the goroutine. Because of this (I assume), you can't use the with-open macro with the go-loop macro.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.