viktortnk / zio-logging-context-demo

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Demo of context-aware logging capabilities in ZIO environment

sbt example/run
curl -XPOST -H 'access-token: 1234' -H 'x-correlation-id: id22234' -H 'content-type: application/json; charset=utf-8' 'http://127.0.0.1:9090/whisk.console.recipe.v1.RecipeAPI/GetRecipe' -d '{
  "id": "dsfdsf"
}'

Info

com.whisk.util.logging.LoggingContext - view to underlying context. Likely only need to be used directly when constructing program on top level. It is ZIO-independent, we can implement similar for Monix

com.whisk.util.logging.Logging - Type for constructing Loggers and accessing/modifying underlying context

com.whisk.util.logging.ZIOLoggingContext - ZIO implementation of LoggingContext, which is using FiberRef

whisk.console.logging.GrpcLoggingContext - extracts correlationId from grpc request context and puts it into LoggingContext

Usage

Example of effectful creation of Logger. The returned type is log4cats.StructuredLogger

class RecipeDao[F[_]: Monad: Logging] {

  def get(id: String): F[Option[RecipeDetails]] = {
    for {
      logger <- Logging[F].fromName(getClass.getName)
      _ <- logger.info(Map("extraParam" -> "0"))("requesting with id=" + id)
    } yield {
      Some(RecipeDetails(id))
    }
  }
}

Example with 'unsafe' creation of Logger within class

class RecipeDao2[F[_]: Monad: Logging] {

  private val logger = Logging[F].getLoggerFromClass(getClass)

  def get(id: String): F[Option[RecipeDetails]] = {
    logger.info(Map("extraParam" -> "0"))("requesting with id=" + id) *>
      Applicative[F].pure(Some(RecipeDetails(id)))
  }
}

Injecting more powerful MDCLogging[F[_]] construct when needed the access to underlying context

  class Live(recipeDao: RecipeDao[Task], recipeDao2: RecipeDao2[Task])(implicit logging: MDCLogging[Task])
      extends Service {

    override def getRecipe(request: GetRecipeRequest): ZIO[Has[User], Status, GetRecipeResponse] = {

      (for {
        user <- ZIO.service[User]
        logger <- logging.fromName(getClass.getName)
        _ <- logger.info("logging request: " + user)
        _ <- logging.withLocal(Map("localValue" -> "123")) {
          logger.info("local message")
        }
        details <- recipeDao.get(request.id)
        _ <- recipeDao2.get(request.id)
      } yield {
        GetRecipeResponse(details)
      }).mapError(Status.fromThrowable)
    }
  }

About


Languages

Language:Scala 100.0%