Skip to content

Instantly share code, notes, and snippets.

@rhyskeepence
Created August 14, 2018 16:45
Show Gist options
  • Save rhyskeepence/804e0f3d418897463f6636f6a6f05eba to your computer and use it in GitHub Desktop.
Save rhyskeepence/804e0f3d418897463f6636f6a6f05eba to your computer and use it in GitHub Desktop.
Demonstrate tracing at the system boundaries
import cats.data.{Kleisli, ReaderT}
import cats.effect.IO
import org.http4s.client.{Client, DisposableResponse}
import org.http4s.dsl.Http4sDsl
import org.http4s.{HttpService, Request}
class Something(client: Client[IO]) extends Http4sDsl[IO] {
private val service =
new ServiceThatKnowsNothingAboutTracing(new TracingAwareHttpClient(client))
val endpoints: HttpService[IO] = HttpService[IO] {
case GET -> Root / "fetch" =>
service.fetchSomething
.apply(RequestContext("1234"))
.flatMap(response => Ok(response))
}
}
class ServiceThatKnowsNothingAboutTracing[F[_]](client: HttpClient[F]) {
def fetchSomething: F[String] =
client(_.expect[String]("http://localhost"))
}
trait HttpClient[F[_]] {
def apply[A](f: Client[IO] => IO[A]): F[A]
}
class TracingAwareHttpClient(underlying: Client[IO]) extends HttpClient[http.RequestIO] {
def apply[A](f: Client[IO] => IO[A]): http.RequestIO[A] =
Kleisli { context: RequestContext => f(underlying.copy(open = log(context, underlying.open)))}
def log(context: RequestContext, delegate: Kleisli[IO, Request[IO], DisposableResponse[IO]]): Kleisli[IO, Request[IO], DisposableResponse[IO]] =
Kleisli ({request: Request[IO] =>
for {
_ <- putStrLn(s"${context.id}: $request")
response <- delegate.apply(request)
_ <- putStrLn(s"${context.id}: $response")
} yield response
})
def putStrLn(s: String): IO[Unit] = IO(println(s))
}
object http {
type RequestIO[A] = ReaderT[IO, RequestContext, A]
}
case class RequestContext(id: String)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment