Compojureを使っていて標準出力にログが出力されないことがあった。はじめは以下のように書いていた。
(ns hello-world.core
(:require [compojure.core :refer :all]
[compojure.route :as route]))
(defroutes app
(GET "/" [] "<h1>Hello World</h1>")
(GET "/debug" []
(print "debug") ;; これが表示されない :(
"This is debug")
(route/not-found "<h1>Page not found</h1>"))
ところがこれは出力されなかった。少し調べてみてこの記事を見つけた。どうやらflushの問題らしい。printは内部的にはflushをしていないのでこれを呼ぶだけだと直ちに標準出力からdebugログが見られるわけじゃない。
printlnで書き換えてみるとうまくいった。
(defroutes app
(GET "/debug" []
(println "debug")
"This is debug")
実際ソースを見てみるとflushしていることがわかる。
user=> (source print)
(defn print
"Prints the object(s) to the output stream that is the current value
of *out*. print and println produce output for human consumption."
{:added "1.0"
:static true}
[& more]
(binding [*print-readably* nil]
(apply pr more)))
printは内部的にprを使ってる。
user=> (source println)
(defn println
"Same as print followed by (newline)"
{:added "1.0"
:static true}
[& more]
(binding [*print-readably* nil]
(apply prn more)))
printlnはprnを使ってる。
prとprn関数を見比べてみる。
user=> (source pr)
(defn pr
"Prints the object(s) to the output stream that is the current value
of *out*. Prints the object(s), separated by spaces if there is
more than one. By default, pr and prn print in a way that objects
can be read by the reader"
{:dynamic true
:added "1.0"}
([] nil)
([x]
(pr-on x *out*))
([x & more]
(pr x)
(. *out* (append \space)) ;; とくにflushを呼んでいるわけではなさそう
(if-let [nmore (next more)]
(recur (first more) nmore)
(apply pr more))))
user=> (source prn)
(defn prn
"Same as pr followed by (newline). Observes *flush-on-newline*"
{:added "1.0"
:static true}
[& more]
(apply pr more) ;; 実際の表示にはprを使ってる
(newline)
(when *flush-on-newline*
(flush))) ;; 確かにここでflushをしている
debug用だったらprintlnをいつも使うようにしておいた方が困惑しなさそう。