aboutsummaryrefslogblamecommitdiff
path: root/kamon-core/src/main/scala/kamon/metric/instrument/InstrumentFactory.scala
blob: 33a34bdfb80fb101c25ae026d23de5717ba8ecb6 (plain) (tree)
1
2
3
4
5
6
7
8
9







                                                                         
                                 

 
                                                




                                                                      
                                                                                                             
                                                                                                                 







                                                        

                                                                                                                 
                                                                                                                                                                            
 

                                                                                         

             
                          

                                                            
   
 

                                                                                                                                                   
 

                                                                                                                                                       



















                                                                                                                               
                          
 




                                                                                                               
 
                                                                   
























                                                                                                                         














                                                                                                                 
package kamon
package metric
package instrument

import java.time.Duration

import com.typesafe.config.Config
import kamon.metric.instrument.InstrumentFactory.CustomInstrumentSettings
import kamon.util.MeasurementUnit


private[kamon] class InstrumentFactory private (
    defaultHistogramDynamicRange: DynamicRange,
    defaultMMCounterDynamicRange: DynamicRange,
    defaultMMCounterSampleRate: Duration,
    customSettings: Map[(String, String), CustomInstrumentSettings]) {

  def buildHistogram(entity: Entity, name: String, dynamicRange: DynamicRange = defaultHistogramDynamicRange,
      measurementUnit: MeasurementUnit = MeasurementUnit.none): Histogram with DistributionSnapshotInstrument = {

    new HdrHistogram(
      entity,
      name,
      measurementUnit,
      instrumentDynamicRange(entity, name, dynamicRange)
    )
  }

  def buildMinMaxCounter(entity: Entity, name: String, dynamicRange: DynamicRange = defaultMMCounterDynamicRange,
      sampleInterval: Duration = defaultMMCounterSampleRate, measurementUnit: MeasurementUnit = MeasurementUnit.none): MinMaxCounter with DistributionSnapshotInstrument = {

    val underlyingHistogram = buildHistogram(entity, name, dynamicRange, measurementUnit)
    new PaddedMinMaxCounter(
      entity,
      name,
      underlyingHistogram,
      instrumentSampleInterval(entity, name, sampleInterval)
    )
  }

  def buildGauge(entity: Entity, name: String, measurementUnit: MeasurementUnit = MeasurementUnit.none): Gauge with SingleValueSnapshotInstrument =
    new AtomicLongGauge(entity, name, measurementUnit)

  def buildCounter(entity: Entity, name: String, measurementUnit: MeasurementUnit = MeasurementUnit.none): Counter with SingleValueSnapshotInstrument =
    new LongAdderCounter(entity, name, measurementUnit)


  private def instrumentDynamicRange(entity: Entity, instrumentName: String, dynamicRange: DynamicRange): DynamicRange =
    customSettings.get((entity.category, instrumentName)).fold(dynamicRange) { cs =>
      overrideDynamicRange(dynamicRange, cs)
    }

  private def instrumentSampleInterval(entity: Entity, instrumentName: String, sampleInterval: Duration): Duration =
    customSettings.get((entity.category, instrumentName)).fold(sampleInterval) { cs =>
      cs.sampleInterval.getOrElse(sampleInterval)
    }

  private def overrideDynamicRange(defaultDynamicRange: DynamicRange, customSettings: CustomInstrumentSettings): DynamicRange =
    DynamicRange(
      customSettings.lowestDiscernibleValue.getOrElse(defaultDynamicRange.lowestDiscernibleValue),
      customSettings.highestTrackableValue.getOrElse(defaultDynamicRange.highestTrackableValue),
      customSettings.significantValueDigits.getOrElse(defaultDynamicRange.significantValueDigits)
    )
}

object InstrumentFactory {

  def fromConfig(config: Config): InstrumentFactory = {
    val factoryConfig = config.getConfig("kamon.metric.instrument-factory")
    val histogramDynamicRange = readDynamicRange(factoryConfig.getConfig("default-settings.histogram"))
    val mmCounterDynamicRange = readDynamicRange(factoryConfig.getConfig("default-settings.min-max-counter"))
    val mmCounterSampleInterval = factoryConfig.getDuration("default-settings.min-max-counter.sample-interval")

    val customSettings = factoryConfig.getConfig("custom-settings")
      .configurations
      .filter(nonEmptyCategories)
      .flatMap(buildCustomInstrumentSettings)

    new InstrumentFactory(histogramDynamicRange, mmCounterDynamicRange, mmCounterSampleInterval, customSettings)
  }

  private def nonEmptyCategories(entry: (String, Config)): Boolean = entry match {
    case (_, config) => config.firstLevelKeys.nonEmpty
  }

  private def buildCustomInstrumentSettings(entry: (String, Config)): Map[(String, String), CustomInstrumentSettings] = {
    val (category, categoryConfig) = entry
    categoryConfig.configurations.map {
      case (instrumentName, instrumentConfig) => (category, instrumentName) -> readCustomSettings(instrumentConfig)
    }
  }

  private def readDynamicRange(config: Config): DynamicRange =
    DynamicRange(
      lowestDiscernibleValue = config.getLong("lowest-discernible-value"),
      highestTrackableValue = config.getLong("highest-trackable-value"),
      significantValueDigits = config.getInt("significant-value-digits")
    )

  private case class CustomInstrumentSettings(
    lowestDiscernibleValue: Option[Long],
    highestTrackableValue: Option[Long],
    significantValueDigits: Option[Int],
    sampleInterval: Option[Duration]
  )

  private def readCustomSettings(config: Config): CustomInstrumentSettings =
    CustomInstrumentSettings(
      if (config.hasPath("lowest-discernible-value")) Some(config.getLong("lowest-discernible-value")) else None,
      if (config.hasPath("highest-trackable-value")) Some(config.getLong("highest-trackable-value")) else None,
      if (config.hasPath("significant-value-digits")) Some(config.getInt("significant-value-digits")) else None,
      if (config.hasPath("sample-interval")) Some(config.getDuration("sample-interval")) else None
    )
}