aboutsummaryrefslogblamecommitdiff
path: root/kamon-core/src/main/scala/kamon/metric/Registry.scala
blob: 3f549802edf201b9771278e0ef93984efadceb45 (plain) (tree)





























































































































































































































                                                                                                                                                                          
package kamon
package metric

import java.time.Duration
import java.util.concurrent.ScheduledThreadPoolExecutor
import java.util.concurrent.atomic.AtomicReference

import com.typesafe.config.{Config, ConfigFactory}
import com.typesafe.scalalogging.Logger
import kamon.metric.instrument._
import kamon.util.MeasurementUnit

import scala.collection.concurrent.TrieMap
/*


Kamon.metrics.histogram("http.latency").withMeasurementUnit(Time.Microseconds)


Histogram.create("http.latency", Time.Milliseconds)



val histogram = Histogram.builder("http.latency")
  .tag("method", "get")
  .build()


val actorMetrics = MetricGroup("method" -> "get")


val actorMetrics = MetricGroup.builder()
  .tag("method", "get")
  .build()

actorMetrics.histogram(

Options for a Histogram:
  - MeasurementUnit
  - Dynamic Range

HistogramConfig.forLatency().inMicroseconds()

Kamon.metrics.histogram("http.latency").withoutTags()
Kamon.metrics.histogram("http.latency").withTag("method", "get")




Kamon.metrics.histogram("http.latency", Tag.of("color", "blue"), Tag.of("color", "blue"))

Kamon.histogram(named("http.latency").withTag("path", path))
Kamon.counter(named("http.latency").withTag("path", path))








val group = Kamon.metrics.group(tags = Map("path" -> "/my-system/user/test-actor"))
val processingTime = group.histogram("processing-time")



  def histogram(name: String): Histogram =
    histogram(name, MeasurementUnit.none)

  def histogram(name: String, unit: MeasurementUnit): Histogram =
    histogram(name, unit, Map.empty)

  def histogram(name: String, unit: MeasurementUnit, tags: Map[String, String]): Histogram =
    histogram(name, unit, tags, DynamicRange.Default)



 */

trait MetricLookup {

  def histogram(name: String): Histogram =
    histogram(name, MeasurementUnit.none)

  def histogram(name: String, unit: MeasurementUnit): Histogram =
    histogram(name, unit, Map.empty)

  def histogram(name: String, unit: MeasurementUnit, tags: Map[String, String]): Histogram =
    histogram(name, unit, tags, None)

  def histogram(name: String, unit: MeasurementUnit, tags: Map[String, String], dynamicRange: DynamicRange): Histogram =
    histogram(name, unit, tags, Some(dynamicRange))

  def histogram(name: String, unit: MeasurementUnit, tags: Map[String, String], dynamicRange: Option[DynamicRange]): Histogram

}

class Registry(initialConfig: Config) extends RegistrySnapshotGenerator {
  private val logger = Logger(classOf[Registry])
  private val metrics = TrieMap.empty[String, MetricEntry]
  private val instrumentFactory = new AtomicReference[InstrumentFactory]()
  reconfigure(initialConfig)

  def reconfigure(config: Config): Unit = synchronized {
    instrumentFactory.set(InstrumentFactory.fromConfig(config))
  }

  def histogram(name: String, unit: MeasurementUnit, tags: Map[String, String], dynamicRange: Option[DynamicRange]): Histogram =
    lookupInstrument(name, unit, tags, InstrumentType.Histogram, instrumentFactory.get().buildHistogram(dynamicRange))

  def counter(name: String, unit: MeasurementUnit, tags: Map[String, String]): Counter =
    lookupInstrument(name, unit, tags, InstrumentType.Counter, instrumentFactory.get().buildCounter)

  def gauge(name: String, unit: MeasurementUnit, tags: Map[String, String]): Gauge =
    lookupInstrument(name, unit, tags, InstrumentType.Gauge, instrumentFactory.get().buildGauge)

  def minMaxCounter(name: String, unit: MeasurementUnit, tags: Map[String, String], dynamicRange: Option[DynamicRange], sampleInterval: Option[Duration]): MinMaxCounter =
    lookupInstrument(name, unit, tags, InstrumentType.MinMaxCounter, instrumentFactory.get().buildMinMaxCounter(dynamicRange, sampleInterval))


  override def snapshot(): RegistrySnapshot = synchronized {
    var histograms = Seq.empty[DistributionSnapshot]
    var mmCounters = Seq.empty[DistributionSnapshot]
    var counters = Seq.empty[SingleValueSnapshot]
    var gauges = Seq.empty[SingleValueSnapshot]

    for {
      metricEntry <- metrics.values
      instrument  <- metricEntry.instruments.values
    } {
      metricEntry.instrumentType match {
        case InstrumentType.Histogram     => histograms = histograms :+ instrument.asInstanceOf[SnapshotableHistogram].snapshot()
        case InstrumentType.MinMaxCounter => mmCounters = mmCounters :+ instrument.asInstanceOf[SnapshotableMinMaxCounter].snapshot()
        case InstrumentType.Gauge         => gauges = gauges :+ instrument.asInstanceOf[SnapshotableGauge].snapshot()
        case InstrumentType.Counter       => counters = counters :+ instrument.asInstanceOf[SnapshotableCounter].snapshot()
      }
    }

    RegistrySnapshot(histograms, mmCounters, gauges, counters)
  }

  private def lookupInstrument[T](name: String, measurementUnit: MeasurementUnit, tags: Map[String, String],
      instrumentType: InstrumentType, builder: (String, Map[String, String], MeasurementUnit) => T): T = {

    val entry = metrics.atomicGetOrElseUpdate(name, MetricEntry(instrumentType, measurementUnit, TrieMap.empty))
    if(entry.instrumentType != instrumentType)
      sys.error(s"Tried to use metric [$name] as a [${instrumentType.name}] but it is already defined as [${entry.instrumentType.name}] ")

    if(entry.unit != measurementUnit)
      logger.warn("Ignoring attempt to use measurement unit [{}] on metric [name={}, tags={}], the metric uses [{}]",
        measurementUnit.magnitude.name, name, tags.prettyPrint(), entry.unit.magnitude.name)

    entry.instruments.getOrElseUpdate(tags, builder(name, tags, measurementUnit)).asInstanceOf[T]
  }

  private case class InstrumentType(name: String)
  private object InstrumentType {
    val Histogram     = InstrumentType("Histogram")
    val MinMaxCounter = InstrumentType("MinMaxCounter")
    val Counter       = InstrumentType("Counter")
    val Gauge         = InstrumentType("Gauge")
  }

  private case class MetricEntry(instrumentType: InstrumentType, unit: MeasurementUnit, instruments: TrieMap[Map[String, String], Any])
}



//
//
//trait RecorderRegistry {
//  def shouldTrack(entity: Entity): Boolean
//  def getRecorder(entity: Entity): EntityRecorder
//  def removeRecorder(entity: Entity): Boolean
//}
//
//class RecorderRegistryImpl(initialConfig: Config) extends RecorderRegistry {
//  private val scheduler = new ScheduledThreadPoolExecutor(1, numberedThreadFactory("kamon.metric.refresh-scheduler"))
//  private val instrumentFactory = new AtomicReference[InstrumentFactory]()
//  private val entityFilter = new AtomicReference[Filter]()
//  private val entities = TrieMap.empty[Entity, EntityRecorder with EntitySnapshotProducer]
//
//  reconfigure(initialConfig)
//
//
//  override def shouldTrack(entity: Entity): Boolean =
//    entityFilter.get().accept(entity)
//
//  override def getRecorder(entity: Entity): EntityRecorder =
//    entities.atomicGetOrElseUpdate(entity, new DefaultEntityRecorder(entity, instrumentFactory.get(), scheduler))
//
//  override def removeRecorder(entity: Entity): Boolean =
//    entities.remove(entity).nonEmpty
//
//  private[kamon] def reconfigure(config: Config): Unit = synchronized {
//    instrumentFactory.set(InstrumentFactory.fromConfig(config))
//    entityFilter.set(Filter.fromConfig(config))
//
//    val refreshSchedulerPoolSize = config.getInt("kamon.metric.refresh-scheduler-pool-size")
//    scheduler.setCorePoolSize(refreshSchedulerPoolSize)
//  }
//
//  //private[kamon] def diagnosticData
//}
//
//case class RecorderRegistryDiagnostic(entities: Seq[Entity])
//


object Test extends App {
  val registry = new Registry(ConfigFactory.load())

  println(registry.histogram("test-1", MeasurementUnit.none, Map.empty, Some(DynamicRange.Default)).dynamicRange)
  println(registry.histogram("test-2", MeasurementUnit.none, Map.empty, Option(DynamicRange.Fine)).dynamicRange)

  println(Kamon.histogram("my-test"))
}