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

utils.CustomCollector.scala Maven / Gradle / Ivy

package otoroshi.utils.prometheus

import com.codahale.metrics._
import com.spotify.metrics.core.{MetricId, SemanticMetricRegistry}
import io.prometheus.client.Collector.{MetricFamilySamples, Type}
import io.prometheus.client.CollectorRegistry
import io.prometheus.client.dropwizard.samplebuilder.{DefaultSampleBuilder, SampleBuilder}

import java.util
import java.util.concurrent.TimeUnit
import scala.jdk.CollectionConverters.mapAsScalaMapConverter

class CustomCollector(registry: SemanticMetricRegistry, _jmxRegistry: MetricRegistry)
    extends io.prometheus.client.Collector
    with io.prometheus.client.Collector.Describable {

  private val sampleBuilder: SampleBuilder = new DefaultSampleBuilder

  def fromCounter(key: MetricId, entryValue: Counter): MetricFamilySamples = {
    val sample = getSample(key, entryValue.getCount.doubleValue)
    new MetricFamilySamples(sample.name, Type.GAUGE, "", util.Arrays.asList(sample))
  }

  private def getSample(metric: MetricId, value: Double, suffix: String = ""): MetricFamilySamples.Sample = {
    sampleBuilder.createSample(
      metric.getKey,
      suffix,
      new util.ArrayList[String](metric.getTags.keySet),
      new util.ArrayList[String](metric.getTags.values),
      value
    )
  }

  def fromGauge(key: MetricId, entryValue: Gauge[_]): MetricFamilySamples = {
    val obj   = entryValue.getValue
    var value = .0

    obj match {
      case number: Number => value = number.doubleValue
      case bool: Boolean  => value = if (bool) 1 else 0
      case _              => return null
    }

    val sample = getSample(key, value)
    new MetricFamilySamples(sample.name, Type.GAUGE, "", util.Arrays.asList(sample))
  }

  private def combineValueAndList(value: String, l: util.Collection[String]) = {
    val half = new util.ArrayList[String]() { { value } }
    half.addAll(new util.ArrayList[String](l))
    half
  }

  def fromSnapshotAndCount(
      name: String,
      snapshot: Snapshot,
      count: Long,
      factor: Double,
      tags: util.Map[String, String]
  ): MetricFamilySamples = {
    val quantile = new util.ArrayList[String]() { { "quantile" } }
    quantile.addAll(new util.ArrayList[String](tags.keySet))

    val samples = util.Arrays.asList(
      sampleBuilder.createSample(
        name,
        "",
        quantile,
        combineValueAndList("0.5", tags.values),
        snapshot.getMedian * factor
      ),
      sampleBuilder.createSample(
        name,
        "",
        quantile,
        combineValueAndList("0.75", tags.values),
        snapshot.get75thPercentile * factor
      ),
      sampleBuilder.createSample(
        name,
        "",
        quantile,
        combineValueAndList("0.95", tags.values),
        snapshot.get95thPercentile * factor
      ),
      sampleBuilder.createSample(
        name,
        "",
        quantile,
        combineValueAndList("0.98", tags.values),
        snapshot.get98thPercentile * factor
      ),
      sampleBuilder.createSample(
        name,
        "",
        quantile,
        combineValueAndList("0.99", tags.values),
        snapshot.get99thPercentile * factor
      ),
      sampleBuilder.createSample(
        name,
        "",
        quantile,
        combineValueAndList("0.999", tags.values),
        snapshot.get999thPercentile * factor
      ),
      sampleBuilder.createSample(
        name,
        "_count",
        new util.ArrayList[String](tags.keySet),
        new util.ArrayList[String](tags.values),
        count
      )
    )
    new MetricFamilySamples(samples.get(0).name, Type.SUMMARY, "", samples)
  }

  def fromHistogram(key: MetricId, entryValue: Histogram): MetricFamilySamples =
    fromSnapshotAndCount(
      key.getKey,
      entryValue.getSnapshot,
      entryValue.getCount,
      1.0,
      key.getTags
    )

  def fromTimer(key: MetricId, entryValue: Timer): MetricFamilySamples =
    fromSnapshotAndCount(
      key.getKey,
      entryValue.getSnapshot,
      entryValue.getCount,
      1.0d / TimeUnit.SECONDS.toNanos(1L),
      key.getTags
    )

  def fromMeter(key: MetricId, entryValue: Meter): MetricFamilySamples = {
    val sample = getSample(key, entryValue.getCount, "_count")
    new MetricFamilySamples(sample.name, Type.COUNTER, "", util.Arrays.asList(sample))
  }

  override def collect: util.List[MetricFamilySamples] = {
    val mfSamplesMap = new util.HashMap[String, MetricFamilySamples]

    registry.getGauges.entrySet.forEach(entry => addToMap(mfSamplesMap, fromGauge(entry.getKey, entry.getValue)))
    registry.getCounters.entrySet.forEach(entry => addToMap(mfSamplesMap, fromCounter(entry.getKey, entry.getValue)))
    registry.getHistograms.entrySet.forEach(entry =>
      addToMap(mfSamplesMap, fromHistogram(entry.getKey, entry.getValue))
    )
    registry.getTimers.entrySet.forEach(entry => addToMap(mfSamplesMap, fromTimer(entry.getKey, entry.getValue)))
    registry.getMeters.entrySet.forEach(entry => addToMap(mfSamplesMap, fromMeter(entry.getKey, entry.getValue)))

    // jmxRegistry.getGauges.entrySet.forEach(entry =>
    //   addToMap(mfSamplesMap, fromGauge(MetricId.build(entry.getKey), entry.getValue))
    // )
    // jmxRegistry.getCounters.entrySet.forEach(entry =>
    //   addToMap(mfSamplesMap, fromCounter(MetricId.build(entry.getKey), entry.getValue))
    // )
    // jmxRegistry.getHistograms.entrySet.forEach(entry =>
    //   addToMap(mfSamplesMap, fromHistogram(MetricId.build(entry.getKey), entry.getValue))
    // )
    // jmxRegistry.getTimers.entrySet.forEach(entry =>
    //   addToMap(mfSamplesMap, fromTimer(MetricId.build(entry.getKey), entry.getValue))
    // )
    // jmxRegistry.getMeters.entrySet.forEach(entry =>
    //   addToMap(mfSamplesMap, fromMeter(MetricId.build(entry.getKey), entry.getValue))
    // )

    new util.ArrayList[MetricFamilySamples](mfSamplesMap.values)
  }

  def getKeyOrTags(metric: MetricId): String =
    if (metric.getTags.isEmpty) metric.getKey else metric.getTags.asScala.mkString(",")

  private def addToMap(mfSamplesMap: util.Map[String, MetricFamilySamples], newMfSamples: MetricFamilySamples): Unit = {
    if (newMfSamples != null) {
      val currentMfSamples = mfSamplesMap.get(newMfSamples.name)
      if (currentMfSamples == null) mfSamplesMap.put(newMfSamples.name, newMfSamples)
      else {
        val samples = new util.ArrayList[MetricFamilySamples.Sample](currentMfSamples.samples)
        samples.addAll(newMfSamples.samples)
        mfSamplesMap.put(
          newMfSamples.name,
          new MetricFamilySamples(newMfSamples.name, currentMfSamples.`type`, currentMfSamples.help, samples)
        )
      }
    }
  }

  override def describe = new util.ArrayList[MetricFamilySamples]
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy