From 901ed721524cdbcdb4f90374ab2f0ba55b32b802 Mon Sep 17 00:00:00 2001 From: mentegy Date: Tue, 18 Jul 2017 15:01:53 +0300 Subject: [PATCH] Make logger to consume args of type `Any` with slf4 interpolator. Box `Any` to `AnyRef` before each call to underlying logger --- .../typesafe/scalalogging/LoggerMacro.scala | 60 ++++++++++++------- .../typesafe/scalalogging/LoggerSpec.scala | 24 ++++++++ 2 files changed, 61 insertions(+), 23 deletions(-) diff --git a/src/main/scala/com/typesafe/scalalogging/LoggerMacro.scala b/src/main/scala/com/typesafe/scalalogging/LoggerMacro.scala index 7d4ff70..519439a 100644 --- a/src/main/scala/com/typesafe/scalalogging/LoggerMacro.scala +++ b/src/main/scala/com/typesafe/scalalogging/LoggerMacro.scala @@ -39,10 +39,11 @@ private object LoggerMacro { def errorMessageArgs(c: LoggerContext)(message: c.Expr[String], args: c.Expr[Any]*) = { import c.universe._ val underlying = q"${c.prefix}.underlying" + val anyRefArgs = formatArgs(c)(args: _*) if (args.length == 2) - q"if ($underlying.isErrorEnabled) $underlying.error($message, _root_.scala.Array(${args(0)}, ${args(1)}): _*)" + q"if ($underlying.isErrorEnabled) $underlying.error($message, _root_.scala.Array(${anyRefArgs(0)}, ${anyRefArgs(1)}): _*)" else - q"if ($underlying.isErrorEnabled) $underlying.error($message, ..$args)" + q"if ($underlying.isErrorEnabled) $underlying.error($message, ..$anyRefArgs)" } def errorMessageMarker(c: LoggerContext)(marker: c.Expr[Marker], message: c.Expr[String]) = { @@ -59,10 +60,11 @@ private object LoggerMacro { def errorMessageArgsMarker(c: LoggerContext)(marker: c.Expr[Marker], message: c.Expr[String], args: c.Expr[Any]*) = { import c.universe._ val underlying = q"${c.prefix}.underlying" + val anyRefArgs = formatArgs(c)(args: _*) if (args.length == 2) - q"if ($underlying.isErrorEnabled) $underlying.error($marker, $message, _root_.scala.Array(${args(0)}, ${args(1)}): _*)" + q"if ($underlying.isErrorEnabled) $underlying.error($marker, $message, _root_.scala.Array(${anyRefArgs(0)}, ${anyRefArgs(1)}): _*)" else - q"if ($underlying.isErrorEnabled) $underlying.error($marker, $message, ..$args)" + q"if ($underlying.isErrorEnabled) $underlying.error($marker, $message, ..$anyRefArgs)" } // Warn @@ -81,10 +83,11 @@ private object LoggerMacro { def warnMessageArgs(c: LoggerContext)(message: c.Expr[String], args: c.Expr[Any]*) = { import c.universe._ val underlying = q"${c.prefix}.underlying" + val anyRefArgs = formatArgs(c)(args: _*) if (args.length == 2) - q"if ($underlying.isWarnEnabled) $underlying.warn($message, _root_.scala.Array(${args(0)}, ${args(1)}): _*)" + q"if ($underlying.isWarnEnabled) $underlying.warn($message, _root_.scala.Array(${anyRefArgs(0)}, ${anyRefArgs(1)}): _*)" else - q"if ($underlying.isWarnEnabled) $underlying.warn($message, ..$args)" + q"if ($underlying.isWarnEnabled) $underlying.warn($message, ..$anyRefArgs)" } def warnMessageMarker(c: LoggerContext)(marker: c.Expr[Marker], message: c.Expr[String]) = { @@ -101,10 +104,11 @@ private object LoggerMacro { def warnMessageArgsMarker(c: LoggerContext)(marker: c.Expr[Marker], message: c.Expr[String], args: c.Expr[Any]*) = { import c.universe._ val underlying = q"${c.prefix}.underlying" + val anyRefArgs = formatArgs(c)(args: _*) if (args.length == 2) - q"if ($underlying.isWarnEnabled) $underlying.warn($marker, $message, _root_.scala.Array(${args(0)}, ${args(1)}): _*)" + q"if ($underlying.isWarnEnabled) $underlying.warn($marker, $message, _root_.scala.Array(${anyRefArgs(0)}, ${anyRefArgs(1)}): _*)" else - q"if ($underlying.isWarnEnabled) $underlying.warn($marker, $message, ..$args)" + q"if ($underlying.isWarnEnabled) $underlying.warn($marker, $message, ..$anyRefArgs)" } // Info @@ -123,10 +127,11 @@ private object LoggerMacro { def infoMessageArgs(c: LoggerContext)(message: c.Expr[String], args: c.Expr[Any]*) = { import c.universe._ val underlying = q"${c.prefix}.underlying" + val anyRefArgs = formatArgs(c)(args: _*) if (args.length == 2) - q"if ($underlying.isInfoEnabled) $underlying.info($message, _root_.scala.Array(${args(0)}, ${args(1)}): _*)" + q"if ($underlying.isInfoEnabled) $underlying.info($message, _root_.scala.Array(${anyRefArgs(0)}, ${anyRefArgs(1)}): _*)" else - q"if ($underlying.isInfoEnabled) $underlying.info($message, ..$args)" + q"if ($underlying.isInfoEnabled) $underlying.info($message, ..$anyRefArgs)" } def infoMessageMarker(c: LoggerContext)(marker: c.Expr[Marker], message: c.Expr[String]) = { @@ -143,10 +148,11 @@ private object LoggerMacro { def infoMessageArgsMarker(c: LoggerContext)(marker: c.Expr[Marker], message: c.Expr[String], args: c.Expr[Any]*) = { import c.universe._ val underlying = q"${c.prefix}.underlying" + val anyRefArgs = formatArgs(c)(args: _*) if (args.length == 2) - q"if ($underlying.isInfoEnabled) $underlying.info($marker, $message, _root_.scala.Array(${args(0)}, ${args(1)}): _*)" + q"if ($underlying.isInfoEnabled) $underlying.info($marker, $message, _root_.scala.Array(${anyRefArgs(0)}, ${anyRefArgs(1)}): _*)" else - q"if ($underlying.isInfoEnabled) $underlying.info($marker, $message, ..$args)" + q"if ($underlying.isInfoEnabled) $underlying.info($marker, $message, ..$anyRefArgs)" } // Debug @@ -165,10 +171,11 @@ private object LoggerMacro { def debugMessageArgs(c: LoggerContext)(message: c.Expr[String], args: c.Expr[Any]*) = { import c.universe._ val underlying = q"${c.prefix}.underlying" + val anyRefArgs = formatArgs(c)(args: _*) if (args.length == 2) - q"if ($underlying.isDebugEnabled) $underlying.debug($message, _root_.scala.Array(${args(0)}, ${args(1)}): _*)" + q"if ($underlying.isDebugEnabled) $underlying.debug($message, _root_.scala.Array(${anyRefArgs(0)}, ${anyRefArgs(1)}): _*)" else - q"if ($underlying.isDebugEnabled) $underlying.debug($message, ..$args)" + q"if ($underlying.isDebugEnabled) $underlying.debug($message, ..$anyRefArgs)" } def debugMessageMarker(c: LoggerContext)(marker: c.Expr[Marker], message: c.Expr[String]) = { @@ -185,10 +192,11 @@ private object LoggerMacro { def debugMessageArgsMarker(c: LoggerContext)(marker: c.Expr[Marker], message: c.Expr[String], args: c.Expr[Any]*) = { import c.universe._ val underlying = q"${c.prefix}.underlying" + val anyRefArgs = formatArgs(c)(args: _*) if (args.length == 2) - q"if ($underlying.isDebugEnabled) $underlying.debug($marker, $message, _root_.scala.Array(${args(0)}, ${args(1)}): _*)" + q"if ($underlying.isDebugEnabled) $underlying.debug($marker, $message, _root_.scala.Array(${anyRefArgs(0)}, ${anyRefArgs(1)}): _*)" else - q"if ($underlying.isDebugEnabled) $underlying.debug($marker, $message, ..$args)" + q"if ($underlying.isDebugEnabled) $underlying.debug($marker, $message, ..$anyRefArgs)" } // Trace @@ -207,10 +215,11 @@ private object LoggerMacro { def traceMessageArgs(c: LoggerContext)(message: c.Expr[String], args: c.Expr[Any]*) = { import c.universe._ val underlying = q"${c.prefix}.underlying" + val anyRefArgs = formatArgs(c)(args: _*) if (args.length == 2) - q"if ($underlying.isTraceEnabled) $underlying.trace($message, _root_.scala.Array(${args(0)}, ${args(1)}): _*)" + q"if ($underlying.isTraceEnabled) $underlying.trace($message, _root_.scala.Array(${anyRefArgs(0)}, ${anyRefArgs(1)}): _*)" else - q"if ($underlying.isTraceEnabled) $underlying.trace($message, ..$args)" + q"if ($underlying.isTraceEnabled) $underlying.trace($message, ..$anyRefArgs)" } def traceMessageMarker(c: LoggerContext)(marker: c.Expr[Marker], message: c.Expr[String]) = { @@ -227,10 +236,11 @@ private object LoggerMacro { def traceMessageArgsMarker(c: LoggerContext)(marker: c.Expr[Marker], message: c.Expr[String], args: c.Expr[Any]*) = { import c.universe._ val underlying = q"${c.prefix}.underlying" + val anyRefArgs = formatArgs(c)(args: _*) if (args.length == 2) - q"if ($underlying.isTraceEnabled) $underlying.trace($marker, $message, _root_.scala.Array(${args(0)}, ${args(1)}): _*)" + q"if ($underlying.isTraceEnabled) $underlying.trace($marker, $message, _root_.scala.Array(${anyRefArgs(0)}, ${anyRefArgs(1)}): _*)" else - q"if ($underlying.isTraceEnabled) $underlying.trace($marker, $message, ..$args)" + q"if ($underlying.isTraceEnabled) $underlying.trace($marker, $message, ..$anyRefArgs)" } /** Checks whether `messsage` is an interpolated string and transforms it into SLF4J string interpolation. */ @@ -246,9 +256,7 @@ private object LoggerMacro { .map(str => if (args.nonEmpty) str.replace("{}", "\\{}") else str) .mkString("{}") - val formatArgs = args map { arg => - c.Expr[AnyRef](if (arg.tpe <:< weakTypeOf[AnyRef]) arg else q"$arg.asInstanceOf[_root_.scala.AnyRef]") - } + val formatArgs = args.map(t => c.Expr[Any](t)) (c.Expr(q"$format"), formatArgs) @@ -256,4 +264,10 @@ private object LoggerMacro { } } + private def formatArgs(c: LoggerContext)(args: c.Expr[Any]*) = { + import c.universe._ + args.map { arg => + c.Expr[AnyRef](if (arg.tree.tpe <:< weakTypeOf[AnyRef]) arg.tree else q"$arg.asInstanceOf[_root_.scala.AnyRef]") + } + } } diff --git a/src/test/scala/com/typesafe/scalalogging/LoggerSpec.scala b/src/test/scala/com/typesafe/scalalogging/LoggerSpec.scala index 68ce466..06a908f 100644 --- a/src/test/scala/com/typesafe/scalalogging/LoggerSpec.scala +++ b/src/test/scala/com/typesafe/scalalogging/LoggerSpec.scala @@ -463,6 +463,24 @@ class LoggerSpec extends WordSpec with Matchers with MockitoSugar { } } + "Logging a message using slf4 interpolator and Any args" should { + "map args to AnyRef for 2 args" in { + val f = fixture(_.isErrorEnabled, true) + import f._ + logger.error("foo {}, bar {}", arg4, arg5) + verify(underlying).error("foo {}, bar {}", Array(arg4ref, arg5ref): _*) + } + + "map args to AnyRef for non 2 args" in { + val f = fixture(_.isErrorEnabled, true) + import f._ + logger.error("foo {}", arg4) + verify(underlying).error("foo {}", arg4ref) + logger.error("foo {}, bar {}, {}", arg4, arg5, arg6) + verify(underlying).error("foo {}, bar {}, {}", arg4ref, arg5ref, arg6ref) + } + } + "Serializing Logger" should { def serialize(logger: Logger): Array[Byte] = { @@ -513,6 +531,12 @@ class LoggerSpec extends WordSpec with Matchers with MockitoSugar { val arg1 = "arg1" val arg2 = new Integer(1) val arg3 = "arg3" + val arg4 = 4 + val arg4ref = arg4.asInstanceOf[AnyRef] + val arg5 = true + val arg5ref = arg5.asInstanceOf[AnyRef] + val arg6 = 6L + val arg6ref = arg6.asInstanceOf[AnyRef] val underlying = mock[org.slf4j.Logger] when(p(underlying)).thenReturn(isEnabled) val logger = Logger(underlying)