diff --git a/src/main/scala/com/typesafe/scalalogging/ALogger.scala b/src/main/scala/com/typesafe/scalalogging/ALogger.scala new file mode 100644 index 0000000..9bbcc20 --- /dev/null +++ b/src/main/scala/com/typesafe/scalalogging/ALogger.scala @@ -0,0 +1,85 @@ +package com.typesafe.scalalogging + +import org.slf4j.Marker + +/** + * + * abstract class common for both Logger and LoggerTakingConstructorArg, + * if you have a library that is sometimes used in a context - in which case you want to log the context, + * but other times is used outside of a context in which case you want to log "normally", your base class can have a logger of this abstract type +*/ +trait ALogger { + + // Error + + def error(message: String): Unit = {} + + def error(message: String, cause: Throwable): Unit = {} + + def error(message: String, args: Any*): Unit = {} + + def error(marker: Marker, message: String): Unit = {} + + def error(marker: Marker, message: String, cause: Throwable): Unit = {} + + def error(marker: Marker, message: String, args: Any*): Unit = {} + + // Warn + + def warn(message: String): Unit = {} + + def warn(message: String, cause: Throwable): Unit = {} + + def warn(message: String, args: Any*): Unit = {} + + def warn(marker: Marker, message: String): Unit = {} + + def warn(marker: Marker, message: String, cause: Throwable): Unit = {} + + def warn(marker: Marker, message: String, args: Any*): Unit = {} + + // Info + + def info(message: String): Unit = {} + + def info(message: String, cause: Throwable): Unit = {} + + def info(message: String, args: Any*): Unit = {} + + def info(marker: Marker, message: String): Unit = {} + + def info(marker: Marker, message: String, cause: Throwable): Unit = {} + + def info(marker: Marker, message: String, args: Any*): Unit = {} + + // Debug + + def debug(message: String): Unit = {} + + def debug(message: String, cause: Throwable): Unit = {} + + def debug(message: String, args: Any*): Unit = {} + + def debug(marker: Marker, message: String): Unit = {} + + def debug(marker: Marker, message: String, cause: Throwable): Unit = {} + + def debug(marker: Marker, message: String, args: Any*): Unit = {} + + // Trace + + def trace(message: String): Unit = {} + + def trace(message: String, cause: Throwable): Unit = {} + + def trace(message: String, args: Any*): Unit = {} + + def trace(marker: Marker, message: String): Unit = {} + + def trace(marker: Marker, message: String, cause: Throwable): Unit = {} + + def trace(marker: Marker, message: String, args: Any*): Unit = {} + +} + + diff --git a/src/main/scala/com/typesafe/scalalogging/Logger.scala b/src/main/scala/com/typesafe/scalalogging/Logger.scala index e69b352..fcdc747 100644 --- a/src/main/scala/com/typesafe/scalalogging/Logger.scala +++ b/src/main/scala/com/typesafe/scalalogging/Logger.scala @@ -37,6 +37,12 @@ object Logger { def takingImplicit[A](underlying: Underlying)(implicit ev: CanLog[A]): LoggerTakingImplicit[A] = new LoggerTakingImplicit[A](underlying) + /** + * Create a [[LoggerTakingConstructorArg]] wrapping the given underlying `org.slf4j.Logger`. + */ + def inContextOf[A](underlying: Underlying)(implicit ev: CanLog[A], a: A): LoggerTakingConstructorArg[A] = + new LoggerTakingConstructorArg[A](underlying, ev, a) + /** * Create a [[Logger]] for the given name. * Example: @@ -57,6 +63,17 @@ object Logger { def takingImplicit[A](name: String)(implicit ev: CanLog[A]): LoggerTakingImplicit[A] = new LoggerTakingImplicit[A](LoggerFactory.getLogger(name)) + + /** + * Create a [[LoggerTakingConstructorArg]] for the given name. + * Example: + * {{{ + * val logger = Logger.inContextOf[CorrelationId]("application") + * }}} + */ + def inContextOf[A](name: String)(implicit ev: CanLog[A], a: A): LoggerTakingConstructorArg[A] = + new LoggerTakingConstructorArg[A](LoggerFactory.getLogger(name), ev, a) + /** * Create a [[Logger]] wrapping the created underlying `org.slf4j.Logger`. */ @@ -69,6 +86,12 @@ object Logger { def takingImplicit[A](clazz: Class[_])(implicit ev: CanLog[A]): LoggerTakingImplicit[A] = new LoggerTakingImplicit[A](LoggerFactory.getLogger(clazz.getName)) + /** + * Create a [[LoggerTakingConstructorArg]] named after the given class parameter. + */ + def inContextOf[A](clazz: Class[_])(implicit ev: CanLog[A], a: A): LoggerTakingConstructorArg[A] = + new LoggerTakingConstructorArg[A](LoggerFactory.getLogger(clazz.getName), ev, a) + /** * Create a [[Logger]] for the runtime class wrapped by the implicit class * tag parameter. @@ -90,91 +113,102 @@ object Logger { */ def takingImplicit[T, A](implicit ct: ClassTag[T], ev: CanLog[A]): LoggerTakingImplicit[A] = new LoggerTakingImplicit[A](LoggerFactory.getLogger(ct.runtimeClass.getName.stripSuffix("$"))) + + /** + * Create a [[LoggerTakingConstructorArg]] for the runtime class wrapped by the implicit class + * tag parameter. + * Example: + * {{{ + * val logger = Logger.inContextOf[MyClass, CorrelationId] + * }}} + */ + def inContextOf[T,A](implicit ct: ClassTag[T], ev: CanLog[A], a: A): LoggerTakingConstructorArg[A] = + new LoggerTakingConstructorArg[A](LoggerFactory.getLogger(ct.runtimeClass.getName.stripSuffix("$")), ev, a) } /** * Implementation of a fast logger based on macros and an underlying `org.slf4j.Logger`. */ @SerialVersionUID(538248225L) -final class Logger private (val underlying: Underlying) extends Serializable { +final class Logger private (val underlying: Underlying) extends ALogger with Serializable { // Error - def error(message: String): Unit = macro LoggerMacro.errorMessage + override def error(message: String): Unit = macro LoggerMacro.errorMessage - def error(message: String, cause: Throwable): Unit = macro LoggerMacro.errorMessageCause + override def error(message: String, cause: Throwable): Unit = macro LoggerMacro.errorMessageCause - def error(message: String, args: Any*): Unit = macro LoggerMacro.errorMessageArgs + override def error(message: String, args: Any*): Unit = macro LoggerMacro.errorMessageArgs - def error(marker: Marker, message: String): Unit = macro LoggerMacro.errorMessageMarker + override def error(marker: Marker, message: String): Unit = macro LoggerMacro.errorMessageMarker - def error(marker: Marker, message: String, cause: Throwable): Unit = macro LoggerMacro.errorMessageCauseMarker + override def error(marker: Marker, message: String, cause: Throwable): Unit = macro LoggerMacro.errorMessageCauseMarker - def error(marker: Marker, message: String, args: Any*): Unit = macro LoggerMacro.errorMessageArgsMarker + override def error(marker: Marker, message: String, args: Any*): Unit = macro LoggerMacro.errorMessageArgsMarker def whenErrorEnabled(body: Unit): Unit = macro LoggerMacro.errorCode // Warn - def warn(message: String): Unit = macro LoggerMacro.warnMessage + override def warn(message: String): Unit = macro LoggerMacro.warnMessage - def warn(message: String, cause: Throwable): Unit = macro LoggerMacro.warnMessageCause + override def warn(message: String, cause: Throwable): Unit = macro LoggerMacro.warnMessageCause - def warn(message: String, args: Any*): Unit = macro LoggerMacro.warnMessageArgs + override def warn(message: String, args: Any*): Unit = macro LoggerMacro.warnMessageArgs - def warn(marker: Marker, message: String): Unit = macro LoggerMacro.warnMessageMarker + override def warn(marker: Marker, message: String): Unit = macro LoggerMacro.warnMessageMarker - def warn(marker: Marker, message: String, cause: Throwable): Unit = macro LoggerMacro.warnMessageCauseMarker + override def warn(marker: Marker, message: String, cause: Throwable): Unit = macro LoggerMacro.warnMessageCauseMarker - def warn(marker: Marker, message: String, args: Any*): Unit = macro LoggerMacro.warnMessageArgsMarker + override def warn(marker: Marker, message: String, args: Any*): Unit = macro LoggerMacro.warnMessageArgsMarker def whenWarnEnabled(body: Unit): Unit = macro LoggerMacro.warnCode // Info - def info(message: String): Unit = macro LoggerMacro.infoMessage + override def info(message: String): Unit = macro LoggerMacro.infoMessage - def info(message: String, cause: Throwable): Unit = macro LoggerMacro.infoMessageCause + override def info(message: String, cause: Throwable): Unit = macro LoggerMacro.infoMessageCause - def info(message: String, args: Any*): Unit = macro LoggerMacro.infoMessageArgs + override def info(message: String, args: Any*): Unit = macro LoggerMacro.infoMessageArgs - def info(marker: Marker, message: String): Unit = macro LoggerMacro.infoMessageMarker + override def info(marker: Marker, message: String): Unit = macro LoggerMacro.infoMessageMarker - def info(marker: Marker, message: String, cause: Throwable): Unit = macro LoggerMacro.infoMessageCauseMarker + override def info(marker: Marker, message: String, cause: Throwable): Unit = macro LoggerMacro.infoMessageCauseMarker - def info(marker: Marker, message: String, args: Any*): Unit = macro LoggerMacro.infoMessageArgsMarker + override def info(marker: Marker, message: String, args: Any*): Unit = macro LoggerMacro.infoMessageArgsMarker def whenInfoEnabled(body: Unit): Unit = macro LoggerMacro.infoCode // Debug - def debug(message: String): Unit = macro LoggerMacro.debugMessage + override def debug(message: String): Unit = macro LoggerMacro.debugMessage - def debug(message: String, cause: Throwable): Unit = macro LoggerMacro.debugMessageCause + override def debug(message: String, cause: Throwable): Unit = macro LoggerMacro.debugMessageCause - def debug(message: String, args: Any*): Unit = macro LoggerMacro.debugMessageArgs + override def debug(message: String, args: Any*): Unit = macro LoggerMacro.debugMessageArgs - def debug(marker: Marker, message: String): Unit = macro LoggerMacro.debugMessageMarker + override def debug(marker: Marker, message: String): Unit = macro LoggerMacro.debugMessageMarker - def debug(marker: Marker, message: String, cause: Throwable): Unit = macro LoggerMacro.debugMessageCauseMarker + override def debug(marker: Marker, message: String, cause: Throwable): Unit = macro LoggerMacro.debugMessageCauseMarker - def debug(marker: Marker, message: String, args: Any*): Unit = macro LoggerMacro.debugMessageArgsMarker + override def debug(marker: Marker, message: String, args: Any*): Unit = macro LoggerMacro.debugMessageArgsMarker def whenDebugEnabled(body: Unit): Unit = macro LoggerMacro.debugCode // Trace - def trace(message: String): Unit = macro LoggerMacro.traceMessage + override def trace(message: String): Unit = macro LoggerMacro.traceMessage - def trace(message: String, cause: Throwable): Unit = macro LoggerMacro.traceMessageCause + override def trace(message: String, cause: Throwable): Unit = macro LoggerMacro.traceMessageCause - def trace(message: String, args: Any*): Unit = macro LoggerMacro.traceMessageArgs + override def trace(message: String, args: Any*): Unit = macro LoggerMacro.traceMessageArgs - def trace(marker: Marker, message: String): Unit = macro LoggerMacro.traceMessageMarker + override def trace(marker: Marker, message: String): Unit = macro LoggerMacro.traceMessageMarker - def trace(marker: Marker, message: String, cause: Throwable): Unit = macro LoggerMacro.traceMessageCauseMarker + override def trace(marker: Marker, message: String, cause: Throwable): Unit = macro LoggerMacro.traceMessageCauseMarker - def trace(marker: Marker, message: String, args: Any*): Unit = macro LoggerMacro.traceMessageArgsMarker + override def trace(marker: Marker, message: String, args: Any*): Unit = macro LoggerMacro.traceMessageArgsMarker def whenTraceEnabled(body: Unit): Unit = macro LoggerMacro.traceCode diff --git a/src/main/scala/com/typesafe/scalalogging/LoggerTakingConstructorArg.scala b/src/main/scala/com/typesafe/scalalogging/LoggerTakingConstructorArg.scala new file mode 100644 index 0000000..6e513aa --- /dev/null +++ b/src/main/scala/com/typesafe/scalalogging/LoggerTakingConstructorArg.scala @@ -0,0 +1,83 @@ +package com.typesafe.scalalogging + +import org.slf4j.{Marker, Logger => Underlying} + +import scala.language.experimental.macros + +/** + * ALogger that takes some data A and uses it according to strategy CanLog[A] during every log operation. + * Useful for logging things in a context, such as a request id, assuming it's available during construction time. + * */ +class LoggerTakingConstructorArg[A] private[scalalogging](val underlying: Underlying, val canLogEv: CanLog[A], val a: A) extends ALogger with Serializable with LogsAdditionalData[A] { + + // Error + + override def error(message: String): Unit = macro LoggerTakingConstructorArgMacro.errorMessage[A] + + override def error(message: String, cause: Throwable): Unit = macro LoggerTakingConstructorArgMacro.errorMessageCause[A] + + override def error(message: String, args: Any*): Unit = macro LoggerTakingConstructorArgMacro.errorMessageArgs[A] + + override def error(marker: Marker, message: String): Unit = macro LoggerTakingConstructorArgMacro.errorMessageMarker[A] + + override def error(marker: Marker, message: String, cause: Throwable): Unit = macro LoggerTakingConstructorArgMacro.errorMessageCauseMarker[A] + + override def error(marker: Marker, message: String, args: Any*): Unit = macro LoggerTakingConstructorArgMacro.errorMessageArgsMarker[A] + + // Warn + + override def warn(message: String): Unit = macro LoggerTakingConstructorArgMacro.warnMessage[A] + + override def warn(message: String, cause: Throwable): Unit = macro LoggerTakingConstructorArgMacro.warnMessageCause[A] + + override def warn(message: String, args: Any*): Unit = macro LoggerTakingConstructorArgMacro.warnMessageArgs[A] + + override def warn(marker: Marker, message: String): Unit = macro LoggerTakingConstructorArgMacro.warnMessageMarker[A] + + override def warn(marker: Marker, message: String, cause: Throwable): Unit = macro LoggerTakingConstructorArgMacro.warnMessageCauseMarker[A] + + override def warn(marker: Marker, message: String, args: Any*): Unit = macro LoggerTakingConstructorArgMacro.warnMessageArgsMarker[A] + + // Info + + override def info(message: String): Unit = macro LoggerTakingConstructorArgMacro.infoMessage[A] + + override def info(message: String, cause: Throwable): Unit = macro LoggerTakingConstructorArgMacro.infoMessageCause[A] + + override def info(message: String, args: Any*): Unit = macro LoggerTakingConstructorArgMacro.infoMessageArgs[A] + + override def info(marker: Marker, message: String): Unit = macro LoggerTakingConstructorArgMacro.infoMessageMarker[A] + + override def info(marker: Marker, message: String, cause: Throwable): Unit = macro LoggerTakingConstructorArgMacro.infoMessageCauseMarker[A] + + override def info(marker: Marker, message: String, args: Any*): Unit = macro LoggerTakingConstructorArgMacro.infoMessageArgsMarker[A] + + // Debug + + override def debug(message: String): Unit = macro LoggerTakingConstructorArgMacro.debugMessage[A] + + override def debug(message: String, cause: Throwable): Unit = macro LoggerTakingConstructorArgMacro.debugMessageCause[A] + + override def debug(message: String, args: Any*): Unit = macro LoggerTakingConstructorArgMacro.debugMessageArgs[A] + + override def debug(marker: Marker, message: String): Unit = macro LoggerTakingConstructorArgMacro.debugMessageMarker[A] + + override def debug(marker: Marker, message: String, cause: Throwable): Unit = macro LoggerTakingConstructorArgMacro.debugMessageCauseMarker[A] + + override def debug(marker: Marker, message: String, args: Any*): Unit = macro LoggerTakingConstructorArgMacro.debugMessageArgsMarker[A] + + // Trace + + override def trace(message: String): Unit = macro LoggerTakingConstructorArgMacro.traceMessage[A] + + override def trace(message: String, cause: Throwable): Unit = macro LoggerTakingConstructorArgMacro.traceMessageCause[A] + + override def trace(message: String, args: Any*): Unit = macro LoggerTakingConstructorArgMacro.traceMessageArgs[A] + + override def trace(marker: Marker, message: String): Unit = macro LoggerTakingConstructorArgMacro.traceMessageMarker[A] + + override def trace(marker: Marker, message: String, cause: Throwable): Unit = macro LoggerTakingConstructorArgMacro.traceMessageCauseMarker[A] + + override def trace(marker: Marker, message: String, args: Any*): Unit = macro LoggerTakingConstructorArgMacro.traceMessageArgsMarker[A] + +} diff --git a/src/main/scala/com/typesafe/scalalogging/LoggerTakingConstructorArgMacro.scala b/src/main/scala/com/typesafe/scalalogging/LoggerTakingConstructorArgMacro.scala new file mode 100644 index 0000000..d783b4a --- /dev/null +++ b/src/main/scala/com/typesafe/scalalogging/LoggerTakingConstructorArgMacro.scala @@ -0,0 +1,207 @@ +package com.typesafe.scalalogging + +import org.slf4j.Marker + +import scala.reflect.macros.blackbox + +/*** + * macros for logging, just a thin layer that extracts an instance A from the containing LoggerTakingConstructorArg[A] + * and uses LogsAdditionalDataMacro with it + */ +private object LoggerTakingConstructorArgMacro { + + type LoggerContext[A] = blackbox.Context { type PrefixType = LogsAdditionalData[A] } + + // Error + + def errorMessage[A](c: LoggerContext[A])(message: c.Expr[String]): c.universe.Tree = { + import c.universe._ + val a = q"${c.prefix}.a" + LogsAdditionalDataMacro.errorMessage[A](c)(message)(c.Expr(a)) + } + + def errorMessageCause[A](c: LoggerContext[A])(message: c.Expr[String], cause: c.Expr[Throwable]): c.universe.Tree = { + import c.universe._ + val a = q"${c.prefix}.a" + LogsAdditionalDataMacro.errorMessageCause[A](c)(message, cause)(c.Expr(a)) + } + + def errorMessageArgs[A](c: LoggerContext[A])(message: c.Expr[String], args: c.Expr[Any]*): c.universe.Tree = { + import c.universe._ + val a = q"${c.prefix}.a" + LogsAdditionalDataMacro.errorMessageArgs[A](c)(message, args:_*)(c.Expr(a)) + } + + def errorMessageMarker[A](c: LoggerContext[A])(marker: c.Expr[Marker], message: c.Expr[String]): c.universe.Tree = { + import c.universe._ + val a = q"${c.prefix}.a" + LogsAdditionalDataMacro.errorMessageMarker[A](c)(marker, message)(c.Expr(a)) + } + + def errorMessageCauseMarker[A](c: LoggerContext[A])(marker: c.Expr[Marker], message: c.Expr[String], cause: c.Expr[Throwable]): c.universe.Tree = { + import c.universe._ + val a = q"${c.prefix}.a" + LogsAdditionalDataMacro.errorMessageCauseMarker[A](c)(marker, message, cause)(c.Expr(a)) + } + + def errorMessageArgsMarker[A](c: LoggerContext[A])(marker: c.Expr[Marker], message: c.Expr[String], args: c.Expr[Any]*): c.universe.Tree = { + import c.universe._ + val a = q"${c.prefix}.a" + LogsAdditionalDataMacro.errorMessageArgsMarker[A](c)(marker, message, args:_*)(c.Expr(a)) + } + + // Warn + + def warnMessage[A](c: LoggerContext[A])(message: c.Expr[String]): c.universe.Tree = { + import c.universe._ + val a = q"${c.prefix}.a" + LogsAdditionalDataMacro.warnMessage[A](c)(message)(c.Expr(a)) + } + + def warnMessageCause[A](c: LoggerContext[A])(message: c.Expr[String], cause: c.Expr[Throwable]): c.universe.Tree = { + import c.universe._ + val a = q"${c.prefix}.a" + LogsAdditionalDataMacro.warnMessageCause[A](c)(message, cause)(c.Expr(a)) + } + + def warnMessageArgs[A](c: LoggerContext[A])(message: c.Expr[String], args: c.Expr[Any]*): c.universe.Tree = { + import c.universe._ + val a = q"${c.prefix}.a" + LogsAdditionalDataMacro.warnMessageArgs[A](c)(message, args:_*)(c.Expr(a)) + } + + def warnMessageMarker[A](c: LoggerContext[A])(marker: c.Expr[Marker], message: c.Expr[String]): c.universe.Tree = { + import c.universe._ + val a = q"${c.prefix}.a" + LogsAdditionalDataMacro.warnMessageMarker[A](c)(marker, message)(c.Expr(a)) + } + + def warnMessageCauseMarker[A](c: LoggerContext[A])(marker: c.Expr[Marker], message: c.Expr[String], cause: c.Expr[Throwable]): c.universe.Tree = { + import c.universe._ + val a = q"${c.prefix}.a" + LogsAdditionalDataMacro.warnMessageCauseMarker[A](c)(marker, message, cause)(c.Expr(a)) + } + + def warnMessageArgsMarker[A](c: LoggerContext[A])(marker: c.Expr[Marker], message: c.Expr[String], args: c.Expr[Any]*): c.universe.Tree = { + import c.universe._ + val a = q"${c.prefix}.a" + LogsAdditionalDataMacro.warnMessageArgsMarker[A](c)(marker, message, args:_*)(c.Expr(a)) + } + + // Info + + def infoMessage[A](c: LoggerContext[A])(message: c.Expr[String]): c.universe.Tree = { + import c.universe._ + val a = q"${c.prefix}.a" + LogsAdditionalDataMacro.infoMessage[A](c)(message)(c.Expr(a)) + } + + def infoMessageCause[A](c: LoggerContext[A])(message: c.Expr[String], cause: c.Expr[Throwable]): c.universe.Tree = { + import c.universe._ + val a = q"${c.prefix}.a" + LogsAdditionalDataMacro.infoMessageCause[A](c)(message, cause)(c.Expr(a)) + } + + def infoMessageArgs[A](c: LoggerContext[A])(message: c.Expr[String], args: c.Expr[Any]*): c.universe.Tree = { + import c.universe._ + val a = q"${c.prefix}.a" + LogsAdditionalDataMacro.infoMessageArgs[A](c)(message, args:_*)(c.Expr(a)) + } + + def infoMessageMarker[A](c: LoggerContext[A])(marker: c.Expr[Marker], message: c.Expr[String]): c.universe.Tree = { + import c.universe._ + val a = q"${c.prefix}.a" + LogsAdditionalDataMacro.infoMessageMarker[A](c)(marker, message)(c.Expr(a)) + } + + def infoMessageCauseMarker[A](c: LoggerContext[A])(marker: c.Expr[Marker], message: c.Expr[String], cause: c.Expr[Throwable]): c.universe.Tree = { + import c.universe._ + val a = q"${c.prefix}.a" + LogsAdditionalDataMacro.infoMessageCauseMarker[A](c)(marker, message, cause)(c.Expr(a)) + } + + + def infoMessageArgsMarker[A](c: LoggerContext[A])(marker: c.Expr[Marker], message: c.Expr[String], args: c.Expr[Any]*): c.universe.Tree = { + import c.universe._ + val a = q"${c.prefix}.a" + LogsAdditionalDataMacro.infoMessageArgsMarker[A](c)(marker, message, args:_*)(c.Expr(a)) + } + + + // Debug + + def debugMessage[A](c: LoggerContext[A])(message: c.Expr[String]): c.universe.Tree = { + import c.universe._ + val a = q"${c.prefix}.a" + LogsAdditionalDataMacro.debugMessage[A](c)(message)(c.Expr(a)) + } + + + def debugMessageCause[A](c: LoggerContext[A])(message: c.Expr[String], cause: c.Expr[Throwable]): c.universe.Tree = { + import c.universe._ + val a = q"${c.prefix}.a" + LogsAdditionalDataMacro.debugMessageCause[A](c)(message, cause)(c.Expr(a)) + } + + def debugMessageArgs[A](c: LoggerContext[A])(message: c.Expr[String], args: c.Expr[Any]*): c.universe.Tree = { + import c.universe._ + val a = q"${c.prefix}.a" + LogsAdditionalDataMacro.debugMessageArgs[A](c)(message, args:_*)(c.Expr(a)) + } + + def debugMessageMarker[A](c: LoggerContext[A])(marker: c.Expr[Marker], message: c.Expr[String]): c.universe.Tree = { + import c.universe._ + val a = q"${c.prefix}.a" + LogsAdditionalDataMacro.debugMessageMarker[A](c)(marker, message)(c.Expr(a)) + } + + def debugMessageCauseMarker[A](c: LoggerContext[A])(marker: c.Expr[Marker], message: c.Expr[String], cause: c.Expr[Throwable]): c.universe.Tree = { + import c.universe._ + val a = q"${c.prefix}.a" + LogsAdditionalDataMacro.debugMessageCauseMarker[A](c)(marker, message, cause)(c.Expr(a)) + } + + def debugMessageArgsMarker[A](c: LoggerContext[A])(marker: c.Expr[Marker], message: c.Expr[String], args: c.Expr[Any]*): c.universe.Tree = { + import c.universe._ + val a = q"${c.prefix}.a" + LogsAdditionalDataMacro.debugMessageArgsMarker[A](c)(marker, message, args:_*)(c.Expr(a)) + } + + // Trace + + def traceMessage[A](c: LoggerContext[A])(message: c.Expr[String]): c.universe.Tree = { + import c.universe._ + val a = q"${c.prefix}.a" + LogsAdditionalDataMacro.traceMessage[A](c)(message)(c.Expr(a)) + } + + def traceMessageCause[A](c: LoggerContext[A])(message: c.Expr[String], cause: c.Expr[Throwable]): c.universe.Tree = { + import c.universe._ + val a = q"${c.prefix}.a" + LogsAdditionalDataMacro.traceMessageCause[A](c)(message, cause)(c.Expr(a)) + } + + def traceMessageArgs[A](c: LoggerContext[A])(message: c.Expr[String], args: c.Expr[Any]*): c.universe.Tree = { + import c.universe._ + val a = q"${c.prefix}.a" + LogsAdditionalDataMacro.traceMessageArgs[A](c)(message, args:_*)(c.Expr(a)) + } + + def traceMessageMarker[A](c: LoggerContext[A])(marker: c.Expr[Marker], message: c.Expr[String]): c.universe.Tree = { + import c.universe._ + val a = q"${c.prefix}.a" + LogsAdditionalDataMacro.traceMessageMarker[A](c)(marker, message)(c.Expr(a)) + } + + def traceMessageCauseMarker[A](c: LoggerContext[A])(marker: c.Expr[Marker], message: c.Expr[String], cause: c.Expr[Throwable]): c.universe.Tree = { + import c.universe._ + val a = q"${c.prefix}.a" + LogsAdditionalDataMacro.traceMessageCauseMarker[A](c)(marker, message, cause)(c.Expr(a)) + } + + def traceMessageArgsMarker[A](c: LoggerContext[A])(marker: c.Expr[Marker], message: c.Expr[String], args: c.Expr[Any]*): c.universe.Tree = { + import c.universe._ + val a = q"${c.prefix}.a" + LogsAdditionalDataMacro.traceMessageArgsMarker[A](c)(marker, message, args:_*)(c.Expr(a)) + } +} diff --git a/src/main/scala/com/typesafe/scalalogging/LoggerTakingImplicit.scala b/src/main/scala/com/typesafe/scalalogging/LoggerTakingImplicit.scala index e4a5584..a09929a 100644 --- a/src/main/scala/com/typesafe/scalalogging/LoggerTakingImplicit.scala +++ b/src/main/scala/com/typesafe/scalalogging/LoggerTakingImplicit.scala @@ -9,76 +9,76 @@ trait CanLog[A] { } @SerialVersionUID(957385465L) -class LoggerTakingImplicit[A] private[scalalogging] (val underlying: Underlying)(implicit val canLogEv: CanLog[A]) extends Serializable { +class LoggerTakingImplicit[A] private[scalalogging] (val underlying: Underlying)(implicit val canLogEv: CanLog[A]) extends Serializable with LogsAdditionalData[A] { // Error - def error(message: String)(implicit a: A): Unit = macro LoggerTakingImplicitMacro.errorMessage[A] + def error(message: String)(implicit a: A): Unit = macro LogsAdditionalDataMacro.errorMessage[A] - def error(message: String, cause: Throwable)(implicit a: A): Unit = macro LoggerTakingImplicitMacro.errorMessageCause[A] + def error(message: String, cause: Throwable)(implicit a: A): Unit = macro LogsAdditionalDataMacro.errorMessageCause[A] - def error(message: String, args: Any*)(implicit a: A): Unit = macro LoggerTakingImplicitMacro.errorMessageArgs[A] + def error(message: String, args: Any*)(implicit a: A): Unit = macro LogsAdditionalDataMacro.errorMessageArgs[A] - def error(marker: Marker, message: String)(implicit a: A): Unit = macro LoggerTakingImplicitMacro.errorMessageMarker[A] + def error(marker: Marker, message: String)(implicit a: A): Unit = macro LogsAdditionalDataMacro.errorMessageMarker[A] - def error(marker: Marker, message: String, cause: Throwable)(implicit a: A): Unit = macro LoggerTakingImplicitMacro.errorMessageCauseMarker[A] + def error(marker: Marker, message: String, cause: Throwable)(implicit a: A): Unit = macro LogsAdditionalDataMacro.errorMessageCauseMarker[A] - def error(marker: Marker, message: String, args: Any*)(implicit a: A): Unit = macro LoggerTakingImplicitMacro.errorMessageArgsMarker[A] + def error(marker: Marker, message: String, args: Any*)(implicit a: A): Unit = macro LogsAdditionalDataMacro.errorMessageArgsMarker[A] // Warn - def warn(message: String)(implicit a: A): Unit = macro LoggerTakingImplicitMacro.warnMessage[A] + def warn(message: String)(implicit a: A): Unit = macro LogsAdditionalDataMacro.warnMessage[A] - def warn(message: String, cause: Throwable)(implicit a: A): Unit = macro LoggerTakingImplicitMacro.warnMessageCause[A] + def warn(message: String, cause: Throwable)(implicit a: A): Unit = macro LogsAdditionalDataMacro.warnMessageCause[A] - def warn(message: String, args: Any*)(implicit a: A): Unit = macro LoggerTakingImplicitMacro.warnMessageArgs[A] + def warn(message: String, args: Any*)(implicit a: A): Unit = macro LogsAdditionalDataMacro.warnMessageArgs[A] - def warn(marker: Marker, message: String)(implicit a: A): Unit = macro LoggerTakingImplicitMacro.warnMessageMarker[A] + def warn(marker: Marker, message: String)(implicit a: A): Unit = macro LogsAdditionalDataMacro.warnMessageMarker[A] - def warn(marker: Marker, message: String, cause: Throwable)(implicit a: A): Unit = macro LoggerTakingImplicitMacro.warnMessageCauseMarker[A] + def warn(marker: Marker, message: String, cause: Throwable)(implicit a: A): Unit = macro LogsAdditionalDataMacro.warnMessageCauseMarker[A] - def warn(marker: Marker, message: String, args: Any*)(implicit a: A): Unit = macro LoggerTakingImplicitMacro.warnMessageArgsMarker[A] + def warn(marker: Marker, message: String, args: Any*)(implicit a: A): Unit = macro LogsAdditionalDataMacro.warnMessageArgsMarker[A] // Info - def info(message: String)(implicit a: A): Unit = macro LoggerTakingImplicitMacro.infoMessage[A] + def info(message: String)(implicit a: A): Unit = macro LogsAdditionalDataMacro.infoMessage[A] - def info(message: String, cause: Throwable)(implicit a: A): Unit = macro LoggerTakingImplicitMacro.infoMessageCause[A] + def info(message: String, cause: Throwable)(implicit a: A): Unit = macro LogsAdditionalDataMacro.infoMessageCause[A] - def info(message: String, args: Any*)(implicit a: A): Unit = macro LoggerTakingImplicitMacro.infoMessageArgs[A] + def info(message: String, args: Any*)(implicit a: A): Unit = macro LogsAdditionalDataMacro.infoMessageArgs[A] - def info(marker: Marker, message: String)(implicit a: A): Unit = macro LoggerTakingImplicitMacro.infoMessageMarker[A] + def info(marker: Marker, message: String)(implicit a: A): Unit = macro LogsAdditionalDataMacro.infoMessageMarker[A] - def info(marker: Marker, message: String, cause: Throwable)(implicit a: A): Unit = macro LoggerTakingImplicitMacro.infoMessageCauseMarker[A] + def info(marker: Marker, message: String, cause: Throwable)(implicit a: A): Unit = macro LogsAdditionalDataMacro.infoMessageCauseMarker[A] - def info(marker: Marker, message: String, args: Any*)(implicit a: A): Unit = macro LoggerTakingImplicitMacro.infoMessageArgsMarker[A] + def info(marker: Marker, message: String, args: Any*)(implicit a: A): Unit = macro LogsAdditionalDataMacro.infoMessageArgsMarker[A] // Debug - def debug(message: String)(implicit a: A): Unit = macro LoggerTakingImplicitMacro.debugMessage[A] + def debug(message: String)(implicit a: A): Unit = macro LogsAdditionalDataMacro.debugMessage[A] - def debug(message: String, cause: Throwable)(implicit a: A): Unit = macro LoggerTakingImplicitMacro.debugMessageCause[A] + def debug(message: String, cause: Throwable)(implicit a: A): Unit = macro LogsAdditionalDataMacro.debugMessageCause[A] - def debug(message: String, args: Any*)(implicit a: A): Unit = macro LoggerTakingImplicitMacro.debugMessageArgs[A] + def debug(message: String, args: Any*)(implicit a: A): Unit = macro LogsAdditionalDataMacro.debugMessageArgs[A] - def debug(marker: Marker, message: String)(implicit a: A): Unit = macro LoggerTakingImplicitMacro.debugMessageMarker[A] + def debug(marker: Marker, message: String)(implicit a: A): Unit = macro LogsAdditionalDataMacro.debugMessageMarker[A] - def debug(marker: Marker, message: String, cause: Throwable)(implicit a: A): Unit = macro LoggerTakingImplicitMacro.debugMessageCauseMarker[A] + def debug(marker: Marker, message: String, cause: Throwable)(implicit a: A): Unit = macro LogsAdditionalDataMacro.debugMessageCauseMarker[A] - def debug(marker: Marker, message: String, args: Any*)(implicit a: A): Unit = macro LoggerTakingImplicitMacro.debugMessageArgsMarker[A] + def debug(marker: Marker, message: String, args: Any*)(implicit a: A): Unit = macro LogsAdditionalDataMacro.debugMessageArgsMarker[A] // Trace - def trace(message: String)(implicit a: A): Unit = macro LoggerTakingImplicitMacro.traceMessage[A] + def trace(message: String)(implicit a: A): Unit = macro LogsAdditionalDataMacro.traceMessage[A] - def trace(message: String, cause: Throwable)(implicit a: A): Unit = macro LoggerTakingImplicitMacro.traceMessageCause[A] + def trace(message: String, cause: Throwable)(implicit a: A): Unit = macro LogsAdditionalDataMacro.traceMessageCause[A] - def trace(message: String, args: Any*)(implicit a: A): Unit = macro LoggerTakingImplicitMacro.traceMessageArgs[A] + def trace(message: String, args: Any*)(implicit a: A): Unit = macro LogsAdditionalDataMacro.traceMessageArgs[A] - def trace(marker: Marker, message: String)(implicit a: A): Unit = macro LoggerTakingImplicitMacro.traceMessageMarker[A] + def trace(marker: Marker, message: String)(implicit a: A): Unit = macro LogsAdditionalDataMacro.traceMessageMarker[A] - def trace(marker: Marker, message: String, cause: Throwable)(implicit a: A): Unit = macro LoggerTakingImplicitMacro.traceMessageCauseMarker[A] + def trace(marker: Marker, message: String, cause: Throwable)(implicit a: A): Unit = macro LogsAdditionalDataMacro.traceMessageCauseMarker[A] - def trace(marker: Marker, message: String, args: Any*)(implicit a: A): Unit = macro LoggerTakingImplicitMacro.traceMessageArgsMarker[A] + def trace(marker: Marker, message: String, args: Any*)(implicit a: A): Unit = macro LogsAdditionalDataMacro.traceMessageArgsMarker[A] } diff --git a/src/main/scala/com/typesafe/scalalogging/LogsAdditionalData.scala b/src/main/scala/com/typesafe/scalalogging/LogsAdditionalData.scala new file mode 100644 index 0000000..7891074 --- /dev/null +++ b/src/main/scala/com/typesafe/scalalogging/LogsAdditionalData.scala @@ -0,0 +1,12 @@ +package com.typesafe.scalalogging + +import org.slf4j.{Logger => Underlying} + +/** + * common trait for loggers, such as LoggerTakingConstructorArg and LoggerTakingImplicit who use a strategy CanLog[A] + * to log some additional data A that they have access too + * */ +trait LogsAdditionalData[A] { + protected def underlying: Underlying + protected def canLogEv: CanLog[A] +} \ No newline at end of file diff --git a/src/main/scala/com/typesafe/scalalogging/LoggerTakingImplicitMacro.scala b/src/main/scala/com/typesafe/scalalogging/LogsAdditionalDataMacro.scala similarity index 99% rename from src/main/scala/com/typesafe/scalalogging/LoggerTakingImplicitMacro.scala rename to src/main/scala/com/typesafe/scalalogging/LogsAdditionalDataMacro.scala index c046191..31c62ca 100644 --- a/src/main/scala/com/typesafe/scalalogging/LoggerTakingImplicitMacro.scala +++ b/src/main/scala/com/typesafe/scalalogging/LogsAdditionalDataMacro.scala @@ -3,9 +3,9 @@ package com.typesafe.scalalogging import org.slf4j.Marker import scala.reflect.macros.blackbox -private object LoggerTakingImplicitMacro { +private object LogsAdditionalDataMacro { - type LoggerContext[A] = blackbox.Context { type PrefixType = LoggerTakingImplicit[A] } + type LoggerContext[A] = blackbox.Context { type PrefixType = LogsAdditionalData[A] } // Error diff --git a/src/test/scala/com/typesafe/scalalogging/LoggerTakingConstructorArgSpec.scala b/src/test/scala/com/typesafe/scalalogging/LoggerTakingConstructorArgSpec.scala new file mode 100644 index 0000000..a4235f2 --- /dev/null +++ b/src/test/scala/com/typesafe/scalalogging/LoggerTakingConstructorArgSpec.scala @@ -0,0 +1,393 @@ +package com.typesafe.scalalogging + +import org.mockito.ArgumentMatchers._ +import org.mockito.Mockito._ +import org.scalatest.{Matchers, WordSpec} +import org.scalatestplus.mockito.MockitoSugar +import org.slf4j.{Logger => Underlying} + +class LoggerTakingConstructorArgSpec extends WordSpec with Matchers with MockitoSugar with Varargs { + + case class CorrelationId(value: String) + + // Error + + "Calling error with a message" should { + + "call the underlying logger's error method if the error level is enabled" in { + val f = fixture(_.isErrorEnabled, isEnabled = true) + import f._ + logger.error(msg) + verify(canLogCorrelationId).logMessage(msg, correlationId) + verify(canLogCorrelationId).afterLog(correlationId) + verify(underlying).error(logMsg) + } + + "not call the underlying logger's error method if the error level is not enabled" in { + val f = fixture(_.isErrorEnabled, isEnabled = false) + import f._ + logger.error(msg) + verify(canLogCorrelationId, never).logMessage(anyString, any[CorrelationId]) + verify(canLogCorrelationId, never).afterLog(any[CorrelationId]) + verify(underlying, never).error(anyString) + } + } + + "Calling error with a message and cause" should { + + "call the underlying logger's error method if the error level is enabled" in { + val f = fixture(_.isErrorEnabled, isEnabled = true) + import f._ + logger.error(msg, cause) + verify(canLogCorrelationId).logMessage(msg, correlationId) + verify(canLogCorrelationId).afterLog(correlationId) + verify(underlying).error(logMsg, cause) + } + + "not call the underlying logger's error method if the error level is not enabled" in { + val f = fixture(_.isErrorEnabled, isEnabled = false) + import f._ + logger.error(msg, cause) + verify(canLogCorrelationId, never).logMessage(anyString, any[CorrelationId]) + verify(canLogCorrelationId, never).afterLog(any[CorrelationId]) + verify(underlying, never).error(anyString, any[Object]) + } + } + + "Calling error with a message and parameters" should { + + "call the underlying logger's error method if the error level is enabled" in { + val f = fixture(_.isErrorEnabled, isEnabled = true) + import f._ + logger.error(msg, arg1) + verify(underlying).error(logMsg, arg1) + logger.error(msg, arg1, arg2) + verify(underlying).error(logMsg, forceVarargs(arg1, arg2): _*) + logger.error(msg, arg1, arg2, arg3) + verify(underlying).error(logMsg, arg1, arg2, arg3) + verify(canLogCorrelationId, times(3)).logMessage(msg, correlationId) + verify(canLogCorrelationId, times(3)).afterLog(correlationId) + } + + "not call the underlying logger's error method if the error level is not enabled" in { + val f = fixture(_.isErrorEnabled, isEnabled = false) + import f._ + logger.error(msg, arg1) + verify(underlying, never).error(logMsg, arg1) + logger.error(msg, arg1, arg2) + verify(underlying, never).error(logMsg, forceVarargs(arg1, arg2): _*) + logger.error(msg, arg1, arg2, arg3) + verify(underlying, never).error(logMsg, arg1, arg2, arg3) + verify(canLogCorrelationId, never).logMessage(anyString, any[CorrelationId]) + verify(canLogCorrelationId, never).afterLog(any[CorrelationId]) + } + } + + // Warn + + "Calling warn with a message" should { + + "call the underlying logger's warn method if the warn level is enabled" in { + val f = fixture(_.isWarnEnabled, isEnabled = true) + import f._ + logger.warn(msg) + verify(canLogCorrelationId).logMessage(msg, correlationId) + verify(canLogCorrelationId).afterLog(correlationId) + verify(underlying).warn(logMsg) + } + + "not call the underlying logger's warn method if the warn level is not enabled" in { + val f = fixture(_.isWarnEnabled, isEnabled = false) + import f._ + logger.warn(msg) + verify(canLogCorrelationId, never).logMessage(anyString, any[CorrelationId]) + verify(canLogCorrelationId, never).afterLog(any[CorrelationId]) + verify(underlying, never).warn(anyString) + } + } + + "Calling warn with a message and cause" should { + + "call the underlying logger's warn method if the warn level is enabled" in { + val f = fixture(_.isWarnEnabled, isEnabled = true) + import f._ + logger.warn(msg, cause) + verify(canLogCorrelationId).logMessage(msg, correlationId) + verify(canLogCorrelationId).afterLog(correlationId) + verify(underlying).warn(logMsg, cause) + } + + "not call the underlying logger's warn method if the warn level is not enabled" in { + val f = fixture(_.isWarnEnabled, isEnabled = false) + import f._ + logger.warn(msg, cause) + verify(canLogCorrelationId, never).logMessage(anyString, any[CorrelationId]) + verify(canLogCorrelationId, never).afterLog(any[CorrelationId]) + verify(underlying, never).warn(anyString, any[Object]) + } + } + + "Calling warn with a message and parameters" should { + + "call the underlying logger's warn method if the warn level is enabled" in { + val f = fixture(_.isWarnEnabled, isEnabled = true) + import f._ + logger.warn(msg, arg1) + verify(underlying).warn(logMsg, arg1) + logger.warn(msg, arg1, arg2) + verify(underlying).warn(logMsg, forceVarargs(arg1, arg2): _*) + logger.warn(msg, arg1, arg2, arg3) + verify(underlying).warn(logMsg, arg1, arg2, arg3) + verify(canLogCorrelationId, times(3)).logMessage(msg, correlationId) + verify(canLogCorrelationId, times(3)).afterLog(correlationId) + } + + "not call the underlying logger's warn method if the warn level is not enabled" in { + val f = fixture(_.isWarnEnabled, isEnabled = false) + import f._ + logger.warn(msg, arg1) + verify(underlying, never).warn(logMsg, arg1) + logger.warn(msg, arg1, arg2) + verify(underlying, never).warn(logMsg, forceVarargs(arg1, arg2): _*) + logger.warn(msg, arg1, arg2, arg3) + verify(underlying, never).warn(logMsg, arg1, arg2, arg3) + verify(canLogCorrelationId, never).logMessage(anyString, any[CorrelationId]) + verify(canLogCorrelationId, never).afterLog(any[CorrelationId]) + } + } + + // Info + + "Calling info with a message" should { + + "call the underlying logger's info method if the info level is enabled" in { + val f = fixture(_.isInfoEnabled, isEnabled = true) + import f._ + logger.info(msg) + verify(canLogCorrelationId).logMessage(msg, correlationId) + verify(canLogCorrelationId).afterLog(correlationId) + verify(underlying).info(logMsg) + } + + "not call the underlying logger's info method if the info level is not enabled" in { + val f = fixture(_.isInfoEnabled, isEnabled = false) + import f._ + logger.info(msg) + verify(canLogCorrelationId, never).logMessage(anyString, any[CorrelationId]) + verify(canLogCorrelationId, never).afterLog(any[CorrelationId]) + verify(underlying, never).info(anyString) + } + } + + "Calling info with a message and cause" should { + + "call the underlying logger's info method if the info level is enabled" in { + val f = fixture(_.isInfoEnabled, isEnabled = true) + import f._ + logger.info(msg, cause) + verify(canLogCorrelationId).logMessage(msg, correlationId) + verify(canLogCorrelationId).afterLog(correlationId) + verify(underlying).info(logMsg, cause) + } + + "not call the underlying logger's info method if the info level is not enabled" in { + val f = fixture(_.isInfoEnabled, isEnabled = false) + import f._ + logger.info(msg, cause) + verify(canLogCorrelationId, never).logMessage(anyString, any[CorrelationId]) + verify(canLogCorrelationId, never).afterLog(any[CorrelationId]) + verify(underlying, never).info(anyString, any[Object]) + } + } + + "Calling info with a message and parameters" should { + + "call the underlying logger's info method if the info level is enabled" in { + val f = fixture(_.isInfoEnabled, isEnabled = true) + import f._ + logger.info(msg, arg1) + verify(underlying).info(logMsg, arg1) + logger.info(msg, arg1, arg2) + verify(underlying).info(logMsg, forceVarargs(arg1, arg2): _*) + logger.info(msg, arg1, arg2, arg3) + verify(underlying).info(logMsg, arg1, arg2, arg3) + verify(canLogCorrelationId, times(3)).logMessage(msg, correlationId) + verify(canLogCorrelationId, times(3)).afterLog(correlationId) + } + + "not call the underlying logger's info method if the info level is not enabled" in { + val f = fixture(_.isInfoEnabled, isEnabled = false) + import f._ + logger.info(msg, arg1) + verify(underlying, never).info(logMsg, arg1) + logger.info(msg, arg1, arg2) + verify(underlying, never).info(logMsg, forceVarargs(arg1, arg2): _*) + logger.info(msg, arg1, arg2, arg3) + verify(underlying, never).info(logMsg, arg1, arg2, arg3) + verify(canLogCorrelationId, never).logMessage(anyString, any[CorrelationId]) + verify(canLogCorrelationId, never).afterLog(any[CorrelationId]) + } + } + + // Debug + + "Calling debug with a message" should { + + "call the underlying logger's debug method if the debug level is enabled" in { + val f = fixture(_.isDebugEnabled, isEnabled = true) + import f._ + logger.debug(msg) + verify(canLogCorrelationId).logMessage(msg, correlationId) + verify(canLogCorrelationId).afterLog(correlationId) + verify(underlying).debug(logMsg) + } + + "not call the underlying logger's debug method if the debug level is not enabled" in { + val f = fixture(_.isDebugEnabled, isEnabled = false) + import f._ + logger.debug(msg) + verify(canLogCorrelationId, never).logMessage(anyString, any[CorrelationId]) + verify(canLogCorrelationId, never).afterLog(any[CorrelationId]) + verify(underlying, never).debug(anyString) + } + } + + "Calling debug with a message and cause" should { + + "call the underlying logger's debug method if the debug level is enabled" in { + val f = fixture(_.isDebugEnabled, isEnabled = true) + import f._ + logger.debug(msg, cause) + verify(canLogCorrelationId).logMessage(msg, correlationId) + verify(canLogCorrelationId).afterLog(correlationId) + verify(underlying).debug(logMsg, cause) + } + + "not call the underlying logger's debug method if the debug level is not enabled" in { + val f = fixture(_.isDebugEnabled, isEnabled = false) + import f._ + logger.debug(msg, cause) + verify(canLogCorrelationId, never).logMessage(anyString, any[CorrelationId]) + verify(canLogCorrelationId, never).afterLog(any[CorrelationId]) + verify(underlying, never).debug(anyString, any[Object]) + } + } + + "Calling debug with a message and parameters" should { + + "call the underlying logger's debug method if the debug level is enabled" in { + val f = fixture(_.isDebugEnabled, isEnabled = true) + import f._ + logger.debug(msg, arg1) + verify(underlying).debug(logMsg, arg1) + logger.debug(msg, arg1, arg2) + verify(underlying).debug(logMsg, forceVarargs(arg1, arg2): _*) + logger.debug(msg, arg1, arg2, arg3) + verify(underlying).debug(logMsg, arg1, arg2, arg3) + verify(canLogCorrelationId, times(3)).logMessage(msg, correlationId) + verify(canLogCorrelationId, times(3)).afterLog(correlationId) + } + + "not call the underlying logger's debug method if the debug level is not enabled" in { + val f = fixture(_.isDebugEnabled, isEnabled = false) + import f._ + logger.debug(msg, arg1) + verify(underlying, never).debug(logMsg, arg1) + logger.debug(msg, arg1, arg2) + verify(underlying, never).debug(logMsg, forceVarargs(arg1, arg2): _*) + logger.debug(msg, arg1, arg2, arg3) + verify(underlying, never).debug(logMsg, arg1, arg2, arg3) + verify(canLogCorrelationId, never).logMessage(anyString, any[CorrelationId]) + verify(canLogCorrelationId, never).afterLog(any[CorrelationId]) + } + } + + // Trace + + "Calling trace with a message" should { + + "call the underlying logger's trace method if the trace level is enabled" in { + val f = fixture(_.isTraceEnabled, isEnabled = true) + import f._ + logger.trace(msg) + verify(canLogCorrelationId).logMessage(msg, correlationId) + verify(canLogCorrelationId).afterLog(correlationId) + verify(underlying).trace(logMsg) + } + + "not call the underlying logger's trace method if the trace level is not enabled" in { + val f = fixture(_.isTraceEnabled, isEnabled = false) + import f._ + logger.trace(msg) + verify(canLogCorrelationId, never).logMessage(anyString, any[CorrelationId]) + verify(canLogCorrelationId, never).afterLog(any[CorrelationId]) + verify(underlying, never).trace(anyString) + } + } + + "Calling trace with a message and cause" should { + + "call the underlying logger's trace method if the trace level is enabled" in { + val f = fixture(_.isTraceEnabled, isEnabled = true) + import f._ + logger.trace(msg, cause) + verify(canLogCorrelationId).logMessage(msg, correlationId) + verify(canLogCorrelationId).afterLog(correlationId) + verify(underlying).trace(logMsg, cause) + } + + "not call the underlying logger's trace method if the trace level is not enabled" in { + val f = fixture(_.isTraceEnabled, isEnabled = false) + import f._ + logger.trace(msg, cause) + verify(canLogCorrelationId, never).logMessage(anyString, any[CorrelationId]) + verify(canLogCorrelationId, never).afterLog(any[CorrelationId]) + verify(underlying, never).trace(anyString, any[Object]) + } + } + + "Calling trace with a message and parameters" should { + + "call the underlying logger's trace method if the trace level is enabled" in { + val f = fixture(_.isTraceEnabled, isEnabled = true) + import f._ + logger.trace(msg, arg1) + verify(underlying).trace(logMsg, arg1) + logger.trace(msg, arg1, arg2) + verify(underlying).trace(logMsg, forceVarargs(arg1, arg2): _*) + logger.trace(msg, arg1, arg2, arg3) + verify(underlying).trace(logMsg, arg1, arg2, arg3) + verify(canLogCorrelationId, times(3)).logMessage(msg, correlationId) + verify(canLogCorrelationId, times(3)).afterLog(correlationId) + } + + "not call the underlying logger's trace method if the trace level is not enabled" in { + val f = fixture(_.isTraceEnabled, isEnabled = false) + import f._ + logger.trace(msg, arg1) + verify(underlying, never).trace(logMsg, arg1) + logger.trace(msg, arg1, arg2) + verify(underlying, never).trace(logMsg, forceVarargs(arg1, arg2): _*) + logger.trace(msg, arg1, arg2, arg3) + verify(underlying, never).trace(logMsg, arg1, arg2, arg3) + verify(canLogCorrelationId, never).logMessage(anyString, any[CorrelationId]) + verify(canLogCorrelationId, never).afterLog(any[CorrelationId]) + } + } + + def fixture(p: Underlying => Boolean, isEnabled: Boolean) = + new { + implicit val correlationId = CorrelationId("corrId") + implicit val canLogCorrelationId = mock[CanLog[CorrelationId]] + val msg = "msg" + val cause = new RuntimeException("cause") + val arg1 = "arg1" + val arg2 = new Integer(1) + val arg3 = "arg3" + val logMsg = "corrId - msg" + val underlying = mock[org.slf4j.Logger] + when(p(underlying)).thenReturn(isEnabled) + when(canLogCorrelationId.logMessage(anyString(), any[CorrelationId])).thenReturn(logMsg) + val logger = Logger.inContextOf[CorrelationId](underlying) + } +}