diff --git a/modules/logging/api/src/main/scala/sharry/logging/LazyMap.scala b/modules/logging/api/src/main/scala/sharry/logging/LazyMap.scala new file mode 100644 index 00000000..f1940018 --- /dev/null +++ b/modules/logging/api/src/main/scala/sharry/logging/LazyMap.scala @@ -0,0 +1,40 @@ +package sharry.logging + +import sharry.logging.LazyMap.Val + +final class LazyMap[A, B]( + private val values: Map[A, Val[B]] +) { + lazy val toMap: Map[A, B] = values.view.mapValues(_.value).toMap + + def updated(key: A, value: => B): LazyMap[A, B] = + new LazyMap(values.updated(key, Val(value))) + + def get(key: A): Option[() => B] = + values.get(key).map(e => () => e.value) + + def ++(lm: LazyMap[A, B]): LazyMap[A, B] = + new LazyMap(values ++ lm.values) + + def addMap(m: Map[A, B]): LazyMap[A, B] = + this ++ LazyMap.fromMap(m) + + def toDeferred: Map[A, () => B] = + values.view.mapValues(e => () => e.value).toMap +} + +object LazyMap { + private[this] val emptyMap = new LazyMap[Any, Any](Map.empty) + + def empty[A, B]: LazyMap[A, B] = emptyMap.asInstanceOf[LazyMap[A, B]] + + def fromMap[A, B](m: Map[A, B]): LazyMap[A, B] = + new LazyMap(m.view.mapValues(a => Val(a)).toMap) + + final private class Val[B](v: => B) { + lazy val value = v + } + private object Val { + def apply[B](v: => B): Val[B] = new Val(v) + } +} diff --git a/modules/logging/api/src/main/scala/sharry/logging/LogEvent.scala b/modules/logging/api/src/main/scala/sharry/logging/LogEvent.scala index a0b573d0..f241169f 100644 --- a/modules/logging/api/src/main/scala/sharry/logging/LogEvent.scala +++ b/modules/logging/api/src/main/scala/sharry/logging/LogEvent.scala @@ -12,8 +12,8 @@ import sourcecode._ final case class LogEvent( level: Level, msg: () => String, - additional: List[() => LogEvent.AdditionalMsg], - data: Map[String, () => Json], + additional: LazyList[LogEvent.AdditionalMsg], + data: LazyMap[String, Json], pkg: Pkg, fileName: FileName, name: Name, @@ -24,21 +24,21 @@ final case class LogEvent( s"${level.name} ${name.value}/${fileName}:${line.value} - ${msg()}" def data[A: Encoder](key: String, value: => A): LogEvent = - copy(data = data.updated(key, () => Encoder[A].apply(value))) + copy(data = data.updated(key, Encoder[A].apply(value))) def addData(m: Map[String, Json]): LogEvent = - copy(data = data ++ m.view.mapValues(json => () => json).toMap) + copy(data = data.addMap(m)) def addMessage(msg: => String): LogEvent = - copy(additional = (() => Left(msg)) :: additional) + copy(additional = Left(msg) #:: additional) def addError(ex: Throwable): LogEvent = - copy(additional = (() => Right(ex)) :: additional) + copy(additional = Right(ex) #:: additional) def findErrors: List[Throwable] = - additional.map(a => a()).collect { case Right(ex) => + additional.collect { case Right(ex) => ex - } + }.toList } object LogEvent { @@ -50,5 +50,6 @@ object LogEvent { fileName: FileName, name: Name, line: Line - ): LogEvent = LogEvent(l, () => m, Nil, Map.empty, pkg, fileName, name, line) + ): LogEvent = + LogEvent(l, () => m, LazyList.empty, LazyMap.empty, pkg, fileName, name, line) } diff --git a/modules/logging/scribe/src/main/scala/sharry/logging/impl/Record.scala b/modules/logging/scribe/src/main/scala/sharry/logging/impl/Record.scala index ca60d693..f83631d0 100644 --- a/modules/logging/scribe/src/main/scala/sharry/logging/impl/Record.scala +++ b/modules/logging/scribe/src/main/scala/sharry/logging/impl/Record.scala @@ -12,7 +12,7 @@ import io.circe.syntax._ import io.circe.{Encoder, Json} import perfolation._ import scribe.LogRecord -import scribe.data.MDC +import scribe.mdc.MDC import scribe.message.Message // From: https://github.com/outr/scribe/blob/8e99521e1ee1f0c421629764dd96e4eb193d84bd/json/shared/src/main/scala/scribe/json/JsonWriter.scala diff --git a/modules/logging/scribe/src/main/scala/sharry/logging/impl/ScribeWrapper.scala b/modules/logging/scribe/src/main/scala/sharry/logging/impl/ScribeWrapper.scala index e063b9b5..a4b69677 100644 --- a/modules/logging/scribe/src/main/scala/sharry/logging/impl/ScribeWrapper.scala +++ b/modules/logging/scribe/src/main/scala/sharry/logging/impl/ScribeWrapper.scala @@ -12,7 +12,7 @@ import cats.effect.Sync import sharry.logging.{Level, LogEvent, Logger} import scribe.LoggerSupport -import scribe.data.MDC +import scribe.mdc.{MDC, MDCMap} import scribe.message.LoggableMessage private[logging] object ScribeWrapper { @@ -39,14 +39,18 @@ private[logging] object ScribeWrapper { case Level.Trace => scribe.Level.Trace } + private[this] def emptyMDC: MDC = + new MDCMap(None) + private[this] def convert(ev: LogEvent) = { val level = convertLevel(ev.level) - val additional: List[LoggableMessage] = ev.additional.map { x => - x() match { - case Right(ex) => LoggableMessage.throwable2Message(ex) - case Left(msg) => LoggableMessage.string2Message(msg) + val additional: List[LoggableMessage] = ev.additional + .map { + case Right(ex) => LoggableMessage.throwableList2Messages(List(ex)) + case Left(msg) => LoggableMessage.stringList2Messages(List(msg)) } - } + .toList + .flatten LoggerSupport( level, ev.msg() :: additional, @@ -54,8 +58,8 @@ private[logging] object ScribeWrapper { ev.fileName, ev.name, ev.line, - MDC.instance + emptyMDC ) - .copy(data = ev.data) + .copy(data = ev.data.toDeferred) } } diff --git a/project/Dependencies.scala b/project/Dependencies.scala index cc4800e5..491ca4b5 100644 --- a/project/Dependencies.scala +++ b/project/Dependencies.scala @@ -21,7 +21,7 @@ object Dependencies { val OrganizeImportsVersion = "0.6.0" val PostgresVersion = "42.7.1" val PureConfigVersion = "0.17.4" - val ScribeVersion = "3.11.9" + val ScribeVersion = "3.13.0" val SourcecodeVersion = "0.3.1" val SwaggerVersion = "5.10.3" val TikaVersion = "2.9.1"