LogStage is a zero-cost structural logging framework.

Key features:

  1. LogStage extracts structure from ordinary string interpolations in your log messages with zero changes to code.
  2. LogStage uses macros to extract log structure, its faster at runtime than typical reflective structural logging frameworks,
  3. Log contexts
  4. Console, File and SLF4J sinks included, File sink supports log rotation,
  5. Human-readable output and JSON output included,
  6. Method-level logging granularity. Can configure methods com.example.Service.start and com.example.Service.doSomething independently,
  7. Slf4J adapters: route legacy Slf4J logs into LogStage router


The following snippet:

class ExampleService(logger: IzLogger) {
  val justAnArg = "example"
  val justAList = List[Any](10, "green", "bottles")

  logger.trace(s"Argument: $justAnArg, another arg: $justAList")
  logger.info(s"Named expression: ${Random.nextInt() -> "random number"}")
  logger.warn(s"Invisible argument: ${Random.nextInt() -> "random number" -> null}")

  val ctxLogger = logger("userId" -> "user@google.com", "company" -> "acme")
  val delta = Random.nextInt(1000)

  ctxLogger.info(s"Processing time: $delta")

Will look like this in string form:


And like this in JSON:



  1. JSON formatter is type aware!
  2. Each JSON message contains @class field with holds a unique event class identifier. All events produced by the same source code line will share the same event class.


libraryDependencies += Izumi.R.logstage_core

libraryDependencies ++= Seq(
  // file sink
  // json output
  , Izumi.R.logstage_rendering_circe
  // router from Slf4j to LogStage
  , Izumi.R.logstage_adapter-slf4j


val izumi_version = "0.7.0-SNAPSHOT"
// LogStage API, you need it to use the logger
libraryDependencies += "com.github.pshirshov.izumi.r2" %% "logstage-core" % izumi_version

// LogStage machinery
libraryDependencies ++= Seq(
  // file sink
  "com.github.pshirshov.izumi.r2" %% "logstage-sink-file" % izumi_version
  // json output
  , "com.github.pshirshov.izumi.r2" %% "logstage-rendering-circe" % izumi_version
  // router from Slf4j to LogStage
  , "com.github.pshirshov.izumi.r2" %% "logstage-adapter-slf4j" % izumi_version    

If you’re not using sbt-izumi-deps plugin.

Basic setup

import logstage._
import logstage.circe._

val jsonSink = ConsoleSink.json(prettyPrint = true)
val textSink = ConsoleSink.text(colored = true)

val sinks = List(jsonSink, textSink)

val logger: IzLogger = IzLogger(Trace, sinks)
val contextLogger: IzLogger = logger(Map("key" -> "value"))

// Hey; @type=const

// {key=value} Hey