Skip to content

Instantly share code, notes, and snippets.

@keynmol
Last active June 5, 2023 12:19
Show Gist options
  • Save keynmol/60a86d9c92e48d8405b545a62b9f124e to your computer and use it in GitHub Desktop.
Save keynmol/60a86d9c92e48d8405b545a62b9f124e to your computer and use it in GitHub Desktop.
Example of contextual logging with IOLocal and Scribe in Cats Effect

Run with scala-cli run context-logging.scala

Screenshot 2023-06-05 at 13 18 17

//> using dep org.typelevel::cats-effect:3.5.0
//> using dep com.outr::scribe-cats:3.11.5
import cats.effect.*
import scribe.data.MDC
import scribe.Scribe
import scala.util.Random
class MyLogger private (orig: Scribe[IO], loc: IOLocal[Map[String, String]]):
inline def annotate[A](key: String, value: String)(io: IO[A]) =
loc.set(Map(key -> value)).flatMap(_ => io).guarantee(loc.set(Map.empty))
inline def info(msg: String): IO[Unit] =
loc.get.flatMap { context =>
MDC { implicit mdc =>
context.foreach((k, v) => mdc.update(k, v))
orig.info(msg)
}
}
object MyLogger:
def create(orig: Scribe[IO]) = IOLocal(Map.empty).map(new MyLogger(orig, _))
object My extends IOApp.Simple:
import cats.syntax.all.*
import concurrent.duration.*
val randomDelay = cats.effect.std.Random
.scalaUtilRandom[IO]
.flatMap(_.nextIntBounded(1000))
.flatMap(t => IO.sleep(t.millis))
val run =
MyLogger
.create(scribe.cats.io)
.flatMap { log =>
List("UserA", "UserB", "UserC").parTraverse { userId =>
log.annotate("user-id", userId) {
for
_ <- randomDelay
_ <- log.info("fetching user from database")
_ <- randomDelay
_ <- log.info("downloading user's profile picture")
yield ()
}
}
}
.void
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment