Flog: a functional logger for Scala

Robin Hillyard
May 12 · 3 min read

Logging can, unfortunately, be either a blessing or a curse. For production systems, logging is a discipline all of its own. But often, it seems, it’s not used as much as it could be in code development. It should be so simple that it’s the first, not the last, resort when trying to understand why code is not working as expected. And nowhere is this more true than in functional programming languages. That’s because logging is, well, statement-oriented rather than expression-oriented. Even if you don’t bother with logging, but use println instead, you will still have to wrestle with your code because println yields Unit, i.e. it is statement-oriented.

That’s why I developed Flog, a functional logger for Scala (2). It’s really easy to use. Let’s say you want to define a val x of type X as some expression (expr) and you write:

val x: X = expr

But now you decide that you’d like to know what the actual value of expr is. Just add a msg (the log message, a String) and the operator !! as follows:

val flog = Flog[MyClass]
import flog._
// other codeval x: X = msg !! expr

That’s it! That’s basically all you have to do. A representation of expr will be appended to the log and, otherwise, the program behaves exactly as it did before. But what if you don’t want to see that value in the logs again? Just replace the !! operator by |! and the program will run the same but there will be no logging at this point (oh, and by the way, msg will not be evaluated).

The !! operator corresponds to info if you are using a standard logger. You can also use !? for debug or !?? for trace.

Alternatively, you can emasculate Flog for all its uses in a module simply by replacing Flog() with Flog().disabled. Eventually, when you are sure you never want to log this expression again, you simply remove the msg |! construct altogether.

The actual logging utility used, by default, by Flog is org.slf4j.LoggerFactory.getLogger for the Flog class itself. For serious use, you’ll want to use a logger for your own class. You can do this by instantiating flog as:

val flog: Flog = Flog[MyClass]

But, you’re also probably wondering how the logger will know how to represent instances of type X. If X is some compound but familiar type such as Iterable[Int], Future[Double], or Option[String] (there are many other supported containers) then the logger will just do the sensible thing without any extra work on your part. But what if X is a type defined in your own code? Is it a case class (or other Product)? Then simply invoke the loggableN method with the appropriate number of parameters:

case class Complex(real: Double, imag: Double)
implicit val complexLoggable: Loggable[Complex] = new Loggables {}.loggable2(Complex)
"test complex" !! Complex(1, 0)

But, what if your home-grown class isn’t a Product? You have two choices then. The quick and dirty version where you use !| operator. This will apply toString to the value and use that. The better approach, and the necessary one if you will be logging values of types such as Try[X] or List[X], is to create an implicit value of Loggable[X] in the companion object of X. This is easy to do, and is described in the README.

You can find this logging library at https://github.com/rchillyard/Flog. Sorry, but it’s not in Maven central yet, but hopefully will be soon.

Edited 2021/5/18 to show correct setup for latest version (1.0.8).

CodeX

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store