Clojure Logging Overview

Javaの資産を使うか否かが採用のポイントかな?Javaのロギングライブラリは歴史がある.

timbreはpure clojureではあるが, やはり設定例やノウハウがGoogle検索で見つかるのは, Javaライブラリが多い(logback).

Clojure Logging Libraries

clojure/tools.logging

clojure/tools.logging libaryでJavaの資産を活用.


logf

formatを伴うlogにはlogfという関数が用意されている. infof, debugf, errorfなどなど.

(log/info (format "%s" "hello"))

スタックトレースのロギング

通常は第一引数にメッセージをいれるが, マルチアリティで第一引数にJava, 例外(Throwable), 第2引数にメッセージを渡すことも出来る.

この場合, ログのメッセージの下にずらずらとスタックトレースが表示される. ログのみやすさと相談してつかう(Unknown/Unexpected Errorとか).

unilog

clojure.tools.loggingの設定をかんたんにする. ロギングライブラリそのものでない.

ref. https://github.com/pyr/unilog

patternの書き方reference.

https://logback.qos.ch/manual/layouts.html

timbre

Pure Clojure/Script logging library.

GitHub - ptaoussanis/timbre: Pure Clojure/Script logging library

slf4j-timbre をつかうとJavaのロギングライブラリと連携可能.

websocketライブラリのsenteと同じ作者.

clojure/tools.loggingとは比べてClojureのnamespace単位のログ設定ができる.

日本の時刻設定例

(def timbre-config
  {:timestamp-opts
   {:pattern  "yyyy-MM-dd HH:mm:ss,SSS"
    :locale   (java.util.Locale. "ja_JP")
    :tiemzone (java.util.TimeZone/getTimeZone "Asia/Tokyo")}})
(timbre/merge-config! timbre-config)

また現実的な問題点として, timbreはpure clojureではあるものの, 3rd party libraryがjavaのライブラリに依存していると,その制御をtimbreからはできない(Javaから独立していることが利点なので). そのため結局 logback.xmlを書かないといけないかもしれない.

https://github.com/ptaoussanis/timbre/issues/138

(なんかcider-nreplとの相性なのか CIDEE環境でerrorが動作しない. これはstderrの扱いかもしれない).

Cambium

better timbreとか.

Cambium Home - Structured logging for Clojure | Cambium

✅Clojure Logging Tips

💡tips: うるさいサーバのログを黙らせる

jetty serverを起動したりclj-httpを使うとREPLを侵食する問題.

以下はlogback.xmlを設定する例.

timbre


{"org.apache.http" :error
 "io.netty"        :error}

💡ログ表示がUTCでJSTではない

この方法が正しいのかわからないけどとりあえず直ったので. さくらサーバを借りてClojureいれてclojure.tools.loggingでログしたら時刻がUTCだった.

これはclojureの起動オプションでJVM_OPTにタイムゾーン, 具体的には”-Duser.timezone=Asia/Tokyo”を設定することで解決した. deps.ednならaliasの定義のなかに以下を追加する.

{:jvm-opts    ["-Duser.timezone=Asia/Tokyo"]}

たたしさくらサーバ以外の環境では問題ないので原因がよくわからない.

🔍Clojureテスト時にログを抑止するには?

良い方法を探している… 以下でフォーム内のロギングを抑止できる.

ref. Clojure - how to disable logging temporarily? - Stack Overflow

(binding [clojure.tools.logging/*logger-factory*
          clojure.tools.logging.impl/disabled-logger-factory]
  (do-stuff-that-will-not-be-logged))

マクロ化した.

(defmacro with-out-log [& body]
  `(binding [clojure.tools.logging/*logger-factory*
             clojure.tools.logging.impl/disabled-logger-factory]
     ~@body))

もしくは, ロギング関数を🔧nubank/mockfnなどでモック化するのもよい.


💡浮動小数点のフォーマットは丸められる

ハマったのでメモ. (logf “.2f”)で0.008を表示すると, 0.01で丸められるので注意.

References