ScalaLogging の使い方

https://github.com/typesafehub/scalalogging


Scala 2.10.0 に合わせて ScalaLogging が 1.0.0 としてリリースされました。
ScalaLogging とはその名の通りロギングのためのライブラリです。と言ってもログを出力するためのライブラリではなく、log4j や slf4j を使うのをちょっとだけ楽にしてくれるヘルパーです。

これはなんのためですか?

ログ出力処理はたいてい

logger.info("Hello!")

のように書きます。ログレベルが ERROR だった場合、「Hello!」というメッセージはログに出力されません。当たり前ですね。info メソッドがログレベルが ERROR だからログを吐かないと判断してるからです。

ただし、ログを実際に吐くかどうかは関係なく、info メソッドに渡される引数は評価されてしまいます。
Scala であれば名前渡しで引数の評価を遅延させたりして回避できます(PlayのLoggerがそれ)が、Java のロギングライブラリを使っている場合は無理です。


試しに、info に渡す引数の中に sleep を入れて見ましょう。
ログは出ませんが、10秒スリープするはずです。

logger.info({ Thread.sleep(10000); "Hello!" })

このように、引数に重た〜いものを渡すとパフォーマンスに影響が出てしまいます。
対策は、3つ思いつきました。

  • ログ処理をそもそもとってしまう。
  • まあいいか、と特になにもしない。
  • if でガードする。


1,2 にするとこのエントリは終了してしまいますので、3にします。

if (logger.isInfoEnabled) {
  logger.info("Hello!")
}

はい、これいちいち書くのめんどくさすぎですね。ていうのがここでの問題意識です。

ScalaLogging のアプローチ

ScalaLogging はこれを Scala 2.10 の新機能のマクロを使って解決します。
めちゃくちゃ単純で、

logger.info(…)

を、コンパイル時に

if (logger.isInfoEnabled) {
  logger.info("Hello!")
}

に変えてしまう、ただそれだけ。ここらへんですね。

https://github.com/typesafehub/scalalogging/blob/v1.0.0/scalalogging-slf4j/src/main/scala/com/typesafe/scalalogging/slf4j/LoggerMacros.scala#L188-L203



以上が前置きです。

設定

log4j と slf4j が使えます。
ここでは slf4j + logback で。

scalaVersion := "2.10.0"

libraryDependencies ++= Seq(
  "com.typesafe" %% "scalalogging-slf4j" % "1.0.0",
  "org.slf4j" % "slf4j-api" % "1.7.1",
  "ch.qos.logback" % "logback-classic" % "1.0.7"
)

logback なので細かいログの設定は src/main/resources/logback.xml で行います。

Logging トレイト

Logging トレイトを使うのが一番シンプルです。
このトレイトによって logger が提供されます。

import com.typesafe.scalalogging.slf4j._
object ScalaLoggingExample extends App with Logging {
  logger.info("Hello!")
}

実行すると以下のようなメッセージが出力されます。

22:31:18.042 [run-main] INFO  ScalaLoggingExample$ - Hello!

StrictLogging トレイト

実は Logging トレイトで提供される logger は lazy です。それがやだって場合は StrictLogging トレイトを使ってくれ、とのことです。
特に理由がなければ Logging で良いです。

Logger オブジェクト

Logging では提供される Logger インスタンスは1つだけです。
複数の Logger インスタンスを扱うには Logger オブジェクトを使用します。


Logger.apply を使って org.slf4j.Logger をラップします。

import com.typesafe.scalalogging.slf4j._
import org.slf4j.{ Logger => Underlying, LoggerFactory }

object ScalaLoggingSample extends App {

  val consoleLoggerUnderlying: Underlying = LoggerFactory.getLogger("consoleLogger")
  val consoleLogger = Logger(consoleLoggerUnderlying)
  consoleLoggerUnderlying.info("Hello")

  val fileLoggerUnderlying = LoggerFactory.getLogger("fileLogger")
  val fileLogger = Logger(fileLoggerUnderlying)
  fileLogger.info("Hello")

}


とまあ、これだけなライブラリです。
多分 Typesafe 的にはマクロの実用例として用意したんじゃないかなあとおもいます。
でもシンプルで良いんじゃないでしょうか。