Skip to content

Commit

Permalink
implement zio2 tofu logging like zio1, write example
Browse files Browse the repository at this point in the history
  • Loading branch information
Ivan Malyshev committed Nov 15, 2022
1 parent 0605c23 commit 8b47ed3
Show file tree
Hide file tree
Showing 12 changed files with 297 additions and 4 deletions.
27 changes: 23 additions & 4 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,26 @@ lazy val zioLogging =
)
.dependsOn(loggingStr, loggingDer % "test", zioCore % Test)

lazy val zio2Logging =
project
.in(file("modules/zio2/logging"))
.settings(
defaultSettings,
name := "tofu-zio2-logging",
libraryDependencies ++= List(zio2, slf4j, logback % Test, zio2Test, zio2TestSbt)
)
.dependsOn(loggingStr, loggingDer % "test")

lazy val examplesZIO2 =
project
.in(file("examples-zio2"))
.settings(
defaultSettings,
name := "tofu-examples-zio2",
noPublishSettings
)
.dependsOn(zio2Logging, loggingDer, loggingLayout)

lazy val zioInterop = project
.in(file("modules/zio"))
.settings(
Expand Down Expand Up @@ -373,7 +393,7 @@ lazy val ce3CoreModules = Vector(
)

lazy val commonModules =
Vector(observable, logging, enums, config, zioInterop, fs2Interop, doobie, doobieLogging)
Vector(observable, logging, enums, config, zioInterop, zio2Logging, fs2Interop, doobie, doobieLogging)

lazy val ce3CommonModules =
Vector(loggingStr, loggingDer, loggingLayout, doobieCE3, doobieLoggingCE3, fs2CE3Interop)
Expand Down Expand Up @@ -407,9 +427,8 @@ lazy val tofu = project
name := "tofu"
)
.aggregate(
(coreModules ++ commonModules ++ ce3CoreModules ++ ce3CommonModules :+ docs :+ examples :+ examplesCE3).map(x =>
x: ProjectReference
): _*
(coreModules ++ commonModules ++ ce3CoreModules ++ ce3CommonModules :+ docs :+ examples :+ examplesCE3 :+ examplesZIO2)
.map(x => x: ProjectReference): _*
)
.dependsOn(coreModules.map(x => x: ClasspathDep[ProjectReference]): _*)

Expand Down
13 changes: 13 additions & 0 deletions examples-zio2/src/main/resources/logback.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration scan="true" scanPeriod="10 minutes" >
<appender name="structured" class="ch.qos.logback.core.ConsoleAppender" packagingData="true">
<encoder class="ch.qos.logback.core.encoder.LayoutWrappingEncoder">
<charset>UTF-8</charset>
<layout class="tofu.logging.ELKLayout"/>
</encoder>
</appender>

<root level="DEBUG">
<appender-ref ref="structured"/>
</root>
</configuration>
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package tofu.example.logging

import tofu.example.logging.impl.{FooService, SimpleContext}
import tofu.logging.zlogs.{ZLogging, ZLogs}
import zio._

object ZMakeSimpleExample extends ZIOAppDefault {

val tasks = (1 to 3)
.map(i =>
for {
id <- Random.nextIntBetween(1000, 4000)
_ <- ZIO.serviceWithZIO[SimpleContext](_.set(id.toHexString))
_ <- ZIO.serviceWithZIO[FooService](_.foo(i))
} yield ()
)

override def run =
ZIO
.collectAllParDiscard(tasks)
.provide(
FooService.layer,
ZLogging.Make.layerPlainWithContext,
SimpleContext.layer
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package tofu.example.logging.impl

import tofu.logging.zlogs.{ULogging, ZLogging}
import zio._

class FooService(
logs: ZLogging.Make
) {
private val logger: ULogging = logs.forService[FooService]

def foo(i: Int): UIO[Int] =
for {
_ <- logger.debug("Starting Foo! i={}", i)
_ <- Clock.sleep(i.seconds)
_ <- logger.info("Foo completed!")
} yield i
}

object FooService {
val layer: URLayer[ZLogging.Make, FooService] = ZLayer.fromFunction(new FooService(_))
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package tofu.example.logging.impl

import tofu.logging.{Loggable, LoggedValue}
import tofu.logging.zlogs.ContextProvider
import zio.{FiberRef, UIO, ZLayer}

class SimpleContext(ref: FiberRef[String]) extends ContextProvider {
private implicit val requestIdLoggable: Loggable[String] =
Loggable.stringValue.named("requestId")

override def getCtx: UIO[LoggedValue] = ref.get.map(x => x)

def set(requestId: String): UIO[Unit] =
ref.set(requestId)
}

object SimpleContext {
val layer = ZLayer.scoped(
FiberRef.make[String]("")
.map(new SimpleContext(_))
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package tofu.logging.impl

import org.slf4j.{Logger, Marker}
import tofu.logging.zlogs.ZLogging
import tofu.logging.{Loggable, LoggedValue, Logging}
import zio._

class ZContextLogging[R, Ctx: Loggable](logger: => Logger, ctxLog: URIO[R, Ctx]) extends ZLogging[R] {
override def write(level: Logging.Level, message: String, values: LoggedValue*): URIO[R, Unit] =
ctxLog.flatMap { ctx =>
ZIO.succeed(
ZUniversalContextLogging.write(level, logger, message, ctx, values, Nil)
)
}

override def writeMarker(level: Logging.Level, message: String, marker: Marker, values: LoggedValue*): URIO[R, Unit] =
ctxLog.flatMap { ctx =>
ZIO.succeed(
ZUniversalContextLogging.write(level, logger, message, ctx, values, marker :: Nil)
)
}

override def writeCause(level: Logging.Level, message: String, cause: Throwable, values: LoggedValue*): URIO[R, Unit] =
ctxLog.flatMap { ctx =>
ZIO.succeed(
ZUniversalContextLogging.writeCause(level, logger, cause, message, ctx, values, Nil)
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package tofu.logging.impl

import org.slf4j.{Logger, LoggerFactory, Marker}
import tofu.logging._
import zio.URIO

class ZUniversalContextLogging[R, Ctx: Loggable](name: String, ctxLog: URIO[R, Ctx])
extends ZContextLogging[R, Ctx](LoggerFactory.getLogger(name), ctxLog)

object ZUniversalContextLogging {

private[logging] def write(
level: Logging.Level,
logger: Logger,
message: => String,
ctx: LoggedValue,
values: Seq[LoggedValue],
markers: List[Marker] = Nil
): Unit = {
if (UniversalLogging.enabled(level, logger))
UniversalLogging.writeMarker(
level = level,
logger = logger,
marker = ContextMarker(ctx, markers),
message = message,
values = values
)
}

private[logging] def writeCause(
level: Logging.Level,
logger: Logger,
cause: Throwable,
message: => String,
ctx: LoggedValue,
values: Seq[LoggedValue],
markers: List[Marker] = Nil
): Unit = {
if (UniversalLogging.enabled(level, logger))
UniversalLogging.writeMarkerCause(
level = level,
logger = logger,
marker = ContextMarker(ctx, markers),
cause = cause,
message = message,
values = values
)
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package tofu.logging.zlogs

import tofu.logging.LoggedValue
import zio.UIO

trait ContextProvider {
def getCtx: UIO[LoggedValue]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package tofu.logging.zlogs

import tofu.logging._
import tofu.logging.impl.ZUniversalContextLogging
import zio._

import scala.annotation.unused

object ZLogging {

type ZMake[R] = Logging.Make[URIO[R, *]]

type Make = Logging.Make[UIO]

def empty[R]: ZLogging[R] = new Logging[URIO[R, *]] {
override def write(level: Logging.Level, message: String, values: LoggedValue*): URIO[R, Unit] = ZIO.unit
}

/** Unlike [[ZLogs]] layers, these helpers are effect-less.
*/
object Make {

/** Creates layer with a helper producing simple [[tofu.logging.Logging]].
*/
val layerPlain: ULayer[ZLogging.Make] = ZLayer.succeed(new ZUniversalContextLogging(_, ZIO.unit))

/** Creates layer with a helper [[ZMake]] producing logging `ZLogging[R]`. Logging methods will add the
* context from the ZIO environment.
*
* @tparam R
* the context, an environment of the logging methods.
*/
def layerContextual[R: Loggable](implicit @unused RT: Tag[R]): ULayer[ZLogging.ZMake[R]] = ZLayer.succeed(
new ZUniversalContextLogging(_, ZIO.service[R])
)

/** Creates layer with a helper [[Make]] producing plain `ULogging` with encapsulated context. You have to
* provide an implementation of `ContextProvider`.
*/
def layerPlainWithContext: URLayer[ContextProvider, ZLogging.Make] =
ZLayer(
ZIO.serviceWith[ContextProvider](cp => new ZUniversalContextLogging(_, cp.getCtx))
)

val layerEmpty: ULayer[ZLogging.Make] = ZLayer.succeed(_ => empty[Any])
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package tofu.logging

import zio.{UIO, URIO}

package object zlogs {
type ZLogs[R] = Logs[UIO, URIO[R, *]]
type ULogs = Logs[UIO, UIO]
type ZLogging[R] = Logging[URIO[R, *]]
type ULogging = Logging[UIO]
}
42 changes: 42 additions & 0 deletions modules/zio2/logging/src/main/scala/tofu/logging/zlogs/zlogs.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package tofu.logging.zlogs

import org.slf4j.{Logger, LoggerFactory}
import tofu.logging.impl.ZContextLogging
import tofu.logging.zlogs.ZLogging.ZMake
import tofu.logging.{Loggable, Logs}
import zio._

import scala.annotation.unused

object ZLogs {

private def make[R](f: Logger => ZLogging[R]) =
new Logs[UIO, URIO[R, *]] {
override def byName(name: String): UIO[ZLogging[R]] =
ZIO.succeed(LoggerFactory.getLogger(name)).map(f)
}

/** Creates layer with a helper producing simple [[tofu.logging.Logging]].
*/
def layerPlain: ULayer[ULogs] =
ZLayer.succeed(make(new ZContextLogging(_, ZIO.unit)))

/** Creates layer with a helper [[ZLogs]] producing logging `ZLogging[R]`. Logging methods will add the context
* from the ZIO environment.
*
* @tparam R
* the context, an environment of the logging methods.
*/
def layerContextual[R: Loggable](implicit @unused RT: Tag[R]): ULayer[ZLogs[R]] =
ZLayer.succeed(make(new ZContextLogging(_, ZIO.service[R])))

/** Creates layer with a helper [[ULogs]] producing plain `ULogging` with encapsulated context. You have to
* provide an implementation of `ContextProvider`.
*/
val layerPlainWithContext: URLayer[ContextProvider, ULogs] = ZLayer(
ZIO.serviceWith[ContextProvider](cp => make(new ZContextLogging(_, cp.getCtx)))
)

val layerEmpty: ULayer[ULogs] = ZLayer.succeed(make(_ => ZLogging.empty[Any]))

}
5 changes: 5 additions & 0 deletions project/Dependencies.scala
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,8 @@ object Dependencies {

val zio = "1.0.17"

val zio2 = "2.0.3"

val zioCats = "2.5.1.0"

val shapeless = "2.3.10"
Expand Down Expand Up @@ -109,6 +111,9 @@ object Dependencies {
val catsTagless = "org.typelevel" %% "cats-tagless-macros" % Version.catsTagless
val typesafeConfig = "com.typesafe" % "config" % Version.typesafeConfig
val zio = "dev.zio" %% "zio" % Version.zio
val zio2 = "dev.zio" %% "zio" % Version.zio2
val zio2Test = "dev.zio" %% "zio-test" % Version.zio2 % Test
val zio2TestSbt = "dev.zio" %% "zio-test-sbt" % Version.zio2 % Test
val zioCats = "dev.zio" %% "zio-interop-cats" % Version.zioCats
val scalatest = "org.scalatest" %% "scalatest" % Version.scalatest % Test
val shapeless = "com.chuusai" %% "shapeless" % Version.shapeless
Expand Down

0 comments on commit 8b47ed3

Please sign in to comment.