From 4f92ff3d6a4e1cd1f506b14d9bdb9edaa40b940f Mon Sep 17 00:00:00 2001 From: Erlend Hamnaberg Date: Thu, 24 Mar 2022 15:12:29 +0200 Subject: [PATCH 01/18] Add LoggerFactory typeclass The reasoning for this commit is that I want to avoid having a Sync instance just for being able to log in a http4s api. Extract LoggerName from macro and make it an implicit. This makes it easier to have forwarders to Slf4jLogger. This should be binary compatible, I had to add some exclusions to mima because of the missing macro methods. --- build.sbt | 8 +++- .../typelevel/log4cats/slf4j/LoggerName.scala | 9 ++++ .../log4cats/slf4j/Slf4jLogger.scala | 30 ++++-------- .../log4cats/slf4j/Slf4jLoggerFactory.scala | 44 +++++++++++++++++ .../slf4j/internal/GetLoggerMacros.scala | 28 +++-------- .../typelevel/log4cats/slf4j/LoggerName.scala | 12 +++++ .../log4cats/slf4j/Slf4jLogger.scala | 32 +++++-------- .../log4cats/slf4j/Slf4jLoggerFactory.scala | 48 +++++++++++++++++++ .../slf4j/internal/GetLoggerMacros.scala | 26 +++++----- 9 files changed, 160 insertions(+), 77 deletions(-) create mode 100644 slf4j/src/main/scala-2/org/typelevel/log4cats/slf4j/LoggerName.scala create mode 100644 slf4j/src/main/scala-2/org/typelevel/log4cats/slf4j/Slf4jLoggerFactory.scala create mode 100644 slf4j/src/main/scala-3/org/typelevel/log4cats/slf4j/LoggerName.scala create mode 100644 slf4j/src/main/scala-3/org/typelevel/log4cats/slf4j/Slf4jLoggerFactory.scala diff --git a/build.sbt b/build.sbt index 1540d07b..9dcd3b1c 100644 --- a/build.sbt +++ b/build.sbt @@ -1,3 +1,5 @@ +import com.typesafe.tools.mima.core._ + val Scala213 = "2.13.8" val Scala212 = "2.12.15" val Scala3 = "3.0.2" @@ -84,7 +86,11 @@ lazy val slf4j = project libraryDependencies ++= { if (tlIsScala3.value) Seq.empty else Seq("org.scala-lang" % "scala-reflect" % scalaVersion.value % Provided) - } + }, + mimaBinaryIssueFilters ++= Seq( + ProblemFilters.exclude[DirectMissingMethodProblem]("org.typelevel.log4cats.slf4j.internal.GetLoggerMacros.createImpl"), + ProblemFilters.exclude[DirectMissingMethodProblem]("org.typelevel.log4cats.slf4j.internal.GetLoggerMacros.getLoggerImpl") + ) ) lazy val commonSettings = Seq( diff --git a/slf4j/src/main/scala-2/org/typelevel/log4cats/slf4j/LoggerName.scala b/slf4j/src/main/scala-2/org/typelevel/log4cats/slf4j/LoggerName.scala new file mode 100644 index 00000000..91933d13 --- /dev/null +++ b/slf4j/src/main/scala-2/org/typelevel/log4cats/slf4j/LoggerName.scala @@ -0,0 +1,9 @@ +package org.typelevel.log4cats.slf4j + +import internal.GetLoggerMacros + +object LoggerName { + implicit def name: LoggerName = macro GetLoggerMacros.getLoggerName +} + +final case class LoggerName(value: String) \ No newline at end of file diff --git a/slf4j/src/main/scala-2/org/typelevel/log4cats/slf4j/Slf4jLogger.scala b/slf4j/src/main/scala-2/org/typelevel/log4cats/slf4j/Slf4jLogger.scala index fa89a091..e2a3610f 100644 --- a/slf4j/src/main/scala-2/org/typelevel/log4cats/slf4j/Slf4jLogger.scala +++ b/slf4j/src/main/scala-2/org/typelevel/log4cats/slf4j/Slf4jLogger.scala @@ -18,41 +18,31 @@ package org.typelevel.log4cats.slf4j import cats.effect.Sync import org.typelevel.log4cats.SelfAwareStructuredLogger -import org.typelevel.log4cats.slf4j.internal._ +import org.typelevel.log4cats.slf4j.internal.{_} import org.slf4j.{Logger => JLogger} +import scala.annotation.nowarn object Slf4jLogger { - def getLogger[F[_]: Sync]: SelfAwareStructuredLogger[F] = - macro GetLoggerMacros.unsafeCreateImpl[F[_]] + @nowarn("cat=unused") + private def getLogger[F[_]: Sync]: SelfAwareStructuredLogger[F] = ??? + @nowarn("cat=unused") + private def create[F[_]: Sync]: F[SelfAwareStructuredLogger[F]] = ??? - @deprecated("0.3.0", "Use getLogger instead") - def unsafeCreate[F[_]: Sync]: SelfAwareStructuredLogger[F] = - macro GetLoggerMacros.unsafeCreateImpl[F[_]] + def getLogger[F[_]: Sync](implicit name: LoggerName): SelfAwareStructuredLogger[F] = + getLoggerFromName(name.value.stripSuffix("$")) def getLoggerFromName[F[_]: Sync](name: String): SelfAwareStructuredLogger[F] = getLoggerFromSlf4j(org.slf4j.LoggerFactory.getLogger(name)) - @deprecated("0.3.0", "Use getLoggerFromName") - def unsafeFromName[F[_]: Sync](name: String): SelfAwareStructuredLogger[F] = - getLoggerFromName[F](name) - def getLoggerFromClass[F[_]: Sync](clazz: Class[_]): SelfAwareStructuredLogger[F] = getLoggerFromSlf4j[F](org.slf4j.LoggerFactory.getLogger(clazz)) - @deprecated("0.3.0", "Use getLoggerFromClass") - def unsafeFromClass[F[_]: Sync](clazz: Class[_]): SelfAwareStructuredLogger[F] = - getLoggerFromClass[F](clazz) - def getLoggerFromSlf4j[F[_]: Sync](logger: JLogger): SelfAwareStructuredLogger[F] = new Slf4jLoggerInternal.Slf4jLogger(logger) - @deprecated("0.3.0", "Use getLoggerFromSlf4J instead") - def unsafeFromSlf4j[F[_]: Sync](logger: JLogger): SelfAwareStructuredLogger[F] = - getLoggerFromSlf4j[F](logger) - - def create[F[_]: Sync]: F[SelfAwareStructuredLogger[F]] = - macro GetLoggerMacros.safeCreateImpl[F[_]] + def create[F[_]: Sync](implicit name: LoggerName): F[SelfAwareStructuredLogger[F]] = + Sync[F].delay(getLoggerFromName(name.value.stripSuffix("$"))) def fromName[F[_]: Sync](name: String): F[SelfAwareStructuredLogger[F]] = Sync[F].delay(getLoggerFromName(name)) diff --git a/slf4j/src/main/scala-2/org/typelevel/log4cats/slf4j/Slf4jLoggerFactory.scala b/slf4j/src/main/scala-2/org/typelevel/log4cats/slf4j/Slf4jLoggerFactory.scala new file mode 100644 index 00000000..2788d9a0 --- /dev/null +++ b/slf4j/src/main/scala-2/org/typelevel/log4cats/slf4j/Slf4jLoggerFactory.scala @@ -0,0 +1,44 @@ +package org.typelevel.log4cats +package slf4j + +import cats.effect.Sync +import org.slf4j.{Logger => JLogger} + +trait Slf4jLoggerFactory[F[_]] { + def getLogger(implicit name: LoggerName): SelfAwareStructuredLogger[F] + def getLoggerFromName(name: String): SelfAwareStructuredLogger[F] + def getLoggerFromClass(clazz: Class[_]): SelfAwareStructuredLogger[F] + def getLoggerFromSlf4j(logger: JLogger): SelfAwareStructuredLogger[F] + def create(implicit name: LoggerName): F[SelfAwareStructuredLogger[F]] + def fromName(name: String): F[SelfAwareStructuredLogger[F]] + def fromClass(clazz: Class[_]): F[SelfAwareStructuredLogger[F]] + def fromSlf4j(logger: JLogger): F[SelfAwareStructuredLogger[F]] +} + +object Slf4jLoggerFactory { + def apply[F[_]](lf: Slf4jLoggerFactory[F]): Slf4jLoggerFactory[F] = lf + + implicit def forSync[F[_]: Sync]: Slf4jLoggerFactory[F] = new Slf4jLoggerFactory[F] { + override def getLogger(implicit name: LoggerName): SelfAwareStructuredLogger[F] = + Slf4jLogger.getLogger + + override def getLoggerFromName(name: String): SelfAwareStructuredLogger[F] = + Slf4jLogger.getLoggerFromName(name) + override def getLoggerFromClass(clazz: Class[_]): SelfAwareStructuredLogger[F] = + Slf4jLogger.getLoggerFromClass(clazz) + override def getLoggerFromSlf4j(logger: JLogger): SelfAwareStructuredLogger[F] = + Slf4jLogger.getLoggerFromSlf4j(logger) + + def create(implicit name: LoggerName): F[SelfAwareStructuredLogger[F]] = + Slf4jLogger.create + + override def fromName(name: String): F[SelfAwareStructuredLogger[F]] = + Slf4jLogger.fromName(name) + + override def fromClass(clazz: Class[_]): F[SelfAwareStructuredLogger[F]] = + Slf4jLogger.fromClass(clazz) + + override def fromSlf4j(logger: JLogger): F[SelfAwareStructuredLogger[F]] = + Slf4jLogger.fromSlf4j(logger) + } +} diff --git a/slf4j/src/main/scala-2/org/typelevel/log4cats/slf4j/internal/GetLoggerMacros.scala b/slf4j/src/main/scala-2/org/typelevel/log4cats/slf4j/internal/GetLoggerMacros.scala index b5596a53..1e600732 100644 --- a/slf4j/src/main/scala-2/org/typelevel/log4cats/slf4j/internal/GetLoggerMacros.scala +++ b/slf4j/src/main/scala-2/org/typelevel/log4cats/slf4j/internal/GetLoggerMacros.scala @@ -16,7 +16,7 @@ package org.typelevel.log4cats.slf4j.internal -import scala.annotation.{nowarn, tailrec} +import scala.annotation.tailrec import scala.reflect.macros.blackbox /** @@ -29,13 +29,10 @@ import scala.reflect.macros.blackbox */ private[slf4j] class GetLoggerMacros(val c: blackbox.Context) { - final def safeCreateImpl[F: c.WeakTypeTag](f: c.Expr[F]) = getLoggerImpl[F](f, true) - - final def unsafeCreateImpl[F: c.WeakTypeTag](f: c.Expr[F]) = getLoggerImpl[F](f, false) + final def getLoggerName = getLoggerNameImpl /** Get a logger by reflecting the enclosing class name. */ - @nowarn("cat=unused") - private def getLoggerImpl[F: c.WeakTypeTag](f: c.Expr[F], delayed: Boolean) = { + private def getLoggerNameImpl = { import c.universe._ @tailrec def findEnclosingClass(sym: c.universe.Symbol): c.universe.Symbol = { @@ -54,15 +51,6 @@ private[slf4j] class GetLoggerMacros(val c: blackbox.Context) { assert(cls.isModule || cls.isClass, "Enclosing class is always either a module or a class") - def loggerByParam(param: c.Tree) = { - val unsafeCreate = - q"_root_.org.typelevel.log4cats.slf4j.Slf4jLogger.getLoggerFromSlf4j(_root_.org.slf4j.LoggerFactory.getLogger(...${List(param)}))($f)" - if (delayed) - q"_root_.cats.effect.Sync.apply($f).delay(...$unsafeCreate)" - else - unsafeCreate - } - def loggerBySymbolName(s: Symbol) = { def fullName(s: Symbol): String = { @inline def isPackageObject = ( @@ -82,7 +70,7 @@ private[slf4j] class GetLoggerMacros(val c: blackbox.Context) { fullName(s.owner) } } - loggerByParam(q"${fullName(s)}") + q"new _root_.org.typelevel.log4cats.slf4j.LoggerName(${fullName(s)})" } def loggerByType(s: Symbol) = { @@ -90,7 +78,7 @@ private[slf4j] class GetLoggerMacros(val c: blackbox.Context) { val typeParams = typeSymbol.typeParams if (typeParams.isEmpty) { - loggerByParam(q"_root_.scala.Predef.classOf[$typeSymbol]") + q"new _root_.org.typelevel.log4cats.slf4j.LoggerName(_root_.scala.Predef.classOf[$typeSymbol].getName)" } else { if (typeParams.exists(_.asType.typeParams.nonEmpty)) { /* We have at least one higher-kinded type: fall back to by-name logger construction, as @@ -99,7 +87,7 @@ private[slf4j] class GetLoggerMacros(val c: blackbox.Context) { } else { val typeArgs = List.fill(typeParams.length)(WildcardType) val typeConstructor = tq"$typeSymbol[..${typeArgs}]" - loggerByParam(q"_root_.scala.Predef.classOf[$typeConstructor]") + q"new _root_.org.typelevel.log4cats.slf4j.LoggerName(_root_.scala.Predef.classOf[$typeConstructor].getName)" } } } @@ -108,9 +96,7 @@ private[slf4j] class GetLoggerMacros(val c: blackbox.Context) { s.isClass && !(s.owner.isPackage) val instanceByName = - Slf4jLoggerInternal.singletonsByName && (cls.isModule || cls.isModuleClass) || cls.isClass && isInnerClass( - cls - ) + (Slf4jLoggerInternal.singletonsByName && cls.isModule || cls.isModuleClass) || (cls.isClass && isInnerClass(cls)) if (instanceByName) { loggerBySymbolName(cls) diff --git a/slf4j/src/main/scala-3/org/typelevel/log4cats/slf4j/LoggerName.scala b/slf4j/src/main/scala-3/org/typelevel/log4cats/slf4j/LoggerName.scala new file mode 100644 index 00000000..bf178074 --- /dev/null +++ b/slf4j/src/main/scala-3/org/typelevel/log4cats/slf4j/LoggerName.scala @@ -0,0 +1,12 @@ +package org.typelevel.log4cats.slf4j + +import org.typelevel.log4cats.slf4j.internal.GetLoggerMacros + +import scala.quoted.* + +object LoggerName { + implicit inline def name: LoggerName = + ${GetLoggerMacros.getLoggerName } +} + +final case class LoggerName(value: String) diff --git a/slf4j/src/main/scala-3/org/typelevel/log4cats/slf4j/Slf4jLogger.scala b/slf4j/src/main/scala-3/org/typelevel/log4cats/slf4j/Slf4jLogger.scala index 8d4f41f4..26390176 100644 --- a/slf4j/src/main/scala-3/org/typelevel/log4cats/slf4j/Slf4jLogger.scala +++ b/slf4j/src/main/scala-3/org/typelevel/log4cats/slf4j/Slf4jLogger.scala @@ -19,40 +19,32 @@ package org.typelevel.log4cats.slf4j import cats.effect.Sync import org.typelevel.log4cats.SelfAwareStructuredLogger import org.typelevel.log4cats.slf4j.internal._ -import org.slf4j.{Logger => JLogger} +import org.slf4j.Logger as JLogger +import scala.annotation.nowarn object Slf4jLogger { - inline def getLogger[F[_]](implicit F: Sync[F]): SelfAwareStructuredLogger[F] = - ${ GetLoggerMacros.getLoggerImpl('F) } + //for binary compability + @nowarn("cat=unused") + private def create[F[_]: Sync]: F[SelfAwareStructuredLogger[F]] = ??? - @deprecated("0.3.0", "Use getLogger instead") - inline def unsafeCreate[F[_]](implicit F: Sync[F]): SelfAwareStructuredLogger[F] = - ${ GetLoggerMacros.getLoggerImpl('F) } + @nowarn("cat=unused") + private def getLogger[F[_]](using F: Sync[F]): SelfAwareStructuredLogger[F] = ??? + + def getLogger[F[_]: Sync](using n: LoggerName): SelfAwareStructuredLogger[F] = + getLoggerFromName(n.value.stripSuffix("$")) def getLoggerFromName[F[_]: Sync](name: String): SelfAwareStructuredLogger[F] = getLoggerFromSlf4j(org.slf4j.LoggerFactory.getLogger(name)) - @deprecated("0.3.0", "Use getLoggerFromName") - def unsafeFromName[F[_]: Sync](name: String): SelfAwareStructuredLogger[F] = - getLoggerFromName[F](name) - def getLoggerFromClass[F[_]: Sync](clazz: Class[_]): SelfAwareStructuredLogger[F] = getLoggerFromSlf4j[F](org.slf4j.LoggerFactory.getLogger(clazz)) - @deprecated("0.3.0", "Use getLoggerFromClass") - def unsafeFromClass[F[_]: Sync](clazz: Class[_]): SelfAwareStructuredLogger[F] = - getLoggerFromClass[F](clazz) - def getLoggerFromSlf4j[F[_]: Sync](logger: JLogger): SelfAwareStructuredLogger[F] = new Slf4jLoggerInternal.Slf4jLogger(logger) - @deprecated("0.3.0", "Use getLoggerFromSlf4J instead") - def unsafeFromSlf4j[F[_]: Sync](logger: JLogger): SelfAwareStructuredLogger[F] = - getLoggerFromSlf4j[F](logger) - - inline def create[F[_]](implicit F: Sync[F]): F[SelfAwareStructuredLogger[F]] = - ${ GetLoggerMacros.createImpl('F) } + def create[F[_]: Sync](using n: LoggerName): F[SelfAwareStructuredLogger[F]] = + Sync[F].delay(getLoggerFromName(n.value.stripSuffix("$"))) def fromName[F[_]: Sync](name: String): F[SelfAwareStructuredLogger[F]] = Sync[F].delay(getLoggerFromName(name)) diff --git a/slf4j/src/main/scala-3/org/typelevel/log4cats/slf4j/Slf4jLoggerFactory.scala b/slf4j/src/main/scala-3/org/typelevel/log4cats/slf4j/Slf4jLoggerFactory.scala new file mode 100644 index 00000000..6c389ec8 --- /dev/null +++ b/slf4j/src/main/scala-3/org/typelevel/log4cats/slf4j/Slf4jLoggerFactory.scala @@ -0,0 +1,48 @@ +package org.typelevel.log4cats.slf4j + +import cats.effect.Sync +import org.typelevel.log4cats.SelfAwareStructuredLogger +import org.typelevel.log4cats.slf4j.internal.* +import org.slf4j.Logger as JLogger +import org.typelevel.log4cats.slf4j.Slf4jLogger.{ + getLoggerFromClass, + getLoggerFromName, + getLoggerFromSlf4j +} + +trait Slf4jLoggerFactory[F[_]] { + def getLogger(using name: LoggerName): SelfAwareStructuredLogger[F] + def getLoggerFromName(name: String): SelfAwareStructuredLogger[F] + def getLoggerFromClass(clazz: Class[_]): SelfAwareStructuredLogger[F] + def getLoggerFromSlf4j(logger: JLogger): SelfAwareStructuredLogger[F] + def create(using name: LoggerName): F[SelfAwareStructuredLogger[F]] + def fromName(name: String): F[SelfAwareStructuredLogger[F]] + def fromClass(clazz: Class[_]): F[SelfAwareStructuredLogger[F]] + def fromSlf4j(logger: JLogger): F[SelfAwareStructuredLogger[F]] +} + +object Slf4jLoggerFactory { + def apply[F[_]](lf: Slf4jLoggerFactory[F]): Slf4jLoggerFactory[F] = lf + + implicit def forSync[F[_]](implicit F: Sync[F]): Slf4jLoggerFactory[F] = + new Slf4jLoggerFactory[F] { + override def getLogger(using name: LoggerName): SelfAwareStructuredLogger[F] = + Slf4jLogger.getLogger + override def getLoggerFromName(name: String): SelfAwareStructuredLogger[F] = + Slf4jLogger.getLoggerFromName(name) + override def getLoggerFromClass(clazz: Class[_]): SelfAwareStructuredLogger[F] = + Slf4jLogger.getLoggerFromClass(clazz) + override def getLoggerFromSlf4j(logger: JLogger): SelfAwareStructuredLogger[F] = + Slf4jLogger.getLoggerFromSlf4j(logger) + override def create(using name: LoggerName): F[SelfAwareStructuredLogger[F]] = + Slf4jLogger.create + override def fromName(name: String): F[SelfAwareStructuredLogger[F]] = + Slf4jLogger.fromName(name) + + override def fromClass(clazz: Class[_]): F[SelfAwareStructuredLogger[F]] = + Slf4jLogger.fromClass(clazz) + + override def fromSlf4j(logger: JLogger): F[SelfAwareStructuredLogger[F]] = + Slf4jLogger.fromSlf4j(logger) + } +} diff --git a/slf4j/src/main/scala-3/org/typelevel/log4cats/slf4j/internal/GetLoggerMacros.scala b/slf4j/src/main/scala-3/org/typelevel/log4cats/slf4j/internal/GetLoggerMacros.scala index 26129b96..34177f80 100644 --- a/slf4j/src/main/scala-3/org/typelevel/log4cats/slf4j/internal/GetLoggerMacros.scala +++ b/slf4j/src/main/scala-3/org/typelevel/log4cats/slf4j/internal/GetLoggerMacros.scala @@ -18,16 +18,20 @@ package org.typelevel.log4cats.slf4j.internal import cats.effect.Sync import org.slf4j.LoggerFactory -import org.typelevel.log4cats.slf4j.Slf4jLogger +import org.typelevel.log4cats.slf4j.{LoggerName, Slf4jLogger} import org.typelevel.log4cats.SelfAwareStructuredLogger + import scala.annotation.tailrec -import scala.quoted._ +import scala.quoted.* private[slf4j] object GetLoggerMacros { - def getLoggerImpl[F[_]: Type]( - F: Expr[Sync[F]] - )(using qctx: Quotes): Expr[SelfAwareStructuredLogger[F]] = { + def getLoggerName(using qctx: Quotes): Expr[LoggerName] = { + val name = getLoggerNameImpl + '{new LoggerName($name)} + } + + def getLoggerNameImpl(using qctx: Quotes): Expr[String] = { import qctx.reflect._ @tailrec def findEnclosingClass(sym: Symbol): Symbol = { @@ -42,7 +46,7 @@ private[slf4j] object GetLoggerMacros { } } - def logger(s: Symbol): Expr[SelfAwareStructuredLogger[F]] = { + def logger(s: Symbol): Expr[String] = { def fullName(s: Symbol): String = { val flags = s.flags if (flags.is(Flags.Package)) { @@ -63,18 +67,10 @@ private[slf4j] object GetLoggerMacros { } } - val name = Expr(fullName(s)) - '{ Slf4jLogger.getLoggerFromSlf4j(LoggerFactory.getLogger($name))($F) } + Expr(fullName(s)) } val cls = findEnclosingClass(Symbol.spliceOwner) logger(cls) } - - def createImpl[F[_]: Type]( - F: Expr[Sync[F]] - )(using qctx: Quotes): Expr[F[SelfAwareStructuredLogger[F]]] = { - val logger = getLoggerImpl(F) - '{ $F.delay($logger) } - } } From 31097d3d5c5762f6ea5ae9e1ef13f9abe3242d65 Mon Sep 17 00:00:00 2001 From: Erlend Hamnaberg Date: Thu, 24 Mar 2022 18:16:06 +0100 Subject: [PATCH 02/18] Restore binary compatibility * Extract Platform traits for different code * LoggerName moved to shared * LoggerFactory with convenience methods. --- build.sbt | 6 +- ...gerName.scala => LoggerNamePlatform.scala} | 6 +- .../log4cats/slf4j/Slf4jLoggerPlatform.scala | 30 ++++++++++ .../slf4j/internal/GetLoggerMacros.scala | 33 +++++++++-- ...gerName.scala => LoggerNamePlatform.scala} | 6 +- .../log4cats/slf4j/Slf4jLogger.scala | 58 ------------------- .../log4cats/slf4j/Slf4jLoggerFactory.scala | 48 --------------- .../log4cats/slf4j/Slf4jLoggerPlatform.scala | 33 +++++++++++ .../slf4j/internal/GetLoggerMacros.scala | 18 +++++- .../log4cats/slf4j/LoggerFactory.scala} | 44 ++++++++++++-- .../typelevel/log4cats/slf4j/LoggerName.scala | 5 ++ .../log4cats/slf4j/Slf4jLogger.scala | 30 ++-------- 12 files changed, 160 insertions(+), 157 deletions(-) rename slf4j/src/main/scala-2/org/typelevel/log4cats/slf4j/{LoggerName.scala => LoggerNamePlatform.scala} (53%) create mode 100644 slf4j/src/main/scala-2/org/typelevel/log4cats/slf4j/Slf4jLoggerPlatform.scala rename slf4j/src/main/scala-3/org/typelevel/log4cats/slf4j/{LoggerName.scala => LoggerNamePlatform.scala} (61%) delete mode 100644 slf4j/src/main/scala-3/org/typelevel/log4cats/slf4j/Slf4jLogger.scala delete mode 100644 slf4j/src/main/scala-3/org/typelevel/log4cats/slf4j/Slf4jLoggerFactory.scala create mode 100644 slf4j/src/main/scala-3/org/typelevel/log4cats/slf4j/Slf4jLoggerPlatform.scala rename slf4j/src/main/{scala-2/org/typelevel/log4cats/slf4j/Slf4jLoggerFactory.scala => scala/org/typelevel/log4cats/slf4j/LoggerFactory.scala} (54%) create mode 100644 slf4j/src/main/scala/org/typelevel/log4cats/slf4j/LoggerName.scala rename slf4j/src/main/{scala-2 => scala}/org/typelevel/log4cats/slf4j/Slf4jLogger.scala (53%) diff --git a/build.sbt b/build.sbt index 9dcd3b1c..8a31aebb 100644 --- a/build.sbt +++ b/build.sbt @@ -86,11 +86,7 @@ lazy val slf4j = project libraryDependencies ++= { if (tlIsScala3.value) Seq.empty else Seq("org.scala-lang" % "scala-reflect" % scalaVersion.value % Provided) - }, - mimaBinaryIssueFilters ++= Seq( - ProblemFilters.exclude[DirectMissingMethodProblem]("org.typelevel.log4cats.slf4j.internal.GetLoggerMacros.createImpl"), - ProblemFilters.exclude[DirectMissingMethodProblem]("org.typelevel.log4cats.slf4j.internal.GetLoggerMacros.getLoggerImpl") - ) + } ) lazy val commonSettings = Seq( diff --git a/slf4j/src/main/scala-2/org/typelevel/log4cats/slf4j/LoggerName.scala b/slf4j/src/main/scala-2/org/typelevel/log4cats/slf4j/LoggerNamePlatform.scala similarity index 53% rename from slf4j/src/main/scala-2/org/typelevel/log4cats/slf4j/LoggerName.scala rename to slf4j/src/main/scala-2/org/typelevel/log4cats/slf4j/LoggerNamePlatform.scala index 91933d13..b50f5bd4 100644 --- a/slf4j/src/main/scala-2/org/typelevel/log4cats/slf4j/LoggerName.scala +++ b/slf4j/src/main/scala-2/org/typelevel/log4cats/slf4j/LoggerNamePlatform.scala @@ -1,9 +1,7 @@ package org.typelevel.log4cats.slf4j -import internal.GetLoggerMacros +import org.typelevel.log4cats.slf4j.internal.GetLoggerMacros -object LoggerName { +trait LoggerNamePlatform { implicit def name: LoggerName = macro GetLoggerMacros.getLoggerName } - -final case class LoggerName(value: String) \ No newline at end of file diff --git a/slf4j/src/main/scala-2/org/typelevel/log4cats/slf4j/Slf4jLoggerPlatform.scala b/slf4j/src/main/scala-2/org/typelevel/log4cats/slf4j/Slf4jLoggerPlatform.scala new file mode 100644 index 00000000..14e3fb81 --- /dev/null +++ b/slf4j/src/main/scala-2/org/typelevel/log4cats/slf4j/Slf4jLoggerPlatform.scala @@ -0,0 +1,30 @@ +/* + * 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 + +import cats.effect.Sync +import org.typelevel.log4cats.SelfAwareStructuredLogger +import org.typelevel.log4cats.slf4j.internal._ + +trait Slf4jLoggerPlatform { + + private[slf4j] def getLogger[F[_]](implicit f: Sync[F]): SelfAwareStructuredLogger[F] = + macro GetLoggerMacros.unsafeCreateImpl[F[_]] + + private[slf4j] def create[F[_]](implicit f: Sync[F]): F[SelfAwareStructuredLogger[F]] = + macro GetLoggerMacros.safeCreateImpl[F[_]] +} diff --git a/slf4j/src/main/scala-2/org/typelevel/log4cats/slf4j/internal/GetLoggerMacros.scala b/slf4j/src/main/scala-2/org/typelevel/log4cats/slf4j/internal/GetLoggerMacros.scala index 1e600732..aa37ef0a 100644 --- a/slf4j/src/main/scala-2/org/typelevel/log4cats/slf4j/internal/GetLoggerMacros.scala +++ b/slf4j/src/main/scala-2/org/typelevel/log4cats/slf4j/internal/GetLoggerMacros.scala @@ -29,6 +29,25 @@ import scala.reflect.macros.blackbox */ private[slf4j] class GetLoggerMacros(val c: blackbox.Context) { + final def safeCreateImpl[F](f: c.Expr[F]) = getLoggerImpl[F](f, true) + + final def unsafeCreateImpl[F](f: c.Expr[F]) = getLoggerImpl[F](f, false) + + private def getLoggerImpl[F](f: c.Expr[F], delayed: Boolean) = { + import c.universe._ + val loggerName = getLoggerNameImpl + + def loggerByParam(param: c.Tree) = { + val unsafeCreate = + q"_root_.org.typelevel.log4cats.slf4j.Slf4jLogger.getLoggerFromSlf4j(_root_.org.slf4j.LoggerFactory.getLogger(...${List(param)}))($f)" + if (delayed) + q"_root_.cats.effect.Sync.apply($f).delay(...$unsafeCreate)" + else + unsafeCreate + } + loggerByParam(q"$loggerName.value") + } + final def getLoggerName = getLoggerNameImpl /** Get a logger by reflecting the enclosing class name. */ @@ -51,7 +70,7 @@ private[slf4j] class GetLoggerMacros(val c: blackbox.Context) { assert(cls.isModule || cls.isClass, "Enclosing class is always either a module or a class") - def loggerBySymbolName(s: Symbol) = { + def nameBySymbol(s: Symbol) = { def fullName(s: Symbol): String = { @inline def isPackageObject = ( (s.isModule || s.isModuleClass) @@ -73,7 +92,7 @@ private[slf4j] class GetLoggerMacros(val c: blackbox.Context) { q"new _root_.org.typelevel.log4cats.slf4j.LoggerName(${fullName(s)})" } - def loggerByType(s: Symbol) = { + def nameByType(s: Symbol) = { val typeSymbol: ClassSymbol = (if (s.isModule) s.asModule.moduleClass else s).asClass val typeParams = typeSymbol.typeParams @@ -83,7 +102,7 @@ private[slf4j] class GetLoggerMacros(val c: blackbox.Context) { if (typeParams.exists(_.asType.typeParams.nonEmpty)) { /* We have at least one higher-kinded type: fall back to by-name logger construction, as * there's no simple way to declare a higher-kinded type with an "any" parameter. */ - loggerBySymbolName(s) + nameBySymbol(s) } else { val typeArgs = List.fill(typeParams.length)(WildcardType) val typeConstructor = tq"$typeSymbol[..${typeArgs}]" @@ -96,12 +115,14 @@ private[slf4j] class GetLoggerMacros(val c: blackbox.Context) { s.isClass && !(s.owner.isPackage) val instanceByName = - (Slf4jLoggerInternal.singletonsByName && cls.isModule || cls.isModuleClass) || (cls.isClass && isInnerClass(cls)) + (Slf4jLoggerInternal.singletonsByName && cls.isModule || cls.isModuleClass) || (cls.isClass && isInnerClass( + cls + )) if (instanceByName) { - loggerBySymbolName(cls) + nameBySymbol(cls) } else { - loggerByType(cls) + nameByType(cls) } } } diff --git a/slf4j/src/main/scala-3/org/typelevel/log4cats/slf4j/LoggerName.scala b/slf4j/src/main/scala-3/org/typelevel/log4cats/slf4j/LoggerNamePlatform.scala similarity index 61% rename from slf4j/src/main/scala-3/org/typelevel/log4cats/slf4j/LoggerName.scala rename to slf4j/src/main/scala-3/org/typelevel/log4cats/slf4j/LoggerNamePlatform.scala index bf178074..3cf6a95a 100644 --- a/slf4j/src/main/scala-3/org/typelevel/log4cats/slf4j/LoggerName.scala +++ b/slf4j/src/main/scala-3/org/typelevel/log4cats/slf4j/LoggerNamePlatform.scala @@ -4,9 +4,7 @@ import org.typelevel.log4cats.slf4j.internal.GetLoggerMacros import scala.quoted.* -object LoggerName { +trait LoggerNamePlatform { implicit inline def name: LoggerName = - ${GetLoggerMacros.getLoggerName } + ${ GetLoggerMacros.getLoggerName } } - -final case class LoggerName(value: String) diff --git a/slf4j/src/main/scala-3/org/typelevel/log4cats/slf4j/Slf4jLogger.scala b/slf4j/src/main/scala-3/org/typelevel/log4cats/slf4j/Slf4jLogger.scala deleted file mode 100644 index 26390176..00000000 --- a/slf4j/src/main/scala-3/org/typelevel/log4cats/slf4j/Slf4jLogger.scala +++ /dev/null @@ -1,58 +0,0 @@ -/* - * 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 - -import cats.effect.Sync -import org.typelevel.log4cats.SelfAwareStructuredLogger -import org.typelevel.log4cats.slf4j.internal._ -import org.slf4j.Logger as JLogger -import scala.annotation.nowarn - -object Slf4jLogger { - - //for binary compability - @nowarn("cat=unused") - private def create[F[_]: Sync]: F[SelfAwareStructuredLogger[F]] = ??? - - @nowarn("cat=unused") - private def getLogger[F[_]](using F: Sync[F]): SelfAwareStructuredLogger[F] = ??? - - def getLogger[F[_]: Sync](using n: LoggerName): SelfAwareStructuredLogger[F] = - getLoggerFromName(n.value.stripSuffix("$")) - - def getLoggerFromName[F[_]: Sync](name: String): SelfAwareStructuredLogger[F] = - getLoggerFromSlf4j(org.slf4j.LoggerFactory.getLogger(name)) - - def getLoggerFromClass[F[_]: Sync](clazz: Class[_]): SelfAwareStructuredLogger[F] = - getLoggerFromSlf4j[F](org.slf4j.LoggerFactory.getLogger(clazz)) - - def getLoggerFromSlf4j[F[_]: Sync](logger: JLogger): SelfAwareStructuredLogger[F] = - new Slf4jLoggerInternal.Slf4jLogger(logger) - - def create[F[_]: Sync](using n: LoggerName): F[SelfAwareStructuredLogger[F]] = - Sync[F].delay(getLoggerFromName(n.value.stripSuffix("$"))) - - def fromName[F[_]: Sync](name: String): F[SelfAwareStructuredLogger[F]] = - Sync[F].delay(getLoggerFromName(name)) - - def fromClass[F[_]: Sync](clazz: Class[_]): F[SelfAwareStructuredLogger[F]] = - Sync[F].delay(getLoggerFromClass(clazz)) - - def fromSlf4j[F[_]: Sync](logger: JLogger): F[SelfAwareStructuredLogger[F]] = - Sync[F].delay(getLoggerFromSlf4j[F](logger)) - -} diff --git a/slf4j/src/main/scala-3/org/typelevel/log4cats/slf4j/Slf4jLoggerFactory.scala b/slf4j/src/main/scala-3/org/typelevel/log4cats/slf4j/Slf4jLoggerFactory.scala deleted file mode 100644 index 6c389ec8..00000000 --- a/slf4j/src/main/scala-3/org/typelevel/log4cats/slf4j/Slf4jLoggerFactory.scala +++ /dev/null @@ -1,48 +0,0 @@ -package org.typelevel.log4cats.slf4j - -import cats.effect.Sync -import org.typelevel.log4cats.SelfAwareStructuredLogger -import org.typelevel.log4cats.slf4j.internal.* -import org.slf4j.Logger as JLogger -import org.typelevel.log4cats.slf4j.Slf4jLogger.{ - getLoggerFromClass, - getLoggerFromName, - getLoggerFromSlf4j -} - -trait Slf4jLoggerFactory[F[_]] { - def getLogger(using name: LoggerName): SelfAwareStructuredLogger[F] - def getLoggerFromName(name: String): SelfAwareStructuredLogger[F] - def getLoggerFromClass(clazz: Class[_]): SelfAwareStructuredLogger[F] - def getLoggerFromSlf4j(logger: JLogger): SelfAwareStructuredLogger[F] - def create(using name: LoggerName): F[SelfAwareStructuredLogger[F]] - def fromName(name: String): F[SelfAwareStructuredLogger[F]] - def fromClass(clazz: Class[_]): F[SelfAwareStructuredLogger[F]] - def fromSlf4j(logger: JLogger): F[SelfAwareStructuredLogger[F]] -} - -object Slf4jLoggerFactory { - def apply[F[_]](lf: Slf4jLoggerFactory[F]): Slf4jLoggerFactory[F] = lf - - implicit def forSync[F[_]](implicit F: Sync[F]): Slf4jLoggerFactory[F] = - new Slf4jLoggerFactory[F] { - override def getLogger(using name: LoggerName): SelfAwareStructuredLogger[F] = - Slf4jLogger.getLogger - override def getLoggerFromName(name: String): SelfAwareStructuredLogger[F] = - Slf4jLogger.getLoggerFromName(name) - override def getLoggerFromClass(clazz: Class[_]): SelfAwareStructuredLogger[F] = - Slf4jLogger.getLoggerFromClass(clazz) - override def getLoggerFromSlf4j(logger: JLogger): SelfAwareStructuredLogger[F] = - Slf4jLogger.getLoggerFromSlf4j(logger) - override def create(using name: LoggerName): F[SelfAwareStructuredLogger[F]] = - Slf4jLogger.create - override def fromName(name: String): F[SelfAwareStructuredLogger[F]] = - Slf4jLogger.fromName(name) - - override def fromClass(clazz: Class[_]): F[SelfAwareStructuredLogger[F]] = - Slf4jLogger.fromClass(clazz) - - override def fromSlf4j(logger: JLogger): F[SelfAwareStructuredLogger[F]] = - Slf4jLogger.fromSlf4j(logger) - } -} diff --git a/slf4j/src/main/scala-3/org/typelevel/log4cats/slf4j/Slf4jLoggerPlatform.scala b/slf4j/src/main/scala-3/org/typelevel/log4cats/slf4j/Slf4jLoggerPlatform.scala new file mode 100644 index 00000000..862fdf0c --- /dev/null +++ b/slf4j/src/main/scala-3/org/typelevel/log4cats/slf4j/Slf4jLoggerPlatform.scala @@ -0,0 +1,33 @@ +/* + * 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 + +import cats.effect.Sync +import org.typelevel.log4cats.SelfAwareStructuredLogger +import org.typelevel.log4cats.slf4j.internal._ +import org.slf4j.Logger as JLogger +import scala.annotation.nowarn + +trait Slf4jLoggerPlatform { + + // for binary compability + private[slf4j] inline def create[F[_]](F: Sync[F]): F[SelfAwareStructuredLogger[F]] = + ${ GetLoggerMacros.createImpl('F) } + private[slf4j] inline def getLogger[F[_]](using F: Sync[F]): SelfAwareStructuredLogger[F] = + ${ GetLoggerMacros.getLoggerImpl('F) } + +} diff --git a/slf4j/src/main/scala-3/org/typelevel/log4cats/slf4j/internal/GetLoggerMacros.scala b/slf4j/src/main/scala-3/org/typelevel/log4cats/slf4j/internal/GetLoggerMacros.scala index 34177f80..b3816cb4 100644 --- a/slf4j/src/main/scala-3/org/typelevel/log4cats/slf4j/internal/GetLoggerMacros.scala +++ b/slf4j/src/main/scala-3/org/typelevel/log4cats/slf4j/internal/GetLoggerMacros.scala @@ -26,9 +26,23 @@ import scala.quoted.* private[slf4j] object GetLoggerMacros { + def getLoggerImpl[F[_]: Type]( + F: Expr[Sync[F]] + )(using qctx: Quotes): Expr[SelfAwareStructuredLogger[F]] = { + val name = getLoggerNameImpl + '{ Slf4jLogger.getLoggerFromSlf4j(LoggerFactory.getLogger($name))($F) } + } + + def createImpl[F[_]: Type]( + F: Expr[Sync[F]] + )(using qctx: Quotes): Expr[F[SelfAwareStructuredLogger[F]]] = { + val logger = getLoggerImpl(F) + '{ $F.delay($logger) } + } + def getLoggerName(using qctx: Quotes): Expr[LoggerName] = { val name = getLoggerNameImpl - '{new LoggerName($name)} + '{ new LoggerName($name) } } def getLoggerNameImpl(using qctx: Quotes): Expr[String] = { @@ -67,7 +81,7 @@ private[slf4j] object GetLoggerMacros { } } - Expr(fullName(s)) + Expr(fullName(s).stripSuffix("$")) } val cls = findEnclosingClass(Symbol.spliceOwner) diff --git a/slf4j/src/main/scala-2/org/typelevel/log4cats/slf4j/Slf4jLoggerFactory.scala b/slf4j/src/main/scala/org/typelevel/log4cats/slf4j/LoggerFactory.scala similarity index 54% rename from slf4j/src/main/scala-2/org/typelevel/log4cats/slf4j/Slf4jLoggerFactory.scala rename to slf4j/src/main/scala/org/typelevel/log4cats/slf4j/LoggerFactory.scala index 2788d9a0..2b29d0df 100644 --- a/slf4j/src/main/scala-2/org/typelevel/log4cats/slf4j/Slf4jLoggerFactory.scala +++ b/slf4j/src/main/scala/org/typelevel/log4cats/slf4j/LoggerFactory.scala @@ -4,7 +4,7 @@ package slf4j import cats.effect.Sync import org.slf4j.{Logger => JLogger} -trait Slf4jLoggerFactory[F[_]] { +trait LoggerFactory[F[_]] { def getLogger(implicit name: LoggerName): SelfAwareStructuredLogger[F] def getLoggerFromName(name: String): SelfAwareStructuredLogger[F] def getLoggerFromClass(clazz: Class[_]): SelfAwareStructuredLogger[F] @@ -15,10 +15,10 @@ trait Slf4jLoggerFactory[F[_]] { def fromSlf4j(logger: JLogger): F[SelfAwareStructuredLogger[F]] } -object Slf4jLoggerFactory { - def apply[F[_]](lf: Slf4jLoggerFactory[F]): Slf4jLoggerFactory[F] = lf +object LoggerFactory { + def apply[F[_]: LoggerFactory]: LoggerFactory[F] = implicitly - implicit def forSync[F[_]: Sync]: Slf4jLoggerFactory[F] = new Slf4jLoggerFactory[F] { + implicit def forSync[F[_]: Sync]: LoggerFactory[F] = new LoggerFactory[F] { override def getLogger(implicit name: LoggerName): SelfAwareStructuredLogger[F] = Slf4jLogger.getLogger @@ -41,4 +41,40 @@ object Slf4jLoggerFactory { override def fromSlf4j(logger: JLogger): F[SelfAwareStructuredLogger[F]] = Slf4jLogger.fromSlf4j(logger) } + + def getLogger[F[_]](implicit + lf: LoggerFactory[F], + name: LoggerName + ): SelfAwareStructuredLogger[F] = + lf.getLogger + def getLoggerFromName[F[_]](name: String)(implicit + lf: LoggerFactory[F] + ): SelfAwareStructuredLogger[F] = + lf.getLoggerFromName(name) + + def getLoggerFromClass[F[_]](clazz: Class[_])(implicit + lf: LoggerFactory[F] + ): SelfAwareStructuredLogger[F] = + lf.getLoggerFromClass(clazz) + + def getLoggerFromSlf4j[F[_]](logger: JLogger)(implicit + lf: LoggerFactory[F] + ): SelfAwareStructuredLogger[F] = + lf.getLoggerFromSlf4j(logger) + def create[F[_]](implicit + lf: LoggerFactory[F], + name: LoggerName + ): F[SelfAwareStructuredLogger[F]] = + lf.create + def fromName[F[_]](name: String)(implicit lf: LoggerFactory[F]): F[SelfAwareStructuredLogger[F]] = + lf.fromName(name) + def fromClass[F[_]](clazz: Class[_])(implicit + lf: LoggerFactory[F] + ): F[SelfAwareStructuredLogger[F]] = + lf.fromClass(clazz) + def fromSlf4j[F[_]](logger: JLogger)(implicit + lf: LoggerFactory[F] + ): F[SelfAwareStructuredLogger[F]] = + lf.fromSlf4j(logger) + } diff --git a/slf4j/src/main/scala/org/typelevel/log4cats/slf4j/LoggerName.scala b/slf4j/src/main/scala/org/typelevel/log4cats/slf4j/LoggerName.scala new file mode 100644 index 00000000..d8f4634a --- /dev/null +++ b/slf4j/src/main/scala/org/typelevel/log4cats/slf4j/LoggerName.scala @@ -0,0 +1,5 @@ +package org.typelevel.log4cats.slf4j + +object LoggerName extends LoggerNamePlatform + +final case class LoggerName(value: String) diff --git a/slf4j/src/main/scala-2/org/typelevel/log4cats/slf4j/Slf4jLogger.scala b/slf4j/src/main/scala/org/typelevel/log4cats/slf4j/Slf4jLogger.scala similarity index 53% rename from slf4j/src/main/scala-2/org/typelevel/log4cats/slf4j/Slf4jLogger.scala rename to slf4j/src/main/scala/org/typelevel/log4cats/slf4j/Slf4jLogger.scala index e2a3610f..fbf36569 100644 --- a/slf4j/src/main/scala-2/org/typelevel/log4cats/slf4j/Slf4jLogger.scala +++ b/slf4j/src/main/scala/org/typelevel/log4cats/slf4j/Slf4jLogger.scala @@ -1,36 +1,14 @@ -/* - * 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 import cats.effect.Sync import org.typelevel.log4cats.SelfAwareStructuredLogger -import org.typelevel.log4cats.slf4j.internal.{_} +import org.typelevel.log4cats.slf4j.internal.Slf4jLoggerInternal import org.slf4j.{Logger => JLogger} -import scala.annotation.nowarn - -object Slf4jLogger { - @nowarn("cat=unused") - private def getLogger[F[_]: Sync]: SelfAwareStructuredLogger[F] = ??? - @nowarn("cat=unused") - private def create[F[_]: Sync]: F[SelfAwareStructuredLogger[F]] = ??? +object Slf4jLogger extends Slf4jLoggerPlatform { def getLogger[F[_]: Sync](implicit name: LoggerName): SelfAwareStructuredLogger[F] = - getLoggerFromName(name.value.stripSuffix("$")) + getLoggerFromName(name.value) def getLoggerFromName[F[_]: Sync](name: String): SelfAwareStructuredLogger[F] = getLoggerFromSlf4j(org.slf4j.LoggerFactory.getLogger(name)) @@ -42,7 +20,7 @@ object Slf4jLogger { new Slf4jLoggerInternal.Slf4jLogger(logger) def create[F[_]: Sync](implicit name: LoggerName): F[SelfAwareStructuredLogger[F]] = - Sync[F].delay(getLoggerFromName(name.value.stripSuffix("$"))) + Sync[F].delay(getLoggerFromName(name.value)) def fromName[F[_]: Sync](name: String): F[SelfAwareStructuredLogger[F]] = Sync[F].delay(getLoggerFromName(name)) From 24ba584336a5cf09a17f1b3db0088307bb3d158a Mon Sep 17 00:00:00 2001 From: Erlend Hamnaberg Date: Thu, 24 Mar 2022 18:19:20 +0100 Subject: [PATCH 03/18] rename internal macro --- .../typelevel/log4cats/slf4j/internal/GetLoggerMacros.scala | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/slf4j/src/main/scala-3/org/typelevel/log4cats/slf4j/internal/GetLoggerMacros.scala b/slf4j/src/main/scala-3/org/typelevel/log4cats/slf4j/internal/GetLoggerMacros.scala index b3816cb4..2f78d613 100644 --- a/slf4j/src/main/scala-3/org/typelevel/log4cats/slf4j/internal/GetLoggerMacros.scala +++ b/slf4j/src/main/scala-3/org/typelevel/log4cats/slf4j/internal/GetLoggerMacros.scala @@ -60,7 +60,7 @@ private[slf4j] object GetLoggerMacros { } } - def logger(s: Symbol): Expr[String] = { + def symbolName(s: Symbol): Expr[String] = { def fullName(s: Symbol): String = { val flags = s.flags if (flags.is(Flags.Package)) { @@ -85,6 +85,6 @@ private[slf4j] object GetLoggerMacros { } val cls = findEnclosingClass(Symbol.spliceOwner) - logger(cls) + symbolName(cls) } } From 3c3ff46754290714e2f891970a1a43fbf4231c8d Mon Sep 17 00:00:00 2001 From: Erlend Hamnaberg Date: Thu, 24 Mar 2022 18:20:45 +0100 Subject: [PATCH 04/18] Add headers --- .../log4cats/slf4j/LoggerNamePlatform.scala | 16 ++++++++++++++++ .../typelevel/log4cats/slf4j/LoggerFactory.scala | 16 ++++++++++++++++ .../typelevel/log4cats/slf4j/LoggerName.scala | 16 ++++++++++++++++ .../typelevel/log4cats/slf4j/Slf4jLogger.scala | 16 ++++++++++++++++ 4 files changed, 64 insertions(+) diff --git a/slf4j/src/main/scala-2/org/typelevel/log4cats/slf4j/LoggerNamePlatform.scala b/slf4j/src/main/scala-2/org/typelevel/log4cats/slf4j/LoggerNamePlatform.scala index b50f5bd4..bf0b64b5 100644 --- a/slf4j/src/main/scala-2/org/typelevel/log4cats/slf4j/LoggerNamePlatform.scala +++ b/slf4j/src/main/scala-2/org/typelevel/log4cats/slf4j/LoggerNamePlatform.scala @@ -1,3 +1,19 @@ +/* + * 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 import org.typelevel.log4cats.slf4j.internal.GetLoggerMacros diff --git a/slf4j/src/main/scala/org/typelevel/log4cats/slf4j/LoggerFactory.scala b/slf4j/src/main/scala/org/typelevel/log4cats/slf4j/LoggerFactory.scala index 2b29d0df..b2d94bd6 100644 --- a/slf4j/src/main/scala/org/typelevel/log4cats/slf4j/LoggerFactory.scala +++ b/slf4j/src/main/scala/org/typelevel/log4cats/slf4j/LoggerFactory.scala @@ -1,3 +1,19 @@ +/* + * 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 package slf4j diff --git a/slf4j/src/main/scala/org/typelevel/log4cats/slf4j/LoggerName.scala b/slf4j/src/main/scala/org/typelevel/log4cats/slf4j/LoggerName.scala index d8f4634a..4797aad4 100644 --- a/slf4j/src/main/scala/org/typelevel/log4cats/slf4j/LoggerName.scala +++ b/slf4j/src/main/scala/org/typelevel/log4cats/slf4j/LoggerName.scala @@ -1,3 +1,19 @@ +/* + * 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 object LoggerName extends LoggerNamePlatform diff --git a/slf4j/src/main/scala/org/typelevel/log4cats/slf4j/Slf4jLogger.scala b/slf4j/src/main/scala/org/typelevel/log4cats/slf4j/Slf4jLogger.scala index fbf36569..710d95af 100644 --- a/slf4j/src/main/scala/org/typelevel/log4cats/slf4j/Slf4jLogger.scala +++ b/slf4j/src/main/scala/org/typelevel/log4cats/slf4j/Slf4jLogger.scala @@ -1,3 +1,19 @@ +/* + * 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 import cats.effect.Sync From eda4b64b1d8055ca5a54633dd0713a2804d1b452 Mon Sep 17 00:00:00 2001 From: Erlend Hamnaberg Date: Thu, 24 Mar 2022 18:36:49 +0100 Subject: [PATCH 05/18] Add LoggernameTest --- .../log4cats/slf4j/LoggerNameTest.scala | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 slf4j/src/test/scala/org/typelevel/log4cats/slf4j/LoggerNameTest.scala diff --git a/slf4j/src/test/scala/org/typelevel/log4cats/slf4j/LoggerNameTest.scala b/slf4j/src/test/scala/org/typelevel/log4cats/slf4j/LoggerNameTest.scala new file mode 100644 index 00000000..3119bd83 --- /dev/null +++ b/slf4j/src/test/scala/org/typelevel/log4cats/slf4j/LoggerNameTest.scala @@ -0,0 +1,21 @@ +package org.typelevel.log4cats.slf4j + +import munit.FunSuite + +class LoggerNameTest extends FunSuite { + class FooA { + val name = LoggerName.name + } + + object FooB { + val name = LoggerName.name + } + + test("names") { + val name1 = new FooA().name + val name2 = FooB.name + + assertEquals(name1.value, "org.typelevel.log4cats.slf4j.LoggerNameTests.FooA") + assertEquals(name2.value, "org.typelevel.log4cats.slf4j.LoggerNameTests.FooB") + } +} From f2693710a1959fde5546b17631eddfa158ea08f7 Mon Sep 17 00:00:00 2001 From: Erlend Hamnaberg Date: Fri, 25 Mar 2022 07:45:32 +0100 Subject: [PATCH 06/18] Add missing headers --- .../log4cats/slf4j/LoggerNamePlatform.scala | 16 ++++++++++++++++ .../log4cats/slf4j/LoggerNameTest.scala | 16 ++++++++++++++++ 2 files changed, 32 insertions(+) diff --git a/slf4j/src/main/scala-3/org/typelevel/log4cats/slf4j/LoggerNamePlatform.scala b/slf4j/src/main/scala-3/org/typelevel/log4cats/slf4j/LoggerNamePlatform.scala index 3cf6a95a..f730b97f 100644 --- a/slf4j/src/main/scala-3/org/typelevel/log4cats/slf4j/LoggerNamePlatform.scala +++ b/slf4j/src/main/scala-3/org/typelevel/log4cats/slf4j/LoggerNamePlatform.scala @@ -1,3 +1,19 @@ +/* + * 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 import org.typelevel.log4cats.slf4j.internal.GetLoggerMacros diff --git a/slf4j/src/test/scala/org/typelevel/log4cats/slf4j/LoggerNameTest.scala b/slf4j/src/test/scala/org/typelevel/log4cats/slf4j/LoggerNameTest.scala index 3119bd83..97cd0a1a 100644 --- a/slf4j/src/test/scala/org/typelevel/log4cats/slf4j/LoggerNameTest.scala +++ b/slf4j/src/test/scala/org/typelevel/log4cats/slf4j/LoggerNameTest.scala @@ -1,3 +1,19 @@ +/* + * 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 import munit.FunSuite From c82b3face8b991ea6290febc8ddaaf5974ad258d Mon Sep 17 00:00:00 2001 From: Erlend Hamnaberg Date: Tue, 5 Apr 2022 17:49:42 +0200 Subject: [PATCH 07/18] Changes based on feedback * Extracted LoggerFactory and LoggerFactoryGen * Moved LoggerName to core and added macro there * Renamed Platform traits to Compat traits * Moved Slf4jLoggerFactory into Sl4j4Logger.Factory trait --- build.sbt | 6 +- .../typelevel/log4cats/LoggerNameCompat.scala | 7 ++ .../log4cats/internal/LoggerNameMacro.scala | 89 +++++++++++++++++ .../typelevel/log4cats/LoggerNameCompat.scala | 8 +- .../log4cats/internal/LoggerNameMacro.scala | 55 +++++++++++ .../typelevel/log4cats/LoggerFactory.scala | 40 ++++++++ .../typelevel/log4cats/LoggerFactoryGen.scala | 10 ++ .../org/typelevel/log4cats/LoggerName.scala | 5 + .../typelevel/log4cats}/LoggerNameTest.scala | 6 +- .../log4cats/slf4j/LoggerNamePlatform.scala | 23 ----- ...Platform.scala => Slf4jLoggerCompat.scala} | 2 +- .../slf4j/internal/GetLoggerMacros.scala | 84 +--------------- ...Platform.scala => Slf4jLoggerCompat.scala} | 2 +- .../slf4j/internal/GetLoggerMacros.scala | 53 +--------- .../log4cats/slf4j/LoggerFactory.scala | 96 ------------------- .../typelevel/log4cats/slf4j/LoggerName.scala | 21 ---- .../log4cats/slf4j/Slf4jLogger.scala | 38 +++++++- 17 files changed, 261 insertions(+), 284 deletions(-) create mode 100644 core/shared/src/main/scala-2/org/typelevel/log4cats/LoggerNameCompat.scala create mode 100644 core/shared/src/main/scala-2/org/typelevel/log4cats/internal/LoggerNameMacro.scala rename slf4j/src/main/scala-3/org/typelevel/log4cats/slf4j/LoggerNamePlatform.scala => core/shared/src/main/scala-3/org/typelevel/log4cats/LoggerNameCompat.scala (80%) create mode 100644 core/shared/src/main/scala-3/org/typelevel/log4cats/internal/LoggerNameMacro.scala create mode 100644 core/shared/src/main/scala/org/typelevel/log4cats/LoggerFactory.scala create mode 100644 core/shared/src/main/scala/org/typelevel/log4cats/LoggerFactoryGen.scala create mode 100644 core/shared/src/main/scala/org/typelevel/log4cats/LoggerName.scala rename {slf4j/src/test/scala/org/typelevel/log4cats/slf4j => core/shared/src/test/scala/org/typelevel/log4cats}/LoggerNameTest.scala (80%) delete mode 100644 slf4j/src/main/scala-2/org/typelevel/log4cats/slf4j/LoggerNamePlatform.scala rename slf4j/src/main/scala-2/org/typelevel/log4cats/slf4j/{Slf4jLoggerPlatform.scala => Slf4jLoggerCompat.scala} (97%) rename slf4j/src/main/scala-3/org/typelevel/log4cats/slf4j/{Slf4jLoggerPlatform.scala => Slf4jLoggerCompat.scala} (97%) delete mode 100644 slf4j/src/main/scala/org/typelevel/log4cats/slf4j/LoggerFactory.scala delete mode 100644 slf4j/src/main/scala/org/typelevel/log4cats/slf4j/LoggerName.scala diff --git a/build.sbt b/build.sbt index 8a31aebb..14db8df6 100644 --- a/build.sbt +++ b/build.sbt @@ -52,7 +52,11 @@ lazy val core = crossProject(JSPlatform, JVMPlatform) name := "log4cats-core", libraryDependencies ++= Seq( "org.typelevel" %%% "cats-core" % catsV - ) + ), + libraryDependencies ++= { + if (tlIsScala3.value) Seq.empty + else Seq("org.scala-lang" % "scala-reflect" % scalaVersion.value % Provided) + } ) lazy val testing = crossProject(JSPlatform, JVMPlatform) diff --git a/core/shared/src/main/scala-2/org/typelevel/log4cats/LoggerNameCompat.scala b/core/shared/src/main/scala-2/org/typelevel/log4cats/LoggerNameCompat.scala new file mode 100644 index 00000000..eac04889 --- /dev/null +++ b/core/shared/src/main/scala-2/org/typelevel/log4cats/LoggerNameCompat.scala @@ -0,0 +1,7 @@ +package org.typelevel.log4cats + +import org.typelevel.log4cats.internal.LoggerNameMacro + +trait LoggerNameCompat { + implicit def name: LoggerName = macro LoggerNameMacro.getLoggerName +} diff --git a/core/shared/src/main/scala-2/org/typelevel/log4cats/internal/LoggerNameMacro.scala b/core/shared/src/main/scala-2/org/typelevel/log4cats/internal/LoggerNameMacro.scala new file mode 100644 index 00000000..32ab767f --- /dev/null +++ b/core/shared/src/main/scala-2/org/typelevel/log4cats/internal/LoggerNameMacro.scala @@ -0,0 +1,89 @@ +package org.typelevel.log4cats.internal + +import scala.annotation.tailrec +import scala.reflect.macros.blackbox + +private[log4cats] class LoggerNameMacro(val c: blackbox.Context) { + final def getLoggerName = SharedLoggerNameMacro.getLoggerNameImpl(c) +} + +private[log4cats] object SharedLoggerNameMacro { + + /** Get a logger by reflecting the enclosing class name. */ + private[log4cats] def getLoggerNameImpl(c: blackbox.Context) = { + import c.universe._ + + @tailrec def findEnclosingClass(sym: c.universe.Symbol): c.universe.Symbol = { + sym match { + case NoSymbol => + c.abort(c.enclosingPosition, s"Couldn't find an enclosing class or module for the logger") + case s if s.isModule || s.isClass => + s + case other => + /* We're not in a module or a class, so we're probably inside a member definition. Recurse upward. */ + findEnclosingClass(other.owner) + } + } + + val cls = findEnclosingClass(c.internal.enclosingOwner) + + assert(cls.isModule || cls.isClass, "Enclosing class is always either a module or a class") + + def nameBySymbol(s: Symbol) = { + def fullName(s: Symbol): String = { + @inline def isPackageObject = ( + (s.isModule || s.isModuleClass) + && s.owner.isPackage + && s.name.decodedName.toString == termNames.PACKAGE.decodedName.toString + ) + + if (s.isModule || s.isClass) { + if (isPackageObject) { + s.owner.fullName + } else if (s.owner.isStatic) { + s.fullName + } else { + fullName(s.owner) + "." + s.name.encodedName.toString + } + } else { + fullName(s.owner) + } + } + + q"new _root_.org.typelevel.log4cats.LoggerName(${fullName(s)})" + } + + def nameByType(s: Symbol) = { + val typeSymbol: ClassSymbol = (if (s.isModule) s.asModule.moduleClass else s).asClass + val typeParams = typeSymbol.typeParams + + if (typeParams.isEmpty) { + q"new _root_.org.typelevel.log4cats.LoggerName(_root_.scala.Predef.classOf[$typeSymbol].getName)" + } else { + if (typeParams.exists(_.asType.typeParams.nonEmpty)) { + /* We have at least one higher-kinded type: fall back to by-name logger construction, as + * there's no simple way to declare a higher-kinded type with an "any" parameter. */ + nameBySymbol(s) + } else { + val typeArgs = List.fill(typeParams.length)(WildcardType) + val typeConstructor = tq"$typeSymbol[..${typeArgs}]" + q"new _root_.org.typelevel.log4cats.LoggerName(_root_.scala.Predef.classOf[$typeConstructor].getName)" + } + } + } + + @inline def isInnerClass(s: Symbol) = + s.isClass && !(s.owner.isPackage) + + val instanceByName = + (true && cls.isModule || cls.isModuleClass) || (cls.isClass && isInnerClass( + cls + )) + + if (instanceByName) { + nameBySymbol(cls) + } else { + nameByType(cls) + } + } +} diff --git a/slf4j/src/main/scala-3/org/typelevel/log4cats/slf4j/LoggerNamePlatform.scala b/core/shared/src/main/scala-3/org/typelevel/log4cats/LoggerNameCompat.scala similarity index 80% rename from slf4j/src/main/scala-3/org/typelevel/log4cats/slf4j/LoggerNamePlatform.scala rename to core/shared/src/main/scala-3/org/typelevel/log4cats/LoggerNameCompat.scala index f730b97f..27a4ef51 100644 --- a/slf4j/src/main/scala-3/org/typelevel/log4cats/slf4j/LoggerNamePlatform.scala +++ b/core/shared/src/main/scala-3/org/typelevel/log4cats/LoggerNameCompat.scala @@ -14,13 +14,13 @@ * limitations under the License. */ -package org.typelevel.log4cats.slf4j +package org.typelevel.log4cats -import org.typelevel.log4cats.slf4j.internal.GetLoggerMacros +import org.typelevel.log4cats.internal.LoggerNameMacro import scala.quoted.* -trait LoggerNamePlatform { +trait LoggerNameCompat { implicit inline def name: LoggerName = - ${ GetLoggerMacros.getLoggerName } + ${ LoggerNameMacro.getLoggerName } } diff --git a/core/shared/src/main/scala-3/org/typelevel/log4cats/internal/LoggerNameMacro.scala b/core/shared/src/main/scala-3/org/typelevel/log4cats/internal/LoggerNameMacro.scala new file mode 100644 index 00000000..507fe577 --- /dev/null +++ b/core/shared/src/main/scala-3/org/typelevel/log4cats/internal/LoggerNameMacro.scala @@ -0,0 +1,55 @@ +package org.typelevel.log4cats +package internal + +import scala.annotation.tailrec +import scala.quoted.* + +private[log4cats] object LoggerNameMacro { + def getLoggerName(using qctx: Quotes): Expr[LoggerName] = { + val name = getLoggerNameImpl + '{ new LoggerName($name) } + } + + def getLoggerNameImpl(using qctx: Quotes): Expr[String] = { + import qctx.reflect._ + + @tailrec def findEnclosingClass(sym: Symbol): Symbol = { + sym match { + case s if s.isNoSymbol => + report.throwError("Couldn't find an enclosing class or module for the logger") + case s if s.isClassDef => + s + case other => + /* We're not in a module or a class, so we're probably inside a member definition. Recurse upward. */ + findEnclosingClass(other.owner) + } + } + + def symbolName(s: Symbol): Expr[String] = { + def fullName(s: Symbol): String = { + val flags = s.flags + if (flags.is(Flags.Package)) { + s.fullName + } else if (s.isClassDef) { + if (flags.is(Flags.Module)) { + if (s.name == "package$") { + fullName(s.owner) + } else { + val chomped = s.name.stripSuffix("$") + fullName(s.owner) + "." + chomped + } + } else { + fullName(s.owner) + "." + s.name + } + } else { + fullName(s.owner) + } + } + + Expr(fullName(s).stripSuffix("$")) + } + + val cls = findEnclosingClass(Symbol.spliceOwner) + symbolName(cls) + } +} diff --git a/core/shared/src/main/scala/org/typelevel/log4cats/LoggerFactory.scala b/core/shared/src/main/scala/org/typelevel/log4cats/LoggerFactory.scala new file mode 100644 index 00000000..c732502c --- /dev/null +++ b/core/shared/src/main/scala/org/typelevel/log4cats/LoggerFactory.scala @@ -0,0 +1,40 @@ +package org.typelevel.log4cats + +import scala.annotation.implicitNotFound + +@implicitNotFound("""| + |Implicit not found for LoggerFactory[${F}]. + | + |Information can be found here: https://log4cats.github.io/logging-capability.html + |""") +trait LoggerFactory[F[_]] extends LoggerFactoryGen[F, SelfAwareStructuredLogger[F]] +object LoggerFactory extends LoggerFactoryCompanion + +private[log4cats] trait LoggerFactoryCompanion { + def getLogger[F[_]](implicit + lf: LoggerFactory[F], + name: LoggerName + ): SelfAwareStructuredLogger[F] = + lf.getLogger + def getLoggerFromName[F[_]](name: String)(implicit + lf: LoggerFactory[F] + ): SelfAwareStructuredLogger[F] = + lf.getLoggerFromName(name) + + def getLoggerFromClass[F[_]](clazz: Class[_])(implicit + lf: LoggerFactory[F] + ): SelfAwareStructuredLogger[F] = + lf.getLoggerFromClass(clazz) + + def create[F[_]](implicit + lf: LoggerFactory[F], + name: LoggerName + ): F[SelfAwareStructuredLogger[F]] = + lf.create + def fromName[F[_]](name: String)(implicit lf: LoggerFactory[F]): F[SelfAwareStructuredLogger[F]] = + lf.fromName(name) + def fromClass[F[_]](clazz: Class[_])(implicit + lf: LoggerFactory[F] + ): F[SelfAwareStructuredLogger[F]] = + lf.fromClass(clazz) +} diff --git a/core/shared/src/main/scala/org/typelevel/log4cats/LoggerFactoryGen.scala b/core/shared/src/main/scala/org/typelevel/log4cats/LoggerFactoryGen.scala new file mode 100644 index 00000000..790876c5 --- /dev/null +++ b/core/shared/src/main/scala/org/typelevel/log4cats/LoggerFactoryGen.scala @@ -0,0 +1,10 @@ +package org.typelevel.log4cats + +trait LoggerFactoryGen[F[_], LoggerType] { + def getLogger(implicit name: LoggerName): LoggerType = getLoggerFromName(name.value) + def getLoggerFromClass(clazz: Class[_]): LoggerType = getLoggerFromName(clazz.getName) + def create(implicit name: LoggerName): F[LoggerType] = fromName(name.value) + def fromClass(clazz: Class[_]): F[LoggerType] = fromName(clazz.getName) + def getLoggerFromName(name: String): LoggerType + def fromName(name: String): F[LoggerType] +} diff --git a/core/shared/src/main/scala/org/typelevel/log4cats/LoggerName.scala b/core/shared/src/main/scala/org/typelevel/log4cats/LoggerName.scala new file mode 100644 index 00000000..f8cf9a22 --- /dev/null +++ b/core/shared/src/main/scala/org/typelevel/log4cats/LoggerName.scala @@ -0,0 +1,5 @@ +package org.typelevel.log4cats + +object LoggerName extends LoggerNameCompat + +final case class LoggerName(value: String) extends AnyVal diff --git a/slf4j/src/test/scala/org/typelevel/log4cats/slf4j/LoggerNameTest.scala b/core/shared/src/test/scala/org/typelevel/log4cats/LoggerNameTest.scala similarity index 80% rename from slf4j/src/test/scala/org/typelevel/log4cats/slf4j/LoggerNameTest.scala rename to core/shared/src/test/scala/org/typelevel/log4cats/LoggerNameTest.scala index 97cd0a1a..6ae11a5c 100644 --- a/slf4j/src/test/scala/org/typelevel/log4cats/slf4j/LoggerNameTest.scala +++ b/core/shared/src/test/scala/org/typelevel/log4cats/LoggerNameTest.scala @@ -14,7 +14,7 @@ * limitations under the License. */ -package org.typelevel.log4cats.slf4j +package org.typelevel.log4cats import munit.FunSuite @@ -31,7 +31,7 @@ class LoggerNameTest extends FunSuite { val name1 = new FooA().name val name2 = FooB.name - assertEquals(name1.value, "org.typelevel.log4cats.slf4j.LoggerNameTests.FooA") - assertEquals(name2.value, "org.typelevel.log4cats.slf4j.LoggerNameTests.FooB") + assertEquals(name1.value, "org.typelevel.log4cats.LoggerNameTest.FooA") + assertEquals(name2.value, "org.typelevel.log4cats.LoggerNameTest.FooB") } } diff --git a/slf4j/src/main/scala-2/org/typelevel/log4cats/slf4j/LoggerNamePlatform.scala b/slf4j/src/main/scala-2/org/typelevel/log4cats/slf4j/LoggerNamePlatform.scala deleted file mode 100644 index bf0b64b5..00000000 --- a/slf4j/src/main/scala-2/org/typelevel/log4cats/slf4j/LoggerNamePlatform.scala +++ /dev/null @@ -1,23 +0,0 @@ -/* - * 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 - -import org.typelevel.log4cats.slf4j.internal.GetLoggerMacros - -trait LoggerNamePlatform { - implicit def name: LoggerName = macro GetLoggerMacros.getLoggerName -} diff --git a/slf4j/src/main/scala-2/org/typelevel/log4cats/slf4j/Slf4jLoggerPlatform.scala b/slf4j/src/main/scala-2/org/typelevel/log4cats/slf4j/Slf4jLoggerCompat.scala similarity index 97% rename from slf4j/src/main/scala-2/org/typelevel/log4cats/slf4j/Slf4jLoggerPlatform.scala rename to slf4j/src/main/scala-2/org/typelevel/log4cats/slf4j/Slf4jLoggerCompat.scala index 14e3fb81..651fd5d9 100644 --- a/slf4j/src/main/scala-2/org/typelevel/log4cats/slf4j/Slf4jLoggerPlatform.scala +++ b/slf4j/src/main/scala-2/org/typelevel/log4cats/slf4j/Slf4jLoggerCompat.scala @@ -20,7 +20,7 @@ import cats.effect.Sync import org.typelevel.log4cats.SelfAwareStructuredLogger import org.typelevel.log4cats.slf4j.internal._ -trait Slf4jLoggerPlatform { +trait Slf4jLoggerCompat { private[slf4j] def getLogger[F[_]](implicit f: Sync[F]): SelfAwareStructuredLogger[F] = macro GetLoggerMacros.unsafeCreateImpl[F[_]] diff --git a/slf4j/src/main/scala-2/org/typelevel/log4cats/slf4j/internal/GetLoggerMacros.scala b/slf4j/src/main/scala-2/org/typelevel/log4cats/slf4j/internal/GetLoggerMacros.scala index aa37ef0a..14856e24 100644 --- a/slf4j/src/main/scala-2/org/typelevel/log4cats/slf4j/internal/GetLoggerMacros.scala +++ b/slf4j/src/main/scala-2/org/typelevel/log4cats/slf4j/internal/GetLoggerMacros.scala @@ -16,7 +16,8 @@ package org.typelevel.log4cats.slf4j.internal -import scala.annotation.tailrec +import org.typelevel.log4cats.internal.SharedLoggerNameMacro + import scala.reflect.macros.blackbox /** @@ -28,14 +29,13 @@ import scala.reflect.macros.blackbox * Sarah Gerweck */ private[slf4j] class GetLoggerMacros(val c: blackbox.Context) { - final def safeCreateImpl[F](f: c.Expr[F]) = getLoggerImpl[F](f, true) final def unsafeCreateImpl[F](f: c.Expr[F]) = getLoggerImpl[F](f, false) private def getLoggerImpl[F](f: c.Expr[F], delayed: Boolean) = { + val loggerName = SharedLoggerNameMacro.getLoggerNameImpl(c) import c.universe._ - val loggerName = getLoggerNameImpl def loggerByParam(param: c.Tree) = { val unsafeCreate = @@ -47,82 +47,4 @@ private[slf4j] class GetLoggerMacros(val c: blackbox.Context) { } loggerByParam(q"$loggerName.value") } - - final def getLoggerName = getLoggerNameImpl - - /** Get a logger by reflecting the enclosing class name. */ - private def getLoggerNameImpl = { - import c.universe._ - - @tailrec def findEnclosingClass(sym: c.universe.Symbol): c.universe.Symbol = { - sym match { - case NoSymbol => - c.abort(c.enclosingPosition, s"Couldn't find an enclosing class or module for the logger") - case s if s.isModule || s.isClass => - s - case other => - /* We're not in a module or a class, so we're probably inside a member definition. Recurse upward. */ - findEnclosingClass(other.owner) - } - } - - val cls = findEnclosingClass(c.internal.enclosingOwner) - - assert(cls.isModule || cls.isClass, "Enclosing class is always either a module or a class") - - def nameBySymbol(s: Symbol) = { - def fullName(s: Symbol): String = { - @inline def isPackageObject = ( - (s.isModule || s.isModuleClass) - && s.owner.isPackage - && s.name.decodedName.toString == termNames.PACKAGE.decodedName.toString - ) - if (s.isModule || s.isClass) { - if (isPackageObject) { - s.owner.fullName - } else if (s.owner.isStatic) { - s.fullName - } else { - fullName(s.owner) + "." + s.name.encodedName.toString - } - } else { - fullName(s.owner) - } - } - q"new _root_.org.typelevel.log4cats.slf4j.LoggerName(${fullName(s)})" - } - - def nameByType(s: Symbol) = { - val typeSymbol: ClassSymbol = (if (s.isModule) s.asModule.moduleClass else s).asClass - val typeParams = typeSymbol.typeParams - - if (typeParams.isEmpty) { - q"new _root_.org.typelevel.log4cats.slf4j.LoggerName(_root_.scala.Predef.classOf[$typeSymbol].getName)" - } else { - if (typeParams.exists(_.asType.typeParams.nonEmpty)) { - /* We have at least one higher-kinded type: fall back to by-name logger construction, as - * there's no simple way to declare a higher-kinded type with an "any" parameter. */ - nameBySymbol(s) - } else { - val typeArgs = List.fill(typeParams.length)(WildcardType) - val typeConstructor = tq"$typeSymbol[..${typeArgs}]" - q"new _root_.org.typelevel.log4cats.slf4j.LoggerName(_root_.scala.Predef.classOf[$typeConstructor].getName)" - } - } - } - - @inline def isInnerClass(s: Symbol) = - s.isClass && !(s.owner.isPackage) - - val instanceByName = - (Slf4jLoggerInternal.singletonsByName && cls.isModule || cls.isModuleClass) || (cls.isClass && isInnerClass( - cls - )) - - if (instanceByName) { - nameBySymbol(cls) - } else { - nameByType(cls) - } - } } diff --git a/slf4j/src/main/scala-3/org/typelevel/log4cats/slf4j/Slf4jLoggerPlatform.scala b/slf4j/src/main/scala-3/org/typelevel/log4cats/slf4j/Slf4jLoggerCompat.scala similarity index 97% rename from slf4j/src/main/scala-3/org/typelevel/log4cats/slf4j/Slf4jLoggerPlatform.scala rename to slf4j/src/main/scala-3/org/typelevel/log4cats/slf4j/Slf4jLoggerCompat.scala index 862fdf0c..3ad71219 100644 --- a/slf4j/src/main/scala-3/org/typelevel/log4cats/slf4j/Slf4jLoggerPlatform.scala +++ b/slf4j/src/main/scala-3/org/typelevel/log4cats/slf4j/Slf4jLoggerCompat.scala @@ -22,7 +22,7 @@ import org.typelevel.log4cats.slf4j.internal._ import org.slf4j.Logger as JLogger import scala.annotation.nowarn -trait Slf4jLoggerPlatform { +trait Slf4jLoggerCompat { // for binary compability private[slf4j] inline def create[F[_]](F: Sync[F]): F[SelfAwareStructuredLogger[F]] = diff --git a/slf4j/src/main/scala-3/org/typelevel/log4cats/slf4j/internal/GetLoggerMacros.scala b/slf4j/src/main/scala-3/org/typelevel/log4cats/slf4j/internal/GetLoggerMacros.scala index 2f78d613..f611ad97 100644 --- a/slf4j/src/main/scala-3/org/typelevel/log4cats/slf4j/internal/GetLoggerMacros.scala +++ b/slf4j/src/main/scala-3/org/typelevel/log4cats/slf4j/internal/GetLoggerMacros.scala @@ -18,8 +18,9 @@ package org.typelevel.log4cats.slf4j.internal import cats.effect.Sync import org.slf4j.LoggerFactory -import org.typelevel.log4cats.slf4j.{LoggerName, Slf4jLogger} +import org.typelevel.log4cats.slf4j.Slf4jLogger import org.typelevel.log4cats.SelfAwareStructuredLogger +import org.typelevel.log4cats.internal.LoggerNameMacro import scala.annotation.tailrec import scala.quoted.* @@ -29,7 +30,7 @@ private[slf4j] object GetLoggerMacros { def getLoggerImpl[F[_]: Type]( F: Expr[Sync[F]] )(using qctx: Quotes): Expr[SelfAwareStructuredLogger[F]] = { - val name = getLoggerNameImpl + val name = LoggerNameMacro.getLoggerNameImpl '{ Slf4jLogger.getLoggerFromSlf4j(LoggerFactory.getLogger($name))($F) } } @@ -39,52 +40,4 @@ private[slf4j] object GetLoggerMacros { val logger = getLoggerImpl(F) '{ $F.delay($logger) } } - - def getLoggerName(using qctx: Quotes): Expr[LoggerName] = { - val name = getLoggerNameImpl - '{ new LoggerName($name) } - } - - def getLoggerNameImpl(using qctx: Quotes): Expr[String] = { - import qctx.reflect._ - - @tailrec def findEnclosingClass(sym: Symbol): Symbol = { - sym match { - case s if s.isNoSymbol => - report.throwError("Couldn't find an enclosing class or module for the logger") - case s if s.isClassDef => - s - case other => - /* We're not in a module or a class, so we're probably inside a member definition. Recurse upward. */ - findEnclosingClass(other.owner) - } - } - - def symbolName(s: Symbol): Expr[String] = { - def fullName(s: Symbol): String = { - val flags = s.flags - if (flags.is(Flags.Package)) { - s.fullName - } else if (s.isClassDef) { - if (flags.is(Flags.Module)) { - if (s.name == "package$") { - fullName(s.owner) - } else { - val chomped = s.name.stripSuffix("$") - fullName(s.owner) + "." + chomped - } - } else { - fullName(s.owner) + "." + s.name - } - } else { - fullName(s.owner) - } - } - - Expr(fullName(s).stripSuffix("$")) - } - - val cls = findEnclosingClass(Symbol.spliceOwner) - symbolName(cls) - } } diff --git a/slf4j/src/main/scala/org/typelevel/log4cats/slf4j/LoggerFactory.scala b/slf4j/src/main/scala/org/typelevel/log4cats/slf4j/LoggerFactory.scala deleted file mode 100644 index b2d94bd6..00000000 --- a/slf4j/src/main/scala/org/typelevel/log4cats/slf4j/LoggerFactory.scala +++ /dev/null @@ -1,96 +0,0 @@ -/* - * 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 -package slf4j - -import cats.effect.Sync -import org.slf4j.{Logger => JLogger} - -trait LoggerFactory[F[_]] { - def getLogger(implicit name: LoggerName): SelfAwareStructuredLogger[F] - def getLoggerFromName(name: String): SelfAwareStructuredLogger[F] - def getLoggerFromClass(clazz: Class[_]): SelfAwareStructuredLogger[F] - def getLoggerFromSlf4j(logger: JLogger): SelfAwareStructuredLogger[F] - def create(implicit name: LoggerName): F[SelfAwareStructuredLogger[F]] - def fromName(name: String): F[SelfAwareStructuredLogger[F]] - def fromClass(clazz: Class[_]): F[SelfAwareStructuredLogger[F]] - def fromSlf4j(logger: JLogger): F[SelfAwareStructuredLogger[F]] -} - -object LoggerFactory { - def apply[F[_]: LoggerFactory]: LoggerFactory[F] = implicitly - - implicit def forSync[F[_]: Sync]: LoggerFactory[F] = new LoggerFactory[F] { - override def getLogger(implicit name: LoggerName): SelfAwareStructuredLogger[F] = - Slf4jLogger.getLogger - - override def getLoggerFromName(name: String): SelfAwareStructuredLogger[F] = - Slf4jLogger.getLoggerFromName(name) - override def getLoggerFromClass(clazz: Class[_]): SelfAwareStructuredLogger[F] = - Slf4jLogger.getLoggerFromClass(clazz) - override def getLoggerFromSlf4j(logger: JLogger): SelfAwareStructuredLogger[F] = - Slf4jLogger.getLoggerFromSlf4j(logger) - - def create(implicit name: LoggerName): F[SelfAwareStructuredLogger[F]] = - Slf4jLogger.create - - override def fromName(name: String): F[SelfAwareStructuredLogger[F]] = - Slf4jLogger.fromName(name) - - override def fromClass(clazz: Class[_]): F[SelfAwareStructuredLogger[F]] = - Slf4jLogger.fromClass(clazz) - - override def fromSlf4j(logger: JLogger): F[SelfAwareStructuredLogger[F]] = - Slf4jLogger.fromSlf4j(logger) - } - - def getLogger[F[_]](implicit - lf: LoggerFactory[F], - name: LoggerName - ): SelfAwareStructuredLogger[F] = - lf.getLogger - def getLoggerFromName[F[_]](name: String)(implicit - lf: LoggerFactory[F] - ): SelfAwareStructuredLogger[F] = - lf.getLoggerFromName(name) - - def getLoggerFromClass[F[_]](clazz: Class[_])(implicit - lf: LoggerFactory[F] - ): SelfAwareStructuredLogger[F] = - lf.getLoggerFromClass(clazz) - - def getLoggerFromSlf4j[F[_]](logger: JLogger)(implicit - lf: LoggerFactory[F] - ): SelfAwareStructuredLogger[F] = - lf.getLoggerFromSlf4j(logger) - def create[F[_]](implicit - lf: LoggerFactory[F], - name: LoggerName - ): F[SelfAwareStructuredLogger[F]] = - lf.create - def fromName[F[_]](name: String)(implicit lf: LoggerFactory[F]): F[SelfAwareStructuredLogger[F]] = - lf.fromName(name) - def fromClass[F[_]](clazz: Class[_])(implicit - lf: LoggerFactory[F] - ): F[SelfAwareStructuredLogger[F]] = - lf.fromClass(clazz) - def fromSlf4j[F[_]](logger: JLogger)(implicit - lf: LoggerFactory[F] - ): F[SelfAwareStructuredLogger[F]] = - lf.fromSlf4j(logger) - -} diff --git a/slf4j/src/main/scala/org/typelevel/log4cats/slf4j/LoggerName.scala b/slf4j/src/main/scala/org/typelevel/log4cats/slf4j/LoggerName.scala deleted file mode 100644 index 4797aad4..00000000 --- a/slf4j/src/main/scala/org/typelevel/log4cats/slf4j/LoggerName.scala +++ /dev/null @@ -1,21 +0,0 @@ -/* - * 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 - -object LoggerName extends LoggerNamePlatform - -final case class LoggerName(value: String) diff --git a/slf4j/src/main/scala/org/typelevel/log4cats/slf4j/Slf4jLogger.scala b/slf4j/src/main/scala/org/typelevel/log4cats/slf4j/Slf4jLogger.scala index 710d95af..1f82822a 100644 --- a/slf4j/src/main/scala/org/typelevel/log4cats/slf4j/Slf4jLogger.scala +++ b/slf4j/src/main/scala/org/typelevel/log4cats/slf4j/Slf4jLogger.scala @@ -14,16 +14,17 @@ * limitations under the License. */ -package org.typelevel.log4cats.slf4j +package org.typelevel.log4cats +package slf4j import cats.effect.Sync import org.typelevel.log4cats.SelfAwareStructuredLogger import org.typelevel.log4cats.slf4j.internal.Slf4jLoggerInternal import org.slf4j.{Logger => JLogger} -object Slf4jLogger extends Slf4jLoggerPlatform { +object Slf4jLogger extends Slf4jLoggerCompat { - def getLogger[F[_]: Sync](implicit name: LoggerName): SelfAwareStructuredLogger[F] = + def getLogger[F[_]](implicit f: Sync[F], name: LoggerName): SelfAwareStructuredLogger[F] = getLoggerFromName(name.value) def getLoggerFromName[F[_]: Sync](name: String): SelfAwareStructuredLogger[F] = @@ -47,4 +48,35 @@ object Slf4jLogger extends Slf4jLoggerPlatform { def fromSlf4j[F[_]: Sync](logger: JLogger): F[SelfAwareStructuredLogger[F]] = Sync[F].delay(getLoggerFromSlf4j[F](logger)) + trait Factory[F[_]] extends LoggerFactoryGen[F, SelfAwareStructuredLogger[F]] { + def getLoggerFromSlf4j(logger: JLogger): SelfAwareStructuredLogger[F] + def fromSlf4j(logger: JLogger): F[SelfAwareStructuredLogger[F]] + } + + object Factory extends LoggerFactoryCompanion { + def apply[F[_]: Factory] = implicitly[Factory[F]] + + implicit def forSync[F[_]: Sync]: Factory[F] = new Factory[F] { + override def getLoggerFromName(name: String): SelfAwareStructuredLogger[F] = + Slf4jLogger.getLoggerFromName(name) + override def getLoggerFromSlf4j(logger: JLogger): SelfAwareStructuredLogger[F] = + Slf4jLogger.getLoggerFromSlf4j(logger) + + override def fromName(name: String): F[SelfAwareStructuredLogger[F]] = + Slf4jLogger.fromName(name) + + override def fromSlf4j(logger: JLogger): F[SelfAwareStructuredLogger[F]] = + Slf4jLogger.fromSlf4j(logger) + } + + def getLoggerFromSlf4j[F[_]](logger: JLogger)(implicit + lf: Factory[F] + ): SelfAwareStructuredLogger[F] = + lf.getLoggerFromSlf4j(logger) + + def fromSlf4j[F[_]](logger: JLogger)(implicit + lf: Factory[F] + ): F[SelfAwareStructuredLogger[F]] = + lf.fromSlf4j(logger) + } } From af1100e7efc0c86c304b795e98eaf2d0beae9e3d Mon Sep 17 00:00:00 2001 From: Erlend Hamnaberg Date: Tue, 5 Apr 2022 18:09:44 +0200 Subject: [PATCH 08/18] Fix headers again --- .../typelevel/log4cats/LoggerNameCompat.scala | 16 ++++++++++++++++ .../log4cats/internal/LoggerNameMacro.scala | 16 ++++++++++++++++ .../log4cats/internal/LoggerNameMacro.scala | 16 ++++++++++++++++ .../org/typelevel/log4cats/LoggerFactory.scala | 16 ++++++++++++++++ .../typelevel/log4cats/LoggerFactoryGen.scala | 16 ++++++++++++++++ .../org/typelevel/log4cats/LoggerName.scala | 16 ++++++++++++++++ 6 files changed, 96 insertions(+) diff --git a/core/shared/src/main/scala-2/org/typelevel/log4cats/LoggerNameCompat.scala b/core/shared/src/main/scala-2/org/typelevel/log4cats/LoggerNameCompat.scala index eac04889..b43323bc 100644 --- a/core/shared/src/main/scala-2/org/typelevel/log4cats/LoggerNameCompat.scala +++ b/core/shared/src/main/scala-2/org/typelevel/log4cats/LoggerNameCompat.scala @@ -1,3 +1,19 @@ +/* + * 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 import org.typelevel.log4cats.internal.LoggerNameMacro diff --git a/core/shared/src/main/scala-2/org/typelevel/log4cats/internal/LoggerNameMacro.scala b/core/shared/src/main/scala-2/org/typelevel/log4cats/internal/LoggerNameMacro.scala index 32ab767f..b865d60d 100644 --- a/core/shared/src/main/scala-2/org/typelevel/log4cats/internal/LoggerNameMacro.scala +++ b/core/shared/src/main/scala-2/org/typelevel/log4cats/internal/LoggerNameMacro.scala @@ -1,3 +1,19 @@ +/* + * 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.internal import scala.annotation.tailrec diff --git a/core/shared/src/main/scala-3/org/typelevel/log4cats/internal/LoggerNameMacro.scala b/core/shared/src/main/scala-3/org/typelevel/log4cats/internal/LoggerNameMacro.scala index 507fe577..5db94194 100644 --- a/core/shared/src/main/scala-3/org/typelevel/log4cats/internal/LoggerNameMacro.scala +++ b/core/shared/src/main/scala-3/org/typelevel/log4cats/internal/LoggerNameMacro.scala @@ -1,3 +1,19 @@ +/* + * 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 package internal diff --git a/core/shared/src/main/scala/org/typelevel/log4cats/LoggerFactory.scala b/core/shared/src/main/scala/org/typelevel/log4cats/LoggerFactory.scala index c732502c..cd34ff30 100644 --- a/core/shared/src/main/scala/org/typelevel/log4cats/LoggerFactory.scala +++ b/core/shared/src/main/scala/org/typelevel/log4cats/LoggerFactory.scala @@ -1,3 +1,19 @@ +/* + * 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 import scala.annotation.implicitNotFound diff --git a/core/shared/src/main/scala/org/typelevel/log4cats/LoggerFactoryGen.scala b/core/shared/src/main/scala/org/typelevel/log4cats/LoggerFactoryGen.scala index 790876c5..a70982f4 100644 --- a/core/shared/src/main/scala/org/typelevel/log4cats/LoggerFactoryGen.scala +++ b/core/shared/src/main/scala/org/typelevel/log4cats/LoggerFactoryGen.scala @@ -1,3 +1,19 @@ +/* + * 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 trait LoggerFactoryGen[F[_], LoggerType] { diff --git a/core/shared/src/main/scala/org/typelevel/log4cats/LoggerName.scala b/core/shared/src/main/scala/org/typelevel/log4cats/LoggerName.scala index f8cf9a22..801dcadc 100644 --- a/core/shared/src/main/scala/org/typelevel/log4cats/LoggerName.scala +++ b/core/shared/src/main/scala/org/typelevel/log4cats/LoggerName.scala @@ -1,3 +1,19 @@ +/* + * 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 object LoggerName extends LoggerNameCompat From 6aedf0450d1279a00c829cbf7085d13096a959fa Mon Sep 17 00:00:00 2001 From: Erlend Hamnaberg Date: Tue, 5 Apr 2022 20:51:30 +0200 Subject: [PATCH 09/18] Slf4jFactory as toplevel trait --- .../log4cats/slf4j/Slf4jFactory.scala | 54 +++++++++++++++++++ .../log4cats/slf4j/Slf4jLogger.scala | 33 ------------ 2 files changed, 54 insertions(+), 33 deletions(-) create mode 100644 slf4j/src/main/scala/org/typelevel/log4cats/slf4j/Slf4jFactory.scala diff --git a/slf4j/src/main/scala/org/typelevel/log4cats/slf4j/Slf4jFactory.scala b/slf4j/src/main/scala/org/typelevel/log4cats/slf4j/Slf4jFactory.scala new file mode 100644 index 00000000..e392ac08 --- /dev/null +++ b/slf4j/src/main/scala/org/typelevel/log4cats/slf4j/Slf4jFactory.scala @@ -0,0 +1,54 @@ +/* + * 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 + +import cats.effect.Sync +import org.typelevel.log4cats.{LoggerFactory, LoggerFactoryCompanion, SelfAwareStructuredLogger} +import org.slf4j.{Logger => JLogger} + +trait Slf4jFactory[F[_]] extends LoggerFactory[F] { + def getLoggerFromSlf4j(logger: JLogger): SelfAwareStructuredLogger[F] + + def fromSlf4j(logger: JLogger): F[SelfAwareStructuredLogger[F]] +} + +object Slf4jFactory extends LoggerFactoryCompanion { + def apply[F[_]: Slf4jFactory]: Slf4jFactory[F] = implicitly + + implicit def forSync[F[_]: Sync]: Slf4jFactory[F] = new Slf4jFactory[F] { + override def getLoggerFromName(name: String): SelfAwareStructuredLogger[F] = + Slf4jLogger.getLoggerFromName(name) + + override def getLoggerFromSlf4j(logger: JLogger): SelfAwareStructuredLogger[F] = + Slf4jLogger.getLoggerFromSlf4j(logger) + + override def fromName(name: String): F[SelfAwareStructuredLogger[F]] = + Slf4jLogger.fromName(name) + + override def fromSlf4j(logger: JLogger): F[SelfAwareStructuredLogger[F]] = + Slf4jLogger.fromSlf4j(logger) + } + + def getLoggerFromSlf4j[F[_]](logger: JLogger)(implicit + lf: Slf4jFactory[F] + ): SelfAwareStructuredLogger[F] = lf.getLoggerFromSlf4j(logger) + + def fromSlf4j[F[_]](logger: JLogger)(implicit + lf: Slf4jFactory[F] + ): F[SelfAwareStructuredLogger[F]] = + lf.fromSlf4j(logger) +} diff --git a/slf4j/src/main/scala/org/typelevel/log4cats/slf4j/Slf4jLogger.scala b/slf4j/src/main/scala/org/typelevel/log4cats/slf4j/Slf4jLogger.scala index 1f82822a..3fb97803 100644 --- a/slf4j/src/main/scala/org/typelevel/log4cats/slf4j/Slf4jLogger.scala +++ b/slf4j/src/main/scala/org/typelevel/log4cats/slf4j/Slf4jLogger.scala @@ -18,7 +18,6 @@ package org.typelevel.log4cats package slf4j import cats.effect.Sync -import org.typelevel.log4cats.SelfAwareStructuredLogger import org.typelevel.log4cats.slf4j.internal.Slf4jLoggerInternal import org.slf4j.{Logger => JLogger} @@ -47,36 +46,4 @@ object Slf4jLogger extends Slf4jLoggerCompat { def fromSlf4j[F[_]: Sync](logger: JLogger): F[SelfAwareStructuredLogger[F]] = Sync[F].delay(getLoggerFromSlf4j[F](logger)) - - trait Factory[F[_]] extends LoggerFactoryGen[F, SelfAwareStructuredLogger[F]] { - def getLoggerFromSlf4j(logger: JLogger): SelfAwareStructuredLogger[F] - def fromSlf4j(logger: JLogger): F[SelfAwareStructuredLogger[F]] - } - - object Factory extends LoggerFactoryCompanion { - def apply[F[_]: Factory] = implicitly[Factory[F]] - - implicit def forSync[F[_]: Sync]: Factory[F] = new Factory[F] { - override def getLoggerFromName(name: String): SelfAwareStructuredLogger[F] = - Slf4jLogger.getLoggerFromName(name) - override def getLoggerFromSlf4j(logger: JLogger): SelfAwareStructuredLogger[F] = - Slf4jLogger.getLoggerFromSlf4j(logger) - - override def fromName(name: String): F[SelfAwareStructuredLogger[F]] = - Slf4jLogger.fromName(name) - - override def fromSlf4j(logger: JLogger): F[SelfAwareStructuredLogger[F]] = - Slf4jLogger.fromSlf4j(logger) - } - - def getLoggerFromSlf4j[F[_]](logger: JLogger)(implicit - lf: Factory[F] - ): SelfAwareStructuredLogger[F] = - lf.getLoggerFromSlf4j(logger) - - def fromSlf4j[F[_]](logger: JLogger)(implicit - lf: Factory[F] - ): F[SelfAwareStructuredLogger[F]] = - lf.fromSlf4j(logger) - } } From 36d983e93829e49a2be1126e7791427206358f9b Mon Sep 17 00:00:00 2001 From: Erlend Hamnaberg Date: Tue, 5 Apr 2022 21:40:05 +0200 Subject: [PATCH 10/18] The Companion trait did not work as expected --- .../typelevel/log4cats/LoggerFactory.scala | 38 ++----------------- .../log4cats/slf4j/Slf4jFactory.scala | 33 ++++++++++++++-- .../Slf4jLoggerMacroCompilationTests.scala | 2 +- 3 files changed, 34 insertions(+), 39 deletions(-) diff --git a/core/shared/src/main/scala/org/typelevel/log4cats/LoggerFactory.scala b/core/shared/src/main/scala/org/typelevel/log4cats/LoggerFactory.scala index cd34ff30..74a5562b 100644 --- a/core/shared/src/main/scala/org/typelevel/log4cats/LoggerFactory.scala +++ b/core/shared/src/main/scala/org/typelevel/log4cats/LoggerFactory.scala @@ -18,39 +18,7 @@ package org.typelevel.log4cats import scala.annotation.implicitNotFound -@implicitNotFound("""| - |Implicit not found for LoggerFactory[${F}]. - | - |Information can be found here: https://log4cats.github.io/logging-capability.html - |""") +@implicitNotFound("""Implicit not found for LoggerFactory[${F}]. + Information can be found here: https://log4cats.github.io/logging-capability.html +""") trait LoggerFactory[F[_]] extends LoggerFactoryGen[F, SelfAwareStructuredLogger[F]] -object LoggerFactory extends LoggerFactoryCompanion - -private[log4cats] trait LoggerFactoryCompanion { - def getLogger[F[_]](implicit - lf: LoggerFactory[F], - name: LoggerName - ): SelfAwareStructuredLogger[F] = - lf.getLogger - def getLoggerFromName[F[_]](name: String)(implicit - lf: LoggerFactory[F] - ): SelfAwareStructuredLogger[F] = - lf.getLoggerFromName(name) - - def getLoggerFromClass[F[_]](clazz: Class[_])(implicit - lf: LoggerFactory[F] - ): SelfAwareStructuredLogger[F] = - lf.getLoggerFromClass(clazz) - - def create[F[_]](implicit - lf: LoggerFactory[F], - name: LoggerName - ): F[SelfAwareStructuredLogger[F]] = - lf.create - def fromName[F[_]](name: String)(implicit lf: LoggerFactory[F]): F[SelfAwareStructuredLogger[F]] = - lf.fromName(name) - def fromClass[F[_]](clazz: Class[_])(implicit - lf: LoggerFactory[F] - ): F[SelfAwareStructuredLogger[F]] = - lf.fromClass(clazz) -} diff --git a/slf4j/src/main/scala/org/typelevel/log4cats/slf4j/Slf4jFactory.scala b/slf4j/src/main/scala/org/typelevel/log4cats/slf4j/Slf4jFactory.scala index e392ac08..ecff442d 100644 --- a/slf4j/src/main/scala/org/typelevel/log4cats/slf4j/Slf4jFactory.scala +++ b/slf4j/src/main/scala/org/typelevel/log4cats/slf4j/Slf4jFactory.scala @@ -14,10 +14,10 @@ * limitations under the License. */ -package org.typelevel.log4cats.slf4j +package org.typelevel.log4cats +package slf4j import cats.effect.Sync -import org.typelevel.log4cats.{LoggerFactory, LoggerFactoryCompanion, SelfAwareStructuredLogger} import org.slf4j.{Logger => JLogger} trait Slf4jFactory[F[_]] extends LoggerFactory[F] { @@ -26,7 +26,7 @@ trait Slf4jFactory[F[_]] extends LoggerFactory[F] { def fromSlf4j(logger: JLogger): F[SelfAwareStructuredLogger[F]] } -object Slf4jFactory extends LoggerFactoryCompanion { +object Slf4jFactory { def apply[F[_]: Slf4jFactory]: Slf4jFactory[F] = implicitly implicit def forSync[F[_]: Sync]: Slf4jFactory[F] = new Slf4jFactory[F] { @@ -51,4 +51,31 @@ object Slf4jFactory extends LoggerFactoryCompanion { lf: Slf4jFactory[F] ): F[SelfAwareStructuredLogger[F]] = lf.fromSlf4j(logger) + + def getLogger[F[_]](implicit + lf: Slf4jFactory[F], + name: LoggerName + ): SelfAwareStructuredLogger[F] = + lf.getLogger + def getLoggerFromName[F[_]](name: String)(implicit + lf: Slf4jFactory[F] + ): SelfAwareStructuredLogger[F] = + lf.getLoggerFromName(name) + + def getLoggerFromClass[F[_]](clazz: Class[_])(implicit + lf: Slf4jFactory[F] + ): SelfAwareStructuredLogger[F] = + lf.getLoggerFromClass(clazz) + + def create[F[_]](implicit + lf: Slf4jFactory[F], + name: LoggerName + ): F[SelfAwareStructuredLogger[F]] = + lf.create + def fromName[F[_]](name: String)(implicit lf: Slf4jFactory[F]): F[SelfAwareStructuredLogger[F]] = + lf.fromName(name) + def fromClass[F[_]](clazz: Class[_])(implicit + lf: Slf4jFactory[F] + ): F[SelfAwareStructuredLogger[F]] = + lf.fromClass(clazz) } diff --git a/slf4j/src/test/scala/org/typelevel/log4cats/slf4j/Slf4jLoggerMacroCompilationTests.scala b/slf4j/src/test/scala/org/typelevel/log4cats/slf4j/Slf4jLoggerMacroCompilationTests.scala index 566413e7..ce3c1ab7 100644 --- a/slf4j/src/test/scala/org/typelevel/log4cats/slf4j/Slf4jLoggerMacroCompilationTests.scala +++ b/slf4j/src/test/scala/org/typelevel/log4cats/slf4j/Slf4jLoggerMacroCompilationTests.scala @@ -48,7 +48,7 @@ class Slf4jLoggerOuterClassMacroTest { object LoggingBaseline { val t = new Throwable - def logger[F[_]: Sync]: SelfAwareStructuredLogger[F] = Slf4jLogger.getLogger[F] + def logger[F[_]: Sync]: SelfAwareStructuredLogger[F] = Slf4jFactory.getLogger[F] val traceM = logger[IO].trace("") val traceTM = logger[IO].trace(t)("") From b4df30cc41d5e9e1eefe30f9fae2464b4c03145f Mon Sep 17 00:00:00 2001 From: Erlend Hamnaberg Date: Wed, 6 Apr 2022 08:58:45 +0200 Subject: [PATCH 11/18] Revert "The Companion trait did not work as expected" This reverts commit 7167e54a9c2e0a089154d7cda469f33a0797fc4f. --- .../typelevel/log4cats/LoggerFactory.scala | 38 +++++++++++++++++-- .../log4cats/slf4j/Slf4jFactory.scala | 33 ++-------------- .../Slf4jLoggerMacroCompilationTests.scala | 2 +- 3 files changed, 39 insertions(+), 34 deletions(-) diff --git a/core/shared/src/main/scala/org/typelevel/log4cats/LoggerFactory.scala b/core/shared/src/main/scala/org/typelevel/log4cats/LoggerFactory.scala index 74a5562b..cd34ff30 100644 --- a/core/shared/src/main/scala/org/typelevel/log4cats/LoggerFactory.scala +++ b/core/shared/src/main/scala/org/typelevel/log4cats/LoggerFactory.scala @@ -18,7 +18,39 @@ package org.typelevel.log4cats import scala.annotation.implicitNotFound -@implicitNotFound("""Implicit not found for LoggerFactory[${F}]. - Information can be found here: https://log4cats.github.io/logging-capability.html -""") +@implicitNotFound("""| + |Implicit not found for LoggerFactory[${F}]. + | + |Information can be found here: https://log4cats.github.io/logging-capability.html + |""") trait LoggerFactory[F[_]] extends LoggerFactoryGen[F, SelfAwareStructuredLogger[F]] +object LoggerFactory extends LoggerFactoryCompanion + +private[log4cats] trait LoggerFactoryCompanion { + def getLogger[F[_]](implicit + lf: LoggerFactory[F], + name: LoggerName + ): SelfAwareStructuredLogger[F] = + lf.getLogger + def getLoggerFromName[F[_]](name: String)(implicit + lf: LoggerFactory[F] + ): SelfAwareStructuredLogger[F] = + lf.getLoggerFromName(name) + + def getLoggerFromClass[F[_]](clazz: Class[_])(implicit + lf: LoggerFactory[F] + ): SelfAwareStructuredLogger[F] = + lf.getLoggerFromClass(clazz) + + def create[F[_]](implicit + lf: LoggerFactory[F], + name: LoggerName + ): F[SelfAwareStructuredLogger[F]] = + lf.create + def fromName[F[_]](name: String)(implicit lf: LoggerFactory[F]): F[SelfAwareStructuredLogger[F]] = + lf.fromName(name) + def fromClass[F[_]](clazz: Class[_])(implicit + lf: LoggerFactory[F] + ): F[SelfAwareStructuredLogger[F]] = + lf.fromClass(clazz) +} diff --git a/slf4j/src/main/scala/org/typelevel/log4cats/slf4j/Slf4jFactory.scala b/slf4j/src/main/scala/org/typelevel/log4cats/slf4j/Slf4jFactory.scala index ecff442d..e392ac08 100644 --- a/slf4j/src/main/scala/org/typelevel/log4cats/slf4j/Slf4jFactory.scala +++ b/slf4j/src/main/scala/org/typelevel/log4cats/slf4j/Slf4jFactory.scala @@ -14,10 +14,10 @@ * limitations under the License. */ -package org.typelevel.log4cats -package slf4j +package org.typelevel.log4cats.slf4j import cats.effect.Sync +import org.typelevel.log4cats.{LoggerFactory, LoggerFactoryCompanion, SelfAwareStructuredLogger} import org.slf4j.{Logger => JLogger} trait Slf4jFactory[F[_]] extends LoggerFactory[F] { @@ -26,7 +26,7 @@ trait Slf4jFactory[F[_]] extends LoggerFactory[F] { def fromSlf4j(logger: JLogger): F[SelfAwareStructuredLogger[F]] } -object Slf4jFactory { +object Slf4jFactory extends LoggerFactoryCompanion { def apply[F[_]: Slf4jFactory]: Slf4jFactory[F] = implicitly implicit def forSync[F[_]: Sync]: Slf4jFactory[F] = new Slf4jFactory[F] { @@ -51,31 +51,4 @@ object Slf4jFactory { lf: Slf4jFactory[F] ): F[SelfAwareStructuredLogger[F]] = lf.fromSlf4j(logger) - - def getLogger[F[_]](implicit - lf: Slf4jFactory[F], - name: LoggerName - ): SelfAwareStructuredLogger[F] = - lf.getLogger - def getLoggerFromName[F[_]](name: String)(implicit - lf: Slf4jFactory[F] - ): SelfAwareStructuredLogger[F] = - lf.getLoggerFromName(name) - - def getLoggerFromClass[F[_]](clazz: Class[_])(implicit - lf: Slf4jFactory[F] - ): SelfAwareStructuredLogger[F] = - lf.getLoggerFromClass(clazz) - - def create[F[_]](implicit - lf: Slf4jFactory[F], - name: LoggerName - ): F[SelfAwareStructuredLogger[F]] = - lf.create - def fromName[F[_]](name: String)(implicit lf: Slf4jFactory[F]): F[SelfAwareStructuredLogger[F]] = - lf.fromName(name) - def fromClass[F[_]](clazz: Class[_])(implicit - lf: Slf4jFactory[F] - ): F[SelfAwareStructuredLogger[F]] = - lf.fromClass(clazz) } diff --git a/slf4j/src/test/scala/org/typelevel/log4cats/slf4j/Slf4jLoggerMacroCompilationTests.scala b/slf4j/src/test/scala/org/typelevel/log4cats/slf4j/Slf4jLoggerMacroCompilationTests.scala index ce3c1ab7..566413e7 100644 --- a/slf4j/src/test/scala/org/typelevel/log4cats/slf4j/Slf4jLoggerMacroCompilationTests.scala +++ b/slf4j/src/test/scala/org/typelevel/log4cats/slf4j/Slf4jLoggerMacroCompilationTests.scala @@ -48,7 +48,7 @@ class Slf4jLoggerOuterClassMacroTest { object LoggingBaseline { val t = new Throwable - def logger[F[_]: Sync]: SelfAwareStructuredLogger[F] = Slf4jFactory.getLogger[F] + def logger[F[_]: Sync]: SelfAwareStructuredLogger[F] = Slf4jLogger.getLogger[F] val traceM = logger[IO].trace("") val traceTM = logger[IO].trace(t)("") From 40cfa677d817e507a7fc5b514b1abbd099f33914 Mon Sep 17 00:00:00 2001 From: Erlend Hamnaberg Date: Wed, 6 Apr 2022 09:03:56 +0200 Subject: [PATCH 12/18] Companion trait worked, the implicit did not resolve --- .../typelevel/log4cats/LoggerFactory.scala | 13 ++++++------ .../log4cats/slf4j/Slf4jFactory.scala | 19 ++---------------- .../typelevel/log4cats/slf4j/package.scala | 20 +++++++++++++++++++ .../Slf4jLoggerMacroCompilationTests.scala | 2 +- 4 files changed, 30 insertions(+), 24 deletions(-) create mode 100644 slf4j/src/main/scala/org/typelevel/log4cats/slf4j/package.scala diff --git a/core/shared/src/main/scala/org/typelevel/log4cats/LoggerFactory.scala b/core/shared/src/main/scala/org/typelevel/log4cats/LoggerFactory.scala index cd34ff30..82420a3f 100644 --- a/core/shared/src/main/scala/org/typelevel/log4cats/LoggerFactory.scala +++ b/core/shared/src/main/scala/org/typelevel/log4cats/LoggerFactory.scala @@ -18,13 +18,14 @@ package org.typelevel.log4cats import scala.annotation.implicitNotFound -@implicitNotFound("""| - |Implicit not found for LoggerFactory[${F}]. - | - |Information can be found here: https://log4cats.github.io/logging-capability.html - |""") +@implicitNotFound(""" +Implicit not found for LoggerFactory[${F}]. +Information can be found here: https://log4cats.github.io/logging-capability.html +""") trait LoggerFactory[F[_]] extends LoggerFactoryGen[F, SelfAwareStructuredLogger[F]] -object LoggerFactory extends LoggerFactoryCompanion +object LoggerFactory extends LoggerFactoryCompanion { + def apply[F[_]: LoggerFactory]: LoggerFactory[F] = implicitly +} private[log4cats] trait LoggerFactoryCompanion { def getLogger[F[_]](implicit diff --git a/slf4j/src/main/scala/org/typelevel/log4cats/slf4j/Slf4jFactory.scala b/slf4j/src/main/scala/org/typelevel/log4cats/slf4j/Slf4jFactory.scala index e392ac08..89733a67 100644 --- a/slf4j/src/main/scala/org/typelevel/log4cats/slf4j/Slf4jFactory.scala +++ b/slf4j/src/main/scala/org/typelevel/log4cats/slf4j/Slf4jFactory.scala @@ -14,10 +14,9 @@ * limitations under the License. */ -package org.typelevel.log4cats.slf4j +package org.typelevel.log4cats +package slf4j -import cats.effect.Sync -import org.typelevel.log4cats.{LoggerFactory, LoggerFactoryCompanion, SelfAwareStructuredLogger} import org.slf4j.{Logger => JLogger} trait Slf4jFactory[F[_]] extends LoggerFactory[F] { @@ -29,20 +28,6 @@ trait Slf4jFactory[F[_]] extends LoggerFactory[F] { object Slf4jFactory extends LoggerFactoryCompanion { def apply[F[_]: Slf4jFactory]: Slf4jFactory[F] = implicitly - implicit def forSync[F[_]: Sync]: Slf4jFactory[F] = new Slf4jFactory[F] { - override def getLoggerFromName(name: String): SelfAwareStructuredLogger[F] = - Slf4jLogger.getLoggerFromName(name) - - override def getLoggerFromSlf4j(logger: JLogger): SelfAwareStructuredLogger[F] = - Slf4jLogger.getLoggerFromSlf4j(logger) - - override def fromName(name: String): F[SelfAwareStructuredLogger[F]] = - Slf4jLogger.fromName(name) - - override def fromSlf4j(logger: JLogger): F[SelfAwareStructuredLogger[F]] = - Slf4jLogger.fromSlf4j(logger) - } - def getLoggerFromSlf4j[F[_]](logger: JLogger)(implicit lf: Slf4jFactory[F] ): SelfAwareStructuredLogger[F] = lf.getLoggerFromSlf4j(logger) diff --git a/slf4j/src/main/scala/org/typelevel/log4cats/slf4j/package.scala b/slf4j/src/main/scala/org/typelevel/log4cats/slf4j/package.scala new file mode 100644 index 00000000..234063a4 --- /dev/null +++ b/slf4j/src/main/scala/org/typelevel/log4cats/slf4j/package.scala @@ -0,0 +1,20 @@ +package org.typelevel.log4cats + +import cats.effect.Sync +import org.slf4j.{Logger => JLogger} + +package object slf4j { + implicit def loggerFactoryforSync[F[_]: Sync]: Slf4jFactory[F] = new Slf4jFactory[F] { + override def getLoggerFromName(name: String): SelfAwareStructuredLogger[F] = + Slf4jLogger.getLoggerFromName(name) + + override def getLoggerFromSlf4j(logger: JLogger): SelfAwareStructuredLogger[F] = + Slf4jLogger.getLoggerFromSlf4j(logger) + + override def fromName(name: String): F[SelfAwareStructuredLogger[F]] = + Slf4jLogger.fromName(name) + + override def fromSlf4j(logger: JLogger): F[SelfAwareStructuredLogger[F]] = + Slf4jLogger.fromSlf4j(logger) + } +} diff --git a/slf4j/src/test/scala/org/typelevel/log4cats/slf4j/Slf4jLoggerMacroCompilationTests.scala b/slf4j/src/test/scala/org/typelevel/log4cats/slf4j/Slf4jLoggerMacroCompilationTests.scala index 566413e7..ce3c1ab7 100644 --- a/slf4j/src/test/scala/org/typelevel/log4cats/slf4j/Slf4jLoggerMacroCompilationTests.scala +++ b/slf4j/src/test/scala/org/typelevel/log4cats/slf4j/Slf4jLoggerMacroCompilationTests.scala @@ -48,7 +48,7 @@ class Slf4jLoggerOuterClassMacroTest { object LoggingBaseline { val t = new Throwable - def logger[F[_]: Sync]: SelfAwareStructuredLogger[F] = Slf4jLogger.getLogger[F] + def logger[F[_]: Sync]: SelfAwareStructuredLogger[F] = Slf4jFactory.getLogger[F] val traceM = logger[IO].trace("") val traceTM = logger[IO].trace(t)("") From 28dbd1090dc2d42442b4d4e025a809dc790b433e Mon Sep 17 00:00:00 2001 From: Erlend Hamnaberg Date: Wed, 6 Apr 2022 09:17:04 +0200 Subject: [PATCH 13/18] Add headers again --- .../org/typelevel/log4cats/slf4j/package.scala | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/slf4j/src/main/scala/org/typelevel/log4cats/slf4j/package.scala b/slf4j/src/main/scala/org/typelevel/log4cats/slf4j/package.scala index 234063a4..95cfd9f1 100644 --- a/slf4j/src/main/scala/org/typelevel/log4cats/slf4j/package.scala +++ b/slf4j/src/main/scala/org/typelevel/log4cats/slf4j/package.scala @@ -1,3 +1,19 @@ +/* + * 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 import cats.effect.Sync From 496e2c39ae0a44ff75e01ace5136267fe157f461 Mon Sep 17 00:00:00 2001 From: Erlend Hamnaberg Date: Wed, 6 Apr 2022 09:34:08 +0200 Subject: [PATCH 14/18] Exploit path dependent types and get generic companion type to work --- .../typelevel/log4cats/LoggerFactory.scala | 36 +++---------------- .../typelevel/log4cats/LoggerFactoryGen.scala | 18 +++++++++- .../log4cats/slf4j/Slf4jFactory.scala | 2 +- 3 files changed, 23 insertions(+), 33 deletions(-) diff --git a/core/shared/src/main/scala/org/typelevel/log4cats/LoggerFactory.scala b/core/shared/src/main/scala/org/typelevel/log4cats/LoggerFactory.scala index 82420a3f..2988c845 100644 --- a/core/shared/src/main/scala/org/typelevel/log4cats/LoggerFactory.scala +++ b/core/shared/src/main/scala/org/typelevel/log4cats/LoggerFactory.scala @@ -22,36 +22,10 @@ import scala.annotation.implicitNotFound Implicit not found for LoggerFactory[${F}]. Information can be found here: https://log4cats.github.io/logging-capability.html """) -trait LoggerFactory[F[_]] extends LoggerFactoryGen[F, SelfAwareStructuredLogger[F]] -object LoggerFactory extends LoggerFactoryCompanion { - def apply[F[_]: LoggerFactory]: LoggerFactory[F] = implicitly +trait LoggerFactory[F[_]] extends LoggerFactoryGen[F] { + type LoggerType = SelfAwareStructuredLogger[F] } -private[log4cats] trait LoggerFactoryCompanion { - def getLogger[F[_]](implicit - lf: LoggerFactory[F], - name: LoggerName - ): SelfAwareStructuredLogger[F] = - lf.getLogger - def getLoggerFromName[F[_]](name: String)(implicit - lf: LoggerFactory[F] - ): SelfAwareStructuredLogger[F] = - lf.getLoggerFromName(name) - - def getLoggerFromClass[F[_]](clazz: Class[_])(implicit - lf: LoggerFactory[F] - ): SelfAwareStructuredLogger[F] = - lf.getLoggerFromClass(clazz) - - def create[F[_]](implicit - lf: LoggerFactory[F], - name: LoggerName - ): F[SelfAwareStructuredLogger[F]] = - lf.create - def fromName[F[_]](name: String)(implicit lf: LoggerFactory[F]): F[SelfAwareStructuredLogger[F]] = - lf.fromName(name) - def fromClass[F[_]](clazz: Class[_])(implicit - lf: LoggerFactory[F] - ): F[SelfAwareStructuredLogger[F]] = - lf.fromClass(clazz) -} +object LoggerFactory extends LoggerFactoryGenCompanion { + def apply[F[_]: LoggerFactory]: LoggerFactory[F] = implicitly +} \ No newline at end of file diff --git a/core/shared/src/main/scala/org/typelevel/log4cats/LoggerFactoryGen.scala b/core/shared/src/main/scala/org/typelevel/log4cats/LoggerFactoryGen.scala index a70982f4..0c45eb00 100644 --- a/core/shared/src/main/scala/org/typelevel/log4cats/LoggerFactoryGen.scala +++ b/core/shared/src/main/scala/org/typelevel/log4cats/LoggerFactoryGen.scala @@ -16,7 +16,8 @@ package org.typelevel.log4cats -trait LoggerFactoryGen[F[_], LoggerType] { +trait LoggerFactoryGen[F[_]] { + type LoggerType <: Logger[F] def getLogger(implicit name: LoggerName): LoggerType = getLoggerFromName(name.value) def getLoggerFromClass(clazz: Class[_]): LoggerType = getLoggerFromName(clazz.getName) def create(implicit name: LoggerName): F[LoggerType] = fromName(name.value) @@ -24,3 +25,18 @@ trait LoggerFactoryGen[F[_], LoggerType] { def getLoggerFromName(name: String): LoggerType def fromName(name: String): F[LoggerType] } + +private[log4cats] trait LoggerFactoryGenCompanion { + def getLogger[F[_]](implicit lf: LoggerFactoryGen[F], name: LoggerName): lf.LoggerType = + lf.getLogger + def getLoggerFromName[F[_]](name: String)(implicit lf: LoggerFactoryGen[F]): lf.LoggerType = + lf.getLoggerFromName(name) + def getLoggerFromClass[F[_]](clazz: Class[_])(implicit lf: LoggerFactoryGen[F]): lf.LoggerType = + lf.getLoggerFromClass(clazz) + def create[F[_]](implicit lf: LoggerFactoryGen[F], name: LoggerName): F[lf.LoggerType] = + lf.create + def fromName[F[_]](name: String)(implicit lf: LoggerFactoryGen[F]): F[lf.LoggerType] = + lf.fromName(name) + def fromClass[F[_]](clazz: Class[_])(implicit lf: LoggerFactoryGen[F]): F[lf.LoggerType] = + lf.fromClass(clazz) +} diff --git a/slf4j/src/main/scala/org/typelevel/log4cats/slf4j/Slf4jFactory.scala b/slf4j/src/main/scala/org/typelevel/log4cats/slf4j/Slf4jFactory.scala index 89733a67..b210e9a3 100644 --- a/slf4j/src/main/scala/org/typelevel/log4cats/slf4j/Slf4jFactory.scala +++ b/slf4j/src/main/scala/org/typelevel/log4cats/slf4j/Slf4jFactory.scala @@ -25,7 +25,7 @@ trait Slf4jFactory[F[_]] extends LoggerFactory[F] { def fromSlf4j(logger: JLogger): F[SelfAwareStructuredLogger[F]] } -object Slf4jFactory extends LoggerFactoryCompanion { +object Slf4jFactory extends LoggerFactoryGenCompanion { def apply[F[_]: Slf4jFactory]: Slf4jFactory[F] = implicitly def getLoggerFromSlf4j[F[_]](logger: JLogger)(implicit From 18f05907f55bac2c3640ff4dca9b4464b501ff39 Mon Sep 17 00:00:00 2001 From: Erlend Hamnaberg Date: Wed, 6 Apr 2022 15:42:31 +0200 Subject: [PATCH 15/18] Fix formatting --- .../src/main/scala/org/typelevel/log4cats/LoggerFactory.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/shared/src/main/scala/org/typelevel/log4cats/LoggerFactory.scala b/core/shared/src/main/scala/org/typelevel/log4cats/LoggerFactory.scala index 2988c845..06667ac3 100644 --- a/core/shared/src/main/scala/org/typelevel/log4cats/LoggerFactory.scala +++ b/core/shared/src/main/scala/org/typelevel/log4cats/LoggerFactory.scala @@ -28,4 +28,4 @@ trait LoggerFactory[F[_]] extends LoggerFactoryGen[F] { object LoggerFactory extends LoggerFactoryGenCompanion { def apply[F[_]: LoggerFactory]: LoggerFactory[F] = implicitly -} \ No newline at end of file +} From dad7efd97265c6ad43e405d92ad2b9f87eecc511 Mon Sep 17 00:00:00 2001 From: "Ross A. Baker" Date: Sat, 4 Jun 2022 11:11:39 -0400 Subject: [PATCH 16/18] Bump base version to 1.7 --- build.sbt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.sbt b/build.sbt index 14db8df6..b00112b0 100644 --- a/build.sbt +++ b/build.sbt @@ -4,7 +4,7 @@ val Scala213 = "2.13.8" val Scala212 = "2.12.15" val Scala3 = "3.0.2" -ThisBuild / tlBaseVersion := "1.6" +ThisBuild / tlBaseVersion := "1.7" ThisBuild / crossScalaVersions := Seq(Scala213, Scala212, Scala3) ThisBuild / scalaVersion := Scala213 ThisBuild / startYear := Some(2018) From e81ec7999f0425f2ac8b5e662255c599dce787a1 Mon Sep 17 00:00:00 2001 From: "Ross A. Baker" Date: Sun, 5 Jun 2022 22:08:47 -0400 Subject: [PATCH 17/18] Update core/shared/src/main/scala/org/typelevel/log4cats/LoggerFactory.scala Co-authored-by: Daniel Esik --- .../src/main/scala/org/typelevel/log4cats/LoggerFactory.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/shared/src/main/scala/org/typelevel/log4cats/LoggerFactory.scala b/core/shared/src/main/scala/org/typelevel/log4cats/LoggerFactory.scala index 06667ac3..c71d61fb 100644 --- a/core/shared/src/main/scala/org/typelevel/log4cats/LoggerFactory.scala +++ b/core/shared/src/main/scala/org/typelevel/log4cats/LoggerFactory.scala @@ -20,7 +20,7 @@ import scala.annotation.implicitNotFound @implicitNotFound(""" Implicit not found for LoggerFactory[${F}]. -Information can be found here: https://log4cats.github.io/logging-capability.html +Learn about LoggerFactory at https://typelevel.org/log4cats/#logging-using-capabilities """) trait LoggerFactory[F[_]] extends LoggerFactoryGen[F] { type LoggerType = SelfAwareStructuredLogger[F] From ac8a327805ff65ef1462a73d91d96d7ab8fcb50d Mon Sep 17 00:00:00 2001 From: danicheg Date: Thu, 16 Jun 2022 19:36:22 +0400 Subject: [PATCH 18/18] Return unsafe methods of Slf4jLogger --- .../log4cats/slf4j/Slf4jLoggerCompat.scala | 5 +++-- .../typelevel/log4cats/slf4j/Slf4jLogger.scala | 16 ++++++++++++++++ 2 files changed, 19 insertions(+), 2 deletions(-) diff --git a/slf4j/src/main/scala-3/org/typelevel/log4cats/slf4j/Slf4jLoggerCompat.scala b/slf4j/src/main/scala-3/org/typelevel/log4cats/slf4j/Slf4jLoggerCompat.scala index 3ad71219..9f79cab0 100644 --- a/slf4j/src/main/scala-3/org/typelevel/log4cats/slf4j/Slf4jLoggerCompat.scala +++ b/slf4j/src/main/scala-3/org/typelevel/log4cats/slf4j/Slf4jLoggerCompat.scala @@ -25,9 +25,10 @@ import scala.annotation.nowarn trait Slf4jLoggerCompat { // for binary compability - private[slf4j] inline def create[F[_]](F: Sync[F]): F[SelfAwareStructuredLogger[F]] = + private[slf4j] inline def createMacro[F[_]](F: Sync[F]): F[SelfAwareStructuredLogger[F]] = ${ GetLoggerMacros.createImpl('F) } - private[slf4j] inline def getLogger[F[_]](using F: Sync[F]): SelfAwareStructuredLogger[F] = + + private[slf4j] inline def getLoggerMacro[F[_]](using F: Sync[F]): SelfAwareStructuredLogger[F] = ${ GetLoggerMacros.getLoggerImpl('F) } } diff --git a/slf4j/src/main/scala/org/typelevel/log4cats/slf4j/Slf4jLogger.scala b/slf4j/src/main/scala/org/typelevel/log4cats/slf4j/Slf4jLogger.scala index 3fb97803..7a01124a 100644 --- a/slf4j/src/main/scala/org/typelevel/log4cats/slf4j/Slf4jLogger.scala +++ b/slf4j/src/main/scala/org/typelevel/log4cats/slf4j/Slf4jLogger.scala @@ -26,15 +26,31 @@ object Slf4jLogger extends Slf4jLoggerCompat { def getLogger[F[_]](implicit f: Sync[F], name: LoggerName): SelfAwareStructuredLogger[F] = getLoggerFromName(name.value) + @deprecated("0.3.0", "Use getLogger instead") + def unsafeCreate[F[_]: Sync](implicit name: LoggerName): SelfAwareStructuredLogger[F] = + getLogger[F] + def getLoggerFromName[F[_]: Sync](name: String): SelfAwareStructuredLogger[F] = getLoggerFromSlf4j(org.slf4j.LoggerFactory.getLogger(name)) + @deprecated("0.3.0", "Use getLoggerFromName") + def unsafeFromName[F[_]: Sync](name: String): SelfAwareStructuredLogger[F] = + getLoggerFromName[F](name) + def getLoggerFromClass[F[_]: Sync](clazz: Class[_]): SelfAwareStructuredLogger[F] = getLoggerFromSlf4j[F](org.slf4j.LoggerFactory.getLogger(clazz)) + @deprecated("0.3.0", "Use getLoggerFromClass") + def unsafeFromClass[F[_]: Sync](clazz: Class[_]): SelfAwareStructuredLogger[F] = + getLoggerFromClass[F](clazz) + def getLoggerFromSlf4j[F[_]: Sync](logger: JLogger): SelfAwareStructuredLogger[F] = new Slf4jLoggerInternal.Slf4jLogger(logger) + @deprecated("0.3.0", "Use getLoggerFromSlf4J instead") + def unsafeFromSlf4j[F[_]: Sync](logger: JLogger): SelfAwareStructuredLogger[F] = + getLoggerFromSlf4j[F](logger) + def create[F[_]: Sync](implicit name: LoggerName): F[SelfAwareStructuredLogger[F]] = Sync[F].delay(getLoggerFromName(name.value))