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

kadai.log.json.JsonLogging.scala Maven / Gradle / Ivy

The newest version!
package kadai
package log
package json

import io.circe.{ Encoder, Json }
import io.circe.syntax._

/**
 * Mixin if you want your class to be able to log structured objects in
 * JSON format. You will need an argonaut.EncodeJson instance in implicit
 * scope for the object you try and log.
 *
 * To get the instances, you need to also "import JsonLogging._"
 *
 * Note that you normally only need an implicit EncodeJson[A] for any type
 * you want to log in order to encode the JSON representation  that is logged.
 * If you do not have an EncodeJson for the message object, then it will fall back
 * to a String representation given by the Show[Foo] instance in scope.
 *
 * If you want fine-grained control of the output, and in particular want to
 * control the top level names that are produced, please create a custom implicit
 * JsonMessgae.Qualified[Foo] that turns your Foo into a List[JsonAssoc]. Care is
 * needed though about the names as any clashes can lead to bugs in some log
 * processing systems, such as https://github.com/elastic/elasticsearch/issues/12366
 *
 * See JsonLayout for details on how to configure log4j2 to support JSON output
 */
trait JsonLogging extends Logging

object JsonLogging extends JsonLoggingInstances

trait JsonLoggingInstances {
  implicit def QualifiedEncodeJsonLogWriter[A: JsonMessage.Qualified]: LogWriter[A] =
    new LogWriter[A] {
      def apply(a: => A) = JsonMessage(a, JsonMessage.Qualified[A].fields(a))
    }

  implicit val EncodeInvalid: Encoder[Invalid] =
    Encoder.instance {
      case Invalid.Err(t) => Json.obj("error" -> EncodeThrowable(t))
      case Invalid.Message(m) => Json.obj("error" -> m.asJson)
      case Invalid.Composite(i) => Json.obj("errors" -> i.list.toList.asJson)
      case Invalid.Zero => Json.obj()
    }

  implicit val EncodeThrowable: Encoder[Throwable] =
    Encoder.instance { t =>
      Json.obj(
        "message" -> Option(t.getMessage).asJson,
        "class" -> t.getClass.getName.asJson,
        "stacktrace" -> t.getStackTrace.toVector.asJson,
        "cause" -> Option(t.getCause).filter(_ != t).asJson
      )
    }

  implicit val EncodeStackTraceElement: Encoder[StackTraceElement] =
    Encoder[String].contramap { _.toString }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy