Metrics Reporting

Currently, mu provides two different ways to monitor gRPC services: Prometheus and Dropwizard (using the Prometheus extension). The usage is quite similar for both.

Monitor Server Calls

In order to monitor the RPC calls on the server side, it’s necessary to intercept them. We’ll see how to do this in the next code fragment:

import cats.effect.IO
import higherkindness.mu.rpc.server._
import higherkindness.mu.rpc.prometheus.shared.Configuration
import higherkindness.mu.rpc.prometheus.server.MonitoringServerInterceptor
import io.prometheus.client.CollectorRegistry
import service._

object InterceptingServerCalls extends CommonRuntime {

  import higherkindness.mu.rpc.interceptors.implicits._

  lazy val cr: CollectorRegistry = new CollectorRegistry()
  lazy val monitorInterceptor = MonitoringServerInterceptor(
    Configuration.defaultBasicMetrics.withCollectorRegistry(cr)
  )

  implicit val greeterServiceHandler: ServiceHandler[IO] = new ServiceHandler[IO]

  // The Greeter service is the service defined in the Core concepts section
  val grpcConfigs: IO[List[GrpcConfig]] = 
    Greeter.bindService[IO]
      .map(_.interceptWith(monitorInterceptor))
      .map(AddService)
      .map(List(_))

  val server: IO[GrpcServer[IO]] = grpcConfigs.flatMap(GrpcServer.default[IO](8080, _))

}

Monitor Client Calls

In this case, in order to intercept the client calls we need additional configuration settings (by using AddInterceptor):

import cats.effect.{IO, Resource}
import higherkindness.mu.rpc._
import higherkindness.mu.rpc.config._
import higherkindness.mu.rpc.channel._
import higherkindness.mu.rpc.config.channel._
import service._

import higherkindness.mu.rpc.prometheus.shared.Configuration
import higherkindness.mu.rpc.prometheus.client.MonitoringClientInterceptor

object InterceptingClientCalls extends CommonRuntime {

  val channelFor: ChannelFor =
    ConfigForAddress[IO]("rpc.host", "rpc.port").unsafeRunSync

  implicit val serviceClient: Resource[IO, Greeter[IO]] =
    Greeter.client[IO](
      channelFor = channelFor,
      channelConfigList = List(
        UsePlaintext(),
        AddInterceptor(
          MonitoringClientInterceptor(
            Configuration.defaultBasicMetrics
          )
        )
      )
    )
}

That is how we use Prometheus to monitor both gRPC ends.

Dropwizard Metrics

The usage the same as before, but in this case we need to put an instance of com.codahale.metrics.MetricRegistry in our code. Then using the Dropwizard integration that Prometheus already provides (DropwizardExports) we can associate it with the collector registry:

import com.codahale.metrics.MetricRegistry
import io.prometheus.client.dropwizard.DropwizardExports

val metrics: MetricRegistry      = new MetricRegistry
val configuration: Configuration = Configuration.defaultBasicMetrics
configuration.collectorRegistry.register(new DropwizardExports(metrics))