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

org.zalando.hutmann.logging.Context.scala Maven / Gradle / Ivy

There is a newer version: 2.5.4
Show newest version
package org.zalando.hutmann.logging

import java.time.ZonedDateTime

import org.zalando.hutmann.authentication.{ AuthorizationProblem, NoAuthorization, User, UserRequest }
import org.zalando.hutmann.filters.FlowIdFilter.FlowIdHeader
import play.api.mvc.{ Request, RequestHeader }

import scala.language.implicitConversions

/** Holds context information about what should be logged.*/
sealed trait Context {
  val contextInitializationTime = ZonedDateTime.now()
  val extraInfo: Map[String, String]
  def updated(key: String, value: String): Context
}

/**
  * The default value when no context information is available -
  * in this case, context information logging is omitted. Must be
  * given explicitly to enforce thinking about what you want to
  * achieve, instead of forgetting to log flow ids and only see it
  * on the live system when it is too late.
  */
case object NoContextAvailable extends Context {
  override val extraInfo: Map[String, String] = Map.empty
  def updated(key: String, value: String): NoContextAvailable.type = this
}

/** Marks objects that have a flow id. Comes with an extractor to get the flow id if needed.*/
trait FlowIdAware {
  val flowId: Option[String]
}

object FlowIdAware {
  /**
    * Unapply method for objects that have a flow id. Can be used to extract flow ids without a hassle, simply do it like this:
    * {{{
    *   //request is given
    *   val context: Context = request
    *   val optFlowId = context match {
    *     case FlowIdAware(flowId) => Some(flowId)
    *     case _ => None
    *   }
    * }}}
    */
  def unapply(flowIdAware: FlowIdAware): Option[String] = flowIdAware.flowId
}

/**
  * Context information that should be logged.
  *
  * @param requestId     The play request id that is unique for a request.
  * @param flowId        The flow id that is used to identify a flow over system boundaries.
  * @param requestHeader The request headers the request has. The request body is not forwarded here since you should do that explicitly if you need it.
  * @param user          The user that issued the request (if any).
  */
case class RequestContext(
    requestId:              Long,
    override val flowId:    Option[String],
    requestHeader:          RequestHeader,
    user:                   Either[AuthorizationProblem, User],
    override val extraInfo: Map[String, String]                = Map.empty
) extends Context with FlowIdAware {
  override def updated(key: String, value: String): RequestContext = this.copy(extraInfo = extraInfo.updated(key, value))
}

object RequestId {
  /**
    * Unapply method for objects that have a request id. Can be used to extract request ids without a hassle, simply do it like this:
    * {{{
    *   //request is given
    *   val context: Context = request
    *   val optFlowId = context match {
    *     case RequestId(requestId) => Some(requestId)
    *     case _ => None
    *   }
    * }}}
    */
  def unapply(requestContext: RequestContext): Option[Long] = Some(requestContext.requestId)
}

case class JobContext(
    name:                   String,
    override val flowId:    Option[String],
    override val extraInfo: Map[String, String] = Map.empty
) extends Context with FlowIdAware {
  override def updated(key: String, value: String): JobContext = this.copy(extraInfo = extraInfo.updated(key, value))
}

object Context {
  /**
    * Implicit conversion to allow easy creation of {{{Context}}}. Usage:
    *
    * {{{
    * implicit val context: ContextInformation = request
    * }}}
    *
    * @param request The play request object that should be used to extract information.
    * @tparam A      The type of the body of the request.
    */
  implicit def request2loggingContext[A](request: UserRequest[A]): RequestContext = request.context

  /**
    * Implicit conversion to allow easy creation of {{{Context}}}. Usage:
    *
    * {{{
    * implicit val context: ContextInformation = request
    * }}}
    *
    * @param request The play request object that should be used to extract information.
    * @tparam A      The type of the body of the request.
    */
  implicit def request2loggingContext[A](request: Request[A]): RequestContext =
    RequestContext(requestId = request.id, flowId = request.headers.get(FlowIdHeader), requestHeader = request, user = Left(NoAuthorization))

  /**
    * Implicit conversion to allow easy creation of {{{Context}}}. Usage:
    *
    * {{{
    * implicit val context: ContextInformation = request
    * }}}
    *
    * @param request The play request object that should be used to extract information.
    * @tparam A      The type of the body of the request.
    */
  implicit def request2loggingContext[A](request: RequestHeader): RequestContext =
    RequestContext(requestId = request.id, flowId = request.headers.get(FlowIdHeader), requestHeader = request, user = Left(NoAuthorization))
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy