LoggerF - Logger for F[_]

website·Indexed 32 days ago

https://logger-f.kevinly.dev

A tool for logging tagless final with an effect library, providing easy ways to log Either and EitherT. It supports Cats, Cats Effect, Monix, and Scalaz Effect, with integration for SLF4J. Available in versions v1 and v2.14.0.

Tokens
6.3K
Snippets
53
Records
59
Agent score
59%

What's inside LoggerF

  1. Overview of the Log algebra

    Log is an algebra used to log various effectful types such as F[A], F[Option[A]], F[Either[A, B]], OptionT[F, A], and EitherT[F, A, B]. It provides an abstraction for logging operations that can be interpreted differently depending on the requirements. To function, it requires Fx from the Effectie library and Monad from the Cats library.
  2. Overview of LoggerF

    LoggerF is a tool for logging in tagless final architectures with an effect library. It requires the Effectie library to construct F[_]. It simplifies logging by allowing developers to attach logging logic directly to the effect chain rather than manually inserting flatMap or delay blocks for every log statement.
    // Traditional approach
    for {
      a <- foo(n)
      _ <- Sync[F].delay(logger.debug(s"a is $a"))
      b <- bar(a)
    } yield b
    
    // With LoggerF
    for {
      a <- foo(n).log(a => debug(s"a is $a"))
      b <- bar(a).log(b => debug(s"b is $b"))
    } yield b
  3. Overview of LoggerF

    v1
    LoggerF is a logging utility for tagless final architectures using effect libraries. It requires the Effectie library to construct the effect type F[_]. It is designed to solve logging inconveniences that arise when using OptionT or EitherT within an effect stack, where standard flatMap logging may not capture the desired state (e.g., logging the None case in an OptionT chain).
  4. Overview of the Log typeclass for Cats

    v1
    The Log typeclass provides a mechanism to log values wrapped in functional containers. It supports F[A], F[Option[A]], F[Either[A, B]], OptionT[F, A], and EitherT[F, A, B]. To use Log, the environment must provide Fx from the Effectie library and Monad from the Cats library.
  5. Overview of Logger-F for tagless final logging

    Logger-F is a tool designed for logging within a tagless final architecture using an effect library. It allows developers to maintain architectural abstraction while implementing logging capabilities with minimal additional code. It specifically provides streamlined methods for logging Either and EitherT types.
  6. Log effects using the Log typeclass in Monix

    v1
    The Log typeclass provides a mechanism to log values wrapped in effect types such as F[A], F[Option[A]], F[Either[A, B]], OptionT[F, A], and EitherT[F, A, B]. To use this typeclass, the environment must provide Fx from Effectie and Monad from Cats.
  7. Log effects using the Scalaz Log typeclass

    v1
    The Log typeclass provides a mechanism to log values within effect types. It is compatible with F[A], F[Option[A]], F[A \/ B], OptionT[F, A], and EitherT[F, A, B]. To use this typeclass, the environment must provide Fx from Effectie and Monad from Scalaz.
  8. Implement logging in a Monix Task application

    v1
    This example demonstrates how to integrate Log within a service (Greeting) and execute it within a TaskApp. It requires a CanLog instance (e.g., Slf4JLogger) to be available in the implicit scope.
    import cats._
    import cats.syntax.all._
    import cats.effect.ExitCode
    import effectie.monix.{ConsoleEffect, Fx}
    import effectie.monix.Effectful._
    import loggerf.logger._
    import loggerf.monix._
    import loggerf.syntax._
    import monix.eval.Task
    import monix.eval.TaskApp
    
    trait Named[A] {
      def name(a: A): String
    }
    
    final case class GivenName(givenName: String) extends AnyVal
    final case class Surname(surname: String) extends AnyVal
    final case class Person(givenName: GivenName, surname: Surname)
    
    object Person {
      implicit val namedPerson: Named[Person] = 
        person => s"${person.givenName.givenName} ${person.surname.surname}"
    }
    
    trait Greeting[F[_]] {
      def greet[A: Named](a: A): F[String]
    }
    
    object Greeting {
      def apply[F[_]: Greeting]: Greeting[F] = implicitly[Greeting[F]]
    
      implicit def hello[F[_]: Fx: Monad: Log]: Greeting[F] = 
        new Greeting[F] {
          def greet[A: Named](a: A): F[String] = 
            for {
              // Log the result of the effect
              name <- log(effectOf(Named[A].name(a)))(x => info(s"The name is $x"))
              greeting <- pureOf(s"Hello $name")
            } yield greeting
        }
    }
    
    object TaskMainApp extends TaskApp {
      // Configure the logger implementation
      implicit val canLog: CanLog = Slf4JLogger.slf4JCanLog("MyApp")
    
      def run(args: List[String]): Task[ExitCode] = 
        for {
          greetingMessage <- Greeting[Task].greet(
            Person(GivenName("Kevin"), Surname("Lee"))
          )
          _ <- ConsoleEffect[Task].putStrLn(greetingMessage)
        } yield ExitCode.Success
    }
  9. Install LoggerF for Cats Effect

    v1
    To use LoggerF with Cats Effect (supporting both version 2 and 3), add the logger-f-cats-effect dependency along with the desired logging backend dependency in your build.sbt.
    // For SLF4J
    libraryDependencies ++= Seq(
      "io.kevinlee" %% "logger-f-cats-effect" % "1.20.0",
      "io.kevinlee" %% "logger-f-slf4j" % "1.20.0"
    )
    
    // For Log4j
    libraryDependencies ++= Seq(
      "io.kevinlee" %% "logger-f-cats-effect" % "1.20.0",
      "io.kevinlee" %% "logger-f-log4j" % "1.20.0"
    )
    
    // For Log4s
    libraryDependencies ++= Seq(
      "io.kevinlee" %% "logger-f-cats-effect" % "1.20.0",
      "io.kevinlee" %% "logger-f-log4s" % "1.20.0"
    )
    
    // For sbt Logging Util (sbt plugin development)
    libraryDependencies ++= Seq(
      "io.kevinlee" %% "logger-f-cats-effect" % "1.20.0",
      "io.kevinlee" %% "logger-f-sbt-logging" % "1.20.0"
    )
  10. Example: Logging with OptionT

    This example demonstrates how to log when an OptionT is empty (using warn) or contains a value (using info), and how to use ignore to skip logging for specific cases.
    import cats._
    import cats.data._
    import cats.syntax.all._
    import cats.effect._
    import effectie.core._
    import effectie.syntax.all._
    import loggerf.core._
    import loggerf.syntax.all._
    import loggerf.logger._
    
    def hello[F[_]: Monad: Fx: Log](maybeName: Option[String]): F[Unit] = 
      (for {
        name    <- OptionT(pureOf(maybeName))
                     .log(
                       warn("No name given"),
                       name => info(s"Name: $name")
                     )
        message <- OptionT.liftF(greeting[F](name))
                     .log(ignore, msg => info(s"Message: $msg"))
      } yield message)
        .foreachF(msg => effectOf(println(msg)))
    
    implicit val canLog: CanLog = Slf4JLogger.slf4JCanLog("MyApp- OptionT[F, A]")
  11. Add LoggerF for Cats dependency to sbt

    To use LoggerF for Cats (version 2.14.0), add the following dependency to your build.sbt file.
    "io.kevinlee" %% "logger-f-cats" % "2.14.0"
  12. Install LoggerF for Scalaz Effect

    v1
    To use LoggerF with Scalaz Effect, add the logger-f-scalaz-effect dependency and the chosen logging backend in build.sbt.
    // For SLF4J
    libraryDependencies ++= Seq(
      "io.kevinlee" %% "logger-f-scalaz-effect" % "1.20.0",
      "io.kevinlee" %% "logger-f-slf4j" % "1.20.0"
    )
    
    // For Log4j
    libraryDependencies ++= Seq(
      "io.kevinlee" %% "logger-f-scalaz-effect" % "1.20.0",
      "io.kevinlee" %% "logger-f-log4j" % "1.20.0"
    )
    
    // For Log4s
    libraryDependencies ++= Seq(
      "io.kevinlee" %% "logger-f-scalaz-effect" % "1.20.0",
      "io.kevinlee" %% "logger-f-log4s" % "1.20.0"
    )
    
    // For sbt Logging Util
    libraryDependencies ++= Seq(
      "io.kevinlee" %% "logger-f-scalaz-effect" % "1.20.0",
      "io.kevinlee" %% "logger-f-sbt-logging" % "1.20.0"
    )