From 2cbf36bbf3ccb7630a94ec16e2ee3ad5de67bf59 Mon Sep 17 00:00:00 2001 From: Ivan Malyshev Date: Mon, 14 Nov 2022 18:16:45 +0300 Subject: [PATCH] introduce ComposedLoggedValue --- .../main/scala/tofu/logging/LoggedValue.scala | 7 +++++++ .../tofu/logging/impl/ComposedLoggedValue.scala | 16 ++++++++++++++++ 2 files changed, 23 insertions(+) create mode 100644 modules/logging/structured/src/main/scala/tofu/logging/impl/ComposedLoggedValue.scala diff --git a/modules/logging/structured/src/main/scala/tofu/logging/LoggedValue.scala b/modules/logging/structured/src/main/scala/tofu/logging/LoggedValue.scala index 93d1e2081..568fea62f 100644 --- a/modules/logging/structured/src/main/scala/tofu/logging/LoggedValue.scala +++ b/modules/logging/structured/src/main/scala/tofu/logging/LoggedValue.scala @@ -1,5 +1,8 @@ package tofu.logging +import cats.kernel.Semigroup +import tofu.logging.impl.ComposedLoggedValue + import scala.{specialized => sp} trait LoggedValue { @@ -30,6 +33,10 @@ object LoggedValue { implicit def loggableToLoggedValue[A](x: A)(implicit loggable: Loggable[A]): LoggedValue = loggable.loggedValue(x) def error(cause: Throwable): LoggedThrowable = new LoggedThrowable(cause) + + implicit val loggedValueSemigroup: Semigroup[LoggedValue] = Semigroup.instance { (a, b) => + new ComposedLoggedValue(a :: b :: Nil) + } } final class LoggedThrowable(cause: Throwable) extends Throwable(cause.getMessage, cause) with LoggedValue { diff --git a/modules/logging/structured/src/main/scala/tofu/logging/impl/ComposedLoggedValue.scala b/modules/logging/structured/src/main/scala/tofu/logging/impl/ComposedLoggedValue.scala new file mode 100644 index 000000000..9ae332ed6 --- /dev/null +++ b/modules/logging/structured/src/main/scala/tofu/logging/impl/ComposedLoggedValue.scala @@ -0,0 +1,16 @@ +package tofu.logging.impl + +import tofu.logging.{LogRenderer, LoggedValue} + +/** This is supposed to be used to log several `LoggedValue` as if they were passed as arguments to the logging method. + * E.g. to provide single `LoggedValue` into `ContextMarker`. Be careful: the resulting structured log may contain the + * same fields. + */ +class ComposedLoggedValue(values: Iterable[LoggedValue]) extends LoggedValue { + override def toString: String = values.map(_.toString).mkString(", ") + + override def logFields[I, V, @specialized R, @specialized M](input: I)(implicit r: LogRenderer[I, V, R, M]): R = + values.foldLeft(r.noop(input)) { (acc, value) => + r.combine(acc, value.logFields(input)) + } +}