A ZIO ZLayer logging example (with Scala-CLI)

As a brief note today, and without much discussion, here’s a ZIO 2 ZLayer example I’ve been working on. The intent of the example is to show one possible way you can enable logging in a ZIO application using ZLayer.

ZIO ZLayer and logging example

As I mentioned, without much discussion, here’s the ZIO 2 source code:

//> using scala "3"
//> using lib "dev.zio::zio::2.1.1"
//> using lib "dev.zio::zio-config:4.0.2"
//> using lib "dev.zio::zio-logging:2.2.4"
//> using lib "dev.zio::zio-logging-slf4j:2.2.4"
//> using lib "ch.qos.logback:logback-classic:1.5.6"
//  ^^^^^ those initial lines are for scala-cli

import zio._
import zio.Console._
import zio.logging._
import zio.logging.backend.SLF4J

// i am experimenting with these annotations to make
// the ZIO type easier to understand:
type NoEnv = Any
type NoExceptions = Nothing

// this is a configuration class.
// it is also a companion class.
case class AppConfig(
    databaseUrl: String,
    websiteUrl: String
)

// a ZLayer implementation for the configuration.
// it is a companion object.
object AppConfig:
    val live: ZLayer[NoEnv, NoExceptions, AppConfig] =
        val appConfig = AppConfig(
            "jdbc:mysql://localhost:3306/mydatabase",
            "https://alvinalexander.com"
        )
        ZLayer.succeed(appConfig)

//requires AppConfig and Logging
val blueprint: ZIO[AppConfig & Unit, Throwable, Unit] =
    for
        config <- ZIO.service[AppConfig]
        _      <- ZIO.logInfo(s"DB URL:      ${config.databaseUrl}")
        _      <- ZIO.logInfo(s"Website URL: ${config.websiteUrl}")
        _      <- printLine("Hello, ZIO 2!")
    yield
        ()

object ZLayerLoggingDemo extends ZIOAppDefault:
    val run: ZIO[NoEnv, NoExceptions, Any] =
        val loggingLayer = SLF4J.slf4j
        val appLayer = AppConfig.live ++ loggingLayer
        blueprint.provideLayer(appLayer)
                 .exitCode

A few things to say about this code are:

  • I use Scala-CLI to run it, and that’s why it has the six initial configuration lines.
  • I’m experimenting with the NoEnv and NoExceptions types to make ZIO types easier to understand.
  • AppConfig is both a companion class and a companion object.
  • A lot of the other code is the usual ZIO and ZLayer code. (Assuming you have read my books, blog posts, and previous examples.)
  • You can think of ZLayer as providing the logging dependency that the application needs.

Other than that, I don’t have time today to write more about this, so I hope this ZIO 2 “ZLayer” example application is helpful.