From 16da823f1eb38398cec3136ca4b1b60a974ad2f4 Mon Sep 17 00:00:00 2001 From: Rat King Date: Wed, 11 May 2022 18:19:35 +0400 Subject: [PATCH] custom log levels, tests are for the weak (#931) Co-authored-by: Simon Nevrev --- .../tofu/logging/derivation/loggingMid.scala | 53 +++++++++++++++++++ .../logging/builder/LoggingBiMidBuilder.scala | 29 +++++----- .../logging/builder/LoggingMidBuilder.scala | 52 ++++++++++++++++-- 3 files changed, 117 insertions(+), 17 deletions(-) diff --git a/modules/logging/derivation/src/main/scala/tofu/logging/derivation/loggingMid.scala b/modules/logging/derivation/src/main/scala/tofu/logging/derivation/loggingMid.scala index 24ba76f44..dc44697f7 100644 --- a/modules/logging/derivation/src/main/scala/tofu/logging/derivation/loggingMid.scala +++ b/modules/logging/derivation/src/main/scala/tofu/logging/derivation/loggingMid.scala @@ -7,6 +7,7 @@ import derevo.DerivationKN11 import tofu.logging.bi.LoggingBiMid import derevo.PassTypeArgs import derevo.ParamRequire +import tofu.logging.Logging.Level import tofu.logging.builder.LoggingMidBuilder import tofu.logging.builder.LoggingErrMidBuilder import tofu.logging.builder.LoggingBiMidBuilder @@ -27,6 +28,23 @@ object loggingMid def instance[U[f[_]]]: U[LoggingMid] = macro HigherKindedMacros.factorizeThis[U] } +/** Default logging derivation mechanism for unary effect algebras + * + * Adds logging around the successful invocation of each method at `logLevel` level. + * + * @note + * Class name is not printed by default. + * + * For customization create an object with the same parents and abstract type member `Result` and redefine [onEnter] + * and [onLeave] methods of the `LoggingMidBuilder` trait. + */ +case class loggingMidCustomLevel(logLevel: Level) + extends LoggingMidBuilder.CustomLevelImpl(logLevel) with DerivationKN3[LoggingMid.Of] with PassTypeArgs + with ParamRequire[Loggable] { + type Result[A] = LoggingMid[A] + def instance[U[f[_]]]: U[LoggingMid] = macro HigherKindedMacros.factorizeThis[U] +} + /** Default logging derivation mechanism for unary effect algebras with error reporting. * * Adds logging around the invocation of each method at DEBUG level and error alert at ERROR level @@ -43,6 +61,23 @@ object loggingMidTry def instance[U[f[_]]]: U[Result] = macro HigherKindedMacros.factorizeThis[U] } +/** Default logging derivation mechanism for unary effect algebras with error reporting. + * + * Adds logging around the invocation of each method at specified `logLevel` and error alert at specified + * `errorLogLevel` level + * @note + * Class name is not printed by default. + * + * For customization create object with the same parents and abstract type member `Result` and redefine [onEnter], + * [onLeave] and [onFault] methods of the `LoggingErrMidBuilder` trait. + */ +case class loggingMidTryCustomLevel(logLevel: Level, errorLogLevel: Level) + extends LoggingErrMidBuilder.CustomLevelImpl[Throwable](logLevel, errorLogLevel) + with DerivationKN3[LoggingErrMid.Try] with PassTypeArgs with ParamRequire[Loggable] { + type Result[A] = LoggingErrMid[Throwable, A] + def instance[U[f[_]]]: U[Result] = macro HigherKindedMacros.factorizeThis[U] +} + /** Default logging with errors derivation mechanism for binary effect algebras. * * Adds logging around invocation of each method at DEBUG level and error alert at ERROR level @@ -59,3 +94,21 @@ object loggingBiMid def instance[U[f[_, _]]]: U[LoggingBiMid] = macro HigherKindedMacros.bifactorizeThis[U] } + +/** Default logging with errors derivation mechanism for binary effect algebras. + * + * Adds logging around the invocation of each method at specified `logLevel` and error alert at specified + * `errorLogLevel` level + * @note + * Class name is not printed by default. + * + * For customization create object with the same parents and abstract type member `Result` and redefine [onEnter], + * [onLeave] methods of the `LoggingBiMidBuilder` trait. + */ +case class loggingBiMidCustomLevel(logLevel: Level, errorLogLevel: Level) + extends LoggingBiMidBuilder.CustomLogLevel(logLevel, errorLogLevel) with DerivationKN11[LoggingBiMid.Of] + with PassTypeArgs with ParamRequire[Loggable] { + type Result[E, A] = LoggingBiMid[E, A] + def instance[U[f[_, _]]]: U[LoggingBiMid] = + macro HigherKindedMacros.bifactorizeThis[U] +} diff --git a/modules/logging/structured/src/main/scala/tofu/logging/builder/LoggingBiMidBuilder.scala b/modules/logging/structured/src/main/scala/tofu/logging/builder/LoggingBiMidBuilder.scala index d6427a4e5..92db514b6 100644 --- a/modules/logging/structured/src/main/scala/tofu/logging/builder/LoggingBiMidBuilder.scala +++ b/modules/logging/structured/src/main/scala/tofu/logging/builder/LoggingBiMidBuilder.scala @@ -1,14 +1,15 @@ package tofu.logging package builder -import scala.collection.mutable.Buffer -import scala.reflect.ClassTag import tofu.control.Bind +import tofu.logging.Logging.Level import tofu.logging.bi.LoggingBiMid import tofu.logging.impl.ArgsLoggable -import tofu.logging.{Loggable, LoggedValue, Logging} import tofu.syntax.bindInv._ +import scala.collection.mutable.Buffer +import scala.reflect.ClassTag + trait BiBuilder[+T[_, _]] { def prepare[Alg[_[_, _]]](implicit Alg: ClassTag[Alg[Any]]): BiPrepared[Alg, T] } @@ -71,24 +72,26 @@ abstract class LoggingBiMidBuilder extends BiBuilder[LoggingBiMid] { } object LoggingBiMidBuilder { - class Default extends LoggingBiMidBuilder { - def onEnter[F[_, _]](cls: Class[_], method: String, args: Seq[(String, LoggedValue)])(implicit + + class CustomLogLevel(logLevel: Level, errorLogLevel: Level) extends LoggingBiMidBuilder { + + override def onEnter[F[+_, +_]](cls: Class[_], method: String, args: Seq[(String, LoggedValue)])(implicit F: Logging.SafeBase[F] - ): F[Nothing, Unit] = F.debug("entering {} {}", method, new ArgsLoggable(args)) + ): F[Nothing, Unit] = F.write(logLevel, "entering {} {}", method, new ArgsLoggable(args)) - def onLeave[F[_, _]]( + override def onLeave[F[+_, +_]]( cls: Class[_], method: String, args: Seq[(String, LoggedValue)], res: LoggedValue, - ok: Boolean, + ok: Boolean )(implicit F: Logging.SafeBase[F] - ): F[Nothing, Unit] = - if (ok) - F.debug("leaving {} {} result is {}", method, new ArgsLoggable(args), res) - else - F.error("error during {} {} error is {}", method, new ArgsLoggable(args), res) + ): F[Nothing, Unit] = if (ok) + F.write(logLevel, "leaving {} {} result is {}", method, new ArgsLoggable(args), res) + else + F.write(errorLogLevel, "error during {} {} error is {}", method, new ArgsLoggable(args), res) } + class Default extends CustomLogLevel(Logging.Debug, Logging.Error) } diff --git a/modules/logging/structured/src/main/scala/tofu/logging/builder/LoggingMidBuilder.scala b/modules/logging/structured/src/main/scala/tofu/logging/builder/LoggingMidBuilder.scala index 52c46a587..6196fb5ba 100644 --- a/modules/logging/structured/src/main/scala/tofu/logging/builder/LoggingMidBuilder.scala +++ b/modules/logging/structured/src/main/scala/tofu/logging/builder/LoggingMidBuilder.scala @@ -3,12 +3,13 @@ package builder import scala.collection.mutable import scala.reflect.ClassTag - import tofu.syntax.monadic._ import cats.Monad import tofu.Errors import tofu.syntax.handle._ import impl.ArgsLoggable +import tofu.logging.Logging.Level +import tofu.logging.LoggingBase trait Builder[+T[_]] { def prepare[Alg[_[_]]](implicit Alg: ClassTag[Alg[Any]]): Prepared[Alg, T] @@ -16,6 +17,7 @@ trait Builder[+T[_]] { trait Method[U[f[_]], Res, +T[_]] { def arg[A: Loggable](name: String, a: A): Method[U, Res, T] + def result: T[Res] } @@ -48,8 +50,10 @@ trait LoggingMidBuilder extends Builder[LoggingMid] { args += (name -> a) this } - def result: LoggingMid[Res] = new LoggingMid[Res] { - private[this] val argSeq = args.toSeq + + def result: LoggingMid[Res] = new LoggingMid[Res] { + private[this] val argSeq = args.toSeq + def around[F[_]: Monad: LoggingBase](fa: F[Res]): F[Res] = onEnter(cls, method, argSeq) *> fa.flatTap(res => onLeave(cls, method, argSeq, res)) } @@ -72,6 +76,23 @@ object LoggingMidBuilder { } class DefaultImpl extends Default + + trait CustomLevel extends LoggingMidBuilder { + def onLog[F[_]](message: String, values: LoggedValue*)(implicit F: LoggingBase[F]): F[Unit] + + def onEnter[F[_]](cls: Class[_], method: String, args: Seq[(String, LoggedValue)])(implicit + F: LoggingBase[F] + ): F[Unit] = onLog("entering {} {}", method, new ArgsLoggable(args)) + + def onLeave[F[_]](cls: Class[_], method: String, args: Seq[(String, LoggedValue)], res: LoggedValue)(implicit + F: LoggingBase[F] + ): F[Unit] = onLog("leaving {} {} with result {}", method, new ArgsLoggable(args), res) + } + + class CustomLevelImpl(logLevel: Level) extends CustomLevel { + override def onLog[F[_]](message: String, values: LoggedValue*)(implicit F: LoggingBase[F]): F[Unit] = + F.write(logLevel, message, values) + } } trait LoggingErrMidBuilder[E] extends LoggingMidBuilder with Builder[LoggingErrMid[E, *]] { @@ -90,7 +111,8 @@ trait LoggingErrMidBuilder[E] extends LoggingMidBuilder with Builder[LoggingErrM args: mutable.Buffer[(String, LoggedValue)] ) extends MethodImpl[U, Res](cls, method, args) with Method[U, Res, LoggingErrMid[E, *]] { override def result: LoggingErrMid[E, Res] = new LoggingErrMid[E, Res] { - private[this] val argSeq = args.toSeq + private[this] val argSeq = args.toSeq + def aroundErr[F[_]: Monad: Errors[*[_], E]: LoggingBase](fa: F[Res]): F[Res] = onEnter(cls, method, argSeq) *> fa.onError(onFault(cls, method, argSeq, _: E)) @@ -117,5 +139,27 @@ object LoggingErrMidBuilder { F.error("error during {} {} error is {}", method, new ArgsLoggable(args), err) } + class DefaultImpl[E](implicit val errLoggable: Loggable[E]) extends Default[E] + + trait CustomLevel[E] extends LoggingMidBuilder.CustomLevel with LoggingErrMidBuilder[E] { + implicit def errLoggable: Loggable[E] + + def onFaultLog[F[_]: LoggingBase](message: String, values: LoggedValue*): F[Unit] + + def onFault[F[_]]( + cls: Class[_], + method: String, + args: Seq[(String, LoggedValue)], + err: E + )(implicit F: LoggingBase[F]): F[Unit] = + onFaultLog("error during {} {} error is {}", method, new ArgsLoggable(args), err) + + } + + class CustomLevelImpl[E](logLevel: Level, errorLogLevel: Level)(implicit val errLoggable: Loggable[E]) + extends LoggingMidBuilder.CustomLevelImpl(logLevel) with CustomLevel[E] { + override def onFaultLog[F[_]](message: String, values: LoggedValue*)(implicit F: LoggingBase[F]): F[Unit] = + F.write(errorLogLevel, message, values) + } }