Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Custom log levels for logger instances #931

Merged
merged 1 commit into from
May 11, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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]
}
Original file line number Diff line number Diff line change
@@ -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]
}
Expand Down Expand Up @@ -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)

}
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,21 @@ 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]
}

trait Method[U[f[_]], Res, +T[_]] {
def arg[A: Loggable](name: String, a: A): Method[U, Res, T]

def result: T[Res]
}

Expand Down Expand Up @@ -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))
}
Expand All @@ -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, *]] {
Expand All @@ -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))
Expand All @@ -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)
}
}