2

LazySeq is kicking my butt when I try to log its value.

(require '[clojure.tools.logging :as log])
(def layer->multipart [{:name "layer-name" :content "veg"} {:name "layer-tag" :content "abs"}])
(def field->multipart [{:name "field-id" :content "12345"} {:name "field-version" :content "v1"}])

(log/infof "concat is %s" (concat layer->multipart field->multipart))
; => 2016-02-16 16:31:11,707  level=INFO [nREPL-worker-38] user:288 - concat is clojure.lang.LazySeq@87177bed 
; WTF is clojure.lang.LazySeq@87177bed?

I've check the How to convert lazy sequence to non-lazy in Clojure answer and it suggests that all I need to do is doall and all my dreams will come true. But alas...no.

(log/infof "concat is %s" (doall (concat layer->multipart field->multipart)))
; => 2016-02-16 16:31:59,958  level=INFO [nREPL-worker-40] user:288 - concat is clojure.lang.LazySeq@87177bed
; still clojure.lang.LazySeq@87177bed is not what I wanted

I've observed that (pr-str (concat layer->multipart field->multipart)) does what I want, but it makes no sense; The docs for pr-str say something about "pr to a string" and the docs for pr say "Prints the object(s) to the output stream that is the current value of *out*.". I don't want anything going to *out*, I just want the string value returned so the logger can use it!

(log/infof "concat is %s" (pr-str (concat layer->multipart field->multipart)))
; => 2016-02-16 16:42:02,927  level=INFO [nREPL-worker-1] user:288 - concat is ({:content "veg", :name "layer-name"} {:content "abs", :name "layer-tag"} {:content "12345", :name "field-id"} {:content "v1", :name "field-version"})
; this is what I wanted but I don't want anything going to *out*...or do I?

What do I have to do to get the effect of the pr-str variant without worrying about anything inadvertently getting dumped to stdout (I'm guessing that is what *out* is)? I want the lazy sequence to be fully realized for logging (it never gets too big...it only ends up as lazy as an accident of concat).

How can I log the full value of my LazySeq?

Community
  • 1
  • 1
Bob Kuhar
  • 10,838
  • 11
  • 62
  • 115
  • @amalloy I'm not actually trying to print it, I'm trying to log it. I don't think this is a dup of "Clojure Printing lazy sequence". At the end of the day, pr-str is what I wanted, I just misunderstood the docs. – Bob Kuhar Feb 17 '16 at 01:38

1 Answers1

3

The problem is that behind the scenes the logger is calling .toString on your lazy sequence. Try this:

user=> (.toString (concat layer->multipart field->multipart))
;; "clojure.lang.LazySeq@87177bed"`

What you really want is to convert the contents of the sequence into a string. For example:

(log/infof "concat is %s" (apply str (concat layer->multipart field->multipart)))
;; Feb 16, 2016 5:10:19 PM clojure.tools.logging$eval420$fn__424 invoke
;; INFO: concat is {:name "layer-name", :content "veg"}{:name "layer-tag",     :content "abs"}{:name "field-id", :content "12345"}{:name "field-version", :content "v1"}

By the way, pr-str is fine too. As it name says it prints to a string, not to *out*. You're using that string.

Bob Kuhar
  • 10,838
  • 11
  • 62
  • 115
Diego Basch
  • 12,764
  • 2
  • 29
  • 24
  • Aha! (pr-str is using a string as \*out\*, or something like that. I misunderstood the docs. pr-str likely is my best choice then. Please excuse my ignorance. I'm new to this. – Bob Kuhar Feb 17 '16 at 01:20