From 71dc4cf68daeaf24d9157046e624d6a168f7565b Mon Sep 17 00:00:00 2001 From: Morgen Peschke Date: Thu, 13 Jun 2024 18:20:35 -0700 Subject: [PATCH 1/4] Improve API around transforming loggers --- .../org/typelevel/log4cats/ErrorLogger.scala | 29 +- .../scala/org/typelevel/log4cats/Logger.scala | 41 +-- .../typelevel/log4cats/MessageLogger.scala | 27 +- .../PagingSelfAwareStructuredLogger.scala | 170 +++------- .../typelevel/log4cats/SelfAwareLogger.scala | 71 ++-- .../log4cats/SelfAwareStructuredLogger.scala | 185 ++++------- .../typelevel/log4cats/StructuredLogger.scala | 185 ++++------- .../log4cats/extras/DeferredLogger.scala | 61 +--- .../DeferredSelfAwareStructuredLogger.scala | 277 +++++----------- .../extras/DeferredStructuredLogger.scala | 193 ++++------- .../log4cats/extras/WriterTLogger.scala | 73 ++--- .../extras/WriterTStructuredLogger.scala | 114 ++----- .../typelevel/log4cats/noop/NoOpLogger.scala | 109 +++--- .../log4cats/console/ConsoleLogger.scala | 29 +- .../slf4j/internal/Slf4jLoggerInternal.scala | 55 +++- .../log4cats/slf4j/internal/JTestLogger.java | 159 +++++++++ .../internal/Slf4jLoggerInternalSuite.scala | 310 +++++++++++++++++- .../testing/StructuredTestingLogger.scala | 93 +++--- .../log4cats/testing/TestingLogger.scala | 57 ++-- .../testing/TestingLoggerFactory.scala | 93 +++--- 20 files changed, 1118 insertions(+), 1213 deletions(-) create mode 100644 slf4j/src/test/scala/org/typelevel/log4cats/slf4j/internal/JTestLogger.java diff --git a/core/shared/src/main/scala/org/typelevel/log4cats/ErrorLogger.scala b/core/shared/src/main/scala/org/typelevel/log4cats/ErrorLogger.scala index 0b5ecc0f..dec36b69 100644 --- a/core/shared/src/main/scala/org/typelevel/log4cats/ErrorLogger.scala +++ b/core/shared/src/main/scala/org/typelevel/log4cats/ErrorLogger.scala @@ -16,13 +16,17 @@ package org.typelevel.log4cats -import cats._ +import cats.* +import org.typelevel.log4cats.extras.LogLevel trait ErrorLogger[F[_]] { - def error(t: Throwable)(message: => String): F[Unit] - def warn(t: Throwable)(message: => String): F[Unit] - def info(t: Throwable)(message: => String): F[Unit] - def debug(t: Throwable)(message: => String): F[Unit] - def trace(t: Throwable)(message: => String): F[Unit] + def error(t: Throwable)(message: => String): F[Unit] = log(LogLevel.Error, t, message) + def warn(t: Throwable)(message: => String): F[Unit] = log(LogLevel.Warn, t, message) + def info(t: Throwable)(message: => String): F[Unit] = log(LogLevel.Info, t, message) + def debug(t: Throwable)(message: => String): F[Unit] = log(LogLevel.Debug, t, message) + def trace(t: Throwable)(message: => String): F[Unit] = log(LogLevel.Trace, t, message) + + def log(ll: LogLevel, t: Throwable, msg: => String): F[Unit] + def mapK[G[_]](fk: F ~> G): ErrorLogger[G] = ErrorLogger.mapK(fk)(this) } @@ -32,16 +36,9 @@ object ErrorLogger { private def mapK[G[_], F[_]](f: G ~> F)(logger: ErrorLogger[G]): ErrorLogger[F] = new ErrorLogger[F] { - def error(t: Throwable)(message: => String): F[Unit] = - f(logger.error(t)(message)) - def warn(t: Throwable)(message: => String): F[Unit] = - f(logger.warn(t)(message)) - def info(t: Throwable)(message: => String): F[Unit] = - f(logger.info(t)(message)) - def debug(t: Throwable)(message: => String): F[Unit] = - f(logger.debug(t)(message)) - def trace(t: Throwable)(message: => String): F[Unit] = - f(logger.trace(t)(message)) + override def log(ll: LogLevel, t: Throwable, msg: => String): F[Unit] = f( + logger.log(ll, t, msg) + ) } } diff --git a/core/shared/src/main/scala/org/typelevel/log4cats/Logger.scala b/core/shared/src/main/scala/org/typelevel/log4cats/Logger.scala index f219436e..6b391c61 100644 --- a/core/shared/src/main/scala/org/typelevel/log4cats/Logger.scala +++ b/core/shared/src/main/scala/org/typelevel/log4cats/Logger.scala @@ -16,8 +16,9 @@ package org.typelevel.log4cats -import cats._ +import cats.* import cats.data.{EitherT, Kleisli, OptionT} +import org.typelevel.log4cats.extras.LogLevel trait Logger[F[_]] extends MessageLogger[F] with ErrorLogger[F] { def withModifiedString(f: String => String): Logger[F] = Logger.withModifiedString[F](this, f) @@ -25,7 +26,7 @@ trait Logger[F[_]] extends MessageLogger[F] with ErrorLogger[F] { } object Logger { - def apply[F[_]](implicit ev: Logger[F]) = ev + def apply[F[_]](implicit ev: Logger[F]): Logger[F] = ev implicit def optionTLogger[F[_]: Logger: Functor]: Logger[OptionT[F, *]] = Logger[F].mapK(OptionT.liftK[F]) @@ -38,40 +39,16 @@ object Logger { private def withModifiedString[F[_]](l: Logger[F], f: String => String): Logger[F] = new Logger[F] { - def error(message: => String): F[Unit] = l.error(f(message)) - def error(t: Throwable)(message: => String): F[Unit] = l.error(t)(f(message)) - def warn(message: => String): F[Unit] = l.warn(f(message)) - def warn(t: Throwable)(message: => String): F[Unit] = l.warn(t)(f(message)) - def info(message: => String): F[Unit] = l.info(f(message)) - def info(t: Throwable)(message: => String): F[Unit] = l.info(t)(f(message)) - def debug(message: => String): F[Unit] = l.debug(f(message)) - def debug(t: Throwable)(message: => String): F[Unit] = l.debug(t)(f(message)) - def trace(message: => String): F[Unit] = l.trace(f(message)) - def trace(t: Throwable)(message: => String): F[Unit] = l.trace(t)(f(message)) + override def log(ll: LogLevel, t: Throwable, msg: => String): F[Unit] = l.log(ll, t, f(msg)) + override def log(ll: LogLevel, msg: => String): F[Unit] = l.log(ll, f(msg)) } private def mapK[G[_], F[_]](f: G ~> F)(logger: Logger[G]): Logger[F] = new Logger[F] { - def error(t: Throwable)(message: => String): F[Unit] = - f(logger.error(t)(message)) - def warn(t: Throwable)(message: => String): F[Unit] = - f(logger.warn(t)(message)) - def info(t: Throwable)(message: => String): F[Unit] = - f(logger.info(t)(message)) - def debug(t: Throwable)(message: => String): F[Unit] = - f(logger.debug(t)(message)) - def trace(t: Throwable)(message: => String): F[Unit] = - f(logger.trace(t)(message)) - def error(message: => String): F[Unit] = - f(logger.error(message)) - def warn(message: => String): F[Unit] = - f(logger.warn(message)) - def info(message: => String): F[Unit] = - f(logger.info(message)) - def debug(message: => String): F[Unit] = - f(logger.debug(message)) - def trace(message: => String): F[Unit] = - f(logger.trace(message)) + override def log(ll: LogLevel, t: Throwable, msg: => String): F[Unit] = f( + logger.log(ll, t, msg) + ) + override def log(ll: LogLevel, msg: => String): F[Unit] = f(logger.log(ll, msg)) } } diff --git a/core/shared/src/main/scala/org/typelevel/log4cats/MessageLogger.scala b/core/shared/src/main/scala/org/typelevel/log4cats/MessageLogger.scala index d6c8de14..54121037 100644 --- a/core/shared/src/main/scala/org/typelevel/log4cats/MessageLogger.scala +++ b/core/shared/src/main/scala/org/typelevel/log4cats/MessageLogger.scala @@ -16,14 +16,18 @@ package org.typelevel.log4cats -import cats._ +import cats.* +import org.typelevel.log4cats.extras.LogLevel trait MessageLogger[F[_]] { - def error(message: => String): F[Unit] - def warn(message: => String): F[Unit] - def info(message: => String): F[Unit] - def debug(message: => String): F[Unit] - def trace(message: => String): F[Unit] + def error(message: => String): F[Unit] = log(LogLevel.Error, message) + def warn(message: => String): F[Unit] = log(LogLevel.Warn, message) + def info(message: => String): F[Unit] = log(LogLevel.Info, message) + def debug(message: => String): F[Unit] = log(LogLevel.Debug, message) + def trace(message: => String): F[Unit] = log(LogLevel.Trace, message) + + def log(ll: LogLevel, msg: => String): F[Unit] + def mapK[G[_]](fk: F ~> G): MessageLogger[G] = MessageLogger.mapK(fk)(this) } @@ -33,15 +37,6 @@ object MessageLogger { private def mapK[G[_], F[_]](f: G ~> F)(logger: MessageLogger[G]): MessageLogger[F] = new MessageLogger[F] { - def error(message: => String): F[Unit] = - f(logger.error(message)) - def warn(message: => String): F[Unit] = - f(logger.warn(message)) - def info(message: => String): F[Unit] = - f(logger.info(message)) - def debug(message: => String): F[Unit] = - f(logger.debug(message)) - def trace(message: => String): F[Unit] = - f(logger.trace(message)) + override def log(ll: LogLevel, msg: => String): F[Unit] = f(logger.log(ll, msg)) } } diff --git a/core/shared/src/main/scala/org/typelevel/log4cats/PagingSelfAwareStructuredLogger.scala b/core/shared/src/main/scala/org/typelevel/log4cats/PagingSelfAwareStructuredLogger.scala index 5ab16662..e2e92771 100644 --- a/core/shared/src/main/scala/org/typelevel/log4cats/PagingSelfAwareStructuredLogger.scala +++ b/core/shared/src/main/scala/org/typelevel/log4cats/PagingSelfAwareStructuredLogger.scala @@ -16,9 +16,10 @@ package org.typelevel.log4cats -import cats._ +import cats.* import cats.effect.std.UUIDGen -import cats.syntax.all._ +import cats.syntax.all.* +import org.typelevel.log4cats.extras.LogLevel import java.io.{PrintWriter, StringWriter} import java.util.UUID @@ -87,15 +88,14 @@ object PagingSelfAwareStructuredLogger { private val pageSize = pageSizeK * 1024 private def pagedLogging( - logOpWithCtx: Map[String, String] => (=> String) => F[Unit], - ctx: Map[String, String], - logSplitId: String, - msg: => String + logLevel: LogLevel, + ctx: Map[String, String], + logSplitId: String, + msg: String ): F[Unit] = { val numOfPagesRaw = (msg.length - 1) / pageSize + 1 val numOfPages = Math.min(numOfPagesRaw, maxPageNeeded) - if (numOfPages <= 1) - logOpWithCtx(addPageCtx(msg, 1, 1, ctx))(msg) + if (numOfPages <= 1) sl.log(logLevel, addPageCtx(msg, 1, 1, ctx), msg) else { val logSplitIdPart1 = logSplitId.split('-').head val pageHeaderTail = s"$numOfPages $logSplitIdPart1" @@ -112,66 +112,55 @@ object PagingSelfAwareStructuredLogger { | |Page $pi/$pageFooterTail""".stripMargin - logOpWithCtx(addPageCtx(page, pi, numOfPages, ctx))(page) + sl.log(logLevel, addPageCtx(page, pi, numOfPages, ctx), page) } } } - private def addMsgCtx( - msg: => String, - ctx: Map[String, String] - ): F[(String, Map[String, String])] = + private def addMsgCtx(msg: String, ctx: Map[String, String]): F[(String, Map[String, String])] = randomUUID.map { uuid => val logSplitId = uuid.show - val msgLength = msg.length.show + val msgLength = s"${msg.length}" ( logSplitId, ctx .updated(logSplitIdN, logSplitId) - .updated("page_size", s"${pageSizeK.show} Kib") + .updated("page_size", s"$pageSizeK Kib") .updated("whole_message_size_bytes", msgLength) // The following is deprecated - .updated("log_size", s"${msgLength} Byte") + .updated("log_size", s"$msgLength Byte") ) } private def addPageCtx( - page: => String, - pageNum: => Int, - totalPages: => Int, + page: String, + pageNum: Int, + totalPages: Int, ctx: Map[String, String] ): Map[String, String] = ctx - .updated("total_pages", totalPages.show) - .updated("page_num", pageNum.show) - .updated("log_size_bytes", page.length.show) - - private def doLogging( - loggingLevelChk: => F[Boolean], - logOpWithCtx: Map[String, String] => (=> String) => F[Unit], - msg: => String, - ctx: Map[String, String] = Map() - ): F[Unit] = { - loggingLevelChk.ifM( - addMsgCtx(msg, ctx).flatMap { case (logSplitId, newCtx) => - pagedLogging(logOpWithCtx, newCtx, logSplitId, msg) - }, - Applicative[F].unit - ) - } + .updated("total_pages", s"$totalPages") + .updated("page_num", s"$pageNum") + .updated("log_size_bytes", s"${page.length}") + + private def doLogging(logLevel: LogLevel, ctx: Map[String, String], msg: => String): F[Unit] = + sl.isEnabled(logLevel) + .ifM( + { + val cachedMsg = msg + addMsgCtx(cachedMsg, ctx).flatMap { case (logSplitId, newCtx) => + pagedLogging(logLevel, newCtx, logSplitId, cachedMsg) + } + }, + Applicative[F].unit + ) private def doLoggingThrowable( - loggingLevelChk: => F[Boolean], - logOpWithCtx: Map[String, String] => (=> String) => F[Unit], - t: Throwable, - msg: => String, - ctx: Map[String, String] = Map() - ): F[Unit] = { - loggingLevelChk.ifM( - doLogging(loggingLevelChk, logOpWithCtx, s"$msg\n${getStackTrace(t)}", ctx), - Applicative[F].unit - ) - } + logLevel: LogLevel, + ctx: Map[String, String], + t: Throwable, + msg: => String + ): F[Unit] = doLogging(logLevel, ctx, s"$msg\n${getStackTrace(t)}") def getStackTrace(t: Throwable): String = { val sw = new StringWriter() @@ -180,82 +169,23 @@ object PagingSelfAwareStructuredLogger { sw.getBuffer.toString } - override def isTraceEnabled: F[Boolean] = sl.isTraceEnabled - - override def isDebugEnabled: F[Boolean] = sl.isDebugEnabled - - override def isInfoEnabled: F[Boolean] = sl.isInfoEnabled - - override def isWarnEnabled: F[Boolean] = sl.isWarnEnabled - - override def isErrorEnabled: F[Boolean] = sl.isErrorEnabled - - // Log message - - override def trace(msg: => String): F[Unit] = - doLogging(isTraceEnabled, sl.trace, msg) - - override def debug(msg: => String): F[Unit] = - doLogging(isDebugEnabled, sl.debug, msg) - - override def info(msg: => String): F[Unit] = - doLogging(isInfoEnabled, sl.info, msg) - - override def warn(msg: => String): F[Unit] = - doLogging(isWarnEnabled, sl.warn, msg) - - override def error(msg: => String): F[Unit] = - doLogging(isErrorEnabled, sl.error, msg) - - // Log message and throwable - - override def trace(t: Throwable)(msg: => String): F[Unit] = - doLoggingThrowable(isTraceEnabled, sl.trace, t, msg) - - override def debug(t: Throwable)(msg: => String): F[Unit] = - doLoggingThrowable(isDebugEnabled, sl.debug, t, msg) - - override def info(t: Throwable)(msg: => String): F[Unit] = - doLoggingThrowable(isInfoEnabled, sl.info, t, msg) - - override def warn(t: Throwable)(msg: => String): F[Unit] = - doLoggingThrowable(isWarnEnabled, sl.warn, t, msg) - - override def error(t: Throwable)(msg: => String): F[Unit] = - doLoggingThrowable(isErrorEnabled, sl.error, t, msg) - - // Log message, passing context - - override def trace(ctx: Map[String, String])(msg: => String): F[Unit] = - doLogging(isTraceEnabled, sl.trace, msg, ctx) - - override def debug(ctx: Map[String, String])(msg: => String): F[Unit] = - doLogging(isDebugEnabled, sl.debug, msg, ctx) - - override def info(ctx: Map[String, String])(msg: => String): F[Unit] = - doLogging(isInfoEnabled, sl.info, msg, ctx) - - override def warn(ctx: Map[String, String])(msg: => String): F[Unit] = - doLogging(isWarnEnabled, sl.warn, msg, ctx) - - override def error(ctx: Map[String, String])(msg: => String): F[Unit] = - doLogging(isErrorEnabled, sl.error, msg, ctx) - - // Log message and throwable, passing context - - override def trace(ctx: Map[String, String], t: Throwable)(msg: => String): F[Unit] = - doLoggingThrowable(isTraceEnabled, sl.trace, t, msg, ctx) + override def isEnabled(ll: LogLevel): F[Boolean] = sl.isEnabled(ll) - override def debug(ctx: Map[String, String], t: Throwable)(msg: => String): F[Unit] = - doLoggingThrowable(isDebugEnabled, sl.debug, t, msg, ctx) + override def log(ll: LogLevel, msg: => String): F[Unit] = + doLogging(ll, Map.empty, msg) - override def info(ctx: Map[String, String], t: Throwable)(msg: => String): F[Unit] = - doLoggingThrowable(isInfoEnabled, sl.info, t, msg, ctx) + override def log(ll: LogLevel, t: Throwable, msg: => String): F[Unit] = + doLoggingThrowable(ll, Map.empty, t, msg) - override def warn(ctx: Map[String, String], t: Throwable)(msg: => String): F[Unit] = - doLoggingThrowable(isWarnEnabled, sl.warn, t, msg, ctx) + override def log(ll: LogLevel, ctx: Map[String, String], msg: => String): F[Unit] = + doLogging(ll, ctx, msg) - override def error(ctx: Map[String, String], t: Throwable)(msg: => String): F[Unit] = - doLoggingThrowable(isErrorEnabled, sl.error, t, msg, ctx) + override def log( + ll: LogLevel, + ctx: Map[String, String], + t: Throwable, + msg: => String + ): F[Unit] = + doLoggingThrowable(ll, ctx, t, msg) } } diff --git a/core/shared/src/main/scala/org/typelevel/log4cats/SelfAwareLogger.scala b/core/shared/src/main/scala/org/typelevel/log4cats/SelfAwareLogger.scala index 7c85caa2..13733e88 100644 --- a/core/shared/src/main/scala/org/typelevel/log4cats/SelfAwareLogger.scala +++ b/core/shared/src/main/scala/org/typelevel/log4cats/SelfAwareLogger.scala @@ -16,14 +16,18 @@ package org.typelevel.log4cats -import cats._ +import cats.* +import org.typelevel.log4cats.extras.LogLevel trait SelfAwareLogger[F[_]] extends Logger[F] { - def isTraceEnabled: F[Boolean] - def isDebugEnabled: F[Boolean] - def isInfoEnabled: F[Boolean] - def isWarnEnabled: F[Boolean] - def isErrorEnabled: F[Boolean] + def isTraceEnabled: F[Boolean] = isEnabled(LogLevel.Trace) + def isDebugEnabled: F[Boolean] = isEnabled(LogLevel.Debug) + def isInfoEnabled: F[Boolean] = isEnabled(LogLevel.Info) + def isWarnEnabled: F[Boolean] = isEnabled(LogLevel.Warn) + def isErrorEnabled: F[Boolean] = isEnabled(LogLevel.Error) + + def isEnabled(ll: LogLevel): F[Boolean] + override def mapK[G[_]](fk: F ~> G): SelfAwareLogger[G] = SelfAwareLogger.mapK(fk)(this) override def withModifiedString(f: String => String): SelfAwareLogger[F] = @@ -34,37 +38,11 @@ object SelfAwareLogger { private def mapK[G[_], F[_]](f: G ~> F)(logger: SelfAwareLogger[G]): SelfAwareLogger[F] = new SelfAwareLogger[F] { - def isTraceEnabled: F[Boolean] = - f(logger.isTraceEnabled) - def isDebugEnabled: F[Boolean] = - f(logger.isDebugEnabled) - def isInfoEnabled: F[Boolean] = - f(logger.isInfoEnabled) - def isWarnEnabled: F[Boolean] = - f(logger.isWarnEnabled) - def isErrorEnabled: F[Boolean] = - f(logger.isErrorEnabled) - - def error(t: Throwable)(message: => String): F[Unit] = - f(logger.error(t)(message)) - def warn(t: Throwable)(message: => String): F[Unit] = - f(logger.warn(t)(message)) - def info(t: Throwable)(message: => String): F[Unit] = - f(logger.info(t)(message)) - def debug(t: Throwable)(message: => String): F[Unit] = - f(logger.debug(t)(message)) - def trace(t: Throwable)(message: => String): F[Unit] = - f(logger.trace(t)(message)) - def error(message: => String): F[Unit] = - f(logger.error(message)) - def warn(message: => String): F[Unit] = - f(logger.warn(message)) - def info(message: => String): F[Unit] = - f(logger.info(message)) - def debug(message: => String): F[Unit] = - f(logger.debug(message)) - def trace(message: => String): F[Unit] = - f(logger.trace(message)) + override def isEnabled(ll: LogLevel): F[Boolean] = f(logger.isEnabled(ll)) + override def log(ll: LogLevel, t: Throwable, msg: => String): F[Unit] = f( + logger.log(ll, t, msg) + ) + override def log(ll: LogLevel, msg: => String): F[Unit] = f(logger.log(ll, msg)) } private def withModifiedString[F[_]]( @@ -72,21 +50,10 @@ object SelfAwareLogger { f: String => String ): SelfAwareLogger[F] = new SelfAwareLogger[F] { - override def isTraceEnabled: F[Boolean] = l.isTraceEnabled - override def isDebugEnabled: F[Boolean] = l.isDebugEnabled - override def isInfoEnabled: F[Boolean] = l.isInfoEnabled - override def isWarnEnabled: F[Boolean] = l.isWarnEnabled - override def isErrorEnabled: F[Boolean] = l.isErrorEnabled + override def isEnabled(ll: LogLevel): F[Boolean] = l.isEnabled(ll) + + override def log(ll: LogLevel, t: Throwable, msg: => String): F[Unit] = l.log(ll, t, f(msg)) - override def error(message: => String): F[Unit] = l.error(f(message)) - override def error(t: Throwable)(message: => String): F[Unit] = l.error(t)(f(message)) - override def warn(message: => String): F[Unit] = l.warn(f(message)) - override def warn(t: Throwable)(message: => String): F[Unit] = l.warn(t)(f(message)) - override def info(message: => String): F[Unit] = l.info(f(message)) - override def info(t: Throwable)(message: => String): F[Unit] = l.info(t)(f(message)) - override def debug(message: => String): F[Unit] = l.debug(f(message)) - override def debug(t: Throwable)(message: => String): F[Unit] = l.debug(t)(f(message)) - override def trace(message: => String): F[Unit] = l.trace(f(message)) - override def trace(t: Throwable)(message: => String): F[Unit] = l.trace(t)(f(message)) + override def log(ll: LogLevel, msg: => String): F[Unit] = l.log(ll, f(msg)) } } diff --git a/core/shared/src/main/scala/org/typelevel/log4cats/SelfAwareStructuredLogger.scala b/core/shared/src/main/scala/org/typelevel/log4cats/SelfAwareStructuredLogger.scala index f143960a..d92021d4 100644 --- a/core/shared/src/main/scala/org/typelevel/log4cats/SelfAwareStructuredLogger.scala +++ b/core/shared/src/main/scala/org/typelevel/log4cats/SelfAwareStructuredLogger.scala @@ -16,8 +16,9 @@ package org.typelevel.log4cats -import cats._ +import cats.* import cats.Show.Shown +import org.typelevel.log4cats.extras.LogLevel trait SelfAwareStructuredLogger[F[_]] extends SelfAwareLogger[F] with StructuredLogger[F] { override def mapK[G[_]](fk: F ~> G): SelfAwareStructuredLogger[G] = @@ -49,49 +50,25 @@ object SelfAwareStructuredLogger { modify: Map[String, String] => Map[String, String] ) extends SelfAwareStructuredLogger[F] { private lazy val defaultCtx: Map[String, String] = modify(Map.empty) - def error(message: => String): F[Unit] = sl.error(defaultCtx)(message) - def warn(message: => String): F[Unit] = sl.warn(defaultCtx)(message) - def info(message: => String): F[Unit] = sl.info(defaultCtx)(message) - def debug(message: => String): F[Unit] = sl.debug(defaultCtx)(message) - def trace(message: => String): F[Unit] = sl.trace(defaultCtx)(message) - def trace(ctx: Map[String, String])(msg: => String): F[Unit] = - sl.trace(modify(ctx))(msg) - def debug(ctx: Map[String, String])(msg: => String): F[Unit] = - sl.debug(modify(ctx))(msg) - def info(ctx: Map[String, String])(msg: => String): F[Unit] = - sl.info(modify(ctx))(msg) - def warn(ctx: Map[String, String])(msg: => String): F[Unit] = - sl.warn(modify(ctx))(msg) - def error(ctx: Map[String, String])(msg: => String): F[Unit] = - sl.error(modify(ctx))(msg) - - def isTraceEnabled: F[Boolean] = sl.isTraceEnabled - def isDebugEnabled: F[Boolean] = sl.isDebugEnabled - def isInfoEnabled: F[Boolean] = sl.isInfoEnabled - def isWarnEnabled: F[Boolean] = sl.isWarnEnabled - def isErrorEnabled: F[Boolean] = sl.isErrorEnabled - - def error(t: Throwable)(message: => String): F[Unit] = - sl.error(defaultCtx, t)(message) - def warn(t: Throwable)(message: => String): F[Unit] = - sl.warn(defaultCtx, t)(message) - def info(t: Throwable)(message: => String): F[Unit] = - sl.info(defaultCtx, t)(message) - def debug(t: Throwable)(message: => String): F[Unit] = - sl.debug(defaultCtx, t)(message) - def trace(t: Throwable)(message: => String): F[Unit] = - sl.trace(defaultCtx, t)(message) - - def error(ctx: Map[String, String], t: Throwable)(message: => String): F[Unit] = - sl.error(modify(ctx), t)(message) - def warn(ctx: Map[String, String], t: Throwable)(message: => String): F[Unit] = - sl.warn(modify(ctx), t)(message) - def info(ctx: Map[String, String], t: Throwable)(message: => String): F[Unit] = - sl.info(modify(ctx), t)(message) - def debug(ctx: Map[String, String], t: Throwable)(message: => String): F[Unit] = - sl.debug(modify(ctx), t)(message) - def trace(ctx: Map[String, String], t: Throwable)(message: => String): F[Unit] = - sl.trace(modify(ctx), t)(message) + + override def log(ll: LogLevel, ctx: Map[String, String], msg: => String): F[Unit] = + sl.log(ll, modify(ctx), msg) + + override def log( + ll: LogLevel, + ctx: Map[String, String], + t: Throwable, + msg: => String + ): F[Unit] = + sl.log(ll, modify(ctx), t, msg) + + override def log(ll: LogLevel, t: Throwable, msg: => String): F[Unit] = + sl.log(ll, defaultCtx, t, msg) + + override def log(ll: LogLevel, msg: => String): F[Unit] = + sl.log(ll, defaultCtx, msg) + + override def isEnabled(ll: LogLevel): F[Boolean] = sl.isEnabled(ll) } private def withModifiedString[F[_]]( @@ -99,95 +76,47 @@ object SelfAwareStructuredLogger { f: String => String ): SelfAwareStructuredLogger[F] = new SelfAwareStructuredLogger[F] { - def isTraceEnabled: F[Boolean] = l.isTraceEnabled - def isDebugEnabled: F[Boolean] = l.isDebugEnabled - def isInfoEnabled: F[Boolean] = l.isInfoEnabled - def isWarnEnabled: F[Boolean] = l.isWarnEnabled - def isErrorEnabled: F[Boolean] = l.isErrorEnabled - - override def trace(ctx: Map[String, String])(msg: => String): F[Unit] = l.trace(ctx)(f(msg)) - override def trace(ctx: Map[String, String], t: Throwable)(msg: => String): F[Unit] = - l.trace(ctx, t)(f(msg)) - override def debug(ctx: Map[String, String])(msg: => String): F[Unit] = l.debug(ctx)(f(msg)) - override def debug(ctx: Map[String, String], t: Throwable)(msg: => String): F[Unit] = - l.debug(ctx, t)(f(msg)) - override def info(ctx: Map[String, String])(msg: => String): F[Unit] = l.info(ctx)(f(msg)) - override def info(ctx: Map[String, String], t: Throwable)(msg: => String): F[Unit] = - l.info(ctx, t)(f(msg)) - override def warn(ctx: Map[String, String])(msg: => String): F[Unit] = l.warn(ctx)(f(msg)) - override def warn(ctx: Map[String, String], t: Throwable)(msg: => String): F[Unit] = - l.warn(ctx, t)(f(msg)) - override def error(ctx: Map[String, String])(msg: => String): F[Unit] = l.error(ctx)(f(msg)) - override def error(ctx: Map[String, String], t: Throwable)(msg: => String): F[Unit] = - l.error(ctx, t)(f(msg)) - override def error(message: => String): F[Unit] = l.error(f(message)) - override def error(t: Throwable)(message: => String): F[Unit] = l.error(t)(f(message)) - override def warn(message: => String): F[Unit] = l.warn(f(message)) - override def warn(t: Throwable)(message: => String): F[Unit] = l.warn(t)(f(message)) - override def info(message: => String): F[Unit] = l.info(f(message)) - override def info(t: Throwable)(message: => String): F[Unit] = l.info(t)(f(message)) - override def debug(message: => String): F[Unit] = l.debug(f(message)) - override def debug(t: Throwable)(message: => String): F[Unit] = l.debug(t)(f(message)) - override def trace(message: => String): F[Unit] = l.trace(f(message)) - override def trace(t: Throwable)(message: => String): F[Unit] = l.trace(t)(f(message)) + override def log(ll: LogLevel, ctx: Map[String, String], msg: => String): F[Unit] = + l.log(ll, ctx, f(msg)) + + override def log( + ll: LogLevel, + ctx: Map[String, String], + t: Throwable, + msg: => String + ): F[Unit] = + l.log(ll, ctx, t, f(msg)) + + override def log(ll: LogLevel, t: Throwable, msg: => String): F[Unit] = + l.log(ll, t, f(msg)) + + override def log(ll: LogLevel, msg: => String): F[Unit] = + l.log(ll, f(msg)) + + override def isEnabled(ll: LogLevel): F[Boolean] = l.isEnabled(ll) } private def mapK[G[_], F[_]]( f: G ~> F )(logger: SelfAwareStructuredLogger[G]): SelfAwareStructuredLogger[F] = new SelfAwareStructuredLogger[F] { - def isTraceEnabled: F[Boolean] = - f(logger.isTraceEnabled) - def isDebugEnabled: F[Boolean] = - f(logger.isDebugEnabled) - def isInfoEnabled: F[Boolean] = - f(logger.isInfoEnabled) - def isWarnEnabled: F[Boolean] = - f(logger.isWarnEnabled) - def isErrorEnabled: F[Boolean] = - f(logger.isErrorEnabled) - - def trace(ctx: Map[String, String])(msg: => String): F[Unit] = - f(logger.trace(ctx)(msg)) - def debug(ctx: Map[String, String])(msg: => String): F[Unit] = - f(logger.debug(ctx)(msg)) - def info(ctx: Map[String, String])(msg: => String): F[Unit] = - f(logger.info(ctx)(msg)) - def warn(ctx: Map[String, String])(msg: => String): F[Unit] = - f(logger.warn(ctx)(msg)) - def error(ctx: Map[String, String])(msg: => String): F[Unit] = - f(logger.error(ctx)(msg)) - - def error(t: Throwable)(message: => String): F[Unit] = - f(logger.error(t)(message)) - def warn(t: Throwable)(message: => String): F[Unit] = - f(logger.warn(t)(message)) - def info(t: Throwable)(message: => String): F[Unit] = - f(logger.info(t)(message)) - def debug(t: Throwable)(message: => String): F[Unit] = - f(logger.debug(t)(message)) - def trace(t: Throwable)(message: => String): F[Unit] = - f(logger.trace(t)(message)) - def error(message: => String): F[Unit] = - f(logger.error(message)) - def warn(message: => String): F[Unit] = - f(logger.warn(message)) - def info(message: => String): F[Unit] = - f(logger.info(message)) - def debug(message: => String): F[Unit] = - f(logger.debug(message)) - def trace(message: => String): F[Unit] = - f(logger.trace(message)) - - def trace(ctx: Map[String, String], t: Throwable)(msg: => String): F[Unit] = - f(logger.trace(ctx, t)(msg)) - def debug(ctx: Map[String, String], t: Throwable)(msg: => String): F[Unit] = - f(logger.debug(ctx, t)(msg)) - def info(ctx: Map[String, String], t: Throwable)(msg: => String): F[Unit] = - f(logger.info(ctx, t)(msg)) - def warn(ctx: Map[String, String], t: Throwable)(msg: => String): F[Unit] = - f(logger.warn(ctx, t)(msg)) - def error(ctx: Map[String, String], t: Throwable)(msg: => String): F[Unit] = - f(logger.error(ctx, t)(msg)) + override def log(ll: LogLevel, ctx: Map[String, String], msg: => String): F[Unit] = + f(logger.log(ll, ctx, msg)) + + override def log( + ll: LogLevel, + ctx: Map[String, String], + t: Throwable, + msg: => String + ): F[Unit] = + f(logger.log(ll, ctx, t, msg)) + + override def log(ll: LogLevel, t: Throwable, msg: => String): F[Unit] = + f(logger.log(ll, t, msg)) + + override def log(ll: LogLevel, msg: => String): F[Unit] = + f(logger.log(ll, msg)) + + override def isEnabled(ll: LogLevel): F[Boolean] = f(logger.isEnabled(ll)) } } diff --git a/core/shared/src/main/scala/org/typelevel/log4cats/StructuredLogger.scala b/core/shared/src/main/scala/org/typelevel/log4cats/StructuredLogger.scala index 14abbbe9..c1526be2 100644 --- a/core/shared/src/main/scala/org/typelevel/log4cats/StructuredLogger.scala +++ b/core/shared/src/main/scala/org/typelevel/log4cats/StructuredLogger.scala @@ -16,20 +16,30 @@ package org.typelevel.log4cats -import cats._ +import cats.* import cats.Show.Shown +import org.typelevel.log4cats.extras.LogLevel trait StructuredLogger[F[_]] extends Logger[F] { - def trace(ctx: Map[String, String])(msg: => String): F[Unit] - def trace(ctx: Map[String, String], t: Throwable)(msg: => String): F[Unit] - def debug(ctx: Map[String, String])(msg: => String): F[Unit] - def debug(ctx: Map[String, String], t: Throwable)(msg: => String): F[Unit] - def info(ctx: Map[String, String])(msg: => String): F[Unit] - def info(ctx: Map[String, String], t: Throwable)(msg: => String): F[Unit] - def warn(ctx: Map[String, String])(msg: => String): F[Unit] - def warn(ctx: Map[String, String], t: Throwable)(msg: => String): F[Unit] - def error(ctx: Map[String, String])(msg: => String): F[Unit] - def error(ctx: Map[String, String], t: Throwable)(msg: => String): F[Unit] + def trace(ctx: Map[String, String])(msg: => String): F[Unit] = log(LogLevel.Trace, ctx, msg) + def trace(ctx: Map[String, String], t: Throwable)(msg: => String): F[Unit] = + log(LogLevel.Trace, ctx, t, msg) + def debug(ctx: Map[String, String])(msg: => String): F[Unit] = log(LogLevel.Debug, ctx, msg) + def debug(ctx: Map[String, String], t: Throwable)(msg: => String): F[Unit] = + log(LogLevel.Debug, ctx, t, msg) + def info(ctx: Map[String, String])(msg: => String): F[Unit] = log(LogLevel.Info, ctx, msg) + def info(ctx: Map[String, String], t: Throwable)(msg: => String): F[Unit] = + log(LogLevel.Info, ctx, t, msg) + def warn(ctx: Map[String, String])(msg: => String): F[Unit] = log(LogLevel.Warn, ctx, msg) + def warn(ctx: Map[String, String], t: Throwable)(msg: => String): F[Unit] = + log(LogLevel.Warn, ctx, t, msg) + def error(ctx: Map[String, String])(msg: => String): F[Unit] = log(LogLevel.Error, ctx, msg) + def error(ctx: Map[String, String], t: Throwable)(msg: => String): F[Unit] = + log(LogLevel.Error, ctx, t, msg) + + def log(ll: LogLevel, ctx: Map[String, String], msg: => String): F[Unit] + def log(ll: LogLevel, ctx: Map[String, String], t: Throwable, msg: => String): F[Unit] + override def mapK[G[_]](fk: F ~> G): StructuredLogger[G] = StructuredLogger.mapK(fk)(this) @@ -62,43 +72,23 @@ object StructuredLogger { modify: Map[String, String] => Map[String, String] ) extends StructuredLogger[F] { private lazy val defaultCtx: Map[String, String] = modify(Map.empty) - def error(message: => String): F[Unit] = sl.error(defaultCtx)(message) - def warn(message: => String): F[Unit] = sl.warn(defaultCtx)(message) - def info(message: => String): F[Unit] = sl.info(defaultCtx)(message) - def debug(message: => String): F[Unit] = sl.debug(defaultCtx)(message) - def trace(message: => String): F[Unit] = sl.trace(defaultCtx)(message) - def trace(ctx: Map[String, String])(msg: => String): F[Unit] = - sl.trace(modify(ctx))(msg) - def debug(ctx: Map[String, String])(msg: => String): F[Unit] = - sl.debug(modify(ctx))(msg) - def info(ctx: Map[String, String])(msg: => String): F[Unit] = - sl.info(modify(ctx))(msg) - def warn(ctx: Map[String, String])(msg: => String): F[Unit] = - sl.warn(modify(ctx))(msg) - def error(ctx: Map[String, String])(msg: => String): F[Unit] = - sl.error(modify(ctx))(msg) - - def error(t: Throwable)(message: => String): F[Unit] = - sl.error(defaultCtx, t)(message) - def warn(t: Throwable)(message: => String): F[Unit] = - sl.warn(defaultCtx, t)(message) - def info(t: Throwable)(message: => String): F[Unit] = - sl.info(defaultCtx, t)(message) - def debug(t: Throwable)(message: => String): F[Unit] = - sl.debug(defaultCtx, t)(message) - def trace(t: Throwable)(message: => String): F[Unit] = - sl.trace(defaultCtx, t)(message) - - def error(ctx: Map[String, String], t: Throwable)(message: => String): F[Unit] = - sl.error(modify(ctx), t)(message) - def warn(ctx: Map[String, String], t: Throwable)(message: => String): F[Unit] = - sl.warn(modify(ctx), t)(message) - def info(ctx: Map[String, String], t: Throwable)(message: => String): F[Unit] = - sl.info(modify(ctx), t)(message) - def debug(ctx: Map[String, String], t: Throwable)(message: => String): F[Unit] = - sl.debug(modify(ctx), t)(message) - def trace(ctx: Map[String, String], t: Throwable)(message: => String): F[Unit] = - sl.trace(modify(ctx), t)(message) + + override def log(ll: LogLevel, ctx: Map[String, String], msg: => String): F[Unit] = + sl.log(ll, modify(ctx), msg) + + override def log( + ll: LogLevel, + ctx: Map[String, String], + t: Throwable, + msg: => String + ): F[Unit] = + sl.log(ll, modify(ctx), t, msg) + + override def log(ll: LogLevel, t: Throwable, msg: => String): F[Unit] = + sl.log(ll, defaultCtx, t, msg) + + override def log(ll: LogLevel, msg: => String): F[Unit] = + sl.log(ll, defaultCtx, msg) } private def withModifiedString[F[_]]( @@ -106,76 +96,41 @@ object StructuredLogger { f: String => String ): StructuredLogger[F] = new StructuredLogger[F] { - override def trace(ctx: Map[String, String])(msg: => String): F[Unit] = l.trace(ctx)(f(msg)) - override def trace(ctx: Map[String, String], t: Throwable)(msg: => String): F[Unit] = - l.trace(ctx, t)(f(msg)) - override def debug(ctx: Map[String, String])(msg: => String): F[Unit] = l.debug(ctx)(f(msg)) - override def debug(ctx: Map[String, String], t: Throwable)(msg: => String): F[Unit] = - l.debug(ctx, t)(f(msg)) - override def info(ctx: Map[String, String])(msg: => String): F[Unit] = l.info(ctx)(f(msg)) - override def info(ctx: Map[String, String], t: Throwable)(msg: => String): F[Unit] = - l.info(ctx, t)(f(msg)) - override def warn(ctx: Map[String, String])(msg: => String): F[Unit] = l.warn(ctx)(f(msg)) - override def warn(ctx: Map[String, String], t: Throwable)(msg: => String): F[Unit] = - l.warn(ctx, t)(f(msg)) - override def error(ctx: Map[String, String])(msg: => String): F[Unit] = l.error(ctx)(f(msg)) - override def error(ctx: Map[String, String], t: Throwable)(msg: => String): F[Unit] = - l.error(ctx, t)(f(msg)) - override def error(message: => String): F[Unit] = l.error(f(message)) - override def error(t: Throwable)(message: => String): F[Unit] = l.error(t)(f(message)) - override def warn(message: => String): F[Unit] = l.warn(f(message)) - override def warn(t: Throwable)(message: => String): F[Unit] = l.warn(t)(f(message)) - override def info(message: => String): F[Unit] = l.info(f(message)) - override def info(t: Throwable)(message: => String): F[Unit] = l.info(t)(f(message)) - override def debug(message: => String): F[Unit] = l.debug(f(message)) - override def debug(t: Throwable)(message: => String): F[Unit] = l.debug(t)(f(message)) - override def trace(message: => String): F[Unit] = l.trace(f(message)) - override def trace(t: Throwable)(message: => String): F[Unit] = l.trace(t)(f(message)) + override def log(ll: LogLevel, ctx: Map[String, String], msg: => String): F[Unit] = + l.log(ll, ctx, f(msg)) + + override def log( + ll: LogLevel, + ctx: Map[String, String], + t: Throwable, + msg: => String + ): F[Unit] = + l.log(ll, ctx, t, f(msg)) + + override def log(ll: LogLevel, t: Throwable, msg: => String): F[Unit] = + l.log(ll, t, f(msg)) + + override def log(ll: LogLevel, msg: => String): F[Unit] = + l.log(ll, f(msg)) } private def mapK[G[_], F[_]](f: G ~> F)(logger: StructuredLogger[G]): StructuredLogger[F] = new StructuredLogger[F] { - def trace(ctx: Map[String, String])(msg: => String): F[Unit] = - f(logger.trace(ctx)(msg)) - def debug(ctx: Map[String, String])(msg: => String): F[Unit] = - f(logger.debug(ctx)(msg)) - def info(ctx: Map[String, String])(msg: => String): F[Unit] = - f(logger.info(ctx)(msg)) - def warn(ctx: Map[String, String])(msg: => String): F[Unit] = - f(logger.warn(ctx)(msg)) - def error(ctx: Map[String, String])(msg: => String): F[Unit] = - f(logger.error(ctx)(msg)) - - def error(t: Throwable)(message: => String): F[Unit] = - f(logger.error(t)(message)) - def warn(t: Throwable)(message: => String): F[Unit] = - f(logger.warn(t)(message)) - def info(t: Throwable)(message: => String): F[Unit] = - f(logger.info(t)(message)) - def debug(t: Throwable)(message: => String): F[Unit] = - f(logger.debug(t)(message)) - def trace(t: Throwable)(message: => String): F[Unit] = - f(logger.trace(t)(message)) - def error(message: => String): F[Unit] = - f(logger.error(message)) - def warn(message: => String): F[Unit] = - f(logger.warn(message)) - def info(message: => String): F[Unit] = - f(logger.info(message)) - def debug(message: => String): F[Unit] = - f(logger.debug(message)) - def trace(message: => String): F[Unit] = - f(logger.trace(message)) - - def trace(ctx: Map[String, String], t: Throwable)(msg: => String): F[Unit] = - f(logger.trace(ctx, t)(msg)) - def debug(ctx: Map[String, String], t: Throwable)(msg: => String): F[Unit] = - f(logger.debug(ctx, t)(msg)) - def info(ctx: Map[String, String], t: Throwable)(msg: => String): F[Unit] = - f(logger.info(ctx, t)(msg)) - def warn(ctx: Map[String, String], t: Throwable)(msg: => String): F[Unit] = - f(logger.warn(ctx, t)(msg)) - def error(ctx: Map[String, String], t: Throwable)(msg: => String): F[Unit] = - f(logger.error(ctx, t)(msg)) + override def log(ll: LogLevel, ctx: Map[String, String], msg: => String): F[Unit] = + f(logger.log(ll, ctx, msg)) + + override def log( + ll: LogLevel, + ctx: Map[String, String], + t: Throwable, + msg: => String + ): F[Unit] = + f(logger.log(ll, ctx, t, msg)) + + override def log(ll: LogLevel, t: Throwable, msg: => String): F[Unit] = + f(logger.log(ll, t, msg)) + + override def log(ll: LogLevel, msg: => String): F[Unit] = + f(logger.log(ll, msg)) } } diff --git a/core/shared/src/main/scala/org/typelevel/log4cats/extras/DeferredLogger.scala b/core/shared/src/main/scala/org/typelevel/log4cats/extras/DeferredLogger.scala index d4c9ab89..308d116e 100644 --- a/core/shared/src/main/scala/org/typelevel/log4cats/extras/DeferredLogger.scala +++ b/core/shared/src/main/scala/org/typelevel/log4cats/extras/DeferredLogger.scala @@ -66,31 +66,15 @@ object DeferredLogger { new DeferredLogger[F] { private def save(lm: DeferredLogMessage): F[Unit] = ref.update(_.append(lm)) - override def trace(t: Throwable)(msg: => String): F[Unit] = - save(DeferredLogMessage.trace(Map.empty, t.some, () => msg)) - override def debug(t: Throwable)(msg: => String): F[Unit] = - save(DeferredLogMessage.debug(Map.empty, t.some, () => msg)) - override def info(t: Throwable)(msg: => String): F[Unit] = - save(DeferredLogMessage.info(Map.empty, t.some, () => msg)) - override def warn(t: Throwable)(msg: => String): F[Unit] = - save(DeferredLogMessage.warn(Map.empty, t.some, () => msg)) - override def error(t: Throwable)(msg: => String): F[Unit] = - save(DeferredLogMessage.error(Map.empty, t.some, () => msg)) - - override def trace(msg: => String): F[Unit] = - save(DeferredLogMessage.trace(Map.empty, none, () => msg)) - override def debug(msg: => String): F[Unit] = - save(DeferredLogMessage.debug(Map.empty, none, () => msg)) - override def info(msg: => String): F[Unit] = - save(DeferredLogMessage.info(Map.empty, none, () => msg)) - override def warn(msg: => String): F[Unit] = - save(DeferredLogMessage.warn(Map.empty, none, () => msg)) - override def error(msg: => String): F[Unit] = - save(DeferredLogMessage.error(Map.empty, none, () => msg)) - override def inspect: F[Chain[DeferredLogMessage]] = ref.get override def log: F[Unit] = ref.getAndSet(Chain.empty).flatMap(_.traverse_(_.log(logger))) + + override def log(ll: LogLevel, t: Throwable, msg: => String): F[Unit] = + save(DeferredLogMessage(ll, Map.empty, t.some, () => msg)) + + override def log(ll: LogLevel, msg: => String): F[Unit] = + save(DeferredLogMessage(ll, Map.empty, none, () => msg)) } } @@ -100,23 +84,14 @@ object DeferredLogger { ): DeferredLogger[G] = new DeferredLogger[G] { override def inspect: G[Chain[DeferredLogMessage]] = fk(logger.inspect) - override def log: G[Unit] = fk(logger.log) - override def trace(t: Throwable)(message: => String): G[Unit] = fk(logger.trace(t)(message)) - override def debug(t: Throwable)(message: => String): G[Unit] = fk(logger.debug(t)(message)) - override def info(t: Throwable)(message: => String): G[Unit] = fk(logger.info(t)(message)) - override def warn(t: Throwable)(message: => String): G[Unit] = fk(logger.warn(t)(message)) - override def error(t: Throwable)(message: => String): G[Unit] = fk(logger.error(t)(message)) + override def log: G[Unit] = fk(logger.log) - override def trace(message: => String): G[Unit] = fk(logger.trace(message)) - override def debug(message: => String): G[Unit] = fk(logger.debug(message)) - override def info(message: => String): G[Unit] = fk(logger.info(message)) - override def warn(message: => String): G[Unit] = fk(logger.warn(message)) - override def error(message: => String): G[Unit] = fk(logger.error(message)) + override def log(ll: LogLevel, t: Throwable, msg: => String): G[Unit] = fk( + logger.log(ll, t, msg) + ) - override def withModifiedString(f: String => String): DeferredLogger[G] = - DeferredLogger.withModifiedString(this, f) - override def mapK[H[_]](fk: G ~> H): DeferredLogger[H] = DeferredLogger.mapK(this, fk) + override def log(ll: LogLevel, msg: => String): G[Unit] = fk(logger.log(ll, msg)) } def withModifiedString[F[_]]( @@ -125,18 +100,12 @@ object DeferredLogger { ): DeferredLogger[F] = new DeferredLogger[F] { override def inspect: F[Chain[DeferredLogMessage]] = logger.inspect + override def log: F[Unit] = logger.log - override def trace(t: Throwable)(message: => String): F[Unit] = logger.trace(t)(f(message)) - override def debug(t: Throwable)(message: => String): F[Unit] = logger.debug(t)(f(message)) - override def info(t: Throwable)(message: => String): F[Unit] = logger.info(t)(f(message)) - override def warn(t: Throwable)(message: => String): F[Unit] = logger.warn(t)(f(message)) - override def error(t: Throwable)(message: => String): F[Unit] = logger.error(t)(f(message)) + override def log(ll: LogLevel, t: Throwable, msg: => String): F[Unit] = + logger.log(ll, t, f(msg)) - override def trace(message: => String): F[Unit] = logger.trace(f(message)) - override def debug(message: => String): F[Unit] = logger.debug(f(message)) - override def info(message: => String): F[Unit] = logger.info(f(message)) - override def warn(message: => String): F[Unit] = logger.warn(f(message)) - override def error(message: => String): F[Unit] = logger.error(f(message)) + override def log(ll: LogLevel, msg: => String): F[Unit] = logger.log(ll, f(msg)) } } diff --git a/core/shared/src/main/scala/org/typelevel/log4cats/extras/DeferredSelfAwareStructuredLogger.scala b/core/shared/src/main/scala/org/typelevel/log4cats/extras/DeferredSelfAwareStructuredLogger.scala index 778305db..c9a0f4d1 100644 --- a/core/shared/src/main/scala/org/typelevel/log4cats/extras/DeferredSelfAwareStructuredLogger.scala +++ b/core/shared/src/main/scala/org/typelevel/log4cats/extras/DeferredSelfAwareStructuredLogger.scala @@ -58,77 +58,11 @@ object DeferredSelfAwareStructuredLogger { stash: Ref[F, Chain[(DeferredLogMessage, SelfAwareStructuredLogger[F])]] ): DeferredSelfAwareStructuredLogger[F] = new DeferredSelfAwareStructuredLogger[F] { + override def isEnabled(ll: LogLevel): F[Boolean] = logger.isEnabled(ll) + private def save(lm: DeferredLogMessage): F[Unit] = stash.update(_.append(lm -> logger)) - override def isTraceEnabled: F[Boolean] = logger.isTraceEnabled - override def isDebugEnabled: F[Boolean] = logger.isDebugEnabled - override def isInfoEnabled: F[Boolean] = logger.isInfoEnabled - override def isWarnEnabled: F[Boolean] = logger.isWarnEnabled - override def isErrorEnabled: F[Boolean] = logger.isErrorEnabled - - private def saveTrace( - c: Map[String, String], - t: Option[Throwable], - m: () => String - ): F[Unit] = - isTraceEnabled.flatMap(save(DeferredLogMessage.trace(c, t, m)).whenA(_)) - private def saveDebug( - c: Map[String, String], - t: Option[Throwable], - m: () => String - ): F[Unit] = - isDebugEnabled.flatMap(save(DeferredLogMessage.debug(c, t, m)).whenA(_)) - private def saveInfo(c: Map[String, String], t: Option[Throwable], m: () => String): F[Unit] = - isInfoEnabled.flatMap(save(DeferredLogMessage.info(c, t, m)).whenA(_)) - private def saveWarn(c: Map[String, String], t: Option[Throwable], m: () => String): F[Unit] = - isWarnEnabled.flatMap(save(DeferredLogMessage.warn(c, t, m)).whenA(_)) - private def saveError( - c: Map[String, String], - t: Option[Throwable], - m: () => String - ): F[Unit] = - isErrorEnabled.flatMap(save(DeferredLogMessage.error(c, t, m)).whenA(_)) - - override def trace(ctx: Map[String, String])(msg: => String): F[Unit] = - saveTrace(ctx, none, () => msg) - override def debug(ctx: Map[String, String])(msg: => String): F[Unit] = - saveDebug(ctx, none, () => msg) - override def info(ctx: Map[String, String])(msg: => String): F[Unit] = - saveInfo(ctx, none, () => msg) - override def warn(ctx: Map[String, String])(msg: => String): F[Unit] = - saveWarn(ctx, none, () => msg) - override def error(ctx: Map[String, String])(msg: => String): F[Unit] = - saveError(ctx, none, () => msg) - - override def trace(ctx: Map[String, String], t: Throwable)(msg: => String): F[Unit] = - saveTrace(ctx, t.some, () => msg) - override def debug(ctx: Map[String, String], t: Throwable)(msg: => String): F[Unit] = - saveDebug(ctx, t.some, () => msg) - override def info(ctx: Map[String, String], t: Throwable)(msg: => String): F[Unit] = - saveInfo(ctx, t.some, () => msg) - override def warn(ctx: Map[String, String], t: Throwable)(msg: => String): F[Unit] = - saveWarn(ctx, t.some, () => msg) - override def error(ctx: Map[String, String], t: Throwable)(msg: => String): F[Unit] = - saveError(ctx, t.some, () => msg) - - override def trace(t: Throwable)(msg: => String): F[Unit] = - saveTrace(Map.empty, t.some, () => msg) - override def debug(t: Throwable)(msg: => String): F[Unit] = - saveDebug(Map.empty, t.some, () => msg) - override def info(t: Throwable)(msg: => String): F[Unit] = - saveInfo(Map.empty, t.some, () => msg) - override def warn(t: Throwable)(msg: => String): F[Unit] = - saveWarn(Map.empty, t.some, () => msg) - override def error(t: Throwable)(msg: => String): F[Unit] = - saveError(Map.empty, t.some, () => msg) - - override def trace(msg: => String): F[Unit] = saveTrace(Map.empty, none, () => msg) - override def debug(msg: => String): F[Unit] = saveDebug(Map.empty, none, () => msg) - override def info(msg: => String): F[Unit] = saveInfo(Map.empty, none, () => msg) - override def warn(msg: => String): F[Unit] = saveWarn(Map.empty, none, () => msg) - override def error(msg: => String): F[Unit] = saveError(Map.empty, none, () => msg) - override def inspect: F[Chain[DeferredLogMessage]] = stash.get.map(_._1F) override def log: F[Unit] = stash @@ -136,6 +70,23 @@ object DeferredSelfAwareStructuredLogger { .flatMap(_.traverse_ { case (msg, logger) => msg.logStructured(logger) }) + + override def log( + ll: LogLevel, + ctx: Map[String, String], + t: Throwable, + msg: => String + ): F[Unit] = + isEnabled(ll).flatMap(save(DeferredLogMessage(ll, ctx, t.some, () => msg)).whenA(_)) + + override def log(ll: LogLevel, ctx: Map[String, String], msg: => String): F[Unit] = + isEnabled(ll).flatMap(save(DeferredLogMessage(ll, ctx, none, () => msg)).whenA(_)) + + override def log(ll: LogLevel, t: Throwable, msg: => String): F[Unit] = + isEnabled(ll).flatMap(save(DeferredLogMessage(ll, Map.empty, t.some, () => msg)).whenA(_)) + + override def log(ll: LogLevel, msg: => String): F[Unit] = + isEnabled(ll).flatMap(save(DeferredLogMessage(ll, Map.empty, none, () => msg)).whenA(_)) } private[extras] def makeCache[F[_]](implicit @@ -156,113 +107,58 @@ object DeferredSelfAwareStructuredLogger { fk: F ~> G ): DeferredSelfAwareStructuredLogger[G] = new DeferredSelfAwareStructuredLogger[G] { - override def inspect: G[Chain[DeferredLogMessage]] = fk( - logger.inspect - ) + override def isEnabled(ll: LogLevel): G[Boolean] = fk(logger.isEnabled(ll)) + + override def inspect: G[Chain[DeferredLogMessage]] = fk(logger.inspect) + override def log: G[Unit] = fk(logger.log) - override def isTraceEnabled: G[Boolean] = fk(logger.isTraceEnabled) - override def isDebugEnabled: G[Boolean] = fk(logger.isDebugEnabled) - override def isInfoEnabled: G[Boolean] = fk(logger.isInfoEnabled) - override def isWarnEnabled: G[Boolean] = fk(logger.isWarnEnabled) - override def isErrorEnabled: G[Boolean] = fk(logger.isErrorEnabled) - - override def trace(ctx: Map[String, String], t: Throwable)(msg: => String): G[Unit] = fk( - logger.trace(ctx, t)(msg) - ) - override def debug(ctx: Map[String, String], t: Throwable)(msg: => String): G[Unit] = fk( - logger.debug(ctx, t)(msg) - ) - override def info(ctx: Map[String, String], t: Throwable)(msg: => String): G[Unit] = fk( - logger.info(ctx, t)(msg) - ) - override def warn(ctx: Map[String, String], t: Throwable)(msg: => String): G[Unit] = fk( - logger.warn(ctx, t)(msg) - ) - override def error(ctx: Map[String, String], t: Throwable)(msg: => String): G[Unit] = fk( - logger.error(ctx, t)(msg) - ) - override def trace(ctx: Map[String, String])(msg: => String): G[Unit] = fk( - logger.trace(ctx)(msg) - ) - override def debug(ctx: Map[String, String])(msg: => String): G[Unit] = fk( - logger.debug(ctx)(msg) - ) - override def info(ctx: Map[String, String])(msg: => String): G[Unit] = fk( - logger.info(ctx)(msg) - ) - override def warn(ctx: Map[String, String])(msg: => String): G[Unit] = fk( - logger.warn(ctx)(msg) - ) - override def error(ctx: Map[String, String])(msg: => String): G[Unit] = fk( - logger.error(ctx)(msg) + override def log( + ll: LogLevel, + ctx: Map[String, String], + t: Throwable, + msg: => String + ): G[Unit] = + fk(logger.log(ll, ctx, t, msg)) + + override def log(ll: LogLevel, ctx: Map[String, String], msg: => String): G[Unit] = + fk(logger.log(ll, ctx, msg)) + + override def log(ll: LogLevel, t: Throwable, msg: => String): G[Unit] = fk( + logger.log(ll, t, msg) ) - override def trace(t: Throwable)(message: => String): G[Unit] = fk(logger.trace(t)(message)) - override def debug(t: Throwable)(message: => String): G[Unit] = fk(logger.debug(t)(message)) - override def info(t: Throwable)(message: => String): G[Unit] = fk(logger.info(t)(message)) - override def warn(t: Throwable)(message: => String): G[Unit] = fk(logger.warn(t)(message)) - override def error(t: Throwable)(message: => String): G[Unit] = fk(logger.error(t)(message)) - - override def trace(message: => String): G[Unit] = fk(logger.trace(message)) - override def debug(message: => String): G[Unit] = fk(logger.debug(message)) - override def info(message: => String): G[Unit] = fk(logger.info(message)) - override def warn(message: => String): G[Unit] = fk(logger.warn(message)) - override def error(message: => String): G[Unit] = fk(logger.error(message)) + override def log(ll: LogLevel, msg: => String): G[Unit] = fk(logger.log(ll, msg)) } def withContext[F[_]]( logger: DeferredSelfAwareStructuredLogger[F] )(baseCtx: Map[String, String]): DeferredSelfAwareStructuredLogger[F] = new DeferredSelfAwareStructuredLogger[F] { - private def addCtx(ctx: Map[String, String]): Map[String, String] = baseCtx ++ ctx + override def isEnabled(ll: LogLevel): F[Boolean] = logger.isEnabled(ll) override def inspect: F[Chain[DeferredLogMessage]] = logger.inspect + override def log: F[Unit] = logger.log - override def isTraceEnabled: F[Boolean] = logger.isTraceEnabled - override def isDebugEnabled: F[Boolean] = logger.isDebugEnabled - override def isInfoEnabled: F[Boolean] = logger.isInfoEnabled - override def isWarnEnabled: F[Boolean] = logger.isWarnEnabled - override def isErrorEnabled: F[Boolean] = logger.isErrorEnabled - - override def trace(ctx: Map[String, String], t: Throwable)(msg: => String): F[Unit] = - logger.trace(addCtx(ctx), t)(msg) - override def debug(ctx: Map[String, String], t: Throwable)(msg: => String): F[Unit] = - logger.debug(addCtx(ctx), t)(msg) - override def info(ctx: Map[String, String], t: Throwable)(msg: => String): F[Unit] = - logger.info(addCtx(ctx), t)(msg) - override def warn(ctx: Map[String, String], t: Throwable)(msg: => String): F[Unit] = - logger.warn(addCtx(ctx), t)(msg) - override def error(ctx: Map[String, String], t: Throwable)(msg: => String): F[Unit] = - logger.error(addCtx(ctx), t)(msg) - - override def trace(ctx: Map[String, String])(msg: => String): F[Unit] = - logger.trace(addCtx(ctx))(msg) - override def debug(ctx: Map[String, String])(msg: => String): F[Unit] = - logger.debug(addCtx(ctx))(msg) - override def info(ctx: Map[String, String])(msg: => String): F[Unit] = - logger.info(addCtx(ctx))(msg) - override def warn(ctx: Map[String, String])(msg: => String): F[Unit] = - logger.warn(addCtx(ctx))(msg) - override def error(ctx: Map[String, String])(msg: => String): F[Unit] = - logger.error(addCtx(ctx))(msg) - - override def trace(t: Throwable)(message: => String): F[Unit] = - logger.trace(baseCtx, t)(message) - override def debug(t: Throwable)(message: => String): F[Unit] = - logger.debug(baseCtx, t)(message) - override def info(t: Throwable)(message: => String): F[Unit] = - logger.info(baseCtx, t)(message) - override def warn(t: Throwable)(message: => String): F[Unit] = - logger.warn(baseCtx, t)(message) - override def error(t: Throwable)(message: => String): F[Unit] = - logger.error(baseCtx, t)(message) - - override def trace(message: => String): F[Unit] = logger.trace(baseCtx)(message) - override def debug(message: => String): F[Unit] = logger.debug(baseCtx)(message) - override def info(message: => String): F[Unit] = logger.info(baseCtx)(message) - override def warn(message: => String): F[Unit] = logger.warn(baseCtx)(message) - override def error(message: => String): F[Unit] = logger.error(baseCtx)(message) + + private def addCtx(ctx: Map[String, String]): Map[String, String] = baseCtx ++ ctx + + override def log( + ll: LogLevel, + ctx: Map[String, String], + t: Throwable, + msg: => String + ): F[Unit] = + logger.log(ll, addCtx(ctx), t, msg) + + override def log(ll: LogLevel, ctx: Map[String, String], msg: => String): F[Unit] = + logger.log(ll, addCtx(ctx), msg) + + override def log(ll: LogLevel, t: Throwable, msg: => String): F[Unit] = + logger.log(ll, t, msg) + + override def log(ll: LogLevel, msg: => String): F[Unit] = + logger.log(ll, msg) } def withModifiedString[F[_]]( @@ -270,46 +166,25 @@ object DeferredSelfAwareStructuredLogger { f: String => String ): DeferredSelfAwareStructuredLogger[F] = new DeferredSelfAwareStructuredLogger[F] { + override def isEnabled(ll: LogLevel): F[Boolean] = logger.isEnabled(ll) + override def inspect: F[Chain[DeferredLogMessage]] = logger.inspect + override def log: F[Unit] = logger.log - override def isTraceEnabled: F[Boolean] = logger.isTraceEnabled - override def isDebugEnabled: F[Boolean] = logger.isDebugEnabled - override def isInfoEnabled: F[Boolean] = logger.isInfoEnabled - override def isWarnEnabled: F[Boolean] = logger.isWarnEnabled - override def isErrorEnabled: F[Boolean] = logger.isErrorEnabled - - override def trace(ctx: Map[String, String], t: Throwable)(msg: => String): F[Unit] = - logger.trace(ctx, t)(f(msg)) - override def debug(ctx: Map[String, String], t: Throwable)(msg: => String): F[Unit] = - logger.debug(ctx, t)(f(msg)) - override def info(ctx: Map[String, String], t: Throwable)(msg: => String): F[Unit] = - logger.info(ctx, t)(f(msg)) - override def warn(ctx: Map[String, String], t: Throwable)(msg: => String): F[Unit] = - logger.warn(ctx, t)(f(msg)) - override def error(ctx: Map[String, String], t: Throwable)(msg: => String): F[Unit] = - logger.error(ctx, t)(f(msg)) - - override def trace(ctx: Map[String, String])(msg: => String): F[Unit] = - logger.trace(ctx)(f(msg)) - override def debug(ctx: Map[String, String])(msg: => String): F[Unit] = - logger.debug(ctx)(f(msg)) - override def info(ctx: Map[String, String])(msg: => String): F[Unit] = - logger.info(ctx)(f(msg)) - override def warn(ctx: Map[String, String])(msg: => String): F[Unit] = - logger.warn(ctx)(f(msg)) - override def error(ctx: Map[String, String])(msg: => String): F[Unit] = - logger.error(ctx)(f(msg)) - - override def trace(t: Throwable)(message: => String): F[Unit] = logger.trace(t)(f(message)) - override def debug(t: Throwable)(message: => String): F[Unit] = logger.debug(t)(f(message)) - override def info(t: Throwable)(message: => String): F[Unit] = logger.info(t)(f(message)) - override def warn(t: Throwable)(message: => String): F[Unit] = logger.warn(t)(f(message)) - override def error(t: Throwable)(message: => String): F[Unit] = logger.error(t)(f(message)) - - override def trace(message: => String): F[Unit] = logger.trace(f(message)) - override def debug(message: => String): F[Unit] = logger.debug(f(message)) - override def info(message: => String): F[Unit] = logger.info(f(message)) - override def warn(message: => String): F[Unit] = logger.warn(f(message)) - override def error(message: => String): F[Unit] = logger.error(f(message)) + + override def log( + ll: LogLevel, + ctx: Map[String, String], + t: Throwable, + msg: => String + ): F[Unit] = logger.log(ll, ctx, t, f(msg)) + + override def log(ll: LogLevel, ctx: Map[String, String], msg: => String): F[Unit] = + logger.log(ll, ctx, f(msg)) + + override def log(ll: LogLevel, t: Throwable, msg: => String): F[Unit] = + logger.log(ll, t, f(msg)) + + override def log(ll: LogLevel, msg: => String): F[Unit] = logger.log(ll, f(msg)) } } diff --git a/core/shared/src/main/scala/org/typelevel/log4cats/extras/DeferredStructuredLogger.scala b/core/shared/src/main/scala/org/typelevel/log4cats/extras/DeferredStructuredLogger.scala index a1966a91..98b2c114 100644 --- a/core/shared/src/main/scala/org/typelevel/log4cats/extras/DeferredStructuredLogger.scala +++ b/core/shared/src/main/scala/org/typelevel/log4cats/extras/DeferredStructuredLogger.scala @@ -79,54 +79,27 @@ object DeferredStructuredLogger { new DeferredStructuredLogger[F] { private def save(lm: DeferredLogMessage): F[Unit] = ref.update(_.append(lm)) - override def trace(ctx: Map[String, String])(msg: => String): F[Unit] = - save(DeferredLogMessage.trace(ctx, none, () => msg)) - override def debug(ctx: Map[String, String])(msg: => String): F[Unit] = - save(DeferredLogMessage.debug(ctx, none, () => msg)) - override def info(ctx: Map[String, String])(msg: => String): F[Unit] = - save(DeferredLogMessage.info(ctx, none, () => msg)) - override def warn(ctx: Map[String, String])(msg: => String): F[Unit] = - save(DeferredLogMessage.warn(ctx, none, () => msg)) - override def error(ctx: Map[String, String])(msg: => String): F[Unit] = - save(DeferredLogMessage.error(ctx, none, () => msg)) + override def inspect: F[Chain[DeferredLogMessage]] = ref.get - override def trace(ctx: Map[String, String], t: Throwable)(msg: => String): F[Unit] = - save(DeferredLogMessage.trace(ctx, t.some, () => msg)) - override def debug(ctx: Map[String, String], t: Throwable)(msg: => String): F[Unit] = - save(DeferredLogMessage.debug(ctx, t.some, () => msg)) - override def info(ctx: Map[String, String], t: Throwable)(msg: => String): F[Unit] = - save(DeferredLogMessage.info(ctx, t.some, () => msg)) - override def warn(ctx: Map[String, String], t: Throwable)(msg: => String): F[Unit] = - save(DeferredLogMessage.warn(ctx, t.some, () => msg)) - override def error(ctx: Map[String, String], t: Throwable)(msg: => String): F[Unit] = - save(DeferredLogMessage.error(ctx, t.some, () => msg)) + override def log: F[Unit] = + ref.getAndSet(Chain.empty).flatMap(_.traverse_(_.logStructured(logger))) - override def trace(t: Throwable)(msg: => String): F[Unit] = - save(DeferredLogMessage.trace(Map.empty, t.some, () => msg)) - override def debug(t: Throwable)(msg: => String): F[Unit] = - save(DeferredLogMessage.debug(Map.empty, t.some, () => msg)) - override def info(t: Throwable)(msg: => String): F[Unit] = - save(DeferredLogMessage.info(Map.empty, t.some, () => msg)) - override def warn(t: Throwable)(msg: => String): F[Unit] = - save(DeferredLogMessage.warn(Map.empty, t.some, () => msg)) - override def error(t: Throwable)(msg: => String): F[Unit] = - save(DeferredLogMessage.error(Map.empty, t.some, () => msg)) + override def log( + ll: LogLevel, + ctx: Map[String, String], + t: Throwable, + msg: => String + ): F[Unit] = + save(DeferredLogMessage(ll, ctx, t.some, () => msg)) - override def trace(msg: => String): F[Unit] = - save(DeferredLogMessage.trace(Map.empty, none, () => msg)) - override def debug(msg: => String): F[Unit] = - save(DeferredLogMessage.debug(Map.empty, none, () => msg)) - override def info(msg: => String): F[Unit] = - save(DeferredLogMessage.info(Map.empty, none, () => msg)) - override def warn(msg: => String): F[Unit] = - save(DeferredLogMessage.warn(Map.empty, none, () => msg)) - override def error(msg: => String): F[Unit] = - save(DeferredLogMessage.error(Map.empty, none, () => msg)) + override def log(ll: LogLevel, ctx: Map[String, String], msg: => String): F[Unit] = + save(DeferredLogMessage(ll, ctx, none, () => msg)) - override def inspect: F[Chain[DeferredLogMessage]] = ref.get + override def log(ll: LogLevel, t: Throwable, msg: => String): F[Unit] = + save(DeferredLogMessage(ll, Map.empty, t.some, () => msg)) - override def log: F[Unit] = - ref.getAndSet(Chain.empty).flatMap(_.traverse_(_.logStructured(logger))) + override def log(ll: LogLevel, msg: => String): F[Unit] = + save(DeferredLogMessage(ll, Map.empty, none, () => msg)) } } @@ -138,39 +111,22 @@ object DeferredStructuredLogger { override def inspect: G[Chain[DeferredLogMessage]] = fk(logger.inspect) override def log: G[Unit] = fk(logger.log) - override def trace(ctx: Map[String, String], t: Throwable)(msg: => String): G[Unit] = - fk(logger.trace(ctx, t)(msg)) - override def debug(ctx: Map[String, String], t: Throwable)(msg: => String): G[Unit] = - fk(logger.debug(ctx, t)(msg)) - override def info(ctx: Map[String, String], t: Throwable)(msg: => String): G[Unit] = - fk(logger.info(ctx, t)(msg)) - override def warn(ctx: Map[String, String], t: Throwable)(msg: => String): G[Unit] = - fk(logger.warn(ctx, t)(msg)) - override def error(ctx: Map[String, String], t: Throwable)(msg: => String): G[Unit] = - fk(logger.error(ctx, t)(msg)) + override def log( + ll: LogLevel, + ctx: Map[String, String], + t: Throwable, + msg: => String + ): G[Unit] = + fk(logger.log(ll, ctx, t, msg)) - override def trace(ctx: Map[String, String])(msg: => String): G[Unit] = - fk(logger.trace(ctx)(msg)) - override def debug(ctx: Map[String, String])(msg: => String): G[Unit] = - fk(logger.debug(ctx)(msg)) - override def info(ctx: Map[String, String])(msg: => String): G[Unit] = - fk(logger.info(ctx)(msg)) - override def warn(ctx: Map[String, String])(msg: => String): G[Unit] = - fk(logger.warn(ctx)(msg)) - override def error(ctx: Map[String, String])(msg: => String): G[Unit] = - fk(logger.error(ctx)(msg)) + override def log(ll: LogLevel, ctx: Map[String, String], msg: => String): G[Unit] = + fk(logger.log(ll, ctx, msg)) - override def trace(t: Throwable)(message: => String): G[Unit] = fk(logger.trace(t)(message)) - override def debug(t: Throwable)(message: => String): G[Unit] = fk(logger.debug(t)(message)) - override def info(t: Throwable)(message: => String): G[Unit] = fk(logger.info(t)(message)) - override def warn(t: Throwable)(message: => String): G[Unit] = fk(logger.warn(t)(message)) - override def error(t: Throwable)(message: => String): G[Unit] = fk(logger.error(t)(message)) + override def log(ll: LogLevel, t: Throwable, msg: => String): G[Unit] = fk( + logger.log(ll, t, msg) + ) - override def trace(message: => String): G[Unit] = fk(logger.trace(message)) - override def debug(message: => String): G[Unit] = fk(logger.debug(message)) - override def info(message: => String): G[Unit] = fk(logger.info(message)) - override def warn(message: => String): G[Unit] = fk(logger.warn(message)) - override def error(message: => String): G[Unit] = fk(logger.error(message)) + override def log(ll: LogLevel, msg: => String): G[Unit] = fk(logger.log(ll, msg)) } def withContext[F[_]]( @@ -181,46 +137,25 @@ object DeferredStructuredLogger { private def addCtx(ctx: Map[String, String]): Map[String, String] = baseCtx ++ ctx override def inspect: F[Chain[DeferredLogMessage]] = logger.inspect + override def log: F[Unit] = logger.log - override def trace(ctx: Map[String, String], t: Throwable)(msg: => String): F[Unit] = - logger.trace(addCtx(ctx), t)(msg) - override def debug(ctx: Map[String, String], t: Throwable)(msg: => String): F[Unit] = - logger.debug(addCtx(ctx), t)(msg) - override def info(ctx: Map[String, String], t: Throwable)(msg: => String): F[Unit] = - logger.info(addCtx(ctx), t)(msg) - override def warn(ctx: Map[String, String], t: Throwable)(msg: => String): F[Unit] = - logger.warn(addCtx(ctx), t)(msg) - override def error(ctx: Map[String, String], t: Throwable)(msg: => String): F[Unit] = - logger.error(addCtx(ctx), t)(msg) + override def log( + ll: LogLevel, + ctx: Map[String, String], + t: Throwable, + msg: => String + ): F[Unit] = + logger.log(ll, addCtx(ctx), t, msg) - override def trace(ctx: Map[String, String])(msg: => String): F[Unit] = - logger.trace(addCtx(ctx))(msg) - override def debug(ctx: Map[String, String])(msg: => String): F[Unit] = - logger.debug(addCtx(ctx))(msg) - override def info(ctx: Map[String, String])(msg: => String): F[Unit] = - logger.info(addCtx(ctx))(msg) - override def warn(ctx: Map[String, String])(msg: => String): F[Unit] = - logger.warn(addCtx(ctx))(msg) - override def error(ctx: Map[String, String])(msg: => String): F[Unit] = - logger.error(addCtx(ctx))(msg) + override def log(ll: LogLevel, ctx: Map[String, String], msg: => String): F[Unit] = + logger.log(ll, addCtx(ctx), msg) - override def trace(t: Throwable)(message: => String): F[Unit] = - logger.trace(baseCtx, t)(message) - override def debug(t: Throwable)(message: => String): F[Unit] = - logger.debug(baseCtx, t)(message) - override def info(t: Throwable)(message: => String): F[Unit] = - logger.info(baseCtx, t)(message) - override def warn(t: Throwable)(message: => String): F[Unit] = - logger.warn(baseCtx, t)(message) - override def error(t: Throwable)(message: => String): F[Unit] = - logger.error(baseCtx, t)(message) + override def log(ll: LogLevel, t: Throwable, msg: => String): F[Unit] = + logger.log(ll, baseCtx, t, msg) - override def trace(message: => String): F[Unit] = logger.trace(baseCtx)(message) - override def debug(message: => String): F[Unit] = logger.debug(baseCtx)(message) - override def info(message: => String): F[Unit] = logger.info(baseCtx)(message) - override def warn(message: => String): F[Unit] = logger.warn(baseCtx)(message) - override def error(message: => String): F[Unit] = logger.error(baseCtx)(message) + override def log(ll: LogLevel, msg: => String): F[Unit] = + logger.log(ll, baseCtx, msg) } def withModifiedString[F[_]]( @@ -229,40 +164,22 @@ object DeferredStructuredLogger { ): DeferredStructuredLogger[F] = new DeferredStructuredLogger[F] { override def inspect: F[Chain[DeferredLogMessage]] = logger.inspect + override def log: F[Unit] = logger.log - override def trace(ctx: Map[String, String], t: Throwable)(msg: => String): F[Unit] = - logger.trace(ctx, t)(f(msg)) - override def debug(ctx: Map[String, String], t: Throwable)(msg: => String): F[Unit] = - logger.debug(ctx, t)(f(msg)) - override def info(ctx: Map[String, String], t: Throwable)(msg: => String): F[Unit] = - logger.info(ctx, t)(f(msg)) - override def warn(ctx: Map[String, String], t: Throwable)(msg: => String): F[Unit] = - logger.warn(ctx, t)(f(msg)) - override def error(ctx: Map[String, String], t: Throwable)(msg: => String): F[Unit] = - logger.error(ctx, t)(f(msg)) + override def log( + ll: LogLevel, + ctx: Map[String, String], + t: Throwable, + msg: => String + ): F[Unit] = logger.log(ll, ctx, t, f(msg)) - override def trace(ctx: Map[String, String])(msg: => String): F[Unit] = - logger.trace(ctx)(f(msg)) - override def debug(ctx: Map[String, String])(msg: => String): F[Unit] = - logger.debug(ctx)(f(msg)) - override def info(ctx: Map[String, String])(msg: => String): F[Unit] = - logger.info(ctx)(f(msg)) - override def warn(ctx: Map[String, String])(msg: => String): F[Unit] = - logger.warn(ctx)(f(msg)) - override def error(ctx: Map[String, String])(msg: => String): F[Unit] = - logger.error(ctx)(f(msg)) + override def log(ll: LogLevel, ctx: Map[String, String], msg: => String): F[Unit] = + logger.log(ll, ctx, f(msg)) - override def trace(t: Throwable)(message: => String): F[Unit] = logger.trace(t)(f(message)) - override def debug(t: Throwable)(message: => String): F[Unit] = logger.debug(t)(f(message)) - override def info(t: Throwable)(message: => String): F[Unit] = logger.info(t)(f(message)) - override def warn(t: Throwable)(message: => String): F[Unit] = logger.warn(t)(f(message)) - override def error(t: Throwable)(message: => String): F[Unit] = logger.error(t)(f(message)) + override def log(ll: LogLevel, t: Throwable, msg: => String): F[Unit] = + logger.log(ll, t, f(msg)) - override def trace(message: => String): F[Unit] = logger.trace(f(message)) - override def debug(message: => String): F[Unit] = logger.debug(f(message)) - override def info(message: => String): F[Unit] = logger.info(f(message)) - override def warn(message: => String): F[Unit] = logger.warn(f(message)) - override def error(message: => String): F[Unit] = logger.error(f(message)) + override def log(ll: LogLevel, msg: => String): F[Unit] = logger.log(ll, f(msg)) } } diff --git a/core/shared/src/main/scala/org/typelevel/log4cats/extras/WriterTLogger.scala b/core/shared/src/main/scala/org/typelevel/log4cats/extras/WriterTLogger.scala index 6452e6a2..a9e034c8 100644 --- a/core/shared/src/main/scala/org/typelevel/log4cats/extras/WriterTLogger.scala +++ b/core/shared/src/main/scala/org/typelevel/log4cats/extras/WriterTLogger.scala @@ -16,10 +16,11 @@ package org.typelevel.log4cats.extras -import cats._ -import cats.data._ -import cats.syntax.all._ -import org.typelevel.log4cats._ +import cats.* +import cats.data.* +import cats.kernel.Monoid +import cats.syntax.all.* +import org.typelevel.log4cats.* /** * A `SelfAwareLogger` implemented using `cats.data.WriterT`. @@ -40,52 +41,38 @@ object WriterTLogger { errorEnabled: Boolean = true ): SelfAwareLogger[WriterT[F, G[LogMessage], *]] = new SelfAwareLogger[WriterT[F, G[LogMessage], *]] { - override def isTraceEnabled: WriterT[F, G[LogMessage], Boolean] = isEnabled(traceEnabled) - override def isDebugEnabled: WriterT[F, G[LogMessage], Boolean] = isEnabled(debugEnabled) - override def isInfoEnabled: WriterT[F, G[LogMessage], Boolean] = isEnabled(infoEnabled) - override def isWarnEnabled: WriterT[F, G[LogMessage], Boolean] = isEnabled(warnEnabled) - override def isErrorEnabled: WriterT[F, G[LogMessage], Boolean] = isEnabled(errorEnabled) + type LoggerF[A] = WriterT[F, G[LogMessage], A] - override def trace(t: Throwable)(message: => String): WriterT[F, G[LogMessage], Unit] = - build(traceEnabled, LogLevel.Trace, t.some, message) - override def trace(message: => String): WriterT[F, G[LogMessage], Unit] = - build(traceEnabled, LogLevel.Trace, None, message) - - override def debug(t: Throwable)(message: => String): WriterT[F, G[LogMessage], Unit] = - build(debugEnabled, LogLevel.Debug, t.some, message) - override def debug(message: => String): WriterT[F, G[LogMessage], Unit] = - build(debugEnabled, LogLevel.Debug, None, message) - - override def info(t: Throwable)(message: => String): WriterT[F, G[LogMessage], Unit] = - build(infoEnabled, LogLevel.Info, t.some, message) - override def info(message: => String): WriterT[F, G[LogMessage], Unit] = - build(infoEnabled, LogLevel.Info, None, message) + private implicit val monoidGLogMessage: Monoid[G[LogMessage]] = + Alternative[G].algebra[LogMessage] - override def warn(t: Throwable)(message: => String): WriterT[F, G[LogMessage], Unit] = - build(warnEnabled, LogLevel.Warn, t.some, message) - override def warn(message: => String): WriterT[F, G[LogMessage], Unit] = - build(warnEnabled, LogLevel.Warn, None, message) + private def shouldLog(ll: LogLevel): Boolean = ll match { + case LogLevel.Error => errorEnabled + case LogLevel.Warn => warnEnabled + case LogLevel.Info => infoEnabled + case LogLevel.Debug => debugEnabled + case LogLevel.Trace => traceEnabled + } - override def error(t: Throwable)(message: => String): WriterT[F, G[LogMessage], Unit] = - build(errorEnabled, LogLevel.Error, t.some, message) - override def error(message: => String): WriterT[F, G[LogMessage], Unit] = - build(errorEnabled, LogLevel.Error, None, message) + private def build(level: LogLevel, t: Option[Throwable], message: => String): LoggerF[Unit] = + Applicative[LoggerF].whenA(shouldLog(level)) { + WriterT.tell[F, G[LogMessage]](Applicative[G].pure { + LogMessage(level, t, message) + }) + } - private def isEnabled(enabled: Boolean): WriterT[F, G[LogMessage], Boolean] = - WriterT.liftF[F, G[LogMessage], Boolean](Applicative[F].pure(enabled)) + override def isEnabled(ll: LogLevel): WriterT[F, G[LogMessage], Boolean] = + WriterT.liftF[F, G[LogMessage], Boolean](Applicative[F].pure(shouldLog(ll))) - private def build( - enabled: Boolean, - level: LogLevel, - t: Option[Throwable], - message: => String + override def log( + ll: LogLevel, + t: Throwable, + msg: => String ): WriterT[F, G[LogMessage], Unit] = - if (enabled) - WriterT.tell[F, G[LogMessage]](Applicative[G].pure(LogMessage(level, t, message))) - else WriterT.value[F, G[LogMessage], Unit](()) + build(ll, t.some, msg) - private implicit val monoidGLogMessage: Monoid[G[LogMessage]] = - Alternative[G].algebra[LogMessage] + override def log(ll: LogLevel, msg: => String): WriterT[F, G[LogMessage], Unit] = + build(ll, none, msg) } def run[F[_]: Monad, G[_]: Foldable](l: Logger[F]): WriterT[F, G[LogMessage], *] ~> F = diff --git a/core/shared/src/main/scala/org/typelevel/log4cats/extras/WriterTStructuredLogger.scala b/core/shared/src/main/scala/org/typelevel/log4cats/extras/WriterTStructuredLogger.scala index 5403653e..89e41b45 100644 --- a/core/shared/src/main/scala/org/typelevel/log4cats/extras/WriterTStructuredLogger.scala +++ b/core/shared/src/main/scala/org/typelevel/log4cats/extras/WriterTStructuredLogger.scala @@ -43,100 +43,56 @@ object WriterTStructuredLogger { new SelfAwareStructuredLogger[WriterT[F, G[StructuredLogMessage], *]] { type LoggerF[A] = WriterT[F, G[StructuredLogMessage], A] - override def isTraceEnabled: LoggerF[Boolean] = isEnabled(traceEnabled) - - override def isDebugEnabled: LoggerF[Boolean] = isEnabled(debugEnabled) - - override def isInfoEnabled: LoggerF[Boolean] = isEnabled(infoEnabled) - - override def isWarnEnabled: LoggerF[Boolean] = isEnabled(warnEnabled) - - override def isErrorEnabled: LoggerF[Boolean] = isEnabled(errorEnabled) - - override def trace(t: Throwable)(message: => String): LoggerF[Unit] = - build(Map.empty, traceEnabled, LogLevel.Trace, t.some, message) - - override def trace(message: => String): LoggerF[Unit] = - build(Map.empty, traceEnabled, LogLevel.Trace, None, message) - - override def debug(t: Throwable)(message: => String): LoggerF[Unit] = - build(Map.empty, debugEnabled, LogLevel.Debug, t.some, message) - - override def debug(message: => String): LoggerF[Unit] = - build(Map.empty, debugEnabled, LogLevel.Debug, None, message) - - override def info(t: Throwable)(message: => String): LoggerF[Unit] = - build(Map.empty, infoEnabled, LogLevel.Info, t.some, message) - - override def info(message: => String): LoggerF[Unit] = - build(Map.empty, infoEnabled, LogLevel.Info, None, message) - - override def warn(t: Throwable)(message: => String): LoggerF[Unit] = - build(Map.empty, warnEnabled, LogLevel.Warn, t.some, message) - - override def warn(message: => String): LoggerF[Unit] = - build(Map.empty, warnEnabled, LogLevel.Warn, None, message) - - override def error(t: Throwable)(message: => String): LoggerF[Unit] = - build(Map.empty, errorEnabled, LogLevel.Error, t.some, message) - - override def error(message: => String): LoggerF[Unit] = - build(Map.empty, errorEnabled, LogLevel.Error, None, message) + private implicit val monoidGLogMessage: Monoid[G[StructuredLogMessage]] = + Alternative[G].algebra[StructuredLogMessage] - private def isEnabled(enabled: Boolean): LoggerF[Boolean] = - WriterT.liftF[F, G[StructuredLogMessage], Boolean](Applicative[F].pure(enabled)) + private def shouldLog(ll: LogLevel): Boolean = ll match { + case LogLevel.Error => errorEnabled + case LogLevel.Warn => warnEnabled + case LogLevel.Info => infoEnabled + case LogLevel.Debug => debugEnabled + case LogLevel.Trace => traceEnabled + } private def build( - ctx: Map[String, String], - enabled: Boolean, level: LogLevel, + ctx: Map[String, String], t: Option[Throwable], message: => String ): LoggerF[Unit] = - if (enabled) + Applicative[LoggerF].whenA(shouldLog(level)) { WriterT.tell[F, G[StructuredLogMessage]](Applicative[G].pure { StructuredLogMessage(level, ctx, t, message) }) - else WriterT.value[F, G[StructuredLogMessage], Unit](()) - - private implicit val monoidGLogMessage: Monoid[G[StructuredLogMessage]] = - Alternative[G].algebra[StructuredLogMessage] - - override def trace(ctx: Map[String, String])(message: => String): LoggerF[Unit] = - build(ctx, traceEnabled, LogLevel.Trace, None, message) - - override def trace(ctx: Map[String, String], t: Throwable)( - message: => String - ): LoggerF[Unit] = - build(ctx, traceEnabled, LogLevel.Trace, t.some, message) - - override def debug(ctx: Map[String, String])(message: => String): LoggerF[Unit] = - build(ctx, debugEnabled, LogLevel.Debug, None, message) - - override def debug(ctx: Map[String, String], t: Throwable)( - message: => String - ): LoggerF[Unit] = - build(ctx, debugEnabled, LogLevel.Debug, t.some, message) - - override def info(ctx: Map[String, String])(message: => String): LoggerF[Unit] = - build(ctx, infoEnabled, LogLevel.Info, None, message) + } - override def info(ctx: Map[String, String], t: Throwable)(message: => String): LoggerF[Unit] = - build(ctx, infoEnabled, LogLevel.Info, t.some, message) + override def isEnabled(ll: LogLevel): WriterT[F, G[StructuredLogMessage], Boolean] = + WriterT.liftF[F, G[StructuredLogMessage], Boolean](Applicative[F].pure(shouldLog(ll))) - override def warn(ctx: Map[String, String])(message: => String): LoggerF[Unit] = - build(ctx, warnEnabled, LogLevel.Warn, None, message) + override def log(ll: LogLevel, msg: => String): WriterT[F, G[StructuredLogMessage], Unit] = + build(ll, Map.empty, none, msg) - override def warn(ctx: Map[String, String], t: Throwable)(message: => String): LoggerF[Unit] = - build(ctx, warnEnabled, LogLevel.Warn, t.some, message) + override def log( + ll: LogLevel, + t: Throwable, + msg: => String + ): WriterT[F, G[StructuredLogMessage], Unit] = + build(ll, Map.empty, t.some, msg) - override def error(ctx: Map[String, String])(message: => String): LoggerF[Unit] = - build(ctx, errorEnabled, LogLevel.Error, None, message) + override def log( + ll: LogLevel, + ctx: Map[String, String], + msg: => String + ): WriterT[F, G[StructuredLogMessage], Unit] = + build(ll, ctx, none, msg) - override def error(ctx: Map[String, String], t: Throwable)( - message: => String - ): LoggerF[Unit] = - build(ctx, errorEnabled, LogLevel.Error, t.some, message) + override def log( + ll: LogLevel, + ctx: Map[String, String], + t: Throwable, + msg: => String + ): WriterT[F, G[StructuredLogMessage], Unit] = + build(ll, ctx, t.some, msg) } def run[F[_]: Monad, G[_]: Foldable]( diff --git a/core/shared/src/main/scala/org/typelevel/log4cats/noop/NoOpLogger.scala b/core/shared/src/main/scala/org/typelevel/log4cats/noop/NoOpLogger.scala index 95762949..3e101f70 100644 --- a/core/shared/src/main/scala/org/typelevel/log4cats/noop/NoOpLogger.scala +++ b/core/shared/src/main/scala/org/typelevel/log4cats/noop/NoOpLogger.scala @@ -18,6 +18,7 @@ package org.typelevel.log4cats.noop import cats.Applicative import org.typelevel.log4cats.SelfAwareStructuredLogger +import org.typelevel.log4cats.extras.LogLevel object NoOpLogger { def apply[F[_]: Applicative]: SelfAwareStructuredLogger[F] = impl[F] @@ -25,86 +26,50 @@ object NoOpLogger { def strictEvalArgs[F[_]: Applicative]: SelfAwareStructuredLogger[F] = impl_[F](evaluateArgs = true) - def impl[F[_]: Applicative] = impl_[F](evaluateArgs = false) + def impl[F[_]: Applicative]: SelfAwareStructuredLogger[F] = impl_[F](evaluateArgs = false) private[noop] def impl_[F[_]: Applicative](evaluateArgs: Boolean): SelfAwareStructuredLogger[F] = if (evaluateArgs) strictImpl else lazyImpl - private def lazyImpl[F[_]: Applicative] = new SelfAwareStructuredLogger[F] { + private def lazyImpl[F[_]: Applicative]: SelfAwareStructuredLogger[F] = + new SelfAwareStructuredLogger[F] { - val no: F[Boolean] = Applicative[F].pure(false) - val unit: F[Unit] = Applicative[F].pure(()) + val no: F[Boolean] = Applicative[F].pure(false) + val unit: F[Unit] = Applicative[F].pure(()) - @inline override def isTraceEnabled: F[Boolean] = no - @inline override def isDebugEnabled: F[Boolean] = no - @inline override def isInfoEnabled: F[Boolean] = no - @inline override def isWarnEnabled: F[Boolean] = no - @inline override def isErrorEnabled: F[Boolean] = no - @inline override def trace(t: Throwable)(msg: => String): F[Unit] = unit - @inline override def trace(msg: => String): F[Unit] = unit - @inline override def trace(ctx: Map[String, String])(msg: => String): F[Unit] = unit - @inline override def debug(t: Throwable)(msg: => String): F[Unit] = unit - @inline override def debug(msg: => String): F[Unit] = unit - @inline override def debug(ctx: Map[String, String])(msg: => String): F[Unit] = unit - @inline override def info(t: Throwable)(msg: => String): F[Unit] = unit - @inline override def info(msg: => String): F[Unit] = unit - @inline override def info(ctx: Map[String, String])(msg: => String): F[Unit] = unit - @inline override def warn(t: Throwable)(msg: => String): F[Unit] = unit - @inline override def warn(msg: => String): F[Unit] = unit - @inline override def warn(ctx: Map[String, String])(msg: => String): F[Unit] = unit - @inline override def error(t: Throwable)(msg: => String): F[Unit] = unit - @inline override def error(msg: => String): F[Unit] = unit - @inline override def error(ctx: Map[String, String])(msg: => String): F[Unit] = unit - @inline override def trace(ctx: Map[String, String], t: Throwable)(msg: => String): F[Unit] = - unit - @inline override def debug(ctx: Map[String, String], t: Throwable)(msg: => String): F[Unit] = - unit - @inline override def info(ctx: Map[String, String], t: Throwable)(msg: => String): F[Unit] = - unit - @inline override def warn(ctx: Map[String, String], t: Throwable)(msg: => String): F[Unit] = - unit - @inline override def error(ctx: Map[String, String], t: Throwable)(msg: => String): F[Unit] = - unit - } + @inline override def isEnabled(ll: LogLevel): F[Boolean] = no + @inline override def log(ll: LogLevel, ctx: Map[String, String], msg: => String): F[Unit] = + unit + @inline override def log( + ll: LogLevel, + ctx: Map[String, String], + t: Throwable, + msg: => String + ): F[Unit] = unit + @inline override def log(ll: LogLevel, t: Throwable, msg: => String): F[Unit] = unit + @inline override def log(ll: LogLevel, msg: => String): F[Unit] = unit + } - private def strictImpl[F[_]: Applicative] = new SelfAwareStructuredLogger[F] { + private def strictImpl[F[_]: Applicative]: SelfAwareStructuredLogger[F] = + new SelfAwareStructuredLogger[F] { - val yes: F[Boolean] = Applicative[F].pure(true) - def void(arg: => Any): F[Unit] = Applicative[F].pure { - val _ = arg - () - } + val yes: F[Boolean] = Applicative[F].pure(true) + def void(arg: => String): F[Unit] = Applicative[F].pure { + val _ = arg + () + } - @inline override def isTraceEnabled: F[Boolean] = yes - @inline override def isDebugEnabled: F[Boolean] = yes - @inline override def isInfoEnabled: F[Boolean] = yes - @inline override def isWarnEnabled: F[Boolean] = yes - @inline override def isErrorEnabled: F[Boolean] = yes - @inline override def trace(t: Throwable)(msg: => String): F[Unit] = void(t) - @inline override def trace(msg: => String): F[Unit] = void(msg) - @inline override def trace(ctx: Map[String, String])(msg: => String): F[Unit] = void(msg) - @inline override def debug(t: Throwable)(msg: => String): F[Unit] = void(msg) - @inline override def debug(msg: => String): F[Unit] = void(msg) - @inline override def debug(ctx: Map[String, String])(msg: => String): F[Unit] = void(msg) - @inline override def info(t: Throwable)(msg: => String): F[Unit] = void(msg) - @inline override def info(msg: => String): F[Unit] = void(msg) - @inline override def info(ctx: Map[String, String])(msg: => String): F[Unit] = void(msg) - @inline override def warn(t: Throwable)(msg: => String): F[Unit] = void(msg) - @inline override def warn(msg: => String): F[Unit] = void(msg) - @inline override def warn(ctx: Map[String, String])(msg: => String): F[Unit] = void(msg) - @inline override def error(t: Throwable)(msg: => String): F[Unit] = void(msg) - @inline override def error(msg: => String): F[Unit] = void(msg) - @inline override def error(ctx: Map[String, String])(msg: => String): F[Unit] = void(msg) - @inline override def trace(ctx: Map[String, String], t: Throwable)(msg: => String): F[Unit] = - void(msg) - @inline override def debug(ctx: Map[String, String], t: Throwable)(msg: => String): F[Unit] = - void(msg) - @inline override def info(ctx: Map[String, String], t: Throwable)(msg: => String): F[Unit] = - void(msg) - @inline override def warn(ctx: Map[String, String], t: Throwable)(msg: => String): F[Unit] = - void(msg) - @inline override def error(ctx: Map[String, String], t: Throwable)(msg: => String): F[Unit] = - void(msg) - } + @inline override def isEnabled(ll: LogLevel): F[Boolean] = yes + @inline override def log(ll: LogLevel, ctx: Map[String, String], msg: => String): F[Unit] = + void(msg) + @inline override def log( + ll: LogLevel, + ctx: Map[String, String], + t: Throwable, + msg: => String + ): F[Unit] = void(msg) + @inline override def log(ll: LogLevel, t: Throwable, msg: => String): F[Unit] = void(msg) + @inline override def log(ll: LogLevel, msg: => String): F[Unit] = void(msg) + } } diff --git a/js-console/src/main/scala/org/typelevel/log4cats/console/ConsoleLogger.scala b/js-console/src/main/scala/org/typelevel/log4cats/console/ConsoleLogger.scala index 3ae10c4c..3c9e9e11 100644 --- a/js-console/src/main/scala/org/typelevel/log4cats/console/ConsoleLogger.scala +++ b/js-console/src/main/scala/org/typelevel/log4cats/console/ConsoleLogger.scala @@ -25,25 +25,41 @@ import org.typelevel.log4cats.extras.LogLevel._ class ConsoleLogger[F[_]: Sync](logLevel: Option[LogLevel] = Option(Trace)) extends SelfAwareStructuredLogger[F] { private val ConsoleF: ConsoleF[F] = implicitly + + override def isEnabled(ll: LogLevel): F[Boolean] = logLevel.exists(_ <= ll).pure[F] + + override def log(ll: LogLevel, t: Throwable, msg: => String): F[Unit] = + ll match { + case LogLevel.Error => error(t)(msg) + case LogLevel.Warn => warn(t)(msg) + case LogLevel.Info => info(t)(msg) + case LogLevel.Debug => debug(t)(msg) + case LogLevel.Trace => trace(t)(msg) + } + + override def log(ll: LogLevel, msg: => String): F[Unit] = + ll match { + case LogLevel.Error => error(msg) + case LogLevel.Warn => warn(msg) + case LogLevel.Info => info(msg) + case LogLevel.Debug => debug(msg) + case LogLevel.Trace => trace(msg) + } + override def trace(t: Throwable)(message: => String): F[Unit] = ConsoleF.debug(message, t) override def trace(message: => String): F[Unit] = ConsoleF.debug(message) - override def isTraceEnabled: F[Boolean] = logLevel.exists(_ <= Trace).pure[F] override def debug(t: Throwable)(message: => String): F[Unit] = ConsoleF.debug(message, t) override def debug(message: => String): F[Unit] = ConsoleF.debug(message) - override def isDebugEnabled: F[Boolean] = logLevel.exists(_ <= Debug).pure[F] override def info(t: Throwable)(message: => String): F[Unit] = ConsoleF.info(message, t) override def info(message: => String): F[Unit] = ConsoleF.info(message) - override def isInfoEnabled: F[Boolean] = logLevel.exists(_ <= Info).pure[F] override def warn(t: Throwable)(message: => String): F[Unit] = ConsoleF.warn(message, t) override def warn(message: => String): F[Unit] = ConsoleF.warn(message) - override def isWarnEnabled: F[Boolean] = logLevel.exists(_ <= Warn).pure[F] override def error(t: Throwable)(message: => String): F[Unit] = ConsoleF.error(message, t) override def error(message: => String): F[Unit] = ConsoleF.error(message) - override def isErrorEnabled: F[Boolean] = logLevel.exists(_ <= Error).pure[F] /* * ConsoleLogger should probably not extend from StructuredLogger, because there's not @@ -66,4 +82,7 @@ class ConsoleLogger[F[_]: Sync](logLevel: Option[LogLevel] = Option(Trace)) override def error(ctx: Map[String, String])(msg: => String): F[Unit] = error(msg) override def error(ctx: Map[String, String], t: Throwable)(msg: => String): F[Unit] = error(t)(msg) + override def log(ll: LogLevel, ctx: Map[String, String], t: Throwable, msg: => String): F[Unit] = + log(ll, t, msg) + override def log(ll: LogLevel, ctx: Map[String, String], msg: => String): F[Unit] = log(ll, msg) } diff --git a/slf4j/src/main/scala/org/typelevel/log4cats/slf4j/internal/Slf4jLoggerInternal.scala b/slf4j/src/main/scala/org/typelevel/log4cats/slf4j/internal/Slf4jLoggerInternal.scala index 03b67ffb..8f66d893 100644 --- a/slf4j/src/main/scala/org/typelevel/log4cats/slf4j/internal/Slf4jLoggerInternal.scala +++ b/slf4j/src/main/scala/org/typelevel/log4cats/slf4j/internal/Slf4jLoggerInternal.scala @@ -16,11 +16,12 @@ package org.typelevel.log4cats.slf4j.internal -import org.typelevel.log4cats._ -import cats.syntax.all._ -import cats.effect._ -import org.slf4j.{Logger => JLogger} +import org.typelevel.log4cats.* +import cats.syntax.all.* +import cats.effect.* +import org.slf4j.Logger as JLogger import org.slf4j.MDC +import org.typelevel.log4cats.extras.LogLevel private[slf4j] object Slf4jLoggerInternal { @@ -125,5 +126,51 @@ private[slf4j] object Slf4jLoggerInternal { contextLog(isWarnEnabled, ctx, () => logger.warn(msg, t)) override def error(ctx: Map[String, String], t: Throwable)(msg: => String): F[Unit] = contextLog(isErrorEnabled, ctx, () => logger.error(msg, t)) + + override def isEnabled(ll: LogLevel): F[Boolean] = ll match { + case LogLevel.Error => isErrorEnabled + case LogLevel.Warn => isWarnEnabled + case LogLevel.Info => isInfoEnabled + case LogLevel.Debug => isDebugEnabled + case LogLevel.Trace => isTraceEnabled + } + + override def log( + ll: LogLevel, + ctx: Map[String, String], + t: Throwable, + msg: => String + ): F[Unit] = + ll match { + case LogLevel.Error => error(ctx, t)(msg) + case LogLevel.Warn => warn(ctx, t)(msg) + case LogLevel.Info => info(ctx, t)(msg) + case LogLevel.Debug => debug(ctx, t)(msg) + case LogLevel.Trace => trace(ctx, t)(msg) + } + + override def log(ll: LogLevel, ctx: Map[String, String], msg: => String): F[Unit] = ll match { + case LogLevel.Error => error(ctx)(msg) + case LogLevel.Warn => warn(ctx)(msg) + case LogLevel.Info => info(ctx)(msg) + case LogLevel.Debug => debug(ctx)(msg) + case LogLevel.Trace => trace(ctx)(msg) + } + + override def log(ll: LogLevel, t: Throwable, msg: => String): F[Unit] = ll match { + case LogLevel.Error => error(t)(msg) + case LogLevel.Warn => warn(t)(msg) + case LogLevel.Info => info(t)(msg) + case LogLevel.Debug => debug(t)(msg) + case LogLevel.Trace => trace(t)(msg) + } + + override def log(ll: LogLevel, msg: => String): F[Unit] = ll match { + case LogLevel.Error => error(msg) + case LogLevel.Warn => warn(msg) + case LogLevel.Info => info(msg) + case LogLevel.Debug => debug(msg) + case LogLevel.Trace => trace(msg) + } } } diff --git a/slf4j/src/test/scala/org/typelevel/log4cats/slf4j/internal/JTestLogger.java b/slf4j/src/test/scala/org/typelevel/log4cats/slf4j/internal/JTestLogger.java new file mode 100644 index 00000000..fa55ee64 --- /dev/null +++ b/slf4j/src/test/scala/org/typelevel/log4cats/slf4j/internal/JTestLogger.java @@ -0,0 +1,159 @@ +/* + * Copyright 2018 Typelevel + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.typelevel.log4cats.slf4j.internal; + +import org.slf4j.Logger; +import org.slf4j.MDC; +import org.slf4j.Marker; +import org.typelevel.log4cats.extras.DeferredLogMessage; +import org.typelevel.log4cats.extras.DeferredLogMessage$; +import scala.collection.immutable.Map; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.atomic.AtomicReference; +import java.util.function.Function; + +public class JTestLogger implements Logger { + private final String loggerName; + private final boolean traceEnabled; + private final boolean debugEnabled; + private final boolean infoEnabled; + private final boolean warnEnabled; + private final boolean errorEnabled; + private final AtomicReference> loggedMessages; + + public JTestLogger(String loggerName, + boolean traceEnabled, + boolean debugEnabled, + boolean infoEnabled, + boolean warnEnabled, + boolean errorEnabled) { + this.loggerName = loggerName; + this.traceEnabled = traceEnabled; + this.debugEnabled = debugEnabled; + this.infoEnabled = infoEnabled; + this.warnEnabled = warnEnabled; + this.errorEnabled = errorEnabled; + loggedMessages = new AtomicReference<>(new ArrayList()); + } + + // Java -> Scala compat helpers + + private final scala.Option none = scala.Option$.MODULE$.empty(); + private scala.Option some(Throwable t) { return scala.Option$.MODULE$.apply(t); } + + private Map captureContext () { + java.util.Map mdc = MDC.getCopyOfContextMap(); + if (mdc == null) { + return scala.collection.immutable.Map$.MODULE$.empty(); + } + return scala.collection.immutable.Map$.MODULE$.from( + scala.jdk.javaapi.CollectionConverters.asScala(MDC.getCopyOfContextMap()) + ); + } + + // Way to long to type the full DeferredLogMessage$.MODULE$ all the time + private DeferredLogMessage$ DLM = DeferredLogMessage$.MODULE$; + + private void save(Function, DeferredLogMessage> mkLogMessage) { + loggedMessages.updateAndGet(ll -> { + ll.add(mkLogMessage.apply(captureContext())); + return ll; + }); + } + + public List logs() { return loggedMessages.get(); } + public void reset() { loggedMessages.set(new ArrayList<>()); } + + @Override public String getName() { return loggerName;} + + @Override public boolean isTraceEnabled() { return traceEnabled; } + @Override public boolean isDebugEnabled() { return debugEnabled; } + @Override public boolean isInfoEnabled() { return infoEnabled; } + @Override public boolean isWarnEnabled() { return warnEnabled; } + @Override public boolean isErrorEnabled() { return errorEnabled; } + + // We don't use them, so we're going to ignore Markers + @Override public boolean isTraceEnabled(Marker marker) { return traceEnabled; } + @Override public boolean isDebugEnabled(Marker marker) { return debugEnabled; } + @Override public boolean isInfoEnabled(Marker marker) { return infoEnabled; } + @Override public boolean isWarnEnabled(Marker marker) { return warnEnabled; } + @Override public boolean isErrorEnabled(Marker marker) { return errorEnabled; } + + @Override public void trace(String msg) { save(ctx -> DLM.trace(ctx, none, () -> msg)); } + @Override public void trace(String msg, Throwable t) { save(ctx -> DLM.trace(ctx, some(t), () -> msg)); } + + @Override public void debug(String msg) { save(ctx -> DLM.debug(ctx, none, () -> msg)); } + @Override public void debug(String msg, Throwable t) { save(ctx -> DLM.debug(ctx, some(t), () -> msg)); } + + @Override public void info(String msg) { save(ctx -> DLM.info(ctx, none, () -> msg)); } + @Override public void info(String msg, Throwable t) { save(ctx -> DLM.info(ctx, some(t), () -> msg)); } + + @Override public void warn(String msg) { save(ctx -> DLM.warn(ctx, none, () -> msg)); } + @Override public void warn(String msg, Throwable t) { save(ctx -> DLM.warn(ctx, some(t), () -> msg)); } + + @Override public void error(String msg) { save(ctx -> DLM.error(ctx, none, () -> msg)); } + @Override public void error(String msg, Throwable t) { save(ctx -> DLM.error(ctx, some(t), () -> msg)); } + + // We shouldn't need these for our tests, so we're treating these variants as if they were the standard method + + @Override public void trace(String format, Object arg) { trace(format); } + @Override public void trace(String format, Object arg1, Object arg2) { trace(format); } + @Override public void trace(String format, Object... arguments) { trace(format); } + @Override public void trace(Marker marker, String msg) { trace(msg); } + @Override public void trace(Marker marker, String format, Object arg) { trace(format); } + @Override public void trace(Marker marker, String format, Object arg1, Object arg2) { trace(format); } + @Override public void trace(Marker marker, String format, Object... argArray) { trace(format); } + @Override public void trace(Marker marker, String msg, Throwable t) { trace(msg, t); } + + @Override public void debug(String format, Object arg) { debug(format); } + @Override public void debug(String format, Object arg1, Object arg2) { debug(format); } + @Override public void debug(String format, Object... arguments) { debug(format); } + @Override public void debug(Marker marker, String msg) { debug(msg); } + @Override public void debug(Marker marker, String format, Object arg) { debug(format); } + @Override public void debug(Marker marker, String format, Object arg1, Object arg2) { debug(format); } + @Override public void debug(Marker marker, String format, Object... arguments) { debug(format); } + @Override public void debug(Marker marker, String msg, Throwable t) { debug(msg, t); } + + @Override public void info(String format, Object arg) { info(format); } + @Override public void info(String format, Object arg1, Object arg2) { info(format); } + @Override public void info(String format, Object... arguments) { info(format); } + @Override public void info(Marker marker, String msg) { info(msg); } + @Override public void info(Marker marker, String format, Object arg) { info(format); } + @Override public void info(Marker marker, String format, Object arg1, Object arg2) { info(format); } + @Override public void info(Marker marker, String format, Object... arguments) { info(format); } + @Override public void info(Marker marker, String msg, Throwable t) { info(msg, t); } + + @Override public void warn(String format, Object arg) { warn(format); } + @Override public void warn(String format, Object... arguments) { warn(format); } + @Override public void warn(String format, Object arg1, Object arg2) { warn(format); } + @Override public void warn(Marker marker, String msg) { warn(msg); } + @Override public void warn(Marker marker, String format, Object arg) { warn(format); } + @Override public void warn(Marker marker, String format, Object arg1, Object arg2) { warn(format); } + @Override public void warn(Marker marker, String format, Object... arguments) { warn(format); } + @Override public void warn(Marker marker, String msg, Throwable t) { warn(msg, t); } + + @Override public void error(String format, Object arg) { error(format); } + @Override public void error(String format, Object arg1, Object arg2) { error(format); } + @Override public void error(String format, Object... arguments) { error(format); } + @Override public void error(Marker marker, String msg) { error(msg); } + @Override public void error(Marker marker, String format, Object arg) { error(format); } + @Override public void error(Marker marker, String format, Object arg1, Object arg2) { error(format); } + @Override public void error(Marker marker, String format, Object... arguments) { error(format); } + @Override public void error(Marker marker, String msg, Throwable t) { error(msg, t); } +} diff --git a/slf4j/src/test/scala/org/typelevel/log4cats/slf4j/internal/Slf4jLoggerInternalSuite.scala b/slf4j/src/test/scala/org/typelevel/log4cats/slf4j/internal/Slf4jLoggerInternalSuite.scala index 9e81d1d7..8af25d59 100644 --- a/slf4j/src/test/scala/org/typelevel/log4cats/slf4j/internal/Slf4jLoggerInternalSuite.scala +++ b/slf4j/src/test/scala/org/typelevel/log4cats/slf4j/internal/Slf4jLoggerInternalSuite.scala @@ -17,16 +17,30 @@ package org.typelevel.log4cats.slf4j package internal -import cats.effect.IO +import cats.arrow.FunctionK +import cats.effect.{IO, Resource, SyncIO} +import cats.syntax.all.* + import java.util.concurrent.Executors import java.util.concurrent.ThreadFactory import org.slf4j.MDC import munit.CatsEffectSuite +import org.typelevel.log4cats.extras.DeferredLogMessage + import scala.concurrent.ExecutionContext import scala.concurrent.ExecutionContextExecutorService +import scala.jdk.CollectionConverters.* +import scala.util.control.NoStackTrace class Slf4jLoggerInternalSuite extends CatsEffectSuite { + // Fixes a flaky test issue that may or may not be a bug + // See: https://github.com/typelevel/log4cats/issues/851 + override def beforeEach(context: BeforeEach): Unit = { + super.beforeEach(context) + MDC.clear() + } + object dirtyStuff { def namedSingleThreadExecutionContext(name: String): ExecutionContextExecutorService = @@ -36,16 +50,39 @@ class Slf4jLoggerInternalSuite extends CatsEffectSuite { }) ) - def killThreads(threads: List[ExecutionContextExecutorService]) = threads.foreach { thread => - try thread.shutdownNow() - catch { - case e: Throwable => - Console.err.println("Couldn't shutdown thread") - e.printStackTrace() - } + def killThreads(threads: List[ExecutionContextExecutorService]): Unit = threads.foreach { + thread => + try thread.shutdownNow() + catch { + case e: Throwable => + Console.err.println("Couldn't shutdown thread") + e.printStackTrace() + } } } + def testLoggerFixture( + traceEnabled: Boolean = true, + debugEnabled: Boolean = true, + infoEnabled: Boolean = true, + warnEnabled: Boolean = true, + errorEnabled: Boolean = true + ): SyncIO[FunFixture[JTestLogger]] = + ResourceFunFixture( + Resource.eval( + IO( + new JTestLogger( + "Test Logger", + traceEnabled, + debugEnabled, + infoEnabled, + warnEnabled, + errorEnabled + ) + ) + ) + ) + test("Slf4jLoggerInternal resets after logging") { val variable = "foo" val initial = "yellow" @@ -57,4 +94,261 @@ class Slf4jLoggerInternalSuite extends CatsEffectSuite { .as(MDC.get(variable)) .assertEquals(initial) } + + testLoggerFixture().test("Slf4jLoggerInternal correctly sets the MDC") { testLogger => + Slf4jLogger + .getLoggerFromSlf4j[IO](testLogger) + .info(Map("foo" -> "bar"))("A log went here") >> + IO(testLogger.logs()) + .map(_.asScala.toList) + .assertEquals( + List( + DeferredLogMessage.info(Map("foo" -> "bar"), none, () => "A log went here") + ) + ) + } + + testLoggerFixture( + traceEnabled = false, + debugEnabled = false, + infoEnabled = false, + warnEnabled = false, + errorEnabled = false + ).test("Slf4jLoggerInternal is suitably lazy") { testLogger => + def die(): String = throw new IllegalStateException() + val slf4jLogger = Slf4jLogger.getLoggerFromSlf4j[IO](testLogger) + val dummyThrowable = new NoSuchElementException() with NoStackTrace + val ctx = Map("foo" -> "bar") + // If these are lazy the way they need to be, the message won't be evaluated until + // after the log level has been checked + slf4jLogger.trace(die()).assert >> + slf4jLogger.debug(die()).assert >> + slf4jLogger.info(die()).assert >> + slf4jLogger.warn(die()).assert >> + slf4jLogger.error(die()).assert >> + slf4jLogger.trace(dummyThrowable)(die()).assert >> + slf4jLogger.debug(dummyThrowable)(die()).assert >> + slf4jLogger.info(dummyThrowable)(die()).assert >> + slf4jLogger.warn(dummyThrowable)(die()).assert >> + slf4jLogger.error(dummyThrowable)(die()).assert >> + slf4jLogger.trace(ctx)(die()).assert >> + slf4jLogger.debug(ctx)(die()).assert >> + slf4jLogger.info(ctx)(die()).assert >> + slf4jLogger.warn(ctx)(die()).assert >> + slf4jLogger.error(ctx)(die()).assert >> + slf4jLogger.trace(ctx, dummyThrowable)(die()).assert >> + slf4jLogger.debug(ctx, dummyThrowable)(die()).assert >> + slf4jLogger.info(ctx, dummyThrowable)(die()).assert >> + slf4jLogger.warn(ctx, dummyThrowable)(die()).assert >> + slf4jLogger.error(ctx, dummyThrowable)(die()).assert + } + + testLoggerFixture( + traceEnabled = false, + debugEnabled = false, + infoEnabled = false, + warnEnabled = false, + errorEnabled = false + ).test("Slf4jLoggerInternal.mapK is still lazy") { testLogger => + def die(): String = throw new IllegalStateException() + val slf4jLogger = Slf4jLogger.getLoggerFromSlf4j[IO](testLogger).mapK[IO](FunctionK.id) + val dummyThrowable = new NoSuchElementException() with NoStackTrace + val ctx = Map("foo" -> "bar") + // If these are lazy the way they need to be, the message won't be evaluated until + // after the log level has been checked + slf4jLogger.trace(die()).assert >> + slf4jLogger.debug(die()).assert >> + slf4jLogger.info(die()).assert >> + slf4jLogger.warn(die()).assert >> + slf4jLogger.error(die()).assert >> + slf4jLogger.trace(dummyThrowable)(die()).assert >> + slf4jLogger.debug(dummyThrowable)(die()).assert >> + slf4jLogger.info(dummyThrowable)(die()).assert >> + slf4jLogger.warn(dummyThrowable)(die()).assert >> + slf4jLogger.error(dummyThrowable)(die()).assert >> + slf4jLogger.trace(ctx)(die()).assert >> + slf4jLogger.debug(ctx)(die()).assert >> + slf4jLogger.info(ctx)(die()).assert >> + slf4jLogger.warn(ctx)(die()).assert >> + slf4jLogger.error(ctx)(die()).assert >> + slf4jLogger.trace(ctx, dummyThrowable)(die()).assert >> + slf4jLogger.debug(ctx, dummyThrowable)(die()).assert >> + slf4jLogger.info(ctx, dummyThrowable)(die()).assert >> + slf4jLogger.warn(ctx, dummyThrowable)(die()).assert >> + slf4jLogger.error(ctx, dummyThrowable)(die()).assert + } + + testLoggerFixture( + traceEnabled = false, + debugEnabled = false, + infoEnabled = false, + warnEnabled = false, + errorEnabled = false + ).test("Slf4jLoggerInternal.withModifiedString is still lazy") { testLogger => + def die(): String = throw new IllegalStateException() + val slf4jLogger = + Slf4jLogger.getLoggerFromSlf4j[IO](testLogger).withModifiedString(_.toUpperCase) + val dummyThrowable = new NoSuchElementException() with NoStackTrace + val ctx = Map("foo" -> "bar") + // If these are lazy the way they need to be, the message won't be evaluated until + // after the log level has been checked + slf4jLogger.trace(die()).assert >> + slf4jLogger.debug(die()).assert >> + slf4jLogger.info(die()).assert >> + slf4jLogger.warn(die()).assert >> + slf4jLogger.error(die()).assert >> + slf4jLogger.trace(dummyThrowable)(die()).assert >> + slf4jLogger.debug(dummyThrowable)(die()).assert >> + slf4jLogger.info(dummyThrowable)(die()).assert >> + slf4jLogger.warn(dummyThrowable)(die()).assert >> + slf4jLogger.error(dummyThrowable)(die()).assert >> + slf4jLogger.trace(ctx)(die()).assert >> + slf4jLogger.debug(ctx)(die()).assert >> + slf4jLogger.info(ctx)(die()).assert >> + slf4jLogger.warn(ctx)(die()).assert >> + slf4jLogger.error(ctx)(die()).assert >> + slf4jLogger.trace(ctx, dummyThrowable)(die()).assert >> + slf4jLogger.debug(ctx, dummyThrowable)(die()).assert >> + slf4jLogger.info(ctx, dummyThrowable)(die()).assert >> + slf4jLogger.warn(ctx, dummyThrowable)(die()).assert >> + slf4jLogger.error(ctx, dummyThrowable)(die()).assert + } + + testLoggerFixture( + traceEnabled = false, + debugEnabled = false, + infoEnabled = false, + warnEnabled = false, + errorEnabled = false + ).test("Slf4jLoggerInternal.addContext is still lazy") { testLogger => + def die(): String = throw new IllegalStateException() + val slf4jLogger = Slf4jLogger.getLoggerFromSlf4j[IO](testLogger).addContext(Map("bar" -> "foo")) + val dummyThrowable = new NoSuchElementException() with NoStackTrace + val ctx = Map("foo" -> "bar") + // If these are lazy the way they need to be, the message won't be evaluated until + // after the log level has been checked + slf4jLogger.trace(die()).assert >> + slf4jLogger.debug(die()).assert >> + slf4jLogger.info(die()).assert >> + slf4jLogger.warn(die()).assert >> + slf4jLogger.error(die()).assert >> + slf4jLogger.trace(dummyThrowable)(die()).assert >> + slf4jLogger.debug(dummyThrowable)(die()).assert >> + slf4jLogger.info(dummyThrowable)(die()).assert >> + slf4jLogger.warn(dummyThrowable)(die()).assert >> + slf4jLogger.error(dummyThrowable)(die()).assert >> + slf4jLogger.trace(ctx)(die()).assert >> + slf4jLogger.debug(ctx)(die()).assert >> + slf4jLogger.info(ctx)(die()).assert >> + slf4jLogger.warn(ctx)(die()).assert >> + slf4jLogger.error(ctx)(die()).assert >> + slf4jLogger.trace(ctx, dummyThrowable)(die()).assert >> + slf4jLogger.debug(ctx, dummyThrowable)(die()).assert >> + slf4jLogger.info(ctx, dummyThrowable)(die()).assert >> + slf4jLogger.warn(ctx, dummyThrowable)(die()).assert >> + slf4jLogger.error(ctx, dummyThrowable)(die()).assert + } + + testLoggerFixture().test("Slf4jLoggerInternal gets the dispatching right") { testLogger => + val slf4jLogger = Slf4jLogger.getLoggerFromSlf4j[IO](testLogger) + def throwable(tag: String) = new NoSuchElementException(tag) with NoStackTrace + def ctx(tag: String) = Map("tag" -> tag) + // If these are lazy the way they need to be, the message won't be evaluated until + // after the log level has been checked + slf4jLogger.trace("trace(msg)").assert >> + slf4jLogger.debug("debug(msg)").assert >> + slf4jLogger.info("info(msg)").assert >> + slf4jLogger.warn("warn(msg)").assert >> + slf4jLogger.error("error(msg)").assert >> + IO(testLogger.logs().asScala.toList).assertEquals( + List( + DeferredLogMessage.trace(Map.empty, none, () => "trace(msg)"), + DeferredLogMessage.debug(Map.empty, none, () => "debug(msg)"), + DeferredLogMessage.info(Map.empty, none, () => "info(msg)"), + DeferredLogMessage.warn(Map.empty, none, () => "warn(msg)"), + DeferredLogMessage.error(Map.empty, none, () => "error(msg)") + ) + ) >> + IO(testLogger.reset()) >> + slf4jLogger.trace(throwable("trace(t)(msg)"))("trace(t)(msg)").assert >> + slf4jLogger.debug(throwable("debug(t)(msg)"))("debug(t)(msg)").assert >> + slf4jLogger.info(throwable("info(t)(msg)"))("info(t)(msg)").assert >> + slf4jLogger.warn(throwable("warn(t)(msg)"))("warn(t)(msg)").assert >> + slf4jLogger.error(throwable("error(t)(msg)"))("error(t)(msg)").assert >> + IO(testLogger.logs().asScala.toList).assertEquals( + List( + DeferredLogMessage + .trace(Map.empty, throwable("trace(t)(msg)").some, () => "trace(t)(msg)"), + DeferredLogMessage + .debug(Map.empty, throwable("debug(t)(msg)").some, () => "debug(t)(msg)"), + DeferredLogMessage.info(Map.empty, throwable("info(t)(msg)").some, () => "info(t)(msg)"), + DeferredLogMessage.warn(Map.empty, throwable("warn(t)(msg)").some, () => "warn(t)(msg)"), + DeferredLogMessage.error( + Map.empty, + throwable("error(t)(msg)").some, + () => "error(t)(msg)" + ) + ) + ) >> + IO(testLogger.reset()) >> + slf4jLogger.trace(ctx("trace(ctx)(msg)"))("trace(ctx)(msg)").assert >> + slf4jLogger.debug(ctx("debug(ctx)(msg)"))("debug(ctx)(msg)").assert >> + slf4jLogger.info(ctx("info(ctx)(msg)"))("info(ctx)(msg)").assert >> + slf4jLogger.warn(ctx("warn(ctx)(msg)"))("warn(ctx)(msg)").assert >> + slf4jLogger.error(ctx("error(ctx)(msg)"))("error(ctx)(msg)").assert >> + IO(testLogger.logs().asScala.toList).assertEquals( + List( + DeferredLogMessage.trace(ctx("trace(ctx)(msg)"), none, () => "trace(ctx)(msg)"), + DeferredLogMessage.debug(ctx("debug(ctx)(msg)"), none, () => "debug(ctx)(msg)"), + DeferredLogMessage.info(ctx("info(ctx)(msg)"), none, () => "info(ctx)(msg)"), + DeferredLogMessage.warn(ctx("warn(ctx)(msg)"), none, () => "warn(ctx)(msg)"), + DeferredLogMessage.error(ctx("error(ctx)(msg)"), none, () => "error(ctx)(msg)") + ) + ) >> + IO(testLogger.reset()) >> + slf4jLogger + .trace(ctx("trace(ctx, t)(msg)"), throwable("trace(ctx, t)(msg)"))("trace(ctx, t)(msg)") + .assert >> + slf4jLogger + .debug(ctx("debug(ctx, t)(msg)"), throwable("debug(ctx, t)(msg)"))("debug(ctx, t)(msg)") + .assert >> + slf4jLogger + .info(ctx("info(ctx, t)(msg)"), throwable("info(ctx, t)(msg)"))("info(ctx, t)(msg)") + .assert >> + slf4jLogger + .warn(ctx("warn(ctx, t)(msg)"), throwable("warn(ctx, t)(msg)"))("warn(ctx, t)(msg)") + .assert >> + slf4jLogger + .error(ctx("error(ctx, t)(msg)"), throwable("error(ctx, t)(msg)"))("error(ctx, t)(msg)") + .assert >> + IO(testLogger.logs().asScala.toList).assertEquals( + List( + DeferredLogMessage.trace( + ctx("trace(ctx, t)(msg)"), + throwable("trace(ctx, t)(msg)").some, + () => "trace(ctx, t)(msg)" + ), + DeferredLogMessage.debug( + ctx("debug(ctx, t)(msg)"), + throwable("debug(ctx, t)(msg)").some, + () => "debug(ctx, t)(msg)" + ), + DeferredLogMessage.info( + ctx("info(ctx, t)(msg)"), + throwable("info(ctx, t)(msg)").some, + () => "info(ctx, t)(msg)" + ), + DeferredLogMessage.warn( + ctx("warn(ctx, t)(msg)"), + throwable("warn(ctx, t)(msg)").some, + () => "warn(ctx, t)(msg)" + ), + DeferredLogMessage.error( + ctx("error(ctx, t)(msg)"), + throwable("error(ctx, t)(msg)").some, + () => "error(ctx, t)(msg)" + ) + ) + ) + } } diff --git a/testing/shared/src/main/scala/org/typelevel/log4cats/testing/StructuredTestingLogger.scala b/testing/shared/src/main/scala/org/typelevel/log4cats/testing/StructuredTestingLogger.scala index 6f3cb529..27d890d4 100644 --- a/testing/shared/src/main/scala/org/typelevel/log4cats/testing/StructuredTestingLogger.scala +++ b/testing/shared/src/main/scala/org/typelevel/log4cats/testing/StructuredTestingLogger.scala @@ -19,7 +19,8 @@ package org.typelevel.log4cats.testing import cats.data.Chain import org.typelevel.log4cats.SelfAwareStructuredLogger import cats.effect.{Ref, Sync} -import cats.syntax.all._ +import cats.syntax.all.* +import org.typelevel.log4cats.extras.LogLevel import java.util.concurrent.atomic.AtomicReference import scala.annotation.tailrec @@ -139,57 +140,43 @@ object StructuredTestingLogger { new StructuredTestingLogger[F] { def logged: F[Vector[LogMessage]] = read() - def isTraceEnabled: F[Boolean] = Sync[F].pure(traceEnabled) - def isDebugEnabled: F[Boolean] = Sync[F].pure(debugEnabled) - def isInfoEnabled: F[Boolean] = Sync[F].pure(infoEnabled) - def isWarnEnabled: F[Boolean] = Sync[F].pure(warnEnabled) - def isErrorEnabled: F[Boolean] = Sync[F].pure(errorEnabled) - - private val noop = Sync[F].unit - - def error(message: => String): F[Unit] = - if (errorEnabled) appendLogMessage(ERROR(message, None)) else noop - def error(t: Throwable)(message: => String): F[Unit] = - if (errorEnabled) appendLogMessage(ERROR(message, t.some)) else noop - def error(ctx: Map[String, String])(message: => String): F[Unit] = - if (errorEnabled) appendLogMessage(ERROR(message, None, ctx)) else noop - def error(ctx: Map[String, String], t: Throwable)(message: => String): F[Unit] = - if (errorEnabled) appendLogMessage(ERROR(message, t.some, ctx)) else noop - - def warn(message: => String): F[Unit] = - if (warnEnabled) appendLogMessage(WARN(message, None)) else noop - def warn(t: Throwable)(message: => String): F[Unit] = - if (warnEnabled) appendLogMessage(WARN(message, t.some)) else noop - def warn(ctx: Map[String, String])(message: => String): F[Unit] = - if (warnEnabled) appendLogMessage(WARN(message, None, ctx)) else noop - def warn(ctx: Map[String, String], t: Throwable)(message: => String): F[Unit] = - if (warnEnabled) appendLogMessage(WARN(message, t.some, ctx)) else noop - - def info(message: => String): F[Unit] = - if (infoEnabled) appendLogMessage(INFO(message, None)) else noop - def info(t: Throwable)(message: => String): F[Unit] = - if (infoEnabled) appendLogMessage(INFO(message, t.some)) else noop - def info(ctx: Map[String, String])(message: => String): F[Unit] = - if (infoEnabled) appendLogMessage(INFO(message, None, ctx)) else noop - def info(ctx: Map[String, String], t: Throwable)(message: => String): F[Unit] = - if (infoEnabled) appendLogMessage(INFO(message, t.some, ctx)) else noop - - def debug(message: => String): F[Unit] = - if (debugEnabled) appendLogMessage(DEBUG(message, None)) else noop - def debug(t: Throwable)(message: => String): F[Unit] = - if (debugEnabled) appendLogMessage(DEBUG(message, t.some)) else noop - def debug(ctx: Map[String, String])(message: => String): F[Unit] = - if (debugEnabled) appendLogMessage(DEBUG(message, None, ctx)) else noop - def debug(ctx: Map[String, String], t: Throwable)(message: => String): F[Unit] = - if (debugEnabled) appendLogMessage(DEBUG(message, t.some, ctx)) else noop - - def trace(message: => String): F[Unit] = - if (traceEnabled) appendLogMessage(TRACE(message, None)) else noop - def trace(t: Throwable)(message: => String): F[Unit] = - if (traceEnabled) appendLogMessage(TRACE(message, t.some)) else noop - def trace(ctx: Map[String, String])(message: => String): F[Unit] = - if (traceEnabled) appendLogMessage(TRACE(message, None, ctx)) else noop - def trace(ctx: Map[String, String], t: Throwable)(message: => String): F[Unit] = - if (traceEnabled) appendLogMessage(TRACE(message, t.some, ctx)) else noop + private def shouldLog(ll: LogLevel): Boolean = ll match { + case LogLevel.Error => errorEnabled + case LogLevel.Warn => warnEnabled + case LogLevel.Info => infoEnabled + case LogLevel.Debug => debugEnabled + case LogLevel.Trace => traceEnabled + } + + private def save( + ll: LogLevel, + ctx: Map[String, String], + t: Option[Throwable], + msg: => String + ): F[Unit] = + Sync[F].whenA(shouldLog(ll))(appendLogMessage(ll match { + case LogLevel.Error => ERROR(msg, t, ctx) + case LogLevel.Warn => WARN(msg, t, ctx) + case LogLevel.Info => INFO(msg, t, ctx) + case LogLevel.Debug => DEBUG(msg, t, ctx) + case LogLevel.Trace => TRACE(msg, t, ctx) + })) + + override def isEnabled(ll: LogLevel): F[Boolean] = Sync[F].pure(shouldLog(ll)) + + override def log( + ll: LogLevel, + ctx: Map[String, String], + t: Throwable, + msg: => String + ): F[Unit] = save(ll, ctx, t.some, msg) + + override def log(ll: LogLevel, ctx: Map[String, String], msg: => String): F[Unit] = + save(ll, ctx, none, msg) + + override def log(ll: LogLevel, t: Throwable, msg: => String): F[Unit] = + save(ll, Map.empty, t.some, msg) + + override def log(ll: LogLevel, msg: => String): F[Unit] = save(ll, Map.empty, none, msg) } } diff --git a/testing/shared/src/main/scala/org/typelevel/log4cats/testing/TestingLogger.scala b/testing/shared/src/main/scala/org/typelevel/log4cats/testing/TestingLogger.scala index fa80b363..971a87ea 100644 --- a/testing/shared/src/main/scala/org/typelevel/log4cats/testing/TestingLogger.scala +++ b/testing/shared/src/main/scala/org/typelevel/log4cats/testing/TestingLogger.scala @@ -19,7 +19,8 @@ package org.typelevel.log4cats.testing import cats.data.Chain import org.typelevel.log4cats.SelfAwareLogger import cats.effect.{Ref, Sync} -import cats.syntax.all._ +import cats.syntax.all.* +import org.typelevel.log4cats.extras.LogLevel import java.util.concurrent.atomic.AtomicReference import scala.annotation.tailrec @@ -118,38 +119,28 @@ object TestingLogger { new TestingLogger[F] { def logged: F[Vector[LogMessage]] = read() - def isTraceEnabled: F[Boolean] = Sync[F].pure(traceEnabled) - def isDebugEnabled: F[Boolean] = Sync[F].pure(debugEnabled) - def isInfoEnabled: F[Boolean] = Sync[F].pure(infoEnabled) - def isWarnEnabled: F[Boolean] = Sync[F].pure(warnEnabled) - def isErrorEnabled: F[Boolean] = Sync[F].pure(errorEnabled) - - private val noop = Sync[F].unit - - def error(message: => String): F[Unit] = - if (errorEnabled) appendLogMessage(ERROR(message, None)) else noop - def error(t: Throwable)(message: => String): F[Unit] = - if (errorEnabled) appendLogMessage(ERROR(message, t.some)) else noop - - def warn(message: => String): F[Unit] = - if (warnEnabled) appendLogMessage(WARN(message, None)) else noop - def warn(t: Throwable)(message: => String): F[Unit] = - if (warnEnabled) appendLogMessage(WARN(message, t.some)) else noop - - def info(message: => String): F[Unit] = - if (infoEnabled) appendLogMessage(INFO(message, None)) else noop - def info(t: Throwable)(message: => String): F[Unit] = - if (infoEnabled) appendLogMessage(INFO(message, t.some)) else noop - - def debug(message: => String): F[Unit] = - if (debugEnabled) appendLogMessage(DEBUG(message, None)) else noop - def debug(t: Throwable)(message: => String): F[Unit] = - if (debugEnabled) appendLogMessage(DEBUG(message, t.some)) else noop - - def trace(message: => String): F[Unit] = - if (traceEnabled) appendLogMessage(TRACE(message, None)) else noop - def trace(t: Throwable)(message: => String): F[Unit] = - if (traceEnabled) appendLogMessage(TRACE(message, t.some)) else noop + private def shouldLog(ll: LogLevel): Boolean = ll match { + case LogLevel.Error => errorEnabled + case LogLevel.Warn => warnEnabled + case LogLevel.Info => infoEnabled + case LogLevel.Debug => debugEnabled + case LogLevel.Trace => traceEnabled + } + + private def save(ll: LogLevel, t: Option[Throwable], msg: => String): F[Unit] = + Sync[F].whenA(shouldLog(ll))(appendLogMessage(ll match { + case LogLevel.Error => ERROR(msg, t) + case LogLevel.Warn => WARN(msg, t) + case LogLevel.Info => INFO(msg, t) + case LogLevel.Debug => DEBUG(msg, t) + case LogLevel.Trace => TRACE(msg, t) + })) + + override def isEnabled(ll: LogLevel): F[Boolean] = Sync[F].pure(shouldLog(ll)) + + override def log(ll: LogLevel, t: Throwable, msg: => String): F[Unit] = save(ll, t.some, msg) + + override def log(ll: LogLevel, msg: => String): F[Unit] = save(ll, none, msg) } } diff --git a/testing/shared/src/main/scala/org/typelevel/log4cats/testing/TestingLoggerFactory.scala b/testing/shared/src/main/scala/org/typelevel/log4cats/testing/TestingLoggerFactory.scala index c70477ce..8e373658 100644 --- a/testing/shared/src/main/scala/org/typelevel/log4cats/testing/TestingLoggerFactory.scala +++ b/testing/shared/src/main/scala/org/typelevel/log4cats/testing/TestingLoggerFactory.scala @@ -19,7 +19,7 @@ package org.typelevel.log4cats.testing import cats.Show import cats.data.Chain import cats.effect.{Ref, Sync} -import cats.syntax.all._ +import cats.syntax.all.* import org.typelevel.log4cats.extras.LogLevel import org.typelevel.log4cats.testing.TestingLoggerFactory.LogMessage import org.typelevel.log4cats.{LoggerFactory, SelfAwareStructuredLogger} @@ -173,57 +173,46 @@ object TestingLoggerFactory { Sync[F].delay(getLoggerFromName(name)) override def getLoggerFromName(name: String): SelfAwareStructuredLogger[F] = new SelfAwareStructuredLogger[F] { - override val isTraceEnabled: F[Boolean] = traceEnabled.pure[F] - override val isDebugEnabled: F[Boolean] = debugEnabled.pure[F] - override val isInfoEnabled: F[Boolean] = infoEnabled.pure[F] - override val isWarnEnabled: F[Boolean] = warnEnabled.pure[F] - override val isErrorEnabled: F[Boolean] = errorEnabled.pure[F] - - private val noop = Sync[F].unit - - override def trace(ctx: Map[String, String])(msg: => String): F[Unit] = - if (traceEnabled) save(Trace(name, msg, none, ctx)) else noop - override def debug(ctx: Map[String, String])(msg: => String): F[Unit] = - if (debugEnabled) save(Debug(name, msg, none, ctx)) else noop - override def info(ctx: Map[String, String])(msg: => String): F[Unit] = - if (infoEnabled) save(Info(name, msg, none, ctx)) else noop - override def warn(ctx: Map[String, String])(msg: => String): F[Unit] = - if (warnEnabled) save(Warn(name, msg, none, ctx)) else noop - override def error(ctx: Map[String, String])(msg: => String): F[Unit] = - if (errorEnabled) save(Error(name, msg, none, ctx)) else noop - - override def trace(ctx: Map[String, String], t: Throwable)(msg: => String): F[Unit] = - if (traceEnabled) save(Trace(name, msg, t.some, ctx)) else noop - override def debug(ctx: Map[String, String], t: Throwable)(msg: => String): F[Unit] = - if (debugEnabled) save(Debug(name, msg, t.some, ctx)) else noop - override def info(ctx: Map[String, String], t: Throwable)(msg: => String): F[Unit] = - if (infoEnabled) save(Info(name, msg, t.some, ctx)) else noop - override def warn(ctx: Map[String, String], t: Throwable)(msg: => String): F[Unit] = - if (warnEnabled) save(Warn(name, msg, t.some, ctx)) else noop - override def error(ctx: Map[String, String], t: Throwable)(msg: => String): F[Unit] = - if (errorEnabled) save(Error(name, msg, t.some, ctx)) else noop - - override def trace(t: Throwable)(msg: => String): F[Unit] = - if (traceEnabled) save(Trace(name, msg, t.some, Map.empty)) else noop - override def debug(t: Throwable)(msg: => String): F[Unit] = - if (debugEnabled) save(Debug(name, msg, t.some, Map.empty)) else noop - override def info(t: Throwable)(msg: => String): F[Unit] = - if (infoEnabled) save(Info(name, msg, t.some, Map.empty)) else noop - override def warn(t: Throwable)(msg: => String): F[Unit] = - if (warnEnabled) save(Warn(name, msg, t.some, Map.empty)) else noop - override def error(t: Throwable)(msg: => String): F[Unit] = - if (errorEnabled) save(Error(name, msg, t.some, Map.empty)) else noop - - override def trace(msg: => String): F[Unit] = - if (traceEnabled) save(Trace(name, msg, none, Map.empty)) else noop - override def debug(msg: => String): F[Unit] = - if (debugEnabled) save(Debug(name, msg, none, Map.empty)) else noop - override def info(msg: => String): F[Unit] = - if (infoEnabled) save(Info(name, msg, none, Map.empty)) else noop - override def warn(msg: => String): F[Unit] = - if (warnEnabled) save(Warn(name, msg, none, Map.empty)) else noop - override def error(msg: => String): F[Unit] = - if (errorEnabled) save(Error(name, msg, none, Map.empty)) else noop + + private def shouldLog(ll: LogLevel): Boolean = ll match { + case LogLevel.Error => errorEnabled + case LogLevel.Warn => warnEnabled + case LogLevel.Info => infoEnabled + case LogLevel.Debug => debugEnabled + case LogLevel.Trace => traceEnabled + } + + private def write( + ll: LogLevel, + ctx: Map[String, String], + t: Option[Throwable], + msg: => String + ): F[Unit] = + Sync[F].whenA(shouldLog(ll))(save(ll match { + case LogLevel.Error => Error(name, msg, t, ctx) + case LogLevel.Warn => Warn(name, msg, t, ctx) + case LogLevel.Info => Info(name, msg, t, ctx) + case LogLevel.Debug => Debug(name, msg, t, ctx) + case LogLevel.Trace => Trace(name, msg, t, ctx) + })) + + override def isEnabled(ll: LogLevel): F[Boolean] = Sync[F].pure(shouldLog(ll)) + + override def log( + ll: LogLevel, + ctx: Map[String, String], + t: Throwable, + msg: => String + ): F[Unit] = + write(ll, ctx, t.some, msg) + + override def log(ll: LogLevel, ctx: Map[String, String], msg: => String): F[Unit] = + write(ll, ctx, none, msg) + + override def log(ll: LogLevel, t: Throwable, msg: => String): F[Unit] = + write(ll, Map.empty, t.some, msg) + + override def log(ll: LogLevel, msg: => String): F[Unit] = write(ll, Map.empty, none, msg) } } From 1dea00668ae1bec2233c9f07492f9f8756f77cfa Mon Sep 17 00:00:00 2001 From: Morgen Peschke Date: Mon, 17 Jun 2024 14:33:11 -0700 Subject: [PATCH 2/4] Scalafmt --- .../PagingSelfAwareStructuredLogger.scala | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/core/shared/src/main/scala/org/typelevel/log4cats/PagingSelfAwareStructuredLogger.scala b/core/shared/src/main/scala/org/typelevel/log4cats/PagingSelfAwareStructuredLogger.scala index e2e92771..16020ba6 100644 --- a/core/shared/src/main/scala/org/typelevel/log4cats/PagingSelfAwareStructuredLogger.scala +++ b/core/shared/src/main/scala/org/typelevel/log4cats/PagingSelfAwareStructuredLogger.scala @@ -88,10 +88,10 @@ object PagingSelfAwareStructuredLogger { private val pageSize = pageSizeK * 1024 private def pagedLogging( - logLevel: LogLevel, - ctx: Map[String, String], - logSplitId: String, - msg: String + logLevel: LogLevel, + ctx: Map[String, String], + logSplitId: String, + msg: String ): F[Unit] = { val numOfPagesRaw = (msg.length - 1) / pageSize + 1 val numOfPages = Math.min(numOfPagesRaw, maxPageNeeded) @@ -156,10 +156,10 @@ object PagingSelfAwareStructuredLogger { ) private def doLoggingThrowable( - logLevel: LogLevel, - ctx: Map[String, String], - t: Throwable, - msg: => String + logLevel: LogLevel, + ctx: Map[String, String], + t: Throwable, + msg: => String ): F[Unit] = doLogging(logLevel, ctx, s"$msg\n${getStackTrace(t)}") def getStackTrace(t: Throwable): String = { @@ -181,11 +181,11 @@ object PagingSelfAwareStructuredLogger { doLogging(ll, ctx, msg) override def log( - ll: LogLevel, - ctx: Map[String, String], - t: Throwable, - msg: => String - ): F[Unit] = + ll: LogLevel, + ctx: Map[String, String], + t: Throwable, + msg: => String + ): F[Unit] = doLoggingThrowable(ll, ctx, t, msg) } } From 1f95d596af4a5a181105f80d13ced511a3b01722 Mon Sep 17 00:00:00 2001 From: Morgen Peschke Date: Mon, 17 Jun 2024 16:00:21 -0700 Subject: [PATCH 3/4] Work around the collections change between 2.12 and 2.13 --- .../log4cats/slf4j/internal/JTestLogger.java | 118 ++++++++---- .../internal/Slf4jLoggerInternalSuite.scala | 172 +++++++++++------- 2 files changed, 194 insertions(+), 96 deletions(-) diff --git a/slf4j/src/test/scala/org/typelevel/log4cats/slf4j/internal/JTestLogger.java b/slf4j/src/test/scala/org/typelevel/log4cats/slf4j/internal/JTestLogger.java index fa55ee64..7c66fe52 100644 --- a/slf4j/src/test/scala/org/typelevel/log4cats/slf4j/internal/JTestLogger.java +++ b/slf4j/src/test/scala/org/typelevel/log4cats/slf4j/internal/JTestLogger.java @@ -19,23 +19,89 @@ import org.slf4j.Logger; import org.slf4j.MDC; import org.slf4j.Marker; -import org.typelevel.log4cats.extras.DeferredLogMessage; -import org.typelevel.log4cats.extras.DeferredLogMessage$; -import scala.collection.immutable.Map; +import org.typelevel.log4cats.extras.LogLevel; +import scala.Option; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.concurrent.atomic.AtomicReference; import java.util.function.Function; +import java.util.function.Supplier; public class JTestLogger implements Logger { + // Java -> Scala compat helpers + + private static final scala.Option none = scala.Option$.MODULE$.empty(); + private static scala.Option some(Throwable t) { return scala.Option$.MODULE$.apply(t); } + private static final LogLevel.Trace$ Trace = LogLevel.Trace$.MODULE$; + private static final LogLevel.Debug$ Debug = LogLevel.Debug$.MODULE$; + private static final LogLevel.Info$ Info = LogLevel.Info$.MODULE$; + private static final LogLevel.Warn$ Warn = LogLevel.Warn$.MODULE$; + private static final LogLevel.Error$ Error = LogLevel.Error$.MODULE$; + + private Map captureContext () { + java.util.Map mdc = MDC.getCopyOfContextMap(); + if (mdc == null) { + return new HashMap<>(); + } + return MDC.getCopyOfContextMap(); + } + + public static class TestLogMessage { + public final LogLevel logLevel; + public final java.util.Map context; + public final Option throwableOpt; + public final Supplier message; + + public TestLogMessage(LogLevel logLevel, + java.util.Map context, + Option throwableOpt, + Supplier message) { + this.logLevel = logLevel; + this.context = context; + this.throwableOpt = throwableOpt; + this.message = message; + } + + @Override + public String toString() { + return new StringBuilder() + .append("TestLogMessage(") + .append("logLevel=").append(logLevel) + .append(", ") + .append("context=").append(context) + .append(", ") + .append("throwableOpt=").append(throwableOpt) + .append(", ") + .append("message=").append(message.get()) + .append(')') + .toString(); + } + + static TestLogMessage of(LogLevel logLevel, + java.util.Map context, + Throwable throwable, + Supplier message) { + return new TestLogMessage(logLevel, context, some(throwable), message); + } + + static TestLogMessage of(LogLevel logLevel, + java.util.Map context, + Supplier message) { + return new TestLogMessage(logLevel, context, none, message); + } + } + private final String loggerName; private final boolean traceEnabled; private final boolean debugEnabled; private final boolean infoEnabled; private final boolean warnEnabled; private final boolean errorEnabled; - private final AtomicReference> loggedMessages; + private final AtomicReference> loggedMessages; + public JTestLogger(String loggerName, boolean traceEnabled, @@ -49,35 +115,17 @@ public JTestLogger(String loggerName, this.infoEnabled = infoEnabled; this.warnEnabled = warnEnabled; this.errorEnabled = errorEnabled; - loggedMessages = new AtomicReference<>(new ArrayList()); - } - - // Java -> Scala compat helpers - - private final scala.Option none = scala.Option$.MODULE$.empty(); - private scala.Option some(Throwable t) { return scala.Option$.MODULE$.apply(t); } - - private Map captureContext () { - java.util.Map mdc = MDC.getCopyOfContextMap(); - if (mdc == null) { - return scala.collection.immutable.Map$.MODULE$.empty(); - } - return scala.collection.immutable.Map$.MODULE$.from( - scala.jdk.javaapi.CollectionConverters.asScala(MDC.getCopyOfContextMap()) - ); + loggedMessages = new AtomicReference<>(new ArrayList()); } - // Way to long to type the full DeferredLogMessage$.MODULE$ all the time - private DeferredLogMessage$ DLM = DeferredLogMessage$.MODULE$; - - private void save(Function, DeferredLogMessage> mkLogMessage) { + private void save(Function, TestLogMessage> mkLogMessage) { loggedMessages.updateAndGet(ll -> { ll.add(mkLogMessage.apply(captureContext())); return ll; }); } - public List logs() { return loggedMessages.get(); } + public List logs() { return loggedMessages.get(); } public void reset() { loggedMessages.set(new ArrayList<>()); } @Override public String getName() { return loggerName;} @@ -95,20 +143,20 @@ private void save(Function, DeferredLogMessage> mkLogMessage @Override public boolean isWarnEnabled(Marker marker) { return warnEnabled; } @Override public boolean isErrorEnabled(Marker marker) { return errorEnabled; } - @Override public void trace(String msg) { save(ctx -> DLM.trace(ctx, none, () -> msg)); } - @Override public void trace(String msg, Throwable t) { save(ctx -> DLM.trace(ctx, some(t), () -> msg)); } + @Override public void trace(String msg) { save(ctx -> TestLogMessage.of(Trace, ctx, () -> msg)); } + @Override public void trace(String msg, Throwable t) { save(ctx -> TestLogMessage.of(Trace, ctx, t, () -> msg)); } - @Override public void debug(String msg) { save(ctx -> DLM.debug(ctx, none, () -> msg)); } - @Override public void debug(String msg, Throwable t) { save(ctx -> DLM.debug(ctx, some(t), () -> msg)); } + @Override public void debug(String msg) { save(ctx -> TestLogMessage.of(Debug, ctx, () -> msg)); } + @Override public void debug(String msg, Throwable t) { save(ctx -> TestLogMessage.of(Debug, ctx, t, () -> msg)); } - @Override public void info(String msg) { save(ctx -> DLM.info(ctx, none, () -> msg)); } - @Override public void info(String msg, Throwable t) { save(ctx -> DLM.info(ctx, some(t), () -> msg)); } + @Override public void info(String msg) { save(ctx -> TestLogMessage.of(Info, ctx, () -> msg)); } + @Override public void info(String msg, Throwable t) { save(ctx -> TestLogMessage.of(Info, ctx, t, () -> msg)); } - @Override public void warn(String msg) { save(ctx -> DLM.warn(ctx, none, () -> msg)); } - @Override public void warn(String msg, Throwable t) { save(ctx -> DLM.warn(ctx, some(t), () -> msg)); } + @Override public void warn(String msg) { save(ctx -> TestLogMessage.of(Warn, ctx, () -> msg)); } + @Override public void warn(String msg, Throwable t) { save(ctx -> TestLogMessage.of(Warn, ctx, t, () -> msg)); } - @Override public void error(String msg) { save(ctx -> DLM.error(ctx, none, () -> msg)); } - @Override public void error(String msg, Throwable t) { save(ctx -> DLM.error(ctx, some(t), () -> msg)); } + @Override public void error(String msg) { save(ctx -> TestLogMessage.of(Error, ctx, () -> msg)); } + @Override public void error(String msg, Throwable t) { save(ctx -> TestLogMessage.of(Error, ctx, t, () -> msg)); } // We shouldn't need these for our tests, so we're treating these variants as if they were the standard method diff --git a/slf4j/src/test/scala/org/typelevel/log4cats/slf4j/internal/Slf4jLoggerInternalSuite.scala b/slf4j/src/test/scala/org/typelevel/log4cats/slf4j/internal/Slf4jLoggerInternalSuite.scala index 8af25d59..09bea4fb 100644 --- a/slf4j/src/test/scala/org/typelevel/log4cats/slf4j/internal/Slf4jLoggerInternalSuite.scala +++ b/slf4j/src/test/scala/org/typelevel/log4cats/slf4j/internal/Slf4jLoggerInternalSuite.scala @@ -26,10 +26,15 @@ import java.util.concurrent.ThreadFactory import org.slf4j.MDC import munit.CatsEffectSuite import org.typelevel.log4cats.extras.DeferredLogMessage +import org.typelevel.log4cats.slf4j.internal.JTestLogger.TestLogMessage +import java.util +import java.util.function +import java.util.function.{BiConsumer, BinaryOperator, Supplier} +import java.util.stream.Collector +import scala.collection.mutable.ListBuffer import scala.concurrent.ExecutionContext import scala.concurrent.ExecutionContextExecutorService -import scala.jdk.CollectionConverters.* import scala.util.control.NoStackTrace class Slf4jLoggerInternalSuite extends CatsEffectSuite { @@ -95,12 +100,47 @@ class Slf4jLoggerInternalSuite extends CatsEffectSuite { .assertEquals(initial) } + // Collections compat with Java is really annoying across the 2.12 / 2.13 boundary + // + // If you are reading this and support for 2.12 has been dropped, kindly rip this + // out and call one of the helpers from scala.jdk.javaapi instead. + private def toScalaList[A]: Collector[A, ListBuffer[A], List[A]] = + new Collector[A, ListBuffer[A], List[A]] { + override val characteristics: util.Set[Collector.Characteristics] = + new util.HashSet[Collector.Characteristics]() + + override val supplier: Supplier[ListBuffer[A]] = () => new ListBuffer[A] + + override val accumulator: BiConsumer[ListBuffer[A], A] = (b, e) => b.append(e) + + override val combiner: BinaryOperator[ListBuffer[A]] = (a, b) => { + a.appendAll(b) + a + } + + override val finisher: function.Function[ListBuffer[A], List[A]] = _.result() + } + + private def toDeferredLogs(jl: java.util.List[TestLogMessage]): List[DeferredLogMessage] = + jl.stream() + .map[DeferredLogMessage] { tl => + val context = + tl.context + .entrySet() + .stream() + .map[(String, String)](e => e.getKey -> e.getValue) + .collect(toScalaList) + .toMap + DeferredLogMessage(tl.logLevel, context, tl.throwableOpt, () => tl.message.get()) + } + .collect(toScalaList[DeferredLogMessage]) + testLoggerFixture().test("Slf4jLoggerInternal correctly sets the MDC") { testLogger => Slf4jLogger .getLoggerFromSlf4j[IO](testLogger) .info(Map("foo" -> "bar"))("A log went here") >> IO(testLogger.logs()) - .map(_.asScala.toList) + .map(toDeferredLogs) .assertEquals( List( DeferredLogMessage.info(Map("foo" -> "bar"), none, () => "A log went here") @@ -260,51 +300,59 @@ class Slf4jLoggerInternalSuite extends CatsEffectSuite { slf4jLogger.info("info(msg)").assert >> slf4jLogger.warn("warn(msg)").assert >> slf4jLogger.error("error(msg)").assert >> - IO(testLogger.logs().asScala.toList).assertEquals( - List( - DeferredLogMessage.trace(Map.empty, none, () => "trace(msg)"), - DeferredLogMessage.debug(Map.empty, none, () => "debug(msg)"), - DeferredLogMessage.info(Map.empty, none, () => "info(msg)"), - DeferredLogMessage.warn(Map.empty, none, () => "warn(msg)"), - DeferredLogMessage.error(Map.empty, none, () => "error(msg)") - ) - ) >> + IO(testLogger.logs()) + .map(toDeferredLogs) + .assertEquals( + List( + DeferredLogMessage.trace(Map.empty, none, () => "trace(msg)"), + DeferredLogMessage.debug(Map.empty, none, () => "debug(msg)"), + DeferredLogMessage.info(Map.empty, none, () => "info(msg)"), + DeferredLogMessage.warn(Map.empty, none, () => "warn(msg)"), + DeferredLogMessage.error(Map.empty, none, () => "error(msg)") + ) + ) >> IO(testLogger.reset()) >> slf4jLogger.trace(throwable("trace(t)(msg)"))("trace(t)(msg)").assert >> slf4jLogger.debug(throwable("debug(t)(msg)"))("debug(t)(msg)").assert >> slf4jLogger.info(throwable("info(t)(msg)"))("info(t)(msg)").assert >> slf4jLogger.warn(throwable("warn(t)(msg)"))("warn(t)(msg)").assert >> slf4jLogger.error(throwable("error(t)(msg)"))("error(t)(msg)").assert >> - IO(testLogger.logs().asScala.toList).assertEquals( - List( - DeferredLogMessage - .trace(Map.empty, throwable("trace(t)(msg)").some, () => "trace(t)(msg)"), - DeferredLogMessage - .debug(Map.empty, throwable("debug(t)(msg)").some, () => "debug(t)(msg)"), - DeferredLogMessage.info(Map.empty, throwable("info(t)(msg)").some, () => "info(t)(msg)"), - DeferredLogMessage.warn(Map.empty, throwable("warn(t)(msg)").some, () => "warn(t)(msg)"), - DeferredLogMessage.error( - Map.empty, - throwable("error(t)(msg)").some, - () => "error(t)(msg)" + IO(testLogger.logs()) + .map(toDeferredLogs) + .assertEquals( + List( + DeferredLogMessage + .trace(Map.empty, throwable("trace(t)(msg)").some, () => "trace(t)(msg)"), + DeferredLogMessage + .debug(Map.empty, throwable("debug(t)(msg)").some, () => "debug(t)(msg)"), + DeferredLogMessage + .info(Map.empty, throwable("info(t)(msg)").some, () => "info(t)(msg)"), + DeferredLogMessage + .warn(Map.empty, throwable("warn(t)(msg)").some, () => "warn(t)(msg)"), + DeferredLogMessage.error( + Map.empty, + throwable("error(t)(msg)").some, + () => "error(t)(msg)" + ) ) - ) - ) >> + ) >> IO(testLogger.reset()) >> slf4jLogger.trace(ctx("trace(ctx)(msg)"))("trace(ctx)(msg)").assert >> slf4jLogger.debug(ctx("debug(ctx)(msg)"))("debug(ctx)(msg)").assert >> slf4jLogger.info(ctx("info(ctx)(msg)"))("info(ctx)(msg)").assert >> slf4jLogger.warn(ctx("warn(ctx)(msg)"))("warn(ctx)(msg)").assert >> slf4jLogger.error(ctx("error(ctx)(msg)"))("error(ctx)(msg)").assert >> - IO(testLogger.logs().asScala.toList).assertEquals( - List( - DeferredLogMessage.trace(ctx("trace(ctx)(msg)"), none, () => "trace(ctx)(msg)"), - DeferredLogMessage.debug(ctx("debug(ctx)(msg)"), none, () => "debug(ctx)(msg)"), - DeferredLogMessage.info(ctx("info(ctx)(msg)"), none, () => "info(ctx)(msg)"), - DeferredLogMessage.warn(ctx("warn(ctx)(msg)"), none, () => "warn(ctx)(msg)"), - DeferredLogMessage.error(ctx("error(ctx)(msg)"), none, () => "error(ctx)(msg)") - ) - ) >> + IO(testLogger.logs()) + .map(toDeferredLogs) + .assertEquals( + List( + DeferredLogMessage.trace(ctx("trace(ctx)(msg)"), none, () => "trace(ctx)(msg)"), + DeferredLogMessage.debug(ctx("debug(ctx)(msg)"), none, () => "debug(ctx)(msg)"), + DeferredLogMessage.info(ctx("info(ctx)(msg)"), none, () => "info(ctx)(msg)"), + DeferredLogMessage.warn(ctx("warn(ctx)(msg)"), none, () => "warn(ctx)(msg)"), + DeferredLogMessage.error(ctx("error(ctx)(msg)"), none, () => "error(ctx)(msg)") + ) + ) >> IO(testLogger.reset()) >> slf4jLogger .trace(ctx("trace(ctx, t)(msg)"), throwable("trace(ctx, t)(msg)"))("trace(ctx, t)(msg)") @@ -321,34 +369,36 @@ class Slf4jLoggerInternalSuite extends CatsEffectSuite { slf4jLogger .error(ctx("error(ctx, t)(msg)"), throwable("error(ctx, t)(msg)"))("error(ctx, t)(msg)") .assert >> - IO(testLogger.logs().asScala.toList).assertEquals( - List( - DeferredLogMessage.trace( - ctx("trace(ctx, t)(msg)"), - throwable("trace(ctx, t)(msg)").some, - () => "trace(ctx, t)(msg)" - ), - DeferredLogMessage.debug( - ctx("debug(ctx, t)(msg)"), - throwable("debug(ctx, t)(msg)").some, - () => "debug(ctx, t)(msg)" - ), - DeferredLogMessage.info( - ctx("info(ctx, t)(msg)"), - throwable("info(ctx, t)(msg)").some, - () => "info(ctx, t)(msg)" - ), - DeferredLogMessage.warn( - ctx("warn(ctx, t)(msg)"), - throwable("warn(ctx, t)(msg)").some, - () => "warn(ctx, t)(msg)" - ), - DeferredLogMessage.error( - ctx("error(ctx, t)(msg)"), - throwable("error(ctx, t)(msg)").some, - () => "error(ctx, t)(msg)" + IO(testLogger.logs()) + .map(toDeferredLogs) + .assertEquals( + List( + DeferredLogMessage.trace( + ctx("trace(ctx, t)(msg)"), + throwable("trace(ctx, t)(msg)").some, + () => "trace(ctx, t)(msg)" + ), + DeferredLogMessage.debug( + ctx("debug(ctx, t)(msg)"), + throwable("debug(ctx, t)(msg)").some, + () => "debug(ctx, t)(msg)" + ), + DeferredLogMessage.info( + ctx("info(ctx, t)(msg)"), + throwable("info(ctx, t)(msg)").some, + () => "info(ctx, t)(msg)" + ), + DeferredLogMessage.warn( + ctx("warn(ctx, t)(msg)"), + throwable("warn(ctx, t)(msg)").some, + () => "warn(ctx, t)(msg)" + ), + DeferredLogMessage.error( + ctx("error(ctx, t)(msg)"), + throwable("error(ctx, t)(msg)").some, + () => "error(ctx, t)(msg)" + ) ) ) - ) } } From 1198df79c496b2ad7303423749bbf3fda820508e Mon Sep 17 00:00:00 2001 From: Morgen Peschke Date: Thu, 10 Apr 2025 12:26:44 -0700 Subject: [PATCH 4/4] Bump tlBaseVersion --- build.sbt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build.sbt b/build.sbt index d18264ca..8a1e29aa 100644 --- a/build.sbt +++ b/build.sbt @@ -1,10 +1,10 @@ -import com.typesafe.tools.mima.core._ +import com.typesafe.tools.mima.core.* val Scala213 = "2.13.16" val Scala212 = "2.12.20" val Scala3 = "3.3.5" -ThisBuild / tlBaseVersion := "2.7" +ThisBuild / tlBaseVersion := "2.8" ThisBuild / crossScalaVersions := Seq(Scala213, Scala212, Scala3) ThisBuild / scalaVersion := Scala213 ThisBuild / startYear := Some(2018)