scalaprometheusscala-catscats-effecthttp4s

How to integrate Prometheus Metrics Middleware with http4s DSL service


To analyze the performance issues with our ember-server, Trying to get the server metrics on prometheus using the document mentioned here: https://http4s.org/v0.23/middleware/

build.sbt

      "org.http4s"            %% "http4s-ember-server"       % "0.23.1",
      "org.http4s"            %% "http4s-blaze-client"       % "0.23.1",
      "org.http4s"            %% "http4s-dsl"                % "0.23.1",
      "org.http4s"            %% "http4s-prometheus-metrics" % "0.23.1"

Sample code:

import cats.effect._
import org.http4s.metrics.prometheus.Prometheus
import io.prometheus.client.CollectorRegistry
import org.http4s.server.middleware.Metrics

// build router
val testRoute: Resource[IO, HttpRoutes[IO]] = Prometheus
    .metricsOps[IO](registry, "server")
    .map(ops =>
         Metrics[IO](ops)( {
            val dsl = new Http4sDsl[IO] {}
            import dsl._
            HttpRoutes.of[IO] { 
                case req @ POST -> Root / "test" => 
                  OK("test Ok!")
                case _: Exception =>
                  InternalServerError()
             }
           )
        )
     )

// build server with the router
EmberServerBuilder
  .default[IO]
  .withHost(Host.fromString("0.0.0.0").get)
  .withPort(Port.fromInt(8080).get)
  .withHttpApp(testRoute.orNotFound)
  .build

  1. Getting compilation error at .withHttpApp(testRoute.orNotFound) which is expected but not sure of the solution. This is a working example without Prometheus and Metrics wrapping.
  2. Definitely this is a compatibility issue but not sure how to wrap the middleware (which is not supposed to change the return type from HttpRoutes[IO] to Resource[IO, HttpRoutes[IO]] that is happening while wrapping the test Route.

I'm newbie to the functional way of programming (and so to the Scala, Cats lib and http4s) and this all generics seems to be too much confusing.


Solution

  • try:

    // build server with the router
    testRoute.flatMap { route =>
      EmberServerBuilder
        .default[IO]
        .withHost(Host.fromString("0.0.0.0").get)
        .withPort(Port.fromInt(8080).get)
        .withHttpApp(route.orNotFound)
        .build
    }
    

    You need to compose the Resource[IO, HttpRoutes[IO]] from prometheus with the Resource[IO, Server] from http4s.