All Downloads are FREE. Search and download functionalities are using the official Maven repository.

slog4s.LogEncoder.scala Maven / Gradle / Ivy

The newest version!
package slog4s

import cats.syntax.contravariant._
import cats.{Contravariant, Show}
import slog4s.`export`.Exported

/** Typeclass that is able to encode any value of T into logging friendly
  * format. The type of logging format is determined by provided instance of
  * [[StructureBuilder]].
  * @tparam T
  *   type to be encoded
  */
trait LogEncoder[T] {

  /** Encode value of T into desired value of type O that represents structured
    * logging value.
    * @param value
    *   to be encoded
    * @param structureBuilder
    *   instance of [[StructureBuilder]] typeclass used for building resulting
    *   value.
    * @tparam O
    *   type of target structured logging format
    * @return
    *   value encoded into target structured logging format
    */
  def encode[O](value: T)(implicit structureBuilder: StructureBuilder[O]): O
}

object LogEncoder extends HighPriorityLogEncoderImplicits {
  def apply[T](implicit ev: LogEncoder[T]): LogEncoder[T] = ev

  implicit val logEncoderContravariant: Contravariant[LogEncoder] =
    new Contravariant[LogEncoder] {
      override def contramap[A, B](
          fa: LogEncoder[A]
      )(f: B => A): LogEncoder[B] = new LogEncoder[B] {
        override def encode[O](value: B)(implicit
            structureBuilder: StructureBuilder[O]
        ): O = fa.encode(f(value))
      }
    }

}

private[slog4s] trait HighPriorityLogEncoderImplicits
    extends LowPriorityLogEncoderImplicits {

  implicit lazy val longEncoder: LogEncoder[Long] =
    new LogEncoder[Long] {
      override def encode[O](value: Long)(implicit
          structureBuilder: StructureBuilder[O]
      ): O = structureBuilder.long(value)
    }

  implicit lazy val intEncoder: LogEncoder[Int] =
    longEncoder.contramap(_.toLong)
  implicit lazy val shortEncoder: LogEncoder[Short] =
    longEncoder.contramap(_.toLong)
  implicit lazy val byteEncoder: LogEncoder[Byte] =
    longEncoder.contramap(_.toLong)

  implicit lazy val booleanEncoder: LogEncoder[Boolean] = {
    new LogEncoder[Boolean] {
      override def encode[O](value: Boolean)(implicit
          structureBuilder: StructureBuilder[O]
      ): O = structureBuilder.boolean(value)
    }
  }

  implicit lazy val doubleEncoder: LogEncoder[Double] =
    new LogEncoder[Double] {
      override def encode[O](value: Double)(implicit
          structureBuilder: StructureBuilder[O]
      ): O = structureBuilder.double(value)
    }

  implicit lazy val floatEncoder: LogEncoder[Float] =
    doubleEncoder.contramap(_.toDouble)

  implicit lazy val stringEncoder: LogEncoder[String] =
    new LogEncoder[String] {
      override def encode[O](value: String)(implicit
          structureBuilder: StructureBuilder[O]
      ): O = structureBuilder.string(value)
    }

  implicit def iterableEncoder[T: LogEncoder, F[_]](implicit
      ev: F[T] <:< Iterable[T]
  ): LogEncoder[F[T]] =
    new LogEncoder[F[T]] {
      override def encode[O](
          value: F[T]
      )(implicit structureBuilder: StructureBuilder[O]): O = {
        structureBuilder.array(value.map(LogEncoder[T].encode[O]))
      }
    }

  implicit def optionEncoder[T: LogEncoder]: LogEncoder[Option[T]] =
    new LogEncoder[Option[T]] {
      override def encode[O](
          value: Option[T]
      )(implicit structureBuilder: StructureBuilder[O]): O = {
        structureBuilder.option(value.map(LogEncoder[T].encode(_)))
      }
    }

  implicit def tuple2Encoder[A, B](implicit
      ev1: LogEncoder[A],
      ev2: LogEncoder[B]
  ): LogEncoder[(A, B)] = new LogEncoder[(A, B)] {
    override def encode[O](value: (A, B))(implicit
        structureBuilder: StructureBuilder[O]
    ): O = {
      structureBuilder.array(List(ev1.encode(value._1), ev2.encode(value._2)))
    }
  }

  implicit def mapShowKeyEncoder[K: Show, V: LogEncoder]
      : LogEncoder[Map[K, V]] =
    new LogEncoder[Map[K, V]] {
      override def encode[O](
          value: Map[K, V]
      )(implicit structureBuilder: StructureBuilder[O]): O = {
        structureBuilder.map(
          value.map(tuple =>
            Show[K].show(tuple._1) -> LogEncoder[V]
              .encode(tuple._2)
          )
        )
      }
    }

  implicit def fromExported[T](implicit
      ev: Exported[LogEncoder[T]]
  ): LogEncoder[T] = ev.value
}

private[slog4s] trait LowPriorityLogEncoderImplicits {
  implicit def genericMapEncoder[K: LogEncoder, V: LogEncoder]
      : LogEncoder[Map[K, V]] = {
    new LogEncoder[Map[K, V]] {
      private[this] val tupleEncoder = LogEncoder[(K, V)]
      override def encode[O](value: Map[K, V])(implicit
          structureBuilder: StructureBuilder[O]
      ): O = {
        val tuples = value.map(tupleEncoder.encode(_))
        structureBuilder.array(tuples)
      }
    }
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy