Problem: You want to add logging to an application in a more Scala-specific way than simply using SLF4J.
Solution
Grizzled-SLF4J is a thin wrapper around SLF4J that gives you logging in a more Scala-like way.
To get started with Grizzled-SLF4J, create a simple SBT project, then edit your build.sbt file so it has the dependencies you’ll need:
name := "Grizzled" version := "1.0" scalaVersion := "2.10.0" libraryDependencies ++= Seq("org.slf4j" % "slf4j-api" % "1.7.5", "org.slf4j" % "slf4j-simple" % "1.7.5", "org.clapper" %% "grizzled-slf4j" % "1.0.1")
Then create a simple test class to use Grizzled-SLF4J. Put the following code in a file named Main.scala in the root directory of your SBT project:
import grizzled.slf4j.Logger object Main extends App { // create a logger manually using one of these approaches //val logger = Logger("com.alvinalexander.test.Main") //val logger = Logger(classOf[Main]) val logger = Logger[this.type] logger.info("Hello, world") }
As you can see from that example, you can import the Grizzled-SLF4J Logger class, then manually create a Logger
instance in several different ways in a class or object. Running this object with sbt run
prints the following output to STDOUT:
[run-main] INFO Main$ - Hello, world
As a second approach, instead of manually creating a logger instance, you can mix in the Grizzled-SLF4J Logging
trait, which creates the logger
instance for you:
import grizzled.slf4j.Logging object Main extends App with Logging { logger.info("Hello, world") }
Running your object with this approach yields the same output as before:
[run-main] INFO Main$ - Hello, world
Discussion
Grizzled-SLF4J is a simple Scala wrapper around the well-known SLF4J library, has good documentation, and has recently been updated. Other libraries take a similar approach, but Grizzled-SLF4J currently has the best documentation and most recent updates.
A nice feature of Grizzled-SLF4J is that parameters to method calls like log.info
and log.debug
are call-by-name parameters. For instance, the Grizzled-SLF4J documentation shows that the debug
method is defined like this:
@inline final def debug(message: => Any) = if (debugIsEnabled) log(message)
The documentation states:
“Thus,
debug
isn’t a method taking a string; instead, it’s a method taking a function that returns a string ... However, because message is a function that returns a string, it isn’t evaluated until it is called -- which is after the test that determines whether it should be logged.”
Because message
is a call-by-name parameter, it isn’t evaluated until after the debugIsEnabled
check, and if debugIsEnabled
is false, it won’t be evaluated at all. This is another benefit of using Grizzled-SLF4J.
See Also
- A discussion of how Grizzled-SLF4J uses the call-by-name approach: http://software.clapper.org/grizzled-slf4j/#using_the_grizzled_slf4j_library
- The Grizzled-SLF4J library: http://software.clapper.org/grizzled-scala/
- The SLF4J library: http://www.slf4j.org