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

io.janstenpickle.trace4cats.http4s.server.Http4sResourceKleislis.scala Maven / Gradle / Ivy

package io.janstenpickle.trace4cats.http4s.server

import cats.data.Kleisli
import cats.effect.kernel.Resource
import cats.{Applicative, Monad}
import io.janstenpickle.trace4cats.http4s.common.{
  Http4sHeaders,
  Http4sRequestFilter,
  Http4sSpanNamer,
  Http4sStatusMapping,
  Request_
}
import io.janstenpickle.trace4cats.inject.{ResourceKleisli, SpanParams}
import io.janstenpickle.trace4cats.model.SpanKind
import io.janstenpickle.trace4cats.{ErrorHandler, HandledError, Span}
import org.http4s.{Headers, HttpVersion, MessageFailure}
import org.typelevel.ci.CIString

object Http4sResourceKleislis {
  private val messageFailureHandler: ErrorHandler = { case e: MessageFailure =>
    HandledError.Status(Http4sStatusMapping.toSpanStatus(e.toHttpResponse(HttpVersion.`HTTP/1.0`).status))
  }

  def fromHeadersContext[F[_]: Monad, Ctx](
    makeContext: (Request_, Span[F]) => F[Ctx],
    spanNamer: Http4sSpanNamer = Http4sSpanNamer.methodWithPath,
    requestFilter: Http4sRequestFilter = Http4sRequestFilter.allowAll,
    dropHeadersWhen: CIString => Boolean = Headers.SensitiveHeaders.contains,
    errorHandler: ErrorHandler = ErrorHandler.empty,
  )(k: ResourceKleisli[F, SpanParams, Span[F]]): ResourceKleisli[F, Request_, Ctx] =
    fromHeaders[F](spanNamer, requestFilter, dropHeadersWhen, errorHandler)(k).tapWithF { (req, span) =>
      Resource.eval(makeContext(req, span))
    }

  def fromHeaders[F[_]: Applicative](
    spanNamer: Http4sSpanNamer = Http4sSpanNamer.methodWithPath,
    requestFilter: Http4sRequestFilter = Http4sRequestFilter.allowAll,
    dropHeadersWhen: CIString => Boolean = Headers.SensitiveHeaders.contains,
    errorHandler: ErrorHandler = ErrorHandler.empty,
  )(k: ResourceKleisli[F, SpanParams, Span[F]]): ResourceKleisli[F, Request_, Span[F]] =
    Kleisli { req =>
      val filter = requestFilter.lift(req).getOrElse(true)
      lazy val headers = Http4sHeaders.converter.from(req.headers)
      val spanResource =
        if (filter) k.run((spanNamer(req), SpanKind.Server, headers, errorHandler.orElse(messageFailureHandler)))
        else Span.noop[F]

      spanResource.evalTap(_.putAll(Http4sHeaders.requestFields(req, dropHeadersWhen): _*))
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy