diff --git a/build.sbt b/build.sbt index bc88edd..c6c7c12 100644 --- a/build.sbt +++ b/build.sbt @@ -47,7 +47,7 @@ lazy val testSettings = Seq( lazy val `gs-log` = project .in(file(".")) - .aggregate(data, api) + .aggregate(data, api, engine) .settings(noPublishSettings) .settings(name := s"${gsProjectName.value}-v${semVerMajor.value}") @@ -66,3 +66,14 @@ lazy val api = project .settings(sharedSettings) .settings(testSettings) .settings(name := s"${gsProjectName.value}-api-v${semVerMajor.value}") + +lazy val engine = project + .in(file("modules/engine")) + .dependsOn(data, api) + .settings(sharedSettings) + .settings(testSettings) + .settings(name := s"${gsProjectName.value}-engine-v${semVerMajor.value}") + .settings(libraryDependencies ++= Seq( + Deps.Cats.Effect, + Deps.Fs2.Core + )) diff --git a/modules/api/src/main/scala/gs/log/v0/api/Logger.scala b/modules/api/src/main/scala/gs/log/v0/api/Logger.scala index 2be3d77..cc44400 100644 --- a/modules/api/src/main/scala/gs/log/v0/api/Logger.scala +++ b/modules/api/src/main/scala/gs/log/v0/api/Logger.scala @@ -60,7 +60,7 @@ trait Logger[F[_]]: /** * @return The name of this logger. */ - def name(): Logger.Name + def name: Logger.Name /** * Determine whether this logger has the given level enabled. @@ -68,7 +68,7 @@ trait Logger[F[_]]: * @param level The [[LogLevel]] to check. * @return True if the level is enabled, false otherwise. */ - def isLevelEnabled(level: LogLevel): Boolean + def isLevelEnabled(level: LogLevel): F[Boolean] object Logger: diff --git a/modules/engine/src/main/scala/gs/log/v0/engine/QueueLogger.scala b/modules/engine/src/main/scala/gs/log/v0/engine/QueueLogger.scala new file mode 100644 index 0000000..264e37b --- /dev/null +++ b/modules/engine/src/main/scala/gs/log/v0/engine/QueueLogger.scala @@ -0,0 +1,53 @@ +package gs.log.v0.engine + +import gs.log.v0.api.Logger +import cats.effect.Async +import gs.log.v0.data.Log +import gs.log.v0.data.LogLevel +import gs.log.v0.api.Logger.Name +import cats.effect.Ref + +import cats.syntax.all.* +import cats.effect.std.Queue +import java.time.Clock +import java.time.Instant + +final class QueueLogger[F[_]: Async]( + val name: Logger.Name, + private val clock: Clock, + private val maxLevel: Ref[F, LogLevel], + private val queue: Queue[F, (Log, Log.Metadata)] +) extends Logger[F] { + + override def isLevelEnabled(level: LogLevel): F[Boolean] = + maxLevel.get.map(max => level <= max) + + override def warn(log: => Log): F[Unit] = ??? + + override def debug(log: => Log): F[Unit] = ??? + + override def info(log: => Log): F[Unit] = ??? + + override def error(log: => Log): F[Unit] = ??? + + override def fatal(log: => Log): F[Unit] = ??? + + override def trace(log: => Log): F[Unit] = + meta(LogLevel.Trace).flatMap(m => queue.tryOffer((log, m))).flatMap { + case true => Async[F].unit + case false => Async[F].unit + } + + private def now(): F[Instant] = + Async[F].delay(Instant.now(clock)) + + private def meta(level: LogLevel): F[Log.Metadata] = + now().map(timestamp => + Log.Metadata( + level = level, + timestamp = timestamp, + owner = name.show + ) + ) + +}