io.prometheus.client.CollectorRegistry Scala Examples

The following examples show how to use io.prometheus.client.CollectorRegistry. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example.
Example 1
Source File: PrometheusController.scala    From play-prometheus-filters   with MIT License 5 votes vote down vote up
package com.github.stijndehaes.playprometheusfilters.controllers

import akka.util.ByteString
import com.github.stijndehaes.playprometheusfilters.utils.WriterAdapter
import javax.inject._
import play.api.mvc._
import io.prometheus.client.CollectorRegistry
import io.prometheus.client.exporter.common.TextFormat
import org.slf4j.LoggerFactory
import play.api.http.HttpEntity


class PrometheusController @Inject()(registry: CollectorRegistry, cc: ControllerComponents) extends AbstractController(cc) {

  private val logger = LoggerFactory.getLogger(classOf[PrometheusController])

  def getMetrics = Action {
    logger.trace("Metrics call received")
    val samples = new StringBuilder()
    val writer = new WriterAdapter(samples)
    TextFormat.write004(writer, registry.metricFamilySamples())
    writer.close()

    Result(
      header = ResponseHeader(200, Map.empty),
      body = HttpEntity.Strict(ByteString(samples.toString), Some(TextFormat.CONTENT_TYPE_004))
    )
  }

} 
Example 2
Source File: PrometheusMetricsReporterApiSpec.scala    From kafka4s   with Apache License 2.0 5 votes vote down vote up
package com.banno.kafka.metrics.prometheus

import scala.collection.compat._
import cats.implicits._
import cats.effect.IO
import com.banno.kafka._
import com.banno.kafka.producer._
import com.banno.kafka.consumer._
import org.apache.kafka.clients.producer.ProducerRecord
import org.apache.kafka.common.TopicPartition
import io.prometheus.client.CollectorRegistry
import org.scalatest.flatspec.AnyFlatSpec
import org.scalatest.matchers.should.Matchers

import scala.jdk.CollectionConverters._
import scala.concurrent.ExecutionContext
import scala.concurrent.duration._

class PrometheusMetricsReporterApiSpec extends AnyFlatSpec with Matchers with InMemoryKafka {
  implicit val defaultContextShift = IO.contextShift(ExecutionContext.global)
  implicit val defaultConcurrent = IO.ioConcurrentEffect(defaultContextShift)
  implicit val defaultTimer = IO.timer(ExecutionContext.global)

  //when kafka clients change their metrics, this test will help identify the changes we need to make
  "Prometheus reporter" should "register Prometheus collectors for all known Kafka metrics" in {
    val topic = createTopic(2)
    val records =
      List(new ProducerRecord(topic, 0, "a", "a"), new ProducerRecord(topic, 1, "b", "b"))
    ProducerApi
      .resource[IO, String, String](
        BootstrapServers(bootstrapServer),
        MetricReporters[ProducerPrometheusReporter]
      )
      .use(
        p =>
          ConsumerApi
            .resource[IO, String, String](
              BootstrapServers(bootstrapServer),
              ClientId("c1"),
              MetricReporters[ConsumerPrometheusReporter]
            )
            .use(
              c1 =>
                ConsumerApi
                  .resource[IO, String, String](
                    BootstrapServers(bootstrapServer),
                    ClientId("c2"),
                    MetricReporters[ConsumerPrometheusReporter]
                  )
                  .use(
                    c2 =>
                      for {
                        _ <- p.sendSyncBatch(records)

                        _ <- c1.assign(topic, Map.empty[TopicPartition, Long])
                        _ <- c1.poll(1 second)
                        _ <- c1.poll(1 second)

                        _ <- c2.assign(topic, Map.empty[TopicPartition, Long])
                        _ <- c2.poll(1 second)
                        _ <- c2.poll(1 second)

                        _ <- IO.sleep(PrometheusMetricsReporterApi.defaultUpdatePeriod + (1 second))
                        _ <- p.close
                        _ <- c1.close
                        _ <- c2.close
                      } yield {
                        val registry = CollectorRegistry.defaultRegistry
                        registry.metricFamilySamples.asScala
                          .count(_.name.startsWith("kafka_producer")) should ===(56)
                        registry.metricFamilySamples.asScala
                          .find(_.name == "kafka_producer_record_send_total")
                          .map(_.samples.asScala.map(_.value)) should ===(Some(List(2)))

                        registry.metricFamilySamples.asScala
                          .count(_.name.startsWith("kafka_consumer")) should ===(50)
                        registry.metricFamilySamples.asScala
                          .find(_.name == "kafka_consumer_records_consumed_total")
                          .map(_.samples.asScala.map(_.value)) should ===(Some(List(2, 2)))
                        registry.metricFamilySamples.asScala
                          .find(_.name == "kafka_consumer_topic_records_consumed_total")
                          .map(_.samples.asScala.map(_.value)) should ===(Some(List(2, 2)))
                      }
                  )
            )
      )
      .unsafeRunSync()
  }

} 
Example 3
Source File: MetricFamilySamplesEntity.scala    From prometheus-akka-http   with MIT License 5 votes vote down vote up
package com.lonelyplanet.prometheus.api

import java.io.{StringWriter, Writer}
import java.util

import akka.http.scaladsl.marshalling.{ToEntityMarshaller, Marshaller}
import akka.http.scaladsl.model._
import io.prometheus.client.Collector.MetricFamilySamples
import io.prometheus.client.CollectorRegistry
import io.prometheus.client.exporter.common.TextFormat

case class MetricFamilySamplesEntity(samples: util.Enumeration[MetricFamilySamples])

object MetricFamilySamplesEntity {
  private val mediaTypeParams = Map("version" -> "0.0.4")
  private val mediaType = MediaType.customWithFixedCharset("text", "plain", HttpCharsets.`UTF-8`, params = mediaTypeParams)

  def fromRegistry(collectorRegistry: CollectorRegistry): MetricFamilySamplesEntity = {
    MetricFamilySamplesEntity(collectorRegistry.metricFamilySamples())
  }

  def toPrometheusTextFormat(e: MetricFamilySamplesEntity): String = {
    val writer: Writer = new StringWriter()
    TextFormat.write004(writer, e.samples)

    writer.toString
  }

  implicit val metricsFamilySamplesMarshaller: ToEntityMarshaller[MetricFamilySamplesEntity] = {
    Marshaller.withFixedContentType(mediaType) { s =>
      HttpEntity(mediaType, toPrometheusTextFormat(s))
    }
  }

} 
Example 4
Source File: MetricsEndpoint.scala    From prometheus-akka-http   with MIT License 5 votes vote down vote up
package com.lonelyplanet.prometheus.api

import akka.http.scaladsl.server.Directives._
import io.prometheus.client.CollectorRegistry

class MetricsEndpoint(registry: CollectorRegistry) {

  val routes = {
    get {
      path("metrics") {
        complete {
          MetricFamilySamplesEntity.fromRegistry(registry)
        }
      }
    }
  }

} 
Example 5
Source File: ResponseTimeRecorder.scala    From prometheus-akka-http   with MIT License 5 votes vote down vote up
package com.lonelyplanet.prometheus

import io.prometheus.client.{CollectorRegistry, Histogram}

import scala.concurrent.duration
import scala.concurrent.duration.{FiniteDuration, TimeUnit}

trait ResponseTimeRecorder {
  def recordResponseTime(endpoint: String, responseTime: FiniteDuration): Unit
}


class PrometheusResponseTimeRecorder(
    metricName: String,
    metricHelp: String,
    buckets: List[Double],
    endpointLabelName: String,
    registry: CollectorRegistry,
    timeUnit: TimeUnit) extends ResponseTimeRecorder {

  private val responseTimes = buildHistogram.register(registry)

  override def recordResponseTime(endpoint: String, responseTime: FiniteDuration): Unit = {
    responseTimes.labels(endpoint).observe(responseTime.toUnit(timeUnit))
  }

  private def buildHistogram = Histogram
    .build()
    .name(metricName)
    .help(metricHelp)
    .labelNames(endpointLabelName)
    .buckets(buckets: _*)

}

object PrometheusResponseTimeRecorder {
  val DefaultBuckets = List(.01, .025, .05, .075, .10, .125, .15, .175, .20, .225, .25, .275,
    .30, .325, .35, .40, .45, .50, .60, .70, 1.0, 2.0, 3.0, 5.0, 10.0)
  val DefaultMetricName = "request_processing_seconds"
  val DefaultMetricHelp = "Time spent processing request"
  val DefaultEndpointLabel = "endpoint"
  val DefaultTimeUnit = duration.SECONDS

  lazy val DefaultRegistry = CollectorRegistry.defaultRegistry

  lazy val Default = {
    new PrometheusResponseTimeRecorder(
      DefaultMetricName,
      DefaultMetricHelp,
      DefaultBuckets,
      DefaultEndpointLabel,
      DefaultRegistry,
      DefaultTimeUnit)
  }
}

class NoOpResponseTimeRecorder extends ResponseTimeRecorder {
  def recordResponseTime(endpoint: String, responseTime: FiniteDuration): Unit = ()
} 
Example 6
Source File: EventObserver.scala    From prometheus-akka-http   with MIT License 5 votes vote down vote up
package com.lonelyplanet.prometheus

import io.prometheus.client.{Counter, CollectorRegistry}

trait EventObserver {
  def observe(eventName: String, eventDetails: String): Unit
}


class PrometheusEventObserver(
    metricName: String,
    metricHelp: String,
    eventLabelName: String,
    eventDetailsLabelName: String,
    registry: CollectorRegistry) extends EventObserver {

  val counter = buildCounter.register(registry)

  private def buildCounter = Counter
    .build()
    .name(metricName)
    .help(metricHelp)
    .labelNames(eventLabelName, eventDetailsLabelName)

  override def observe(eventName: String, eventDetails: String): Unit = {
    counter.labels(eventName, eventDetails).inc()
  }
}

object PrometheusEventObserver {
  private val SuccessfulOperationMetricName = "operation_success"
  private val SuccessfulOperationMetricHelp = "The number of observed successful operations"
  private val FailedOperationMetricName = "operation_failure"
  private val FailedOperationMetricHelp = "The number of observed failed operations"
  private val DefaultEventLabelName = "event"
  private val DefaultEventDetailsLabelName = "details"
  private val DefaultRegistry = CollectorRegistry.defaultRegistry

  // Common event observers used in scala projects in Open Planet micro-services
  lazy val SuccessfulOperations = withDefaultsFromMetricNameAndHelp(SuccessfulOperationMetricName, SuccessfulOperationMetricHelp)
  lazy val FailedOperations = withDefaultsFromMetricNameAndHelp(FailedOperationMetricName, FailedOperationMetricHelp)

  private def withDefaultsFromMetricNameAndHelp(metricName: String, metricHelp: String) = {
    new PrometheusEventObserver(
      metricName,
      metricHelp,
      DefaultEventLabelName,
      DefaultEventDetailsLabelName,
      DefaultRegistry)
  }
}

class NoOpEventObserver extends EventObserver {
  def observe(eventName: String, eventDetails: String): Unit = ()
} 
Example 7
Source File: MetricsEndpointSpec.scala    From prometheus-akka-http   with MIT License 5 votes vote down vote up
package com.lonelyplanet.prometheus.api

import java.io.StringWriter

import akka.http.scaladsl.model.HttpCharsets
import akka.http.scaladsl.testkit.ScalatestRouteTest
import com.lonelyplanet.prometheus.Utils._
import io.prometheus.client.exporter.common.TextFormat
import io.prometheus.client.{CollectorRegistry, Histogram}
import org.scalatest.flatspec.AnyFlatSpec
import org.scalatest.matchers.should.Matchers

import scala.util.Random

class MetricsEndpointSpec extends AnyFlatSpec with Matchers with ScalatestRouteTest {

  "Metrics endpoint" should "return the correct media type and charset" in {
    val api = createEndpoint(CollectorRegistry.defaultRegistry)
    Get("/metrics") ~> api.routes ~> check {
      mediaType.subType shouldBe "plain"
      mediaType.isText shouldBe true
      mediaType.params shouldBe Map("version" -> "0.0.4")
      charset shouldBe HttpCharsets.`UTF-8`
    }
  }

  it should "return serialized metrics in the prometheus text format" in {
    val registry = new CollectorRegistry()
    val api = createEndpoint(registry)
    val hist = Histogram.build().name(RandomTestName).help(RandomTestHelp).linearBuckets(0, 1, 10).register(registry)

    hist.observe(Math.abs(Random.nextDouble()))

    Get("/metrics") ~> api.routes ~> check {
      val resp = responseAs[String]
      val writer = new StringWriter()
      TextFormat.write004(writer, registry.metricFamilySamples())

      resp shouldBe writer.toString
    }
  }

  private val RandomTestName = generateRandomStringOfLength(16)
  private val RandomTestHelp = generateRandomStringOfLength(16)

  private def createEndpoint(collectorRegistry: CollectorRegistry) = {
    new MetricsEndpoint(collectorRegistry)
  }

} 
Example 8
Source File: PrometheusEventObserverSpec.scala    From prometheus-akka-http   with MIT License 5 votes vote down vote up
package com.lonelyplanet.prometheus

import com.lonelyplanet.prometheus.Utils._
import io.prometheus.client.CollectorRegistry
import org.scalatest.flatspec.AnyFlatSpec
import org.scalatest.matchers.should.Matchers

class PrometheusEventObserverSpec extends AnyFlatSpec with Matchers {

  "PrometheusEventObserver" should "record observed events in a counter" in {
    val registry = new CollectorRegistry()
    val randomMetricName = generateRandomString
    val randomMetricHelp = generateRandomString
    val randomEventLabelName = generateRandomString
    val randomEventDetailsLabelName = generateRandomString

    val randomEventName = generateRandomString
    val randomEventDetails = generateRandomString

    val eventObserver = new PrometheusEventObserver(
      randomMetricName,
      randomMetricHelp,
      randomEventLabelName,
      randomEventDetailsLabelName,
      registry)

    def getCounterValue = {
      registry.getSampleValue(
        randomMetricName,
        Array(randomEventLabelName, randomEventDetailsLabelName),
        Array(randomEventName, randomEventDetails))
    }

    getCounterValue shouldBe null

    eventObserver.observe(randomEventName, randomEventDetails)

    getCounterValue should not be null
    getCounterValue.intValue() shouldBe 1

  }
} 
Example 9
Source File: PrometheusResponseTimeRecorderSpec.scala    From prometheus-akka-http   with MIT License 5 votes vote down vote up
package com.lonelyplanet.prometheus

import io.prometheus.client.{Collector, CollectorRegistry}
import org.scalamock.scalatest.MockFactory
import com.lonelyplanet.prometheus.Utils._
import org.scalatest.flatspec.AnyFlatSpec
import org.scalatest.matchers.should.Matchers

import scala.concurrent.duration
import scala.concurrent.duration.FiniteDuration
import scala.util.Random

class PrometheusResponseTimeRecorderSpec extends AnyFlatSpec with Matchers with MockFactory {

  "PrometheusLatencyRecorder" should "register a histogram and record request latencies" in {
    val registry = new CollectorRegistry()
    val randomMetricName = generateRandomString
    val randomMetricHelp = generateRandomString
    val randomLabelName = generateRandomString
    val randomEndpointName = generateRandomString
    val randomLatency = Math.abs(Random.nextInt(10000))

    // our random value will end up in the second bucket
    val buckets = List((randomLatency - 1).toDouble, (randomLatency + 1).toDouble)

    val recorder = new PrometheusResponseTimeRecorder(
      randomMetricName,
      randomMetricHelp,
      buckets,
      randomLabelName,
      registry,
      duration.MILLISECONDS)

    recorder.recordResponseTime(randomEndpointName, FiniteDuration(randomLatency, duration.MILLISECONDS))

    val first = getBucketValue(registry, randomMetricName, List(randomLabelName), List(randomEndpointName), buckets.head)
    val second = getBucketValue(registry, randomMetricName, List(randomLabelName), List(randomEndpointName), buckets.last)
    val positiveInf = getBucketValue(registry, randomMetricName, List(randomLabelName), List(randomEndpointName), Double.PositiveInfinity)

    first shouldBe 0
    second shouldBe 1
    positiveInf shouldBe 1
  }

  private def getBucketValue(registry: CollectorRegistry, metricName: String, labelNames: List[String], labelValues: List[String], bucket: Double) = {
    val name = metricName + "_bucket"

    // 'le' should be the first label in the list
    val allLabelNames = (Array("le") ++ labelNames).reverse
    val allLabelValues = (Array(Collector.doubleToGoString(bucket)) ++ labelValues).reverse
    registry.getSampleValue(name, allLabelNames, allLabelValues).intValue()
  }

} 
Example 10
Source File: PrometheusModule.scala    From play-prometheus-filters   with MIT License 5 votes vote down vote up
package com.github.stijndehaes.playprometheusfilters

import io.prometheus.client.CollectorRegistry
import io.prometheus.client.hotspot._
import org.slf4j.LoggerFactory
import play.api.inject.{Binding, Module}
import play.api.{Configuration, Environment}

object PrometheusModule {
  val defaultExportsKey = "play-prometheus-filters.register-default-hotspot-collectors"
}

class PrometheusModule extends Module {
  import PrometheusModule._

  private val logger = LoggerFactory.getLogger(classOf[PrometheusModule])

  override def bindings(environment: Environment, configuration: Configuration): Seq[Binding[_]] = {
    CollectorRegistry.defaultRegistry.clear()

    configuration.getOptional[Boolean](defaultExportsKey).foreach { enabled =>
      if (enabled) {
        logger.info("Default exports are enabled")
        DefaultExports.initialize()
        logger.info("Default exports registered")
      } else {
        logger.info("Default exports are disabled")
      }
    }

    Seq(
      bind[CollectorRegistry].to(CollectorRegistry.defaultRegistry)
    )
  }
} 
Example 11
Source File: PrometheusRoutingSpec.scala    From vinyldns   with Apache License 2.0 5 votes vote down vote up
package vinyldns.api.route

import akka.http.scaladsl.model.{HttpProtocol, HttpResponse, StatusCodes}
import akka.http.scaladsl.testkit.ScalatestRouteTest
import io.prometheus.client.CollectorRegistry
import io.prometheus.client.dropwizard.DropwizardExports
import org.scalatestplus.mockito.MockitoSugar
import org.scalatest.matchers.should.Matchers
import org.scalatest.wordspec.AnyWordSpec
import org.scalatest.BeforeAndAfterEach
import vinyldns.core.VinylDNSMetrics

class PrometheusRoutingSpec
    extends AnyWordSpec
    with ScalatestRouteTest
    with PrometheusRoute
    with BeforeAndAfterEach
    with MockitoSugar
    with Matchers {

  val metricRegistry = VinylDNSMetrics.metricsRegistry

  val collectorRegistry = CollectorRegistry.defaultRegistry

  collectorRegistry.register(new DropwizardExports(metricRegistry))

  "GET /metrics/prometheus" should {
    "return metrics logged in prometheus" in {
      Get("/metrics/prometheus") ~> prometheusRoute ~> check {
        response.status shouldBe StatusCodes.OK
        val resultStatus = responseAs[HttpResponse]
        resultStatus.protocol shouldBe HttpProtocol("HTTP/1.1")
      }
    }
  }
} 
Example 12
Source File: PrometheusModuleSpec.scala    From play-prometheus-filters   with MIT License 5 votes vote down vote up
package com.github.stijndehaes.playprometheusfilters

import io.prometheus.client.{Collector, CollectorRegistry}
import org.scalatest.{BeforeAndAfter, MustMatchers, PrivateMethodTester, WordSpec}
import org.scalatestplus.play.guice.GuiceOneAppPerTest
import play.api.inject.guice.GuiceApplicationBuilder

class PrometheusModuleSpec extends WordSpec with MustMatchers with BeforeAndAfter with PrivateMethodTester with GuiceOneAppPerTest {

  before {
    // clearing registry before each test
    CollectorRegistry.defaultRegistry.clear()
  }

  "PrometheusModule" should {
    "register default exporters when enabled" in {
      // default enabled
      val app = new GuiceApplicationBuilder()
        .configure(PrometheusModule.defaultExportsKey -> true)
        .build()

      val collector = app.injector.instanceOf[CollectorRegistry]
      val collectors = PrivateMethod[java.util.HashSet[Collector]]('collectors)
      (collector invokePrivate collectors()).size must be > 0
    }

    "not register default exporters when disabled" in {
      // disable default exporters
      val app = new GuiceApplicationBuilder()
        .configure(PrometheusModule.defaultExportsKey -> false)
        .build()

      val collector = app.injector.instanceOf[CollectorRegistry]
      val collectors = PrivateMethod[java.util.HashSet[Collector]]('collectors)
      (collector invokePrivate collectors()).size must be (0)
    }
  }

  
    def getExporterNames: Seq[String] = {
      val exportNames = collection.mutable.Buffer.empty[String]
      val mfs = registry.metricFamilySamples()
      while(mfs.hasMoreElements) {
        exportNames += mfs.nextElement().name
      }
      exportNames
    }
  }
} 
Example 13
Source File: PrometheusControllerSpec.scala    From play-prometheus-filters   with MIT License 5 votes vote down vote up
package com.github.stijndehaes.playprometheusfilters.controllers

import java.util.Collections

import io.prometheus.client.Collector.MetricFamilySamples
import io.prometheus.client.{Collector, CollectorRegistry}
import org.mockito.Mockito._
import org.scalatest.mockito.MockitoSugar
import org.scalatestplus.play.PlaySpec
import play.api.mvc.Results
import play.api.test.FakeRequest
import play.api.test.Helpers._


class PrometheusControllerSpec extends PlaySpec with Results with MockitoSugar {

  "Get metrics method" should {
    "Return the prometheus metrics" in {
      val collectorRegistry = mock[CollectorRegistry]
      val metricsFamilySample = new MetricFamilySamples("test", Collector.Type.COUNTER, "help", Collections.emptyList())
      when(collectorRegistry.metricFamilySamples()).thenReturn(new java.util.Vector(Collections.singleton(metricsFamilySample)).elements)

      val client = new PrometheusController(collectorRegistry, stubControllerComponents())

      val request = FakeRequest(GET, "/metrics")

      val result = client.getMetrics.apply(request)
      status(result) mustBe OK
      contentAsString(result) mustBe "# HELP test help\n# TYPE test counter\n"
    }
  }

} 
Example 14
Source File: RouteLatencyFilterSpec.scala    From play-prometheus-filters   with MIT License 5 votes vote down vote up
package com.github.stijndehaes.playprometheusfilters.filters

import com.github.stijndehaes.playprometheusfilters.metrics.DefaultPlayUnmatchedDefaults
import com.github.stijndehaes.playprometheusfilters.mocks.MockController
import io.prometheus.client.CollectorRegistry
import org.mockito.ArgumentMatchers.any
import org.mockito.Mockito.verify
import org.scalatest.mockito.MockitoSugar
import org.scalatest.{MustMatchers, WordSpec}
import org.scalatestplus.play.guice.GuiceOneAppPerSuite
import play.api.Configuration
import play.api.libs.typedmap.TypedMap
import play.api.mvc._
import play.api.routing.{HandlerDef, Router}
import play.api.test.Helpers.stubControllerComponents
import play.api.test.{DefaultAwaitTimeout, FakeRequest, FutureAwaits}

import scala.concurrent.ExecutionContext.Implicits.global

class RouteLatencyFilterSpec extends WordSpec with MustMatchers with MockitoSugar with Results with DefaultAwaitTimeout with FutureAwaits with GuiceOneAppPerSuite  {

  private implicit val mat = app.materializer
  private val configuration = mock[Configuration]

  "Filter constructor" should {
    "Add a histogram to the prometheus registry" in {
      val collectorRegistry = mock[CollectorRegistry]
      new RouteLatencyFilter(collectorRegistry, configuration)
      verify(collectorRegistry).register(any())
    }
  }

  "Apply method" should {
    "Measure the latency" in {
      val filter = new RouteLatencyFilter(mock[CollectorRegistry], configuration)
      val rh = FakeRequest().withAttrs( TypedMap(
        Router.Attrs.HandlerDef -> HandlerDef(null, null, null, "test", null, null ,null ,null ,null)
      ))
      val action = new MockController(stubControllerComponents()).ok

      await(filter(action)(rh).run())

      val metrics = filter.metrics(0).metric.collect()
      metrics must have size 1
      val samples = metrics.get(0).samples
      //this is the count sample
      val countSample = samples.get(samples.size() - 2)
      countSample.value mustBe 1.0
      countSample.labelValues must have size 1
      countSample.labelValues.get(0) mustBe "test"
    }

    "Measure the latency for an unmatched route" in {
      val filter = new RouteLatencyFilter(mock[CollectorRegistry], configuration)
      val rh = FakeRequest()
      val action = new MockController(stubControllerComponents()).error

      await(filter(action)(rh).run())

      val metrics = filter.metrics(0).metric.collect()
      metrics must have size 1
      val samples = metrics.get(0).samples
      //this is the count sample
      val countSample = samples.get(samples.size() - 2)
      countSample.value mustBe 1.0
      countSample.labelValues must have size 1
      countSample.labelValues.get(0) mustBe DefaultPlayUnmatchedDefaults.UnmatchedRouteString
    }
  }

} 
Example 15
Source File: MetricFilterSpec.scala    From play-prometheus-filters   with MIT License 5 votes vote down vote up
package com.github.stijndehaes.playprometheusfilters.filters

import com.github.stijndehaes.playprometheusfilters.metrics.CounterRequestMetrics.CounterRequestMetricBuilder
import com.github.stijndehaes.playprometheusfilters.metrics.{DefaultPlayUnmatchedDefaults, RequestMetric}
import com.github.stijndehaes.playprometheusfilters.mocks.MockController
import com.typesafe.config.ConfigFactory
import io.prometheus.client.CollectorRegistry
import org.scalatest.mockito.MockitoSugar
import org.scalatestplus.play.PlaySpec
import org.scalatestplus.play.guice.GuiceOneAppPerSuite
import play.api.Configuration
import play.api.mvc._
import play.api.test.Helpers._
import play.api.test.{DefaultAwaitTimeout, FakeRequest, FutureAwaits}

import scala.concurrent.ExecutionContext.Implicits.global

class MetricFilterSpec extends PlaySpec with MockitoSugar with Results with DefaultAwaitTimeout with FutureAwaits with GuiceOneAppPerSuite {

  val configuration = Configuration(ConfigFactory.parseString(
    """play-prometheus-filters.exclude.paths = ["/test"]"""
  ))

  "Filter constructor" should {
    "Get exclude paths from configuration" in {
      implicit val mat = app.materializer
      val filter = new MetricsFilter(configuration) {
        override val metrics = List.empty[RequestMetric[_, RequestHeader, Result]]
      }

      filter.excludePaths must have size 1 // only check size since cannot compare Regex's
    }
  }

  "Apply method" should {
    "skip metrics for excluded paths" in {
      implicit val mat = app.materializer
      val collectorRegistry = mock[CollectorRegistry]
      val filter = new MetricsFilter(configuration) {
        override val metrics = List(
          CounterRequestMetricBuilder.build(collectorRegistry, DefaultPlayUnmatchedDefaults)
        )
      }

      val rh = FakeRequest("GET", "/test")
      val action = new MockController(stubControllerComponents()).ok

      await(filter(action)(rh).run())

      val metrics = filter.metrics(0).metric.collect()
      metrics must have size 1
      val samples = metrics.get(0).samples
      samples.size() mustBe 0 // expect no metrics
    }
  }
} 
Example 16
Source File: StatusCounterFilterSpec.scala    From play-prometheus-filters   with MIT License 5 votes vote down vote up
package com.github.stijndehaes.playprometheusfilters.filters

import com.github.stijndehaes.playprometheusfilters.mocks.MockController
import io.prometheus.client.CollectorRegistry
import org.mockito.ArgumentMatchers.any
import org.mockito.Mockito.verify
import org.scalatest.mockito.MockitoSugar
import org.scalatest.{MustMatchers, WordSpec}
import org.scalatestplus.play.guice.GuiceOneAppPerSuite
import play.api.Configuration
import play.api.mvc.Results
import play.api.test.Helpers.stubControllerComponents
import play.api.test.{DefaultAwaitTimeout, FakeRequest, FutureAwaits}

import scala.concurrent.ExecutionContext.Implicits.global

class StatusCounterFilterSpec extends WordSpec with MustMatchers with MockitoSugar with Results with DefaultAwaitTimeout with FutureAwaits with GuiceOneAppPerSuite {

  private implicit val mat = app.materializer
  private val configuration = mock[Configuration]

  "Filter constructor" should {
    "Add a counter to the prometheus registry" in {
      val collectorRegistry = mock[CollectorRegistry]
      new StatusCounterFilter(collectorRegistry, configuration)
      verify(collectorRegistry).register(any())
    }
  }

  "Apply method" should {
    "Count the requests with status" in {
      val filter = new StatusCounterFilter(mock[CollectorRegistry], configuration)
      val rh = FakeRequest()
      val action = new MockController(stubControllerComponents()).ok

      await(filter(action)(rh).run())

      val metrics = filter.metrics(0).metric.collect()
      metrics must have size 1
      val samples = metrics.get(0).samples
      samples.get(0).value mustBe 1.0
      samples.get(0).labelValues must have size 1
      samples.get(0).labelValues.get(0) mustBe "200"
    }
  }

} 
Example 17
Source File: StatusAndRouteLatencyFilterSpec.scala    From play-prometheus-filters   with MIT License 5 votes vote down vote up
package com.github.stijndehaes.playprometheusfilters.filters

import com.github.stijndehaes.playprometheusfilters.metrics.DefaultPlayUnmatchedDefaults
import com.github.stijndehaes.playprometheusfilters.mocks.MockController
import io.prometheus.client.CollectorRegistry
import org.mockito.ArgumentMatchers.any
import org.mockito.Mockito.verify
import org.scalatest.mockito.MockitoSugar
import org.scalatest.{MustMatchers, WordSpec}
import org.scalatestplus.play.guice.GuiceOneAppPerSuite
import play.api.Configuration
import play.api.libs.typedmap.TypedMap
import play.api.mvc.Results
import play.api.routing.{HandlerDef, Router}
import play.api.test.Helpers.stubControllerComponents
import play.api.test.{DefaultAwaitTimeout, FakeRequest, FutureAwaits}

import scala.concurrent.ExecutionContext.Implicits.global

class StatusAndRouteLatencyFilterSpec extends WordSpec with MustMatchers with MockitoSugar with Results with DefaultAwaitTimeout with FutureAwaits with GuiceOneAppPerSuite  {

  private implicit val mat = app.materializer
  private val configuration = mock[Configuration]

  "Filter constructor" should {
    "Add a histogram to the prometheus registry" in {
      val collectorRegistry = mock[CollectorRegistry]
      new StatusAndRouteLatencyFilter(collectorRegistry, configuration)
      verify(collectorRegistry).register(any())
    }
  }

  "Apply method" should {
    "Measure the latency" in {
      val filter = new StatusAndRouteLatencyFilter(mock[CollectorRegistry], configuration)
      val rh = FakeRequest().withAttrs( TypedMap(
        Router.Attrs.HandlerDef -> HandlerDef(null, null, "testController", "test", null, "GET", "/path", null ,null)
      ))
      val action = new MockController(stubControllerComponents()).ok

      await(filter(action)(rh).run())

      val metrics = filter.metrics(0).metric.collect()
      metrics must have size 1
      val samples = metrics.get(0).samples
      //this is the count sample
      val countSample = samples.get(samples.size() - 2)
      countSample.value mustBe 1.0
      countSample.labelValues must have size 5
      countSample.labelValues.get(0) mustBe "test"
      countSample.labelValues.get(1) mustBe "200"
      countSample.labelValues.get(2) mustBe "testController"
      countSample.labelValues.get(3) mustBe "/path"
      countSample.labelValues.get(4) mustBe "GET"
    }

    "Measure the latency for an unmatched route" in {
      val filter = new StatusAndRouteLatencyFilter(mock[CollectorRegistry], configuration)
      val rh = FakeRequest()
      val action = new MockController(stubControllerComponents()).error

      await(filter(action)(rh).run())

      val metrics = filter.metrics(0).metric.collect()
      metrics must have size 1
      val samples = metrics.get(0).samples
      //this is the count sample
      val countSample = samples.get(samples.size() - 2)
      countSample.value mustBe 1.0
      countSample.labelValues must have size 5
      countSample.labelValues.get(0) mustBe DefaultPlayUnmatchedDefaults.UnmatchedRouteString
      countSample.labelValues.get(1) mustBe "404"
      countSample.labelValues.get(2) mustBe DefaultPlayUnmatchedDefaults.UnmatchedControllerString
      countSample.labelValues.get(3) mustBe DefaultPlayUnmatchedDefaults.UnmatchedPathString
      countSample.labelValues.get(4) mustBe DefaultPlayUnmatchedDefaults.UnmatchedVerbString
    }
  }
} 
Example 18
Source File: LatencyFilterSpec.scala    From play-prometheus-filters   with MIT License 5 votes vote down vote up
package com.github.stijndehaes.playprometheusfilters.filters

import com.github.stijndehaes.playprometheusfilters.mocks.MockController
import io.prometheus.client.CollectorRegistry
import org.mockito.ArgumentMatchers._
import org.mockito.Mockito._
import org.scalatest.mockito.MockitoSugar
import org.scalatestplus.play.PlaySpec
import org.scalatestplus.play.guice.GuiceOneAppPerSuite
import play.api.Configuration
import play.api.mvc._
import play.api.test.Helpers._
import play.api.test.{DefaultAwaitTimeout, FakeRequest, FutureAwaits}

import scala.concurrent.ExecutionContext.Implicits.global

class LatencyFilterSpec extends PlaySpec with MockitoSugar with Results with DefaultAwaitTimeout with FutureAwaits with GuiceOneAppPerSuite {

  val configuration = mock[Configuration]

  "Filter constructor" should {
    "Add a histogram to the prometheus registry" in {
      implicit val mat = app.materializer
      val collectorRegistry = mock[CollectorRegistry]
      new LatencyFilter(collectorRegistry, configuration)
      verify(collectorRegistry).register(any())
    }
  }

  "Apply method" should {
    "Measure the latency" in {
      implicit val mat = app.materializer
      val filter = new LatencyFilter(mock[CollectorRegistry], configuration)
      val rh = FakeRequest()
      val action = new MockController(stubControllerComponents()).ok

      await(filter(action)(rh).run())

      val metrics = filter.metrics(0).metric.collect()
      metrics must have size 1
      val samples = metrics.get(0).samples
      //this is the count sample
      val countSample = samples.get(samples.size() - 2)
      countSample.value mustBe 1.0
      countSample.labelValues must have size 0
    }
  }

} 
Example 19
Source File: StatusAndRouteCounterFilterSpec.scala    From play-prometheus-filters   with MIT License 5 votes vote down vote up
package com.github.stijndehaes.playprometheusfilters.filters

import com.github.stijndehaes.playprometheusfilters.metrics.DefaultPlayUnmatchedDefaults
import com.github.stijndehaes.playprometheusfilters.mocks.MockController
import io.prometheus.client.CollectorRegistry
import org.mockito.ArgumentMatchers.any
import org.mockito.Mockito.verify
import org.scalatest.mockito.MockitoSugar
import org.scalatest.{MustMatchers, WordSpec}
import org.scalatestplus.play.guice.GuiceOneAppPerSuite
import play.api.Configuration
import play.api.libs.typedmap.TypedMap
import play.api.mvc.Results
import play.api.routing.{HandlerDef, Router}
import play.api.test.Helpers.stubControllerComponents
import play.api.test.{DefaultAwaitTimeout, FakeRequest, FutureAwaits}

import scala.concurrent.ExecutionContext.Implicits.global

class StatusAndRouteCounterFilterSpec extends WordSpec with MustMatchers with MockitoSugar with Results with DefaultAwaitTimeout with FutureAwaits with GuiceOneAppPerSuite  {

  private implicit val mat = app.materializer
  private val configuration = mock[Configuration]

  "Filter constructor" should {
    "Add a histogram to the prometheus registry" in {
      val collectorRegistry = mock[CollectorRegistry]
      new StatusAndRouteLatencyFilter(collectorRegistry, configuration)
      verify(collectorRegistry).register(any())
    }
  }

  "Apply method" should {
    "Measure the count" in {
      val filter = new StatusAndRouteCounterFilter(mock[CollectorRegistry], configuration)
      val rh = FakeRequest().withAttrs( TypedMap(
        Router.Attrs.HandlerDef -> HandlerDef(null, null, "testController", "test", null, "GET", "/path", null ,null)
      ))
      val action = new MockController(stubControllerComponents()).ok

      await(filter(action)(rh).run())

      val metrics = filter.metrics(0).metric.collect()
      metrics must have size 1
      val samples = metrics.get(0).samples
      //this is the count sample
      val countSample = samples.get(0)
      countSample.value mustBe 1.0
      countSample.labelValues must have size 5
      countSample.labelValues.get(0) mustBe "test"
      countSample.labelValues.get(1) mustBe "200"
      countSample.labelValues.get(2) mustBe "testController"
      countSample.labelValues.get(3) mustBe "/path"
      countSample.labelValues.get(4) mustBe "GET"
    }

    "Measure the count for an unmatched route" in {
      val filter = new StatusAndRouteCounterFilter(mock[CollectorRegistry], configuration)
      val rh = FakeRequest()
      val action = new MockController(stubControllerComponents()).error

      await(filter(action)(rh).run())

      val metrics = filter.metrics(0).metric.collect()
      metrics must have size 1
      val samples = metrics.get(0).samples
      //this is the count sample
      val countSample = samples.get(0)
      countSample.value mustBe 1.0
      countSample.labelValues must have size 5
      countSample.labelValues.get(0) mustBe DefaultPlayUnmatchedDefaults.UnmatchedRouteString
      countSample.labelValues.get(1) mustBe "404"
      countSample.labelValues.get(2) mustBe DefaultPlayUnmatchedDefaults.UnmatchedControllerString
      countSample.labelValues.get(3) mustBe DefaultPlayUnmatchedDefaults.UnmatchedPathString
      countSample.labelValues.get(4) mustBe DefaultPlayUnmatchedDefaults.UnmatchedVerbString
    }
  }

} 
Example 20
Source File: PrometheusStatsReceiverTest.scala    From finagle-prometheus   with MIT License 5 votes vote down vote up
package com.samstarling.prometheusfinagle

import com.twitter.app.LoadService
import com.twitter.finagle.stats.{StatsReceiver, Verbosity}
import com.twitter.finagle.util.DefaultTimer
import com.twitter.util.Duration
import io.prometheus.client.CollectorRegistry

class PrometheusStatsReceiverTest extends UnitTest {

  "PrometheusStatsReceiverTest" should {
    "have a zero-argument constructor" in {
      new PrometheusStatsReceiver() must not(throwA[RuntimeException])
    }

    // This depends on content in test/resources/META-INF/services
    "be loaded as a StatsReceiver by LoadService" in {
      val classes: Seq[Class[_]] = LoadService[StatsReceiver]().map(_.getClass)
      classes.contains(classOf[PrometheusStatsReceiver]) ==== true
    }

    "be able to be instantiated by newInstance" in {
      classOf[PrometheusStatsReceiver].newInstance() must not(
        throwA[NoSuchMethodException])
    }

    "allow a registry to be passed" in {
      val registry = CollectorRegistry.defaultRegistry
      new PrometheusStatsReceiver(registry) must not(throwA[RuntimeException])
    }

    "allow a registry, namespace, and a Timer to be passed" in {
      val registry = CollectorRegistry.defaultRegistry
      val namespace = "testnamespace"
      new PrometheusStatsReceiver(registry,
                                  namespace,
                                  DefaultTimer.twitter,
                                  Duration.fromSeconds(1)) must not(
        throwA[RuntimeException])
    }

    "allow metrics and labels with unsafe characters" in {
      val registry = CollectorRegistry.defaultRegistry
      val namespace = "test_metric_names_and_labels"
      val statsReceiver = new PrometheusStatsReceiver(registry,
                                                      namespace,
                                                      DefaultTimer.twitter,
                                                      Duration.fromSeconds(1))
      val metrics = Seq(
        Seq("finagle", "build/revision"),
        Seq("foo/bar", "baz"),
        Seq("foo/bar", "build/revision"),
        Seq("foo-bar", "baz"),
        Seq("finagle", "build-revsion"),
      )
      metrics foreach { name =>
        statsReceiver.stat(Verbosity.Default, name: _*)
      } must not(throwA[IllegalArgumentException])
    }
  }
} 
Example 21
Source File: package.scala    From zio-metrics   with Apache License 2.0 5 votes vote down vote up
package zio.metrics

import zio.{ Has, ZLayer }
import zio.{ Ref, Task, UIO }

package object prometheus {

  import io.prometheus.client.{ Counter => PCounter }
  import io.prometheus.client.{ Gauge => PGauge }
  import io.prometheus.client.{ Histogram => PHistogram }
  import io.prometheus.client.CollectorRegistry
  import io.prometheus.client.{ Summary => PSummary }

  type Registry = Has[Registry.Service]

  object Registry {
    trait Service {
      def getCurrent(): UIO[CollectorRegistry]
      def registerCounter[L: Show](label: Label[L]): Task[PCounter]
      def registerGauge[L: Show](label: Label[L]): Task[PGauge]
      def registerHistogram[L: Show](label: Label[L], buckets: Buckets): Task[PHistogram]
      def registerSummary[L: Show](label: Label[L], quantiles: List[(Double, Double)]): Task[PSummary]
    }

    type PTimer     = PSummary.Timer
    type Percentile = Double
    type Tolerance  = Double

    val explicit: ZLayer[Has[Option[CollectorRegistry]], Nothing, Registry] =
      ZLayer.fromFunction[Has[Option[CollectorRegistry]], Registry.Service](
        optionalRegistry =>
          new Service {
            private val registryRef: UIO[Ref[CollectorRegistry]] = {
              val registry = optionalRegistry.get
              Ref.make(registry.getOrElse(CollectorRegistry.defaultRegistry))
            }

            def getCurrent(): UIO[CollectorRegistry] = registryRef >>= (_.get)

            def registerCounter[A: Show](label: Label[A]): Task[PCounter] =
              registryRef >>= (_.modify(r => {
                val name = Show[A].show(label.name)
                val c = PCounter
                  .build()
                  .name(name)
                  .labelNames(label.labels: _*)
                  .help(s"$name counter")
                  .register(r)
                (c, r)
              }))

            def registerGauge[L: Show](label: Label[L]): Task[PGauge] =
              registryRef >>= (_.modify(r => {
                val name = Show[L].show(label.name)
                val g = PGauge
                  .build()
                  .name(name)
                  .labelNames(label.labels: _*)
                  .help(s"$name gauge")
                  .register(r)
                (g, r)
              }))

            def registerHistogram[L: Show](label: Label[L], buckets: Buckets): Task[PHistogram] =
              registryRef >>= (_.modify(r => {
                val name = Show[L].show(label.name)
                val hb = PHistogram
                  .build()
                  .name(name)
                  .labelNames(label.labels: _*)
                  .help(s"$name histogram")

                val h = buckets match {
                  case DefaultBuckets(bs)          => if (bs.isEmpty) hb else hb.buckets(bs: _*)
                  case LinearBuckets(s, w, c)      => hb.linearBuckets(s, w, c)
                  case ExponentialBuckets(s, f, c) => hb.exponentialBuckets(s, f, c)
                }
                (h.register(r), r)
              }))

            def registerSummary[L: Show](label: Label[L], quantiles: List[(Percentile, Tolerance)]): Task[PSummary] =
              registryRef >>= (_.modify(r => {
                val name = Show[L].show(label.name)
                val sb = PSummary
                  .build()
                  .name(name)
                  .labelNames(label.labels: _*)
                  .help(s"$name timer")

                val s = quantiles.foldLeft(sb)((acc, c) => acc.quantile(c._1, c._2)).register(r)
                (s, r)
              }))
          }
      )

    val live: ZLayer[Any, Nothing, Has[Registry.Service]] = ZLayer.succeed[Option[CollectorRegistry]](None) >>> explicit

  }
} 
Example 22
Source File: PrometheusMarshallersSpec.scala    From akka-http-metrics   with Apache License 2.0 5 votes vote down vote up
package fr.davit.akka.http.metrics.prometheus.marshalling

import akka.http.scaladsl.model.StatusCodes
import akka.http.scaladsl.testkit.ScalatestRouteTest
import fr.davit.akka.http.metrics.core.HttpMetricsRegistry.StatusGroupDimension
import fr.davit.akka.http.metrics.core.scaladsl.server.HttpMetricsDirectives.metrics
import fr.davit.akka.http.metrics.prometheus.{PrometheusRegistry, PrometheusSettings}
import io.prometheus.client.CollectorRegistry
import org.scalatest.BeforeAndAfterAll
import org.scalatest.flatspec.AnyFlatSpec
import org.scalatest.matchers.should.Matchers

import scala.concurrent.duration._

class PrometheusMarshallersSpec extends AnyFlatSpec with Matchers with ScalatestRouteTest with BeforeAndAfterAll {

  trait Fixture extends PrometheusMarshallers {

    val registry = PrometheusRegistry(
      new CollectorRegistry(),
      PrometheusSettings.default.withIncludeStatusDimension(true)
    )

    io.prometheus.client.Counter
      .build("other_metric", "An other metric")
      .register(registry.underlying)
  }

  override def afterAll(): Unit = {
    cleanUp()
    super.afterAll()
  }

  "PrometheusMarshallers" should "expose metrics as prometheus format" in new Fixture {
    // register labeled metrics so they appear at least once
    // use metrics so they appear in the report
    val dimensions = Seq(StatusGroupDimension(StatusCodes.OK))
    registry.requests.inc()
    registry.receivedBytes.update(10)
    registry.active.inc()
    registry.responses.inc(dimensions)
    registry.errors.inc(dimensions)
    registry.duration.observe(1.second, dimensions)
    registry.sentBytes.update(10, dimensions)

    Get() ~> metrics(registry) ~> check {
      response.entity.contentType shouldBe PrometheusMarshallers.PrometheusContentType
      val text = responseAs[String]
      // println(text)
      val metrics = text
        .split('\n')
        .filterNot(_.startsWith("#"))
        .map(_.takeWhile(c => c != ' ' && c != '{'))
        .distinct
      metrics should contain theSameElementsAs Seq(
        "akka_http_requests_active",
        "akka_http_requests_total",
        "akka_http_requests_size_bytes_bucket",
        "akka_http_requests_size_bytes_count",
        "akka_http_requests_size_bytes_sum",
        "akka_http_responses_total",
        "akka_http_responses_errors_total",
        "akka_http_responses_duration_seconds_bucket",
        "akka_http_responses_duration_seconds_count",
        "akka_http_responses_duration_seconds_sum",
        "akka_http_responses_size_bytes_bucket",
        "akka_http_responses_size_bytes_count",
        "akka_http_responses_size_bytes_sum",
        "akka_http_connections_active",
        "akka_http_connections_total",
        "other_metric"
      )
    }
  }
} 
Example 23
Source File: ApiTests.scala    From openwhisk   with Apache License 2.0 5 votes vote down vote up
package org.apache.openwhisk.core.monitoring.metrics

import akka.http.scaladsl.model.headers.HttpEncodings._
import akka.http.scaladsl.model.headers.{`Accept-Encoding`, `Content-Encoding`, HttpEncoding, HttpEncodings}
import akka.http.scaladsl.model.{HttpCharsets, HttpEntity, HttpResponse}
import akka.http.scaladsl.testkit.ScalatestRouteTest
import kamon.prometheus.PrometheusReporter
import org.apache.openwhisk.core.monitoring.metrics.OpenWhiskEvents.MetricConfig
import org.junit.runner.RunWith
import org.scalatest.concurrent.ScalaFutures
import org.scalatest.junit.JUnitRunner
import org.scalatest.matchers.Matcher
import org.scalatest.{BeforeAndAfterAll, FlatSpec, Matchers}
import pureconfig.loadConfigOrThrow
import io.prometheus.client.CollectorRegistry
import pureconfig.generic.auto._

import scala.concurrent.duration.DurationInt

@RunWith(classOf[JUnitRunner])
class ApiTests
    extends FlatSpec
    with Matchers
    with ScalatestRouteTest
    with EventsTestHelper
    with ScalaFutures
    with BeforeAndAfterAll {
  implicit val timeoutConfig = PatienceConfig(1.minute)

  private var api: PrometheusEventsApi = _
  private var consumer: EventConsumer = _

  override protected def beforeAll(): Unit = {
    super.beforeAll()
    CollectorRegistry.defaultRegistry.clear()
    val metricConfig = loadConfigOrThrow[MetricConfig](system.settings.config, "user-events")
    val mericRecorder = PrometheusRecorder(new PrometheusReporter, metricConfig)
    consumer = createConsumer(56754, system.settings.config, mericRecorder)
    api = new PrometheusEventsApi(consumer, createExporter())
  }

  protected override def afterAll(): Unit = {
    consumer.shutdown().futureValue
    super.afterAll()
  }

  behavior of "EventsApi"

  it should "respond ping request" in {
    Get("/ping") ~> api.routes ~> check {
      //Due to retries using a random port does not immediately result in failure
      handled shouldBe true
    }
  }

  it should "respond metrics request" in {
    Get("/metrics") ~> `Accept-Encoding`(gzip) ~> api.routes ~> check {
      contentType.charsetOption shouldBe Some(HttpCharsets.`UTF-8`)
      contentType.mediaType.params("version") shouldBe "0.0.4"
      response should haveContentEncoding(gzip)
    }
  }

  private def haveContentEncoding(encoding: HttpEncoding): Matcher[HttpResponse] =
    be(encoding) compose {
      (_: HttpResponse).header[`Content-Encoding`].map(_.encodings.head).getOrElse(HttpEncodings.identity)
    }

  private def createExporter(): PrometheusExporter = () => HttpEntity(PrometheusExporter.textV4, "foo".getBytes)
} 
Example 24
Source File: OpenWhiskEventsTests.scala    From openwhisk   with Apache License 2.0 5 votes vote down vote up
package org.apache.openwhisk.core.monitoring.metrics

import akka.http.scaladsl.Http
import akka.http.scaladsl.model.{HttpRequest, StatusCodes}
import akka.http.scaladsl.unmarshalling.Unmarshal
import com.typesafe.config.ConfigFactory
import io.prometheus.client.CollectorRegistry
import kamon.Kamon
import org.junit.runner.RunWith
import org.scalatest.junit.JUnitRunner

import scala.concurrent.duration._
import scala.util.Try

@RunWith(classOf[JUnitRunner])
class OpenWhiskEventsTests extends KafkaSpecBase {
  behavior of "Server"

  it should "start working http server" in {
    val httpPort = freePort()
    val globalConfig = system.settings.config
    val config = ConfigFactory.parseString(s"""
           | akka.kafka.consumer.kafka-clients {
           |  bootstrap.servers = "localhost:$kafkaPort"
           | }
           | kamon {
           |  metric {
           |    tick-interval = 50 ms
           |    optimistic-tick-alignment = no
           |  }
           | }
           | whisk {
           |  user-events {
           |    port = $httpPort
           |    rename-tags {
           |      namespace = "ow_namespace"
           |    }
           |  }
           | }
         """.stripMargin).withFallback(globalConfig)
    CollectorRegistry.defaultRegistry.clear()
    val binding = OpenWhiskEvents.start(config).futureValue
    val res = get("localhost", httpPort, "/ping")
    res shouldBe Some(StatusCodes.OK, "pong")

    //Check if metrics using Kamon API gets included in consolidated Prometheus
    Kamon.counter("fooTest").withoutTags().increment(42)
    sleep(1.second)
    val metricRes = get("localhost", httpPort, "/metrics")
    metricRes.get._2 should include("fooTest")

    binding.unbind().futureValue
  }

  def get(host: String, port: Int, path: String = "/") = {
    val response = Try {
      Http()
        .singleRequest(HttpRequest(uri = s"http://$host:$port$path"))
        .futureValue
    }.toOption

    response.map { res =>
      (res.status, Unmarshal(res).to[String].futureValue)
    }
  }
} 
Example 25
Source File: TestServer.scala    From finagle-prometheus   with MIT License 5 votes vote down vote up
package com.samstarling.prometheusfinagle.examples

import java.net.InetSocketAddress

import com.samstarling.prometheusfinagle.PrometheusStatsReceiver
import com.samstarling.prometheusfinagle.metrics.{MetricsService, Telemetry}
import com.twitter.finagle.builder.ServerBuilder
import com.twitter.finagle.http._
import com.twitter.finagle.http.path._
import com.twitter.finagle.http.service.{NotFoundService, RoutingService}
import com.twitter.finagle.loadbalancer.perHostStats
import com.twitter.finagle.{Http, Service}
import io.prometheus.client.CollectorRegistry

object TestServer extends App {

  perHostStats.parse("true")

  val registry = CollectorRegistry.defaultRegistry
  val statsReceiver = new PrometheusStatsReceiver(registry)
  val telemetry = new Telemetry(registry, "namespace")

  val emojiService = new EmojiService(statsReceiver)
  val metricsService = new MetricsService(registry)
  val echoService = new EchoService
  val customTelemetryService = new CustomTelemetryService(telemetry)

  val router: Service[Request, Response] =
    RoutingService.byMethodAndPathObject {
      case (Method.Get, Root / "emoji")   => emojiService
      case (Method.Get, Root / "metrics") => metricsService
      case (Method.Get, Root / "echo")    => echoService
      case (Method.Get, Root / "custom")  => customTelemetryService
      case _                              => new NotFoundService
    }

  ServerBuilder()
    .stack(Http.server)
    .name("testserver")
    .bindTo(new InetSocketAddress(8080))
    .build(router)
} 
Example 26
Source File: MetricsService.scala    From finagle-prometheus   with MIT License 5 votes vote down vote up
package com.samstarling.prometheusfinagle.metrics

import java.io.StringWriter

import com.twitter.finagle.Service
import com.twitter.finagle.http.{Request, Response, Status}
import com.twitter.util.Future
import io.prometheus.client.CollectorRegistry
import io.prometheus.client.exporter.common.TextFormat

class MetricsService(registry: CollectorRegistry)
    extends Service[Request, Response] {

  override def apply(request: Request): Future[Response] = {
    val writer = new StringWriter
    TextFormat.write004(writer, registry.metricFamilySamples())
    val response = Response(request.version, Status.Ok)
    response.setContentString(writer.toString)
    Future(response)
  }
} 
Example 27
Source File: CollectorRegistryHelper.scala    From finagle-prometheus   with MIT License 5 votes vote down vote up
package com.samstarling.prometheusfinagle.helper

import io.prometheus.client.Collector.MetricFamilySamples.{Sample => PrometheusSample}
import io.prometheus.client.{Collector, CollectorRegistry}

import scala.collection.JavaConverters._

case class CollectorRegistryHelper(registry: CollectorRegistry) {

  // TODO: Messy
  def samples: Map[String, List[Sample]] = {
    def metricFamilies = registry.metricFamilySamples.asScala.toList
    def allSamples: List[List[Sample]] =
      metricFamilies.map(_.samples.asScala.toList.map(Sample(_)))
    def flatSamples: List[Sample] = allSamples.flatten
    flatSamples
      .map({ s =>
        s.name -> s
      })
      .groupBy(_._1)
      .mapValues(_.map(_._2)).toMap
  }
}

case class Metric(metric: Collector.MetricFamilySamples) {
  def samples: Map[String, Sample] = {
    metric.samples.asScala.toList
      .map(sample => sample.name -> Sample(sample))
      .toMap
  }
}

case class Sample(sample: PrometheusSample) {
  def name: String = sample.name
  def value: Double = sample.value
  def dimensions: Map[String, String] = {
    sample.labelNames.asScala.zip(sample.labelValues.asScala).toMap
  }
} 
Example 28
Source File: MetricsServiceSpec.scala    From finagle-prometheus   with MIT License 5 votes vote down vote up
package com.samstarling.prometheusfinagle.metrics

import com.samstarling.prometheusfinagle.UnitTest
import com.twitter.finagle.http.{Method, Request}
import com.twitter.util.Await
import io.prometheus.client.CollectorRegistry
import org.specs2.specification.Scope

class MetricsServiceSpec extends UnitTest {

  trait Context extends Scope {
    val registry = new CollectorRegistry(true)
    val telemetry = new Telemetry(registry, "unit_test")
    val service = new MetricsService(registry)
  }

  "it renders metrics correctly" in new Context {
    telemetry.counter("foo").inc()
    val request = Request(Method.Get, "/")
    val response = Await.result(service.apply(request))

    response.getContentString.trim ====
      "# HELP unit_test_foo No help provided\n" +
        "# TYPE unit_test_foo counter\n" +
        "unit_test_foo 1.0"
  }
} 
Example 29
Source File: package.scala    From zio-metrics   with Apache License 2.0 5 votes vote down vote up
package zio.metrics.prometheus

import zio.{ Has, Layer, Task, ZLayer }

import io.prometheus.client.CollectorRegistry
import io.prometheus.client.exporter.{ HTTPServer, PushGateway }
import io.prometheus.client.bridge.Graphite
import io.prometheus.client.exporter.common.TextFormat
import io.prometheus.client.exporter.HttpConnectionFactory
import io.prometheus.client.exporter.BasicAuthHttpConnectionFactory
import io.prometheus.client.hotspot.DefaultExports

import java.net.InetSocketAddress
import java.io.StringWriter

package object exporters {

  type Exporters = Has[Exporters.Service]

  object Exporters {
    trait Service {
      def http(r: CollectorRegistry, port: Int): Task[HTTPServer]

      def graphite(r: CollectorRegistry, host: String, port: Int, intervalSeconds: Int): Task[Thread]

      def pushGateway(
        r: CollectorRegistry,
        hots: String,
        port: Int,
        jobName: String,
        user: Option[String],
        password: Option[String],
        httpConnectionFactory: Option[HttpConnectionFactory]
      ): Task[Unit]

      def write004(r: CollectorRegistry): Task[String]

      def initializeDefaultExports(r: CollectorRegistry): Task[Unit]
    }

    val live: Layer[Nothing, Exporters] = ZLayer.succeed(new Service {
      def http(r: CollectorRegistry, port: Int): zio.Task[HTTPServer] =
        Task {
          new HTTPServer(new InetSocketAddress(port), r)
        }

      def graphite(r: CollectorRegistry, host: String, port: Int, intervalSeconds: Int): Task[Thread] =
        Task {
          val g = new Graphite(host, port)
          g.start(r, intervalSeconds)
        }

      def pushGateway(
        r: CollectorRegistry,
        host: String,
        port: Int,
        jobName: String,
        user: Option[String],
        password: Option[String],
        httpConnectionFactory: Option[HttpConnectionFactory]
      ): Task[Unit] =
        Task {
          val pg = new PushGateway(s"$host:$port")

          if (user.isDefined)
            for {
              u <- user
              p <- password
            } yield pg.setConnectionFactory(new BasicAuthHttpConnectionFactory(u, p))
          else if (httpConnectionFactory.isDefined)
            for {
              conn <- httpConnectionFactory
            } yield pg.setConnectionFactory(conn)

          pg.pushAdd(r, jobName)
        }

      def write004(r: CollectorRegistry): Task[String] =
        Task {
          val writer = new StringWriter
          TextFormat.write004(writer, r.metricFamilySamples)
          writer.toString
        }

      def initializeDefaultExports(r: CollectorRegistry): Task[Unit] =
        Task(DefaultExports.initialize())
    })

    def stopHttp(server: HTTPServer): Task[Unit] =
      Task(server.stop())
  }

} 
Example 30
Source File: HttpLatencyMonitoringFilterSpec.scala    From finagle-prometheus   with MIT License 5 votes vote down vote up
package com.samstarling.prometheusfinagle.filter

import com.samstarling.prometheusfinagle.UnitTest
import com.samstarling.prometheusfinagle.helper.{CollectorHelper, CollectorRegistryHelper}
import com.samstarling.prometheusfinagle.metrics.Telemetry
import com.twitter.finagle.Service
import com.twitter.finagle.http.{Method, Request, Response, Status}
import com.twitter.finagle.util.DefaultTimer
import com.twitter.util.{Await, Duration, Future, Timer}
import io.prometheus.client.CollectorRegistry
import org.specs2.specification.Scope

class HttpLatencyMonitoringFilterSpec extends UnitTest {

  class SlowService extends Service[Request, Response] {
    implicit val timer = DefaultTimer.twitter

    override def apply(request: Request): Future[Response] = {
      Future
        .value(Response(request.version, Status.Ok))
        .delayed(Duration.fromMilliseconds(1500))
    }
  }

  trait Context extends Scope {
    val registry = new CollectorRegistry(true)
    val registryHelper = CollectorRegistryHelper(registry)
    val telemetry = new Telemetry(registry, "test")
    val buckets = Seq(1.0, 2.0)
    val labeller = new TestLabeller
    val filter = new HttpLatencyMonitoringFilter(telemetry, buckets, labeller)
    val service = mock[Service[Request, Response]]
    val slowService = new SlowService
    val request = Request(Method.Get, "/foo/bar")
    val serviceResponse = Response(Status.Created)
    val histogram =
      telemetry.histogram(name = "incoming_http_request_latency_seconds")
    service.apply(request) returns Future.value(serviceResponse)
  }

  "HttpLatencyMonitoringFilter" >> {
    "passes requests on to the next service" in new Context {
      Await.result(filter.apply(request, service))
      there was one(service).apply(request)
    }

    "returns the Response from the next service" in new Context {
      val actualResponse = Await.result(filter.apply(request, service))
      actualResponse ==== serviceResponse
    }

    "counts the request" in new Context {
      Await.result(filter.apply(request, slowService))

      registryHelper.samples
        .get("test_incoming_http_request_latency_seconds_count")
        .map(_.map(_.value).sum) must beSome(1.0).eventually
    }

    "increments the counter with the labels from the labeller" in new Context {
      Await.result(filter.apply(request, service))

      registryHelper.samples
        .get("test_incoming_http_request_latency_seconds_count")
        .map(_.head.dimensions.get("foo").get) must beSome("bar").eventually
    }

    "categorises requests into the correct bucket" in new Context {
      Await.result(filter.apply(request, slowService))

      // Our request takes ~1500ms, so it should NOT fall into the "less than or equal to 1 second" bucket (le=0.5)
      registryHelper.samples
        .get("test_incoming_http_request_latency_seconds_bucket")
        .flatMap(_.find(_.dimensions.get("le").contains("1.0")))
        .map(_.value) must beSome(0.0).eventually

      // However, it should fall into the "less than or equal to 2 seconds" bucket (le=0.5)
      registryHelper.samples
        .get("test_incoming_http_request_latency_seconds_bucket")
        .flatMap(_.find(_.dimensions.get("le").contains("2.0")))
        .map(_.value) must beSome(1.0).eventually

      // It should also fall into the "+Inf" bucket
      registryHelper.samples
        .get("test_incoming_http_request_latency_seconds_bucket")
        .flatMap(_.find(_.dimensions.get("le").contains("+Inf")))
        .map(_.value) must beSome(1.0).eventually
    }
  }
} 
Example 31
Source File: HttpMonitoringFilterSpec.scala    From finagle-prometheus   with MIT License 5 votes vote down vote up
package com.samstarling.prometheusfinagle.filter

import com.samstarling.prometheusfinagle.UnitTest
import com.samstarling.prometheusfinagle.helper.CollectorHelper
import com.samstarling.prometheusfinagle.metrics.Telemetry
import com.twitter.finagle.Service
import com.twitter.finagle.http.{Method, Request, Response, Status}
import com.twitter.util.{Await, Future}
import io.prometheus.client.CollectorRegistry
import org.specs2.specification.Scope

import scala.collection.JavaConverters._

class HttpMonitoringFilterSpec extends UnitTest {

  trait Context extends Scope {
    val registry = new CollectorRegistry(true)
    val telemetry = new Telemetry(registry, "test")
    val labeller = new TestLabeller
    val filter = new HttpMonitoringFilter(telemetry, labeller)
    val service = mock[Service[Request, Response]]
    val request = Request(Method.Get, "/foo/bar")
    val serviceResponse = Response(Status.Created)
    val counter = telemetry.counter(name = "incoming_http_requests_total")
    service.apply(request) returns Future.value(serviceResponse)
  }

  "HttpMonitoringFilter" >> {
    "passes requests on to the next service" in new Context {
      Await.result(filter.apply(request, service))
      there was one(service).apply(request)
    }

    "returns the Response from the next service" in new Context {
      val actualResponse = Await.result(filter.apply(request, service))
      actualResponse ==== serviceResponse
    }

    "increments the incoming_http_requests_total counter" in new Context {
      Await.result(filter.apply(request, service))
      Await.result(filter.apply(request, service))
      CollectorHelper.firstSampleFor(counter).map { sample =>
        sample.value ==== 2.0
      }
    }

    "adds the correct help label" in new Context {
      Await.result(filter.apply(request, service))
      CollectorHelper.firstMetricFor(counter).map { metric =>
        metric.help ==== "The number of incoming HTTP requests"
      }
    }

    "increments the counter with the labels from the labeller" in new Context {
      Await.result(filter.apply(request, service))
      CollectorHelper.firstSampleFor(counter).map { sample =>
        sample.labelNames.asScala(0) ==== "foo"
        sample.labelValues.asScala(0) ==== "bar"
      }
    }
  }
} 
Example 32
Source File: DeduplicatedCollectorRegistry.scala    From spark-metrics   with Apache License 2.0 5 votes vote down vote up
package com.banzaicloud.spark.metrics

import java.{lang, util}
import java.util.Collections

import io.prometheus.client.{Collector, CollectorRegistry}

import scala.collection.JavaConverters._
import org.apache.spark.internal.Logging

import scala.util.{Failure, Try}

class DeduplicatedCollectorRegistry(parent: CollectorRegistry = CollectorRegistry.defaultRegistry)
  extends CollectorRegistry with Logging {
  private type MetricsEnum = util.Enumeration[Collector.MetricFamilySamples]

  override def register(m: Collector): Unit = {

    // in case collectors with the same name are registered multiple times keep the first one
    Try(parent.register(m)) match {
      case Failure(ex) if ex.getMessage.startsWith("Collector already registered that provides name:") =>
        // TODO: find a more robust solution for checking if there is already a collector registered for a specific metric
      case Failure(ex) => throw ex
      case _ =>
    }
  }

  override def unregister(m: Collector): Unit = parent.unregister(m)

  override def clear(): Unit = parent.clear()

  override def getSampleValue(name: String, labelNames: Array[String], labelValues: Array[String]): lang.Double = {
    parent.getSampleValue(name, labelNames, labelValues)
  }

  override def getSampleValue(name: String): lang.Double = parent.getSampleValue(name)

  override def metricFamilySamples(): MetricsEnum = {
    deduplicate(parent.metricFamilySamples())
  }

  override def filteredMetricFamilySamples(includedNames: util.Set[String]): MetricsEnum = {
    deduplicate(parent.filteredMetricFamilySamples(includedNames))
  }

  private def deduplicate(source: MetricsEnum): MetricsEnum = {
    val metrics = source.asScala.toSeq
    val deduplicated = metrics
      .groupBy(f => (f.name, f.`type`))
      .flatMap {
        case (_, single) if single.lengthCompare(2) < 0 =>

          single
        case ((name, metricType), duplicates) =>
          logDebug(s"Found ${duplicates.length} metrics with the same name '${name}' and type ${metricType}")
          duplicates.lastOption
      }
      .toList
      .asJava
    Collections.enumeration(deduplicated)
  }
} 
Example 33
Source File: DeduplicatedCollectorRegistrySuite.scala    From spark-metrics   with Apache License 2.0 5 votes vote down vote up
package com.banzaicloud.spark.metrics

import com.codahale.metrics.MetricRegistry
import io.prometheus.client.{Collector, CollectorRegistry}
import io.prometheus.client.dropwizard.DropwizardExports
import org.junit.{Assert, Test}

import scala.collection.JavaConverters._

class DeduplicatedCollectorRegistrySuite {
    @Test def testDeduplication(): Unit = {
      // given
      val baseRegistry = new MetricRegistry
      val registryA = new MetricRegistry
      val counterA = registryA.counter("counter")
      counterA.inc(20)
      counterA.inc(30)

      val registryB = new MetricRegistry
      val counterB = registryB.counter("counter")
      counterB.inc(40)
      counterB.inc(50)
      baseRegistry.register("hive_", registryA)
      baseRegistry.register("hive.", registryB)

      val metricsExports = new DropwizardExports(baseRegistry)
      val deduplicatedCollectorRegistry = new DeduplicatedCollectorRegistry(new CollectorRegistry(true))

      // when
      metricsExports.register(deduplicatedCollectorRegistry)
      val samples = deduplicatedCollectorRegistry.metricFamilySamples()

      // then
      val actual = samples
        .asScala
        .filter(mfs => mfs.`type`== Collector.Type.GAUGE && mfs.name == "hive__counter")
      Assert.assertEquals(1, actual.size)
    }
} 
Example 34
Source File: AkkaHttpPrometheusExporter.scala    From cloudstate   with Apache License 2.0 5 votes vote down vote up
package io.cloudstate.proxy

import java.io.OutputStreamWriter
import java.util

import akka.actor.ActorSystem
import akka.http.scaladsl.Http
import io.prometheus.client.CollectorRegistry
import akka.http.scaladsl.model._
import akka.http.scaladsl.server.Directives._
import akka.stream.Materializer
import akka.util.ByteString
import io.prometheus.client.exporter.common.TextFormat

import scala.concurrent.Future


class AkkaHttpPrometheusExporter(metricsPort: Int, registry: CollectorRegistry = CollectorRegistry.defaultRegistry)(
    implicit system: ActorSystem,
    mat: Materializer
) {

  private[this] final val PrometheusContentType = ContentType.parse(TextFormat.CONTENT_TYPE_004).right.get

  private def routes = get {
    (path("metrics") | pathSingleSlash) {
      encodeResponse {
        parameter(Symbol("name[]").*) { names =>
          complete {
            val namesSet = new util.HashSet[String]()
            names.foreach(namesSet.add)
            val builder = ByteString.newBuilder
            val writer = new OutputStreamWriter(builder.asOutputStream)
            TextFormat.write004(writer, registry.filteredMetricFamilySamples(namesSet))
            // Very important to flush the writer before we build the byte string!
            writer.flush()
            HttpEntity(PrometheusContentType, builder.result())
          }
        }
      }
    }
  }

  def start(): Future[Http.ServerBinding] =
    Http().bindAndHandle(routes, "0.0.0.0", metricsPort)
} 
Example 35
Source File: PrometheusEndpointSink.scala    From kafka-lag-exporter   with Apache License 2.0 5 votes vote down vote up
package com.lightbend.kafkalagexporter

import com.lightbend.kafkalagexporter.MetricsSink._
import com.lightbend.kafkalagexporter.EndpointSink.ClusterGlobalLabels
import com.lightbend.kafkalagexporter.PrometheusEndpointSink.Metrics
import io.prometheus.client.exporter.HTTPServer
import io.prometheus.client.hotspot.DefaultExports
import io.prometheus.client.{CollectorRegistry, Gauge}

import scala.util.Try

object PrometheusEndpointSink {
  type Metrics = Map[GaugeDefinition, Gauge]

  def apply(definitions: MetricDefinitions, metricWhitelist: List[String], clusterGlobalLabels: ClusterGlobalLabels,
            server: HTTPServer, registry: CollectorRegistry): MetricsSink = {
    Try(new PrometheusEndpointSink(definitions, metricWhitelist, clusterGlobalLabels, server, registry))
      .fold(t => throw new Exception("Could not create Prometheus Endpoint", t), sink => sink)
  }
}

class PrometheusEndpointSink private(definitions: MetricDefinitions, metricWhitelist: List[String], clusterGlobalLabels: ClusterGlobalLabels,
                                     server: HTTPServer, registry: CollectorRegistry) extends EndpointSink(clusterGlobalLabels) {
  DefaultExports.initialize()

  private val metrics: Metrics = {
    definitions.filter(d => metricWhitelist.exists(d.name.matches)).map { d =>
      d -> Gauge.build()
        .name(d.name)
        .help(d.help)
        .labelNames(globalLabelNames ++ d.labels: _*)
        .register(registry)
    }.toMap
  }

  override def report(m: MetricValue): Unit = {
    if (metricWhitelist.exists(m.definition.name.matches)) {
      val metric = metrics.getOrElse(m.definition, throw new IllegalArgumentException(s"No metric with definition ${m.definition.name} registered"))
      metric.labels(getGlobalLabelValuesOrDefault(m.clusterName) ++ m.labels: _*).set(m.value)
    }
  }

  override def remove(m: RemoveMetric): Unit = {
    if (metricWhitelist.exists(m.definition.name.matches)) {
      for {
        gauge <- metrics.get(m.definition)
      } {
        val metricLabels = getGlobalLabelValuesOrDefault(m.clusterName) ++ m.labels
        gauge.remove(metricLabels: _*)
      }
    }
  }

  override def stop(): Unit = {
    
    registry.clear()
    server.stop()
  }


} 
Example 36
Source File: MainApp.scala    From kafka-lag-exporter   with Apache License 2.0 5 votes vote down vote up
package com.lightbend.kafkalagexporter

import java.util.concurrent.Executors

import akka.actor.typed.ActorSystem
import com.typesafe.config.{Config, ConfigFactory}
import io.prometheus.client.CollectorRegistry
import io.prometheus.client.exporter.HTTPServer

import scala.concurrent.duration._
import scala.concurrent.{Await, ExecutionContext}

object MainApp extends App {
  val system = start()

  // Add shutdown hook to respond to SIGTERM and gracefully shutdown the actor system
  sys.ShutdownHookThread {
    system ! KafkaClusterManager.Stop
    Await.result(system.whenTerminated, 10 seconds)
  }

  def start(config: Config = ConfigFactory.load()): ActorSystem[KafkaClusterManager.Message] = {
    // Cached thread pool for various Kafka calls for non-blocking I/O
    val kafkaClientEc = ExecutionContext.fromExecutor(Executors.newCachedThreadPool())

    val appConfig = AppConfig(config)

    val clientCreator = (cluster: KafkaCluster) =>
      KafkaClient(cluster, appConfig.clientGroupId, appConfig.clientTimeout)(kafkaClientEc)
    var endpointCreators : List[KafkaClusterManager.NamedCreator] = List()
    appConfig.prometheusConfig.foreach { prometheus =>
      val prometheusCreator = KafkaClusterManager.NamedCreator(
        "prometheus-lag-reporter", 
        (() => PrometheusEndpointSink(
          Metrics.definitions, appConfig.metricWhitelist, appConfig.clustersGlobalLabels(), new HTTPServer(prometheus.port), CollectorRegistry.defaultRegistry
        ))
      )
      endpointCreators = prometheusCreator :: endpointCreators
    }
    appConfig.graphiteConfig.foreach { _ =>
      val graphiteCreator = KafkaClusterManager.NamedCreator(
        "graphite-lag-reporter",
        (() => GraphiteEndpointSink(appConfig.metricWhitelist, appConfig.clustersGlobalLabels(), appConfig.graphiteConfig)))
      endpointCreators = graphiteCreator :: endpointCreators
    }
    ActorSystem(
      KafkaClusterManager.init(appConfig, endpointCreators, clientCreator), "kafka-lag-exporter")
  }
} 
Example 37
Source File: PrometheusRouting.scala    From vinyldns   with Apache License 2.0 5 votes vote down vote up
package vinyldns.api.route

import java.io.StringWriter

import akka.http.scaladsl.model._
import akka.http.scaladsl.server.Directives
import io.prometheus.client.CollectorRegistry
import io.prometheus.client.exporter.common.TextFormat

import scala.collection.JavaConverters._

trait PrometheusRoute extends Directives {

  def collectorRegistry: CollectorRegistry

  private val `text/plain; version=0.0.4; charset=utf-8` = ContentType {
    MediaType.customWithFixedCharset(
      "text",
      "plain",
      HttpCharsets.`UTF-8`,
      params = Map("version" -> "0.0.4")
    )
  }

  def renderMetrics(registry: CollectorRegistry, names: Set[String]): String = {
    val writer = new StringWriter()
    TextFormat.write004(writer, registry.filteredMetricFamilySamples(names.toSet.asJava))
    writer.toString
  }

  val prometheusRoute =
    (get & path("metrics" / "prometheus") & parameter('name.*)) { names =>
      val content = renderMetrics(collectorRegistry, names.toSet)
      complete {
        HttpResponse(entity = HttpEntity(`text/plain; version=0.0.4; charset=utf-8`, content))
      }
    }
}