From ee4a2f5d2d915f50662e8ef957ab81c297b16c95 Mon Sep 17 00:00:00 2001 From: paweliwanow Date: Sun, 4 Jun 2017 22:51:04 +0200 Subject: [PATCH 1/9] Added LoggerTakingImplicit --- README.md | 39 ++ .../com/typesafe/scalalogging/Logger.scala | 35 +- .../scalalogging/LoggerTakingImplicit.scala | 84 ++++ .../LoggerTakingImplicitMacro.scala | 389 +++++++++++++++ .../LoggerTakingImplicitSpec.scala | 454 ++++++++++++++++++ 5 files changed, 1000 insertions(+), 1 deletion(-) create mode 100644 src/main/scala/com/typesafe/scalalogging/LoggerTakingImplicit.scala create mode 100644 src/main/scala/com/typesafe/scalalogging/LoggerTakingImplicitMacro.scala create mode 100644 src/test/scala/com/typesafe/scalalogging/LoggerTakingImplicitSpec.scala diff --git a/README.md b/README.md index a224ab2..18662d2 100644 --- a/README.md +++ b/README.md @@ -79,6 +79,45 @@ class MyClass extends LazyLogging { } ``` +`LoggerTakingImplicit` provides the same methods as `Logger` class, but with additional implicit parameter `A`. +During creation of the `LoggerTakingImplicit` evidence `CanLog[A]` is required. +It may be useful when contextual parameter (e.g. _Correlation ID_) is being passed around and you would like to include it in the log messages: + +```scala +case class CorrelationId(value: String) +implicit case object CanLogCorrelationId extends CanLog[CorrelationId] { + override def logMessage(originalMsg: String, a: CorrelationId): String = s"${a.value} $originalMsg" +} + + +implicit val correlationId = CorrelationId("ID") + +val logger = Logger.takingImplicit[CorrelationId]("test") +logger.info("Test") // logs "ID Test" +``` + +It's possible to use `MDC` through `CanLog` without any troubles with execution context. + +```scala +case class CorrelationId(value: String) +implicit case object CanLogCorrelationId extends CanLog[CorrelationId] { + override def logMessage(originalMsg: String, a: CorrelationId): String = { + MDC.put("correlationId", a.value) + originalMsg + } + + override def afterLog(a: A): Unit = { + MDC.remove("correlationId") + } +} + + +implicit val correlationId = CorrelationId("ID") + +val logger = Logger.takingImplicit[CorrelationId]("test") +Future(logger.info("Test")) +``` + ### What's new? ##### 3.5.0 diff --git a/src/main/scala/com/typesafe/scalalogging/Logger.scala b/src/main/scala/com/typesafe/scalalogging/Logger.scala index 9b9041a..dc864e9 100644 --- a/src/main/scala/com/typesafe/scalalogging/Logger.scala +++ b/src/main/scala/com/typesafe/scalalogging/Logger.scala @@ -31,6 +31,12 @@ object Logger { def apply(underlying: Underlying): Logger = new Logger(underlying) + /** + * Create a [[LoggerTakingImplicit]] wrapping the given underlying `org.slf4j.Logger`. + */ + def takingImplicit[A](underlying: Underlying)(implicit ev: CanLog[A]): LoggerTakingImplicit[A] = + new LoggerTakingImplicit[A](underlying) + /** * Create a [[Logger]] for the given name. * Example: @@ -41,12 +47,28 @@ object Logger { def apply(name: String): Logger = new Logger(LoggerFactory.getLogger(name)) + /** + * Create a [[LoggerTakingImplicit]] for the given name. + * Example: + * {{{ + * val logger = Logger.takingImplicit[CorrelationId]("application") + * }}} + */ + def takingImplicit[A](name: String)(implicit ev: CanLog[A]): LoggerTakingImplicit[A] = + new LoggerTakingImplicit[A](LoggerFactory.getLogger(name)) + /** * Create a [[Logger]] wrapping the created underlying `org.slf4j.Logger`. */ - def apply(clazz: Class[_]): Logger = + def apply[A](clazz: Class[_]): Logger = new Logger(LoggerFactory.getLogger(clazz.getName)) + /** + * Create a [[LoggerTakingImplicit]] wrapping the created underlying `org.slf4j.Logger`. + */ + def takingImplicit[A](clazz: Class[_])(implicit ev: CanLog[A]): LoggerTakingImplicit[A] = + new LoggerTakingImplicit[A](LoggerFactory.getLogger(clazz.getName)) + /** * Create a [[Logger]] for the runtime class wrapped by the implicit class * tag parameter. @@ -57,6 +79,17 @@ object Logger { */ def apply[T](implicit ct: ClassTag[T]): Logger = new Logger(LoggerFactory.getLogger(ct.runtimeClass.getName.stripSuffix("$"))) + + /** + * Create a [[LoggerTakingImplicit]] for the runtime class wrapped by the implicit class + * tag parameter. + * Example: + * {{{ + * val logger = Logger.takingImplicit[MyClass] + * }}} + */ + def takingImplicit[T, A](implicit ct: ClassTag[T], ev: CanLog[A]): LoggerTakingImplicit[A] = + new LoggerTakingImplicit[A](LoggerFactory.getLogger(ct.runtimeClass.getName.stripSuffix("$"))) } /** diff --git a/src/main/scala/com/typesafe/scalalogging/LoggerTakingImplicit.scala b/src/main/scala/com/typesafe/scalalogging/LoggerTakingImplicit.scala new file mode 100644 index 0000000..70fcb5b --- /dev/null +++ b/src/main/scala/com/typesafe/scalalogging/LoggerTakingImplicit.scala @@ -0,0 +1,84 @@ +package com.typesafe.scalalogging + +import org.slf4j.{ Marker, Logger => Underlying } + +trait CanLog[A] { this: Serializable => + def logMessage(originalMsg: String, a: A): String + def afterLog(a: A): Unit = () +} + +@SerialVersionUID(957385465L) +final class LoggerTakingImplicit[A] private[scalalogging] (val underlying: Underlying) + (implicit val canLogEv: CanLog[A]) extends Serializable { + + // Error + + def error(message: String)(implicit a: A): Unit = macro LoggerTakingImplicitMacro.errorMessage[A] + + def error(message: String, cause: Throwable)(implicit a: A): Unit = macro LoggerTakingImplicitMacro.errorMessageCause[A] + + def error(message: String, args: Any*)(implicit a: A): Unit = macro LoggerTakingImplicitMacro.errorMessageArgs[A] + + def error(marker: Marker, message: String)(implicit a: A): Unit = macro LoggerTakingImplicitMacro.errorMessageMarker[A] + + def error(marker: Marker, message: String, cause: Throwable)(implicit a: A): Unit = macro LoggerTakingImplicitMacro.errorMessageCauseMarker[A] + + def error(marker: Marker, message: String, args: Any*)(implicit a: A): Unit = macro LoggerTakingImplicitMacro.errorMessageArgsMarker[A] + + // Warn + + def warn(message: String)(implicit a: A): Unit = macro LoggerTakingImplicitMacro.warnMessage[A] + + def warn(message: String, cause: Throwable)(implicit a: A): Unit = macro LoggerTakingImplicitMacro.warnMessageCause[A] + + def warn(message: String, args: Any*)(implicit a: A): Unit = macro LoggerTakingImplicitMacro.warnMessageArgs[A] + + def warn(marker: Marker, message: String)(implicit a: A): Unit = macro LoggerTakingImplicitMacro.warnMessageMarker[A] + + def warn(marker: Marker, message: String, cause: Throwable)(implicit a: A): Unit = macro LoggerTakingImplicitMacro.warnMessageCauseMarker[A] + + def warn(marker: Marker, message: String, args: Any*)(implicit a: A): Unit = macro LoggerTakingImplicitMacro.warnMessageArgsMarker[A] + + // Info + + def info(message: String)(implicit a: A): Unit = macro LoggerTakingImplicitMacro.infoMessage[A] + + def info(message: String, cause: Throwable)(implicit a: A): Unit = macro LoggerTakingImplicitMacro.infoMessageCause[A] + + def info(message: String, args: Any*)(implicit a: A): Unit = macro LoggerTakingImplicitMacro.infoMessageArgs[A] + + def info(marker: Marker, message: String)(implicit a: A): Unit = macro LoggerTakingImplicitMacro.infoMessageMarker[A] + + def info(marker: Marker, message: String, cause: Throwable)(implicit a: A): Unit = macro LoggerTakingImplicitMacro.infoMessageCauseMarker[A] + + def info(marker: Marker, message: String, args: Any*)(implicit a: A): Unit = macro LoggerTakingImplicitMacro.infoMessageArgsMarker[A] + + // Debug + + def debug(message: String)(implicit a: A): Unit = macro LoggerTakingImplicitMacro.debugMessage[A] + + def debug(message: String, cause: Throwable)(implicit a: A): Unit = macro LoggerTakingImplicitMacro.debugMessageCause[A] + + def debug(message: String, args: Any*)(implicit a: A): Unit = macro LoggerTakingImplicitMacro.debugMessageArgs[A] + + def debug(marker: Marker, message: String)(implicit a: A): Unit = macro LoggerTakingImplicitMacro.debugMessageMarker[A] + + def debug(marker: Marker, message: String, cause: Throwable)(implicit a: A): Unit = macro LoggerTakingImplicitMacro.debugMessageCauseMarker[A] + + def debug(marker: Marker, message: String, args: Any*)(implicit a: A): Unit = macro LoggerTakingImplicitMacro.debugMessageArgsMarker[A] + + // Trace + + def trace(message: String)(implicit a: A): Unit = macro LoggerTakingImplicitMacro.traceMessage[A] + + def trace(message: String, cause: Throwable)(implicit a: A): Unit = macro LoggerTakingImplicitMacro.traceMessageCause[A] + + def trace(message: String, args: Any*)(implicit a: A): Unit = macro LoggerTakingImplicitMacro.traceMessageArgs[A] + + def trace(marker: Marker, message: String)(implicit a: A): Unit = macro LoggerTakingImplicitMacro.traceMessageMarker[A] + + def trace(marker: Marker, message: String, cause: Throwable)(implicit a: A): Unit = macro LoggerTakingImplicitMacro.traceMessageCauseMarker[A] + + def trace(marker: Marker, message: String, args: Any*)(implicit a: A): Unit = macro LoggerTakingImplicitMacro.traceMessageArgsMarker[A] + +} diff --git a/src/main/scala/com/typesafe/scalalogging/LoggerTakingImplicitMacro.scala b/src/main/scala/com/typesafe/scalalogging/LoggerTakingImplicitMacro.scala new file mode 100644 index 0000000..a3a6472 --- /dev/null +++ b/src/main/scala/com/typesafe/scalalogging/LoggerTakingImplicitMacro.scala @@ -0,0 +1,389 @@ +package com.typesafe.scalalogging + +import org.slf4j.Marker + +import scala.reflect.macros.blackbox.Context + +private object LoggerTakingImplicitMacro { + type LoggerContext[A] = Context { type PrefixType = LoggerTakingImplicit[A] } + + def errorMessage[A](c: LoggerContext[A])(message: c.Expr[String])(a: c.Expr[A]) = { + import c.universe._ + val underlying = q"${c.prefix}.underlying" + val canLogEv = q"${c.prefix}.canLogEv" + q"""if ($underlying.isErrorEnabled) { + $underlying.error($canLogEv.logMessage($message, $a)) + $canLogEv.afterLog($a) + }""" + } + + def errorMessageCause[A](c: LoggerContext[A])(message: c.Expr[String], cause: c.Expr[Throwable])(a: c.Expr[A]) = { + import c.universe._ + val underlying = q"${c.prefix}.underlying" + val canLogEv = q"${c.prefix}.canLogEv" + q"""if ($underlying.isErrorEnabled) { + $underlying.error($canLogEv.logMessage($message, $a), $cause) + $canLogEv.afterLog($a) + }""" + } + + def errorMessageArgs[A](c: LoggerContext[A])(message: c.Expr[String], args: c.Expr[Any]*)(a: c.Expr[A]) = { + import c.universe._ + val underlying = q"${c.prefix}.underlying" + val canLogEv = q"${c.prefix}.canLogEv" + if (args.length == 2) { + q"""if ($underlying.isErrorEnabled) { + $underlying.error($canLogEv.logMessage($message, $a), List(${args(0)}, ${args(1)}): _*) + $canLogEv.afterLog($a) + }""" + } else { + q"""if ($underlying.isErrorEnabled) { + $underlying.error($canLogEv.logMessage($message, $a), ..$args) + $canLogEv.afterLog($a) + }""" + } + } + + def errorMessageMarker[A](c: LoggerContext[A])(marker: c.Expr[Marker], message: c.Expr[String])(a: c.Expr[A]) = { + import c.universe._ + val underlying = q"${c.prefix}.underlying" + val canLogEv = q"${c.prefix}.canLogEv" + q"""if ($underlying.isErrorEnabled) { + $underlying.error($marker, $canLogEv.logMessage($message, $a)) + $canLogEv.afterLog($a) + }""" + } + + def errorMessageCauseMarker[A](c: LoggerContext[A])(marker: c.Expr[Marker], message: c.Expr[String], + cause: c.Expr[Throwable])(a: c.Expr[A]) = { + import c.universe._ + val underlying = q"${c.prefix}.underlying" + val canLogEv = q"${c.prefix}.canLogEv" + q"""if ($underlying.isErrorEnabled) { + $underlying.error($marker, $canLogEv.logMessage($message, $a), $cause) + $canLogEv.afterLog($a) + }""" + } + + def errorMessageArgsMarker[A](c: LoggerContext[A])(marker: c.Expr[Marker], message: c.Expr[String], + args: c.Expr[Any]*)(a: c.Expr[A]) = { + import c.universe._ + val underlying = q"${c.prefix}.underlying" + val canLogEv = q"${c.prefix}.canLogEv" + if (args.length == 2) { + q"""if ($underlying.isErrorEnabled) { + $underlying.error($marker, $canLogEv.logMessage($message, $a), List(${args(0)}, ${args(1)}): _*) + $canLogEv.afterLog($a) + }""" + } else { + q"""if ($underlying.isErrorEnabled) { + $underlying.error($marker, $canLogEv.logMessage($message, $a), ..$args) + $canLogEv.afterLog($a) + }""" + } + } + + def warnMessage[A](c: LoggerContext[A])(message: c.Expr[String])(a: c.Expr[A]) = { + import c.universe._ + val underlying = q"${c.prefix}.underlying" + val canLogEv = q"${c.prefix}.canLogEv" + q"""if ($underlying.isWarnEnabled) { + $underlying.warn($canLogEv.logMessage($message, $a)) + $canLogEv.afterLog($a) + }""" + } + + def warnMessageCause[A](c: LoggerContext[A])(message: c.Expr[String], cause: c.Expr[Throwable])(a: c.Expr[A]) = { + import c.universe._ + val underlying = q"${c.prefix}.underlying" + val canLogEv = q"${c.prefix}.canLogEv" + q"""if ($underlying.isWarnEnabled) { + $underlying.warn($canLogEv.logMessage($message, $a), $cause) + $canLogEv.afterLog($a) + }""" + } + + def warnMessageArgs[A](c: LoggerContext[A])(message: c.Expr[String], args: c.Expr[Any]*)(a: c.Expr[A]) = { + import c.universe._ + val underlying = q"${c.prefix}.underlying" + val canLogEv = q"${c.prefix}.canLogEv" + if (args.length == 2) { + q"""if ($underlying.isWarnEnabled) { + $underlying.warn($canLogEv.logMessage($message, $a), List(${args(0)}, ${args(1)}): _*) + $canLogEv.afterLog($a) + }""" + } else { + q"""if ($underlying.isWarnEnabled) { + $underlying.warn($canLogEv.logMessage($message, $a), ..$args) + $canLogEv.afterLog($a) + }""" + } + } + + def warnMessageMarker[A](c: LoggerContext[A])(marker: c.Expr[Marker], message: c.Expr[String])(a: c.Expr[A]) = { + import c.universe._ + val underlying = q"${c.prefix}.underlying" + val canLogEv = q"${c.prefix}.canLogEv" + q"""if ($underlying.isWarnEnabled) { + $underlying.warn($marker, $canLogEv.logMessage($message, $a)) + $canLogEv.afterLog($a) + }""" + } + + def warnMessageCauseMarker[A](c: LoggerContext[A])(marker: c.Expr[Marker], message: c.Expr[String], + cause: c.Expr[Throwable])(a: c.Expr[A]) = { + import c.universe._ + val underlying = q"${c.prefix}.underlying" + val canLogEv = q"${c.prefix}.canLogEv" + q"""if ($underlying.isWarnEnabled) { + $underlying.warn($marker, $canLogEv.logMessage($message, $a), $cause) + $canLogEv.afterLog($a) + }""" + } + + def warnMessageArgsMarker[A](c: LoggerContext[A])(marker: c.Expr[Marker], message: c.Expr[String], + args: c.Expr[Any]*)(a: c.Expr[A]) = { + import c.universe._ + val underlying = q"${c.prefix}.underlying" + val canLogEv = q"${c.prefix}.canLogEv" + if (args.length == 2) { + q"""if ($underlying.isWarnEnabled) { + $underlying.warn($marker, $canLogEv.logMessage($message, $a), List(${args(0)}, ${args(1)}): _*) + $canLogEv.afterLog($a) + }""" + } else { + q"""if ($underlying.isWarnEnabled) { + $underlying.warn($marker, $canLogEv.logMessage($message, $a), ..$args) + $canLogEv.afterLog($a) + }""" + } + } + + def infoMessage[A](c: LoggerContext[A])(message: c.Expr[String])(a: c.Expr[A]) = { + import c.universe._ + val underlying = q"${c.prefix}.underlying" + val canLogEv = q"${c.prefix}.canLogEv" + q"""if ($underlying.isInfoEnabled) { + $underlying.info($canLogEv.logMessage($message, $a)) + $canLogEv.afterLog($a) + }""" + } + + def infoMessageCause[A](c: LoggerContext[A])(message: c.Expr[String], cause: c.Expr[Throwable])(a: c.Expr[A]) = { + import c.universe._ + val underlying = q"${c.prefix}.underlying" + val canLogEv = q"${c.prefix}.canLogEv" + q"""if ($underlying.isInfoEnabled) { + $underlying.info($canLogEv.logMessage($message, $a), $cause) + $canLogEv.afterLog($a) + }""" + } + + def infoMessageArgs[A](c: LoggerContext[A])(message: c.Expr[String], args: c.Expr[Any]*)(a: c.Expr[A]) = { + import c.universe._ + val underlying = q"${c.prefix}.underlying" + val canLogEv = q"${c.prefix}.canLogEv" + if (args.length == 2) { + q"""if ($underlying.isInfoEnabled) { + $underlying.info($canLogEv.logMessage($message, $a), List(${args(0)}, ${args(1)}): _*) + $canLogEv.afterLog($a) + }""" + } else { + q"""if ($underlying.isInfoEnabled) { + $underlying.info($canLogEv.logMessage($message, $a), ..$args) + $canLogEv.afterLog($a) + }""" + } + } + + def infoMessageMarker[A](c: LoggerContext[A])(marker: c.Expr[Marker], message: c.Expr[String])(a: c.Expr[A]) = { + import c.universe._ + val underlying = q"${c.prefix}.underlying" + val canLogEv = q"${c.prefix}.canLogEv" + q"""if ($underlying.isInfoEnabled) { + $underlying.info($marker, $canLogEv.logMessage($message, $a)) + $canLogEv.afterLog($a) + }""" + } + + def infoMessageCauseMarker[A](c: LoggerContext[A])(marker: c.Expr[Marker], message: c.Expr[String], + cause: c.Expr[Throwable])(a: c.Expr[A]) = { + import c.universe._ + val underlying = q"${c.prefix}.underlying" + val canLogEv = q"${c.prefix}.canLogEv" + q"""if ($underlying.isInfoEnabled) { + $underlying.info($marker, $canLogEv.logMessage($message, $a), $cause) + $canLogEv.afterLog($a) + }""" + } + + def infoMessageArgsMarker[A](c: LoggerContext[A])(marker: c.Expr[Marker], message: c.Expr[String], + args: c.Expr[Any]*)(a: c.Expr[A]) = { + import c.universe._ + val underlying = q"${c.prefix}.underlying" + val canLogEv = q"${c.prefix}.canLogEv" + if (args.length == 2) { + q"""if ($underlying.isInfoEnabled) { + $underlying.info($marker, $canLogEv.logMessage($message, $a), List(${args(0)}, ${args(1)}): _*) + $canLogEv.afterLog($a) + }""" + } else { + q"""if ($underlying.isInfoEnabled) { + $underlying.info($marker, $canLogEv.logMessage($message, $a), ..$args) + $canLogEv.afterLog($a) + }""" + } + } + + def debugMessage[A](c: LoggerContext[A])(message: c.Expr[String])(a: c.Expr[A]) = { + import c.universe._ + val underlying = q"${c.prefix}.underlying" + val canLogEv = q"${c.prefix}.canLogEv" + q"""if ($underlying.isDebugEnabled) { + $underlying.debug($canLogEv.logMessage($message, $a)) + $canLogEv.afterLog($a) + }""" + } + + def debugMessageCause[A](c: LoggerContext[A])(message: c.Expr[String], cause: c.Expr[Throwable])(a: c.Expr[A]) = { + import c.universe._ + val underlying = q"${c.prefix}.underlying" + val canLogEv = q"${c.prefix}.canLogEv" + q"""if ($underlying.isDebugEnabled) { + $underlying.debug($canLogEv.logMessage($message, $a), $cause) + $canLogEv.afterLog($a) + }""" + } + + def debugMessageArgs[A](c: LoggerContext[A])(message: c.Expr[String], args: c.Expr[Any]*)(a: c.Expr[A]) = { + import c.universe._ + val underlying = q"${c.prefix}.underlying" + val canLogEv = q"${c.prefix}.canLogEv" + if (args.length == 2) { + q"""if ($underlying.isDebugEnabled) { + $underlying.debug($canLogEv.logMessage($message, $a), List(${args(0)}, ${args(1)}): _*) + $canLogEv.afterLog($a) + }""" + } else { + q"""if ($underlying.isDebugEnabled) { + $underlying.debug($canLogEv.logMessage($message, $a), ..$args) + $canLogEv.afterLog($a) + }""" + } + } + + def debugMessageMarker[A](c: LoggerContext[A])(marker: c.Expr[Marker], message: c.Expr[String])(a: c.Expr[A]) = { + import c.universe._ + val underlying = q"${c.prefix}.underlying" + val canLogEv = q"${c.prefix}.canLogEv" + q"""if ($underlying.isDebugEnabled) { + $underlying.debug($marker, $canLogEv.logMessage($message, $a)) + $canLogEv.afterLog($a) + }""" + } + + def debugMessageCauseMarker[A](c: LoggerContext[A])(marker: c.Expr[Marker], message: c.Expr[String], + cause: c.Expr[Throwable])(a: c.Expr[A]) = { + import c.universe._ + val underlying = q"${c.prefix}.underlying" + val canLogEv = q"${c.prefix}.canLogEv" + q"""if ($underlying.isDebugEnabled) { + $underlying.debug($marker, $canLogEv.logMessage($message, $a), $cause) + $canLogEv.afterLog($a) + }""" + } + + def debugMessageArgsMarker[A](c: LoggerContext[A])(marker: c.Expr[Marker], message: c.Expr[String], + args: c.Expr[Any]*)(a: c.Expr[A]) = { + import c.universe._ + val underlying = q"${c.prefix}.underlying" + val canLogEv = q"${c.prefix}.canLogEv" + if (args.length == 2) { + q"""if ($underlying.isDebugEnabled) { + $underlying.debug($marker, $canLogEv.logMessage($message, $a), List(${args(0)}, ${args(1)}): _*) + $canLogEv.afterLog($a) + }""" + } else { + q"""if ($underlying.isDebugEnabled) { + $underlying.debug($marker, $canLogEv.logMessage($message, $a), ..$args) + $canLogEv.afterLog($a) + }""" + } + } + + def traceMessage[A](c: LoggerContext[A])(message: c.Expr[String])(a: c.Expr[A]) = { + import c.universe._ + val underlying = q"${c.prefix}.underlying" + val canLogEv = q"${c.prefix}.canLogEv" + q"""if ($underlying.isTraceEnabled) { + $underlying.trace($canLogEv.logMessage($message, $a)) + $canLogEv.afterLog($a) + }""" + } + + def traceMessageCause[A](c: LoggerContext[A])(message: c.Expr[String], cause: c.Expr[Throwable])(a: c.Expr[A]) = { + import c.universe._ + val underlying = q"${c.prefix}.underlying" + val canLogEv = q"${c.prefix}.canLogEv" + q"""if ($underlying.isTraceEnabled) { + $underlying.trace($canLogEv.logMessage($message, $a), $cause) + $canLogEv.afterLog($a) + }""" + } + + def traceMessageArgs[A](c: LoggerContext[A])(message: c.Expr[String], args: c.Expr[Any]*)(a: c.Expr[A]) = { + import c.universe._ + val underlying = q"${c.prefix}.underlying" + val canLogEv = q"${c.prefix}.canLogEv" + if (args.length == 2) { + q"""if ($underlying.isTraceEnabled) { + $underlying.trace($canLogEv.logMessage($message, $a), List(${args(0)}, ${args(1)}): _*) + $canLogEv.afterLog($a) + }""" + } else { + q"""if ($underlying.isTraceEnabled) { + $underlying.trace($canLogEv.logMessage($message, $a), ..$args) + $canLogEv.afterLog($a) + }""" + } + } + + def traceMessageMarker[A](c: LoggerContext[A])(marker: c.Expr[Marker], message: c.Expr[String])(a: c.Expr[A]) = { + import c.universe._ + val underlying = q"${c.prefix}.underlying" + val canLogEv = q"${c.prefix}.canLogEv" + q"""if ($underlying.isTraceEnabled) { + $underlying.trace($marker, $canLogEv.logMessage($message, $a)) + $canLogEv.afterLog($a) + }""" + } + + def traceMessageCauseMarker[A](c: LoggerContext[A])(marker: c.Expr[Marker], message: c.Expr[String], + cause: c.Expr[Throwable])(a: c.Expr[A]) = { + import c.universe._ + val underlying = q"${c.prefix}.underlying" + val canLogEv = q"${c.prefix}.canLogEv" + q"""if ($underlying.isTraceEnabled) { + $underlying.trace($marker, $canLogEv.logMessage($message, $a), $cause) + $canLogEv.afterLog($a) + }""" + } + + def traceMessageArgsMarker[A](c: LoggerContext[A])(marker: c.Expr[Marker], message: c.Expr[String], + args: c.Expr[Any]*)(a: c.Expr[A]) = { + import c.universe._ + val underlying = q"${c.prefix}.underlying" + val canLogEv = q"${c.prefix}.canLogEv" + if (args.length == 2) { + q"""if ($underlying.isTraceEnabled) { + $underlying.trace($marker, $canLogEv.logMessage($message, $a), List(${args(0)}, ${args(1)}): _*) + $canLogEv.afterLog($a) + }""" + } else { + q"""if ($underlying.isTraceEnabled) { + $underlying.trace($marker, $canLogEv.logMessage($message, $a), ..$args) + $canLogEv.afterLog($a) + }""" + } + } +} diff --git a/src/test/scala/com/typesafe/scalalogging/LoggerTakingImplicitSpec.scala b/src/test/scala/com/typesafe/scalalogging/LoggerTakingImplicitSpec.scala new file mode 100644 index 0000000..ab4a3cd --- /dev/null +++ b/src/test/scala/com/typesafe/scalalogging/LoggerTakingImplicitSpec.scala @@ -0,0 +1,454 @@ +package com.typesafe.scalalogging + +import java.io.{ByteArrayInputStream, ByteArrayOutputStream, ObjectInputStream, ObjectOutputStream} + +import org.mockito.Matchers._ +import org.mockito.Mockito._ +import org.scalatest.mockito.MockitoSugar +import org.scalatest.{Matchers, WordSpec} +import org.slf4j.{Logger => Underlying} + +class LoggerTakingImplicitSpec extends WordSpec with Matchers with MockitoSugar { + + 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, anyObject) + } + } + + "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, List(arg1): _*) + logger.error(msg, arg1, arg2) + verify(underlying).error(logMsg, List(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, List(arg1): _*) + logger.error(msg, arg1, arg2) + verify(underlying, never).error(logMsg, List(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, anyObject) + } + } + + "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, List(arg1): _*) + logger.warn(msg, arg1, arg2) + verify(underlying).warn(logMsg, List(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, List(arg1): _*) + logger.warn(msg, arg1, arg2) + verify(underlying, never).warn(logMsg, List(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, anyObject) + } + } + + "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, List(arg1): _*) + logger.info(msg, arg1, arg2) + verify(underlying).info(logMsg, List(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, List(arg1): _*) + logger.info(msg, arg1, arg2) + verify(underlying, never).info(logMsg, List(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, anyObject) + } + } + + "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, List(arg1): _*) + logger.debug(msg, arg1, arg2) + verify(underlying).debug(logMsg, List(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, List(arg1): _*) + logger.debug(msg, arg1, arg2) + verify(underlying, never).debug(logMsg, List(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, anyObject) + } + } + + "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, List(arg1): _*) + logger.trace(msg, arg1, arg2) + verify(underlying).trace(logMsg, List(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, List(arg1): _*) + logger.trace(msg, arg1, arg2) + verify(underlying, never).trace(logMsg, List(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]) + } + } + + "Serializing Logger" should { + implicit val correlationId = CorrelationId(value = "correlationId") + + implicit case object canLogCorrelationId extends CanLog[CorrelationId] { + override def logMessage(originalMsg: String, a: CorrelationId): String = s"${a.value} msg" + } + + def serialize[A](logger: LoggerTakingImplicit[A]): Array[Byte] = { + val byteArrayStream = new ByteArrayOutputStream + val out = new ObjectOutputStream(byteArrayStream) + + out.writeObject(logger) + out.close() + byteArrayStream.close() + + byteArrayStream.toByteArray + } + + def deserialize[A](array: Array[Byte]): LoggerTakingImplicit[A] = { + val byteArrayStream = new ByteArrayInputStream(array) + val in = new ObjectInputStream(byteArrayStream) + + val logger = in.readObject.asInstanceOf[LoggerTakingImplicit[A]] + in.close() + byteArrayStream.close() + + logger + } + + "be usable after deserialization" in { + val logger = + deserialize[CorrelationId]( + serialize[CorrelationId]( + Logger.takingImplicit[CorrelationId]( + org.slf4j.LoggerFactory.getLogger("test")))) + + logger.trace("Back from deserialization") + } + + "constructed by explicit class and be usable after deserialization" in { + val logger = + deserialize[CorrelationId]( + serialize[CorrelationId]( + Logger.takingImplicit[CorrelationId]( + classOf[LoggerSpec]))) + + logger.trace("Back from deserialization") + } + + "constructed by implicit class tag and be usable after deserialization" in { + val logger = + deserialize[CorrelationId]( + serialize[CorrelationId]( + Logger.takingImplicit[LoggerSpec, CorrelationId])) + + logger.trace("Back from deserialization") + } + } + + 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.takingImplicit[CorrelationId](underlying) + } +} From f8400afbb2a922041f7c3ebd77de9c86e4f91119 Mon Sep 17 00:00:00 2001 From: paweliwanow Date: Sun, 4 Jun 2017 22:59:42 +0200 Subject: [PATCH 2/9] Removed redundant spaces in README --- README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/README.md b/README.md index 18662d2..00d7393 100644 --- a/README.md +++ b/README.md @@ -88,7 +88,6 @@ case class CorrelationId(value: String) implicit case object CanLogCorrelationId extends CanLog[CorrelationId] { override def logMessage(originalMsg: String, a: CorrelationId): String = s"${a.value} $originalMsg" } - implicit val correlationId = CorrelationId("ID") @@ -110,7 +109,6 @@ implicit case object CanLogCorrelationId extends CanLog[CorrelationId] { MDC.remove("correlationId") } } - implicit val correlationId = CorrelationId("ID") From 0990d19298d3edd082a541cb58e61ca845622138 Mon Sep 17 00:00:00 2001 From: paweliwanow Date: Mon, 5 Jun 2017 18:43:09 +0200 Subject: [PATCH 3/9] Changed examples in README --- README.md | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 00d7393..e645d75 100644 --- a/README.md +++ b/README.md @@ -92,7 +92,7 @@ implicit case object CanLogCorrelationId extends CanLog[CorrelationId] { implicit val correlationId = CorrelationId("ID") val logger = Logger.takingImplicit[CorrelationId]("test") -logger.info("Test") // logs "ID Test" +logger.info("Test") // takes implicit correlationId and logs "ID Test" ``` It's possible to use `MDC` through `CanLog` without any troubles with execution context. @@ -113,7 +113,13 @@ implicit case object CanLogCorrelationId extends CanLog[CorrelationId] { implicit val correlationId = CorrelationId("ID") val logger = Logger.takingImplicit[CorrelationId]("test") -Future(logger.info("Test")) + +def serviceMethod(implicit correlationId: CorrelationId): Future[Result] = { + dbCall.map { value => + logger.trace(s"Received value $value from db") // takes implicit correlationId + toResult(value) + } +} ``` ### What's new? From 845d80170768c8ef7427cd531020fa5dea19cb14 Mon Sep 17 00:00:00 2001 From: paweliwanow Date: Mon, 5 Jun 2017 18:45:21 +0200 Subject: [PATCH 4/9] Reverting unnecessary change --- src/main/scala/com/typesafe/scalalogging/Logger.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/com/typesafe/scalalogging/Logger.scala b/src/main/scala/com/typesafe/scalalogging/Logger.scala index dc864e9..2abdd19 100644 --- a/src/main/scala/com/typesafe/scalalogging/Logger.scala +++ b/src/main/scala/com/typesafe/scalalogging/Logger.scala @@ -60,7 +60,7 @@ object Logger { /** * Create a [[Logger]] wrapping the created underlying `org.slf4j.Logger`. */ - def apply[A](clazz: Class[_]): Logger = + def apply(clazz: Class[_]): Logger = new Logger(LoggerFactory.getLogger(clazz.getName)) /** From 75701d60b14ef89e148f011792eb39d9d606c0e7 Mon Sep 17 00:00:00 2001 From: paweliwanow Date: Mon, 5 Jun 2017 22:09:24 +0200 Subject: [PATCH 5/9] Fixes in serialization tests for LoggerTakingImplicit --- .../com/typesafe/scalalogging/Logger.scala | 34 +++++----- .../scalalogging/LoggerTakingImplicit.scala | 3 +- .../typesafe/scalalogging/LoggerSpec.scala | 68 +++++++++++++++++++ .../LoggerTakingImplicitSpec.scala | 67 +----------------- 4 files changed, 89 insertions(+), 83 deletions(-) diff --git a/src/main/scala/com/typesafe/scalalogging/Logger.scala b/src/main/scala/com/typesafe/scalalogging/Logger.scala index 2abdd19..0ce5b91 100644 --- a/src/main/scala/com/typesafe/scalalogging/Logger.scala +++ b/src/main/scala/com/typesafe/scalalogging/Logger.scala @@ -32,8 +32,8 @@ object Logger { new Logger(underlying) /** - * Create a [[LoggerTakingImplicit]] wrapping the given underlying `org.slf4j.Logger`. - */ + * Create a [[LoggerTakingImplicit]] wrapping the given underlying `org.slf4j.Logger`. + */ def takingImplicit[A](underlying: Underlying)(implicit ev: CanLog[A]): LoggerTakingImplicit[A] = new LoggerTakingImplicit[A](underlying) @@ -48,12 +48,12 @@ object Logger { new Logger(LoggerFactory.getLogger(name)) /** - * Create a [[LoggerTakingImplicit]] for the given name. - * Example: - * {{{ - * val logger = Logger.takingImplicit[CorrelationId]("application") - * }}} - */ + * Create a [[LoggerTakingImplicit]] for the given name. + * Example: + * {{{ + * val logger = Logger.takingImplicit[CorrelationId]("application") + * }}} + */ def takingImplicit[A](name: String)(implicit ev: CanLog[A]): LoggerTakingImplicit[A] = new LoggerTakingImplicit[A](LoggerFactory.getLogger(name)) @@ -64,8 +64,8 @@ object Logger { new Logger(LoggerFactory.getLogger(clazz.getName)) /** - * Create a [[LoggerTakingImplicit]] wrapping the created underlying `org.slf4j.Logger`. - */ + * Create a [[LoggerTakingImplicit]] wrapping the created underlying `org.slf4j.Logger`. + */ def takingImplicit[A](clazz: Class[_])(implicit ev: CanLog[A]): LoggerTakingImplicit[A] = new LoggerTakingImplicit[A](LoggerFactory.getLogger(clazz.getName)) @@ -81,13 +81,13 @@ object Logger { new Logger(LoggerFactory.getLogger(ct.runtimeClass.getName.stripSuffix("$"))) /** - * Create a [[LoggerTakingImplicit]] for the runtime class wrapped by the implicit class - * tag parameter. - * Example: - * {{{ - * val logger = Logger.takingImplicit[MyClass] - * }}} - */ + * Create a [[LoggerTakingImplicit]] for the runtime class wrapped by the implicit class + * tag parameter. + * Example: + * {{{ + * val logger = Logger.takingImplicit[MyClass, CorrelationId] + * }}} + */ def takingImplicit[T, A](implicit ct: ClassTag[T], ev: CanLog[A]): LoggerTakingImplicit[A] = new LoggerTakingImplicit[A](LoggerFactory.getLogger(ct.runtimeClass.getName.stripSuffix("$"))) } diff --git a/src/main/scala/com/typesafe/scalalogging/LoggerTakingImplicit.scala b/src/main/scala/com/typesafe/scalalogging/LoggerTakingImplicit.scala index 70fcb5b..1d623fb 100644 --- a/src/main/scala/com/typesafe/scalalogging/LoggerTakingImplicit.scala +++ b/src/main/scala/com/typesafe/scalalogging/LoggerTakingImplicit.scala @@ -8,8 +8,7 @@ trait CanLog[A] { this: Serializable => } @SerialVersionUID(957385465L) -final class LoggerTakingImplicit[A] private[scalalogging] (val underlying: Underlying) - (implicit val canLogEv: CanLog[A]) extends Serializable { +final class LoggerTakingImplicit[A] private[scalalogging] (val underlying: Underlying)(implicit val canLogEv: CanLog[A]) extends Serializable { // Error diff --git a/src/test/scala/com/typesafe/scalalogging/LoggerSpec.scala b/src/test/scala/com/typesafe/scalalogging/LoggerSpec.scala index 2e6f5ea..23a7df9 100644 --- a/src/test/scala/com/typesafe/scalalogging/LoggerSpec.scala +++ b/src/test/scala/com/typesafe/scalalogging/LoggerSpec.scala @@ -374,6 +374,74 @@ class LoggerSpec extends WordSpec with Matchers with MockitoSugar { } } + "Serializing LoggerTakingImplicit" should { + case class CorrelationId(value: String) + implicit val correlationId = CorrelationId(value = "correlationId") + + implicit case object canLogCorrelationId extends CanLog[CorrelationId] { + override def logMessage(originalMsg: String, a: CorrelationId): String = s"${a.value} msg" + } + + def serialize[A](logger: LoggerTakingImplicit[A]): Array[Byte] = { + val byteArrayStream = new ByteArrayOutputStream + val out = new ObjectOutputStream(byteArrayStream) + + out.writeObject(logger) + out.close() + byteArrayStream.close() + + byteArrayStream.toByteArray + } + + def deserialize[A](array: Array[Byte]): LoggerTakingImplicit[A] = { + val byteArrayStream = new ByteArrayInputStream(array) + val in = new ObjectInputStream(byteArrayStream) + + val logger = in.readObject.asInstanceOf[LoggerTakingImplicit[A]] + in.close() + byteArrayStream.close() + + logger + } + + "be usable after deserialization" in { + val logger = + deserialize[CorrelationId]( + serialize[CorrelationId]( + Logger.takingImplicit[CorrelationId]( + org.slf4j.LoggerFactory.getLogger("test") + ) + ) + ) + + logger.trace("Back from deserialization") + } + + "constructed by explicit class and be usable after deserialization" in { + val logger = + deserialize[CorrelationId]( + serialize[CorrelationId]( + Logger.takingImplicit[CorrelationId]( + classOf[LoggerSpec] + ) + ) + ) + + logger.trace("Back from deserialization") + } + + "constructed by implicit class tag and be usable after deserialization" in { + val logger = + deserialize[CorrelationId]( + serialize[CorrelationId]( + Logger.takingImplicit[LoggerSpec, CorrelationId] + ) + ) + + logger.trace("Back from deserialization") + } + } + def fixture(p: Underlying => Boolean, isEnabled: Boolean) = new { val msg = "msg" diff --git a/src/test/scala/com/typesafe/scalalogging/LoggerTakingImplicitSpec.scala b/src/test/scala/com/typesafe/scalalogging/LoggerTakingImplicitSpec.scala index ab4a3cd..dbb7783 100644 --- a/src/test/scala/com/typesafe/scalalogging/LoggerTakingImplicitSpec.scala +++ b/src/test/scala/com/typesafe/scalalogging/LoggerTakingImplicitSpec.scala @@ -1,12 +1,10 @@ package com.typesafe.scalalogging -import java.io.{ByteArrayInputStream, ByteArrayOutputStream, ObjectInputStream, ObjectOutputStream} - import org.mockito.Matchers._ import org.mockito.Mockito._ import org.scalatest.mockito.MockitoSugar -import org.scalatest.{Matchers, WordSpec} -import org.slf4j.{Logger => Underlying} +import org.scalatest.{ Matchers, WordSpec } +import org.slf4j.{ Logger => Underlying } class LoggerTakingImplicitSpec extends WordSpec with Matchers with MockitoSugar { @@ -377,69 +375,10 @@ class LoggerTakingImplicitSpec extends WordSpec with Matchers with MockitoSugar } } - "Serializing Logger" should { - implicit val correlationId = CorrelationId(value = "correlationId") - - implicit case object canLogCorrelationId extends CanLog[CorrelationId] { - override def logMessage(originalMsg: String, a: CorrelationId): String = s"${a.value} msg" - } - - def serialize[A](logger: LoggerTakingImplicit[A]): Array[Byte] = { - val byteArrayStream = new ByteArrayOutputStream - val out = new ObjectOutputStream(byteArrayStream) - - out.writeObject(logger) - out.close() - byteArrayStream.close() - - byteArrayStream.toByteArray - } - - def deserialize[A](array: Array[Byte]): LoggerTakingImplicit[A] = { - val byteArrayStream = new ByteArrayInputStream(array) - val in = new ObjectInputStream(byteArrayStream) - - val logger = in.readObject.asInstanceOf[LoggerTakingImplicit[A]] - in.close() - byteArrayStream.close() - - logger - } - - "be usable after deserialization" in { - val logger = - deserialize[CorrelationId]( - serialize[CorrelationId]( - Logger.takingImplicit[CorrelationId]( - org.slf4j.LoggerFactory.getLogger("test")))) - - logger.trace("Back from deserialization") - } - - "constructed by explicit class and be usable after deserialization" in { - val logger = - deserialize[CorrelationId]( - serialize[CorrelationId]( - Logger.takingImplicit[CorrelationId]( - classOf[LoggerSpec]))) - - logger.trace("Back from deserialization") - } - - "constructed by implicit class tag and be usable after deserialization" in { - val logger = - deserialize[CorrelationId]( - serialize[CorrelationId]( - Logger.takingImplicit[LoggerSpec, CorrelationId])) - - logger.trace("Back from deserialization") - } - } - def fixture(p: Underlying => Boolean, isEnabled: Boolean) = new { implicit val correlationId = CorrelationId("corrId") - implicit val canLogCorrelationId = mock[CanLog[CorrelationId]] + implicit val canLogCorrelationId = mock[CanLog[CorrelationId]] val msg = "msg" val cause = new RuntimeException("cause") val arg1 = "arg1" From 32a9d9af0fc7b1243af01612d075320c69174523 Mon Sep 17 00:00:00 2001 From: paweliwanow Date: Mon, 5 Jun 2017 22:29:54 +0200 Subject: [PATCH 6/9] Minor change in tests --- src/test/scala/com/typesafe/scalalogging/LoggerSpec.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/scala/com/typesafe/scalalogging/LoggerSpec.scala b/src/test/scala/com/typesafe/scalalogging/LoggerSpec.scala index 23a7df9..3ff4094 100644 --- a/src/test/scala/com/typesafe/scalalogging/LoggerSpec.scala +++ b/src/test/scala/com/typesafe/scalalogging/LoggerSpec.scala @@ -379,7 +379,7 @@ class LoggerSpec extends WordSpec with Matchers with MockitoSugar { implicit val correlationId = CorrelationId(value = "correlationId") implicit case object canLogCorrelationId extends CanLog[CorrelationId] { - override def logMessage(originalMsg: String, a: CorrelationId): String = s"${a.value} msg" + override def logMessage(originalMsg: String, a: CorrelationId): String = s"${a.value} $originalMsg" } def serialize[A](logger: LoggerTakingImplicit[A]): Array[Byte] = { From b1d93cf4658a4c8f74eb0981d3fc2c37910c3839 Mon Sep 17 00:00:00 2001 From: paweliwanow Date: Mon, 5 Jun 2017 22:58:36 +0200 Subject: [PATCH 7/9] Minor change to retrigger the build after failure in downloading dependency --- src/test/scala/com/typesafe/scalalogging/LoggerSpec.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/scala/com/typesafe/scalalogging/LoggerSpec.scala b/src/test/scala/com/typesafe/scalalogging/LoggerSpec.scala index 3ff4094..027fe0c 100644 --- a/src/test/scala/com/typesafe/scalalogging/LoggerSpec.scala +++ b/src/test/scala/com/typesafe/scalalogging/LoggerSpec.scala @@ -379,7 +379,7 @@ class LoggerSpec extends WordSpec with Matchers with MockitoSugar { implicit val correlationId = CorrelationId(value = "correlationId") implicit case object canLogCorrelationId extends CanLog[CorrelationId] { - override def logMessage(originalMsg: String, a: CorrelationId): String = s"${a.value} $originalMsg" + def logMessage(originalMsg: String, a: CorrelationId): String = s"${a.value} $originalMsg" } def serialize[A](logger: LoggerTakingImplicit[A]): Array[Byte] = { From 8cad146de593f51494bc0c5f891c70066a74fb2a Mon Sep 17 00:00:00 2001 From: paweliwanow Date: Mon, 5 Feb 2018 19:55:01 +0100 Subject: [PATCH 8/9] Minor fix in CanLog typeclass --- .../scala/com/typesafe/scalalogging/LoggerTakingImplicit.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/scala/com/typesafe/scalalogging/LoggerTakingImplicit.scala b/src/main/scala/com/typesafe/scalalogging/LoggerTakingImplicit.scala index 1d623fb..9ebc295 100644 --- a/src/main/scala/com/typesafe/scalalogging/LoggerTakingImplicit.scala +++ b/src/main/scala/com/typesafe/scalalogging/LoggerTakingImplicit.scala @@ -2,7 +2,7 @@ package com.typesafe.scalalogging import org.slf4j.{ Marker, Logger => Underlying } -trait CanLog[A] { this: Serializable => +trait CanLog[A] { def logMessage(originalMsg: String, a: A): String def afterLog(a: A): Unit = () } From a64020706f23c3faa46b592dac36d2a5b0b02945 Mon Sep 17 00:00:00 2001 From: paweliwanow Date: Mon, 5 Feb 2018 20:03:42 +0100 Subject: [PATCH 9/9] Formatting fixes in LoggerSpec --- .../com/typesafe/scalalogging/LoggerSpec.scala | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/src/test/scala/com/typesafe/scalalogging/LoggerSpec.scala b/src/test/scala/com/typesafe/scalalogging/LoggerSpec.scala index 323b7f1..4345c92 100644 --- a/src/test/scala/com/typesafe/scalalogging/LoggerSpec.scala +++ b/src/test/scala/com/typesafe/scalalogging/LoggerSpec.scala @@ -559,10 +559,7 @@ class LoggerSpec extends WordSpec with Matchers with MockitoSugar { deserialize[CorrelationId]( serialize[CorrelationId]( Logger.takingImplicit[CorrelationId]( - org.slf4j.LoggerFactory.getLogger("test") - ) - ) - ) + org.slf4j.LoggerFactory.getLogger("test")))) logger.trace("Back from deserialization") } @@ -572,10 +569,7 @@ class LoggerSpec extends WordSpec with Matchers with MockitoSugar { deserialize[CorrelationId]( serialize[CorrelationId]( Logger.takingImplicit[CorrelationId]( - classOf[LoggerSpec] - ) - ) - ) + classOf[LoggerSpec]))) logger.trace("Back from deserialization") } @@ -584,9 +578,7 @@ class LoggerSpec extends WordSpec with Matchers with MockitoSugar { val logger = deserialize[CorrelationId]( serialize[CorrelationId]( - Logger.takingImplicit[LoggerSpec, CorrelationId] - ) - ) + Logger.takingImplicit[LoggerSpec, CorrelationId])) logger.trace("Back from deserialization") }