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

sttp.client4.logging.LoggingWithResponseBodyBackend.scala Maven / Gradle / Ivy

The newest version!
package sttp.client4.logging

import java.util.concurrent.TimeUnit
import sttp.client4._
import sttp.monad.syntax._

import scala.concurrent.duration.Duration
import sttp.capabilities.Effect
import sttp.client4.wrappers.DelegateBackend
import sttp.shared.Identity

abstract class LoggingWithResponseBodyBackend[F[_], P](
    delegate: GenericBackend[F, P],
    log: Log[F],
    includeTiming: Boolean
) extends DelegateBackend[F, P](delegate) {

  private def now(): Long = System.currentTimeMillis()
  private def elapsed(from: Option[Long]): Option[Duration] = from.map(f => Duration(now() - f, TimeUnit.MILLISECONDS))

  override def send[T](request: GenericRequest[T, P with Effect[F]]): F[Response[T]] =
    log.beforeRequestSend(request).flatMap { _ =>
      val start = if (includeTiming) Some(now()) else None
      def sendAndLog(request: GenericRequest[(T, Option[String]), P with Effect[F]]): F[Response[T]] =
        for {
          r <- delegate.send(request)
          _ <- log.response(request, r, r.body._2, elapsed(start))
        } yield r.copy(body = r.body._1)
      val response = request match {
        case request: Request[T] =>
          sendAndLog(request.response(asBothOption(request.response, asStringAlways)))
        case request: StreamRequest[T, P with Effect[F]] =>
          sendAndLog(request.response(asBothOption(request.response, asStringAlways)))
        case request =>
          for {
            r <- delegate.send(request)
            _ <- log.response(request, r, None, elapsed(start))
          } yield r
      }
      response.handleError { case e: Exception =>
        log
          .requestException(request, elapsed(start), e)
          .flatMap(_ => monad.error(e))
      }
    }
}

object LoggingWithResponseBodyBackend {
  def apply(backend: SyncBackend, log: Log[Identity], includeTiming: Boolean): SyncBackend =
    new LoggingWithResponseBodyBackend(backend, log, includeTiming) with SyncBackend {}

  def apply[F[_]](backend: Backend[F], log: Log[F], includeTiming: Boolean): Backend[F] =
    new LoggingWithResponseBodyBackend(backend, log, includeTiming) with Backend[F] {}

  def apply[F[_]](backend: WebSocketBackend[F], log: Log[F], includeTiming: Boolean): WebSocketBackend[F] =
    new LoggingWithResponseBodyBackend(backend, log, includeTiming) with WebSocketBackend[F] {}

  def apply(backend: WebSocketSyncBackend, log: Log[Identity], includeTiming: Boolean): WebSocketSyncBackend =
    new LoggingWithResponseBodyBackend(backend, log, includeTiming) with WebSocketSyncBackend {}

  def apply[F[_], S](backend: StreamBackend[F, S], log: Log[F], includeTiming: Boolean): StreamBackend[F, S] =
    new LoggingWithResponseBodyBackend(backend, log, includeTiming) with StreamBackend[F, S] {}

  def apply[F[_], S](
      backend: WebSocketStreamBackend[F, S],
      log: Log[F],
      includeTiming: Boolean
  ): WebSocketStreamBackend[F, S] =
    new LoggingWithResponseBodyBackend(backend, log, includeTiming) with WebSocketStreamBackend[F, S] {}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy