diff options
author | Ivan Topolnjak <ivantopo@gmail.com> | 2017-05-25 16:52:52 +0200 |
---|---|---|
committer | Ivan Topolnjak <ivantopo@gmail.com> | 2017-05-25 16:52:52 +0200 |
commit | a3d78ef61a277b0b62dc93daf84756dfa7625d3d (patch) | |
tree | 4fee7ce93ecfb4e32c7aaaa22efb75ed07c667f6 /kamon-core | |
parent | 22379d3f318b2cd3a4c995ff1c45bda33d935a46 (diff) | |
download | Kamon-a3d78ef61a277b0b62dc93daf84756dfa7625d3d.tar.gz Kamon-a3d78ef61a277b0b62dc93daf84756dfa7625d3d.tar.bz2 Kamon-a3d78ef61a277b0b62dc93daf84756dfa7625d3d.zip |
trying to flatten out the structure and eliminate the notion of entitites
Diffstat (limited to 'kamon-core')
30 files changed, 549 insertions, 490 deletions
diff --git a/kamon-core/src/legacy-main/scala/kamon/metric/MetricsSettings.scala b/kamon-core/src/legacy-main/scala/kamon/metric/MetricsSettings.scala index 86968597..f75c6d4d 100644 --- a/kamon-core/src/legacy-main/scala/kamon/metric/MetricsSettings.scala +++ b/kamon-core/src/legacy-main/scala/kamon/metric/MetricsSettings.scala @@ -30,7 +30,7 @@ case class MetricsSettings( tickInterval: FiniteDuration, defaultCollectionContextBufferSize: Int, trackUnmatchedEntities: Boolean, - entityFilters: Map[String, EntityFilter], + entityFilters: Map[String, Filter], instrumentFactories: Map[String, InstrumentFactory], defaultInstrumentFactory: InstrumentFactory, refreshScheduler: RefreshScheduler @@ -89,7 +89,7 @@ object MetricsSettings { * * @return a Map from category name to corresponding entity filter. */ - def loadFilters(filtersConfig: Config): Map[String, EntityFilter] = { + def loadFilters(filtersConfig: Config): Map[String, Filter] = { import scala.collection.JavaConverters._ filtersConfig.firstLevelKeys map { category: String ⇒ @@ -99,7 +99,7 @@ object MetricsSettings { val excludes = filtersConfig.getStringList(s"$category.excludes").asScala.map(exc ⇒ if (asRegex) RegexPathFilter(exc) else new GlobPathFilter(exc)).toList - (category, EntityFilter(includes, excludes)) + (category, Filter(includes, excludes)) } toMap } diff --git a/kamon-core/src/legacy-main/scala/kamon/util/executors/ExecutorServiceMetrics.scala b/kamon-core/src/legacy-main/scala/kamon/util/executors/ExecutorServiceMetrics.scala index 60612beb..482a73c9 100644 --- a/kamon-core/src/legacy-main/scala/kamon/util/executors/ExecutorServiceMetrics.scala +++ b/kamon-core/src/legacy-main/scala/kamon/util/executors/ExecutorServiceMetrics.scala @@ -19,7 +19,6 @@ package kamon.util.executors import java.util.concurrent.{ExecutorService, ForkJoinPool ⇒ JavaForkJoinPool, ThreadPoolExecutor} import kamon.Kamon -import kamon.metric.Entity import scala.concurrent.forkjoin.ForkJoinPool import scala.util.control.NoStackTrace diff --git a/kamon-core/src/legacy-test/scala/kamon/KamonLifecycleSpec.scala b/kamon-core/src/legacy-test/scala/kamon/KamonLifecycleSpec.scala index 2fbd1b71..3847d6b8 100644 --- a/kamon-core/src/legacy-test/scala/kamon/KamonLifecycleSpec.scala +++ b/kamon-core/src/legacy-test/scala/kamon/KamonLifecycleSpec.scala @@ -4,7 +4,7 @@ import akka.actor.ActorSystem import akka.testkit.{TestKitBase, TestProbe} import com.typesafe.config.ConfigFactory import kamon.metric.SubscriptionsDispatcher.TickMetricSnapshot -import kamon.metric.{EntitySnapshot, SubscriptionsDispatcher} +import kamon.metric.SubscriptionsDispatcher import kamon.util.LazyActorRef import org.scalatest.{Matchers, WordSpecLike} import org.scalactic.TimesOnInt._ diff --git a/kamon-core/src/legacy-test/scala/kamon/testkit/BaseKamonSpec.scala b/kamon-core/src/legacy-test/scala/kamon/testkit/BaseKamonSpec.scala index 995f15fa..6899d4e3 100644 --- a/kamon-core/src/legacy-test/scala/kamon/testkit/BaseKamonSpec.scala +++ b/kamon-core/src/legacy-test/scala/kamon/testkit/BaseKamonSpec.scala @@ -20,7 +20,7 @@ import akka.actor.ActorSystem import akka.testkit.{ImplicitSender, TestKitBase} import com.typesafe.config.Config import kamon.{ActorSystemTools, Kamon} -import kamon.metric.{Entity, EntitySnapshot, SubscriptionsDispatcher} +import kamon.metric.SubscriptionsDispatcher import kamon.trace.TraceContext import kamon.util.LazyActorRef import org.scalatest.{BeforeAndAfterAll, Matchers, WordSpecLike} diff --git a/kamon-core/src/legacy-test/scala/kamon/util/executors/ExecutorServiceMetricsSpec.scala b/kamon-core/src/legacy-test/scala/kamon/util/executors/ExecutorServiceMetricsSpec.scala index 4e5394f8..3f1d418a 100644 --- a/kamon-core/src/legacy-test/scala/kamon/util/executors/ExecutorServiceMetricsSpec.scala +++ b/kamon-core/src/legacy-test/scala/kamon/util/executors/ExecutorServiceMetricsSpec.scala @@ -19,7 +19,7 @@ package kamon.util.executors import java.util.concurrent.Executors import kamon.Kamon -import kamon.metric.{Entity, EntityRecorder} +import kamon.metric.EntityRecorder import kamon.testkit.BaseKamonSpec class ExecutorServiceMetricsSpec extends BaseKamonSpec("executor-service-metrics-spec") { diff --git a/kamon-core/src/main/resources/logback.xml b/kamon-core/src/main/resources/logback.xml new file mode 100644 index 00000000..af71060f --- /dev/null +++ b/kamon-core/src/main/resources/logback.xml @@ -0,0 +1,12 @@ +<configuration> + <statusListener class="ch.qos.logback.core.status.NopStatusListener"/> + <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender"> + <encoder> + <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern> + </encoder> + </appender> + + <root level="DEBUG"> + <appender-ref ref="STDOUT"/> + </root> +</configuration>
\ No newline at end of file diff --git a/kamon-core/src/main/resources/reference.conf b/kamon-core/src/main/resources/reference.conf index b514b1b7..f4d180ca 100644 --- a/kamon-core/src/main/resources/reference.conf +++ b/kamon-core/src/main/resources/reference.conf @@ -1,4 +1,10 @@ kamon { + environment { + application = "" + host = "" + instance = "" + } + metric { tick-interval = 60 seconds @@ -11,7 +17,7 @@ kamon { # NOTE: Using entity filters is a commodity for modules that might potentially track thousands of unnecessary # entities, but not all modules are required to use filters, check the your module's documentation to # determine whether setting up filters make sense or not. - accept-unmatched-categories = true + accept-unmatched = true } @@ -35,38 +41,34 @@ kamon { # default-settings { histogram { - lowest-discernible-value = 0 + lowest-discernible-value = 1 highest-trackable-value = 3600000000000 significant-value-digits = 2 } min-max-counter { - lowest-discernible-value = 0 + lowest-discernible-value = 1 highest-trackable-value = 3600000000000 significant-value-digits = 2 sample-interval = 200 millis } } - # Custom settings for instruments of a given category. The settings provided in this section override the default - # and manually provided settings when creating instruments. All settings are optional in this section and default + # Custom settings for instruments of a given metric. The settings provided in this section override the default + # and manually provided settings when creating metrics. All settings are optional in this section and default # values from the `kamon.metric.instrument-factory.default-settings` will be used in case of any setting being # missing. # # Example: - # If you wish to change the highest trackable value setting of the `elapsed-time` instrument in the `span` - # category, you should include the following configuration in your application.conf file: + # If you wish to change the highest trackable value setting of the `span.elapsed-time` metric, you should include + # the following configuration in your application.conf file: # - # kamon.metric.instrument-factory.custom-settings.span { - # elapsed-time { + # kamon.metric.instrument-factory.custom-settings { + # "span.elapsed-time" { # highest-trackable-value = 5000 # } # } # - # After including that configuration, every time a new histogram called `elapsed-time` for a entity with category - # `span`, the highest-trackable-value will be 5000, but lowest-discernible-value and significant-value-digits will - # remain with default values. - # custom-settings { } diff --git a/kamon-core/src/main/scala/kamon/Kamon.scala b/kamon-core/src/main/scala/kamon/Kamon.scala index b318d59d..60956ee0 100644 --- a/kamon-core/src/main/scala/kamon/Kamon.scala +++ b/kamon-core/src/main/scala/kamon/Kamon.scala @@ -3,22 +3,24 @@ package kamon import java.util.concurrent.atomic.AtomicReference import com.typesafe.config.{Config, ConfigFactory} -import kamon.metric.{RecorderRegistry, RecorderRegistryImpl} +import kamon.metric.instrument.{DynamicRange, Histogram} +import kamon.metric.{MetricLookup, Registry} import kamon.trace.Tracer +import kamon.util.MeasurementUnit -object Kamon { +object Kamon extends MetricLookup { private val _initialConfig = ConfigFactory.load() - private val _recorderRegistry = new RecorderRegistryImpl(_initialConfig) - private val _reporterRegistry = new ReporterRegistryImpl(_recorderRegistry, _initialConfig) - private val _tracer = new Tracer(_recorderRegistry, _reporterRegistry) + //private val _recorderRegistry = new RecorderRegistryImpl(_initialConfig) + private val _reporterRegistry = new ReporterRegistryImpl(???, _initialConfig) + private val _tracer = new Tracer(???, _reporterRegistry) private val _environment = new AtomicReference[Environment](environmentFromConfig(ConfigFactory.load())) def tracer: io.opentracing.Tracer = _tracer - def metrics: RecorderRegistry = - _recorderRegistry +// def metrics: RecorderRegistry = +// _recorderRegistry def reporters: ReporterRegistry = _reporterRegistry @@ -27,13 +29,15 @@ object Kamon { _environment.get() def reconfigure(config: Config): Unit = synchronized { - _recorderRegistry.reconfigure(config) + // _recorderRegistry.reconfigure(config) _reporterRegistry.reconfigure(config) _environment.set(environmentFromConfig(config)) } - + private val metricRegistry = new Registry(_initialConfig) + override def histogram(name: String, unit: MeasurementUnit, tags: Map[String, String], dynamicRange: Option[DynamicRange]): Histogram = + metricRegistry.histogram(name, unit, tags, dynamicRange) case class Environment(config: Config, application: String, host: String, instance: String) diff --git a/kamon-core/src/main/scala/kamon/ReporterRegistry.scala b/kamon-core/src/main/scala/kamon/ReporterRegistry.scala index 98bde946..11312512 100644 --- a/kamon-core/src/main/scala/kamon/ReporterRegistry.scala +++ b/kamon-core/src/main/scala/kamon/ReporterRegistry.scala @@ -44,7 +44,7 @@ trait SpansReporter { def reportSpan(span: Span.CompletedSpan): Unit } -class ReporterRegistryImpl(metrics: RecorderRegistryImpl, initialConfig: Config) extends ReporterRegistry { +class ReporterRegistryImpl(metrics: RegistrySnapshotGenerator, initialConfig: Config) extends ReporterRegistry { private val registryExecutionContext = Executors.newSingleThreadScheduledExecutor(threadFactory("kamon-reporter-registry")) private val metricsTickerSchedule = new AtomicReference[ScheduledFuture[_]]() private val metricReporters = new ConcurrentLinkedQueue[ReporterEntry]() @@ -141,7 +141,7 @@ class ReporterRegistryImpl(metrics: RecorderRegistryImpl, initialConfig: Config) executionContext: ExecutionContextExecutorService ) - private class MetricTicker(metricsImpl: RecorderRegistryImpl, reporterEntries: java.util.Queue[ReporterEntry]) extends Runnable { + private class MetricTicker(snapshotGenerator: RegistrySnapshotGenerator, reporterEntries: java.util.Queue[ReporterEntry]) extends Runnable { val logger = LoggerFactory.getLogger(classOf[MetricTicker]) var lastTick = Instant.now() @@ -149,7 +149,7 @@ class ReporterRegistryImpl(metrics: RecorderRegistryImpl, initialConfig: Config) val currentTick = Instant.now() val tickSnapshot = TickSnapshot( interval = Interval(lastTick, currentTick), - entities = metricsImpl.snapshot() + metrics = snapshotGenerator.snapshot() ) reporterEntries.forEach { entry => diff --git a/kamon-core/src/main/scala/kamon/metric/Entity.scala b/kamon-core/src/main/scala/kamon/metric/Entity.scala deleted file mode 100644 index a38a7f46..00000000 --- a/kamon-core/src/main/scala/kamon/metric/Entity.scala +++ /dev/null @@ -1,11 +0,0 @@ -package kamon.metric - - - -case class Entity(name: String, category: String, tags: Map[String, String]) { - - override def toString: String = { - val tagString = tags.map { case (k, v) => k + "=>" + v }.mkString(",") - "Entity(name=\"" + name + "\", category=\"" + category + "\", tags=\"" + tagString + "\"" - } -} diff --git a/kamon-core/src/main/scala/kamon/metric/EntityRecorder.scala b/kamon-core/src/main/scala/kamon/metric/EntityRecorder.scala deleted file mode 100644 index ccdb463e..00000000 --- a/kamon-core/src/main/scala/kamon/metric/EntityRecorder.scala +++ /dev/null @@ -1,90 +0,0 @@ -package kamon.metric - -import java.time.Duration -import java.util.concurrent.{ScheduledExecutorService, ScheduledFuture, TimeUnit} - -import kamon.metric.instrument._ -import kamon.util.MeasurementUnit - -import scala.collection.concurrent.TrieMap -import scala.util.Try - -trait EntityRecorder { - def histogram(name: String): Histogram - def histogram(name: String, measurementUnit: MeasurementUnit, dynamicRange: DynamicRange): Histogram - - def minMaxCounter(name: String): MinMaxCounter - def minMaxCounter(name: String, measurementUnit: MeasurementUnit, dynamicRange: DynamicRange, sampleFrequency: Duration): MinMaxCounter - - def gauge(name: String): Gauge - def gauge(name: String, measurementUnit: MeasurementUnit): Gauge - - def counter(name: String): Counter - def counter(name: String, measurementUnit: MeasurementUnit): Counter -} - -trait EntitySnapshotProducer { - def snapshot(): EntitySnapshot -} - -class DefaultEntityRecorder(entity: Entity, instrumentFactory: InstrumentFactory, scheduler: ScheduledExecutorService) - extends EntityRecorder with EntitySnapshotProducer { - - private val histograms = TrieMap.empty[String, Histogram with DistributionSnapshotInstrument] - private val minMaxCounters = TrieMap.empty[String, MinMaxCounterEntry] - private val counters = TrieMap.empty[String, Counter with SingleValueSnapshotInstrument] - private val gauges = TrieMap.empty[String, Gauge with SingleValueSnapshotInstrument] - - def histogram(name: String): Histogram = - histograms.atomicGetOrElseUpdate(name, instrumentFactory.buildHistogram(entity, name)) - - def histogram(name: String, measurementUnit: MeasurementUnit, dynamicRange: DynamicRange): Histogram = - histograms.atomicGetOrElseUpdate(name, instrumentFactory.buildHistogram(entity, name, dynamicRange, measurementUnit)) - - def minMaxCounter(name: String): MinMaxCounter = - minMaxCounters.atomicGetOrElseUpdate(name, - createMMCounterEntry(instrumentFactory.buildMinMaxCounter(entity, name)) - ).mmCounter - - def minMaxCounter(name: String, measurementUnit: MeasurementUnit, dynamicRange: DynamicRange, sampleFrequency: Duration): MinMaxCounter = - minMaxCounters.atomicGetOrElseUpdate(name, - createMMCounterEntry(instrumentFactory.buildMinMaxCounter(entity, name, dynamicRange, sampleFrequency, measurementUnit)) - ).mmCounter - - def gauge(name: String): Gauge = - gauges.atomicGetOrElseUpdate(name, instrumentFactory.buildGauge(entity, name)) - - def gauge(name: String, measurementUnit: MeasurementUnit): Gauge = - gauges.atomicGetOrElseUpdate(name, instrumentFactory.buildGauge(entity, name, measurementUnit)) - - def counter(name: String): Counter = - counters.atomicGetOrElseUpdate(name, instrumentFactory.buildCounter(entity, name)) - - def counter(name: String, measurementUnit: MeasurementUnit): Counter = - counters.atomicGetOrElseUpdate(name, instrumentFactory.buildCounter(entity, name, measurementUnit)) - - def snapshot(): EntitySnapshot = - new EntitySnapshot( - entity, - histograms = histograms.values.map(_.snapshot()).toSeq, - minMaxCounters = minMaxCounters.values.map(_.mmCounter.snapshot()).toSeq, - gauges = gauges.values.map(_.snapshot()).toSeq, - counters = counters.values.map(_.snapshot()).toSeq - ) - - def cleanup(): Unit = { - minMaxCounters.values.foreach { mmCounter => - Try(mmCounter.refreshFuture.cancel(true)) - } - } - - private case class MinMaxCounterEntry(mmCounter: MinMaxCounter with DistributionSnapshotInstrument, refreshFuture: ScheduledFuture[_]) - - private def createMMCounterEntry(mmCounter: MinMaxCounter with DistributionSnapshotInstrument): MinMaxCounterEntry = { - val refreshFuture = scheduler.schedule(new Runnable { - override def run(): Unit = mmCounter.sample() - }, mmCounter.sampleInterval.toMillis, TimeUnit.MILLISECONDS) - - MinMaxCounterEntry(mmCounter, refreshFuture) - } -}
\ No newline at end of file diff --git a/kamon-core/src/main/scala/kamon/metric/EntitySnapshot.scala b/kamon-core/src/main/scala/kamon/metric/EntitySnapshot.scala deleted file mode 100644 index a7db93eb..00000000 --- a/kamon-core/src/main/scala/kamon/metric/EntitySnapshot.scala +++ /dev/null @@ -1,11 +0,0 @@ -package kamon.metric - -import kamon.metric.instrument.{DistributionSnapshot, SingleValueSnapshot} - -class EntitySnapshot( - val entity: Entity, - val histograms: Seq[DistributionSnapshot], - val minMaxCounters: Seq[DistributionSnapshot], - val gauges: Seq[SingleValueSnapshot], - val counters: Seq[SingleValueSnapshot] -)
\ No newline at end of file diff --git a/kamon-core/src/main/scala/kamon/metric/EntityFilter.scala b/kamon-core/src/main/scala/kamon/metric/Filter.scala index 77fbfc4b..3ad4f7bd 100644 --- a/kamon-core/src/main/scala/kamon/metric/EntityFilter.scala +++ b/kamon-core/src/main/scala/kamon/metric/Filter.scala @@ -4,19 +4,19 @@ package metric import java.util.regex.Pattern import com.typesafe.config.Config -object EntityFilter { - def fromConfig(config: Config): EntityFilter = { +object Filter { + def fromConfig(config: Config): Filter = { val filtersConfig = config.getConfig("kamon.metric.filters") - val acceptUnmatched = filtersConfig.getBoolean("accept-unmatched-categories") + val acceptUnmatched = filtersConfig.getBoolean("accept-unmatched") - val perCategoryFilters = filtersConfig.firstLevelKeys.filter(_ != "accept-unmatched-categories") map { category: String ⇒ - val includes = readFilters(filtersConfig, s"$category.includes") - val excludes = readFilters(filtersConfig, s"$category.excludes") + val perMetricFilter = filtersConfig.firstLevelKeys.filter(_ != "accept-unmatched") map { metricName: String ⇒ + val includes = readFilters(filtersConfig, s"$metricName.includes") + val excludes = readFilters(filtersConfig, s"$metricName.excludes") - (category, new IncludeExcludeNameFilter(includes, excludes)) + (metricName, new IncludeExcludeNameFilter(includes, excludes)) } toMap - new EntityFilter(perCategoryFilters, acceptUnmatched) + new Filter(perMetricFilter, acceptUnmatched) } private def readFilters(filtersConfig: Config, name: String): Seq[NameFilter] = { @@ -37,11 +37,11 @@ object EntityFilter { } } -class EntityFilter(perCategoryFilters: Map[String, NameFilter], acceptUnmatched: Boolean) { - def accept(entity: Entity): Boolean = - perCategoryFilters - .get(entity.category) - .map(_.accept(entity.name)) +class Filter(perMetricFilter: Map[String, NameFilter], acceptUnmatched: Boolean) { + def accept(metricName: String, pattern: String): Boolean = + perMetricFilter + .get(metricName) + .map(_.accept(pattern)) .getOrElse(acceptUnmatched) } @@ -54,10 +54,10 @@ class IncludeExcludeNameFilter(includes: Seq[NameFilter], excludes: Seq[NameFilt includes.exists(_.accept(name)) && !excludes.exists(_.accept(name)) } -class RegexNameFilter(path: String) extends NameFilter { - private val pathRegex = path.r +class RegexNameFilter(pattern: String) extends NameFilter { + private val pathRegex = pattern.r - override def accept(path: String): Boolean = path match { + override def accept(name: String): Boolean = name match { case pathRegex(_*) ⇒ true case _ ⇒ false } diff --git a/kamon-core/src/main/scala/kamon/metric/RecorderRegistry.scala b/kamon-core/src/main/scala/kamon/metric/RecorderRegistry.scala deleted file mode 100644 index fd728b1d..00000000 --- a/kamon-core/src/main/scala/kamon/metric/RecorderRegistry.scala +++ /dev/null @@ -1,61 +0,0 @@ -package kamon -package metric - -import java.util.concurrent.ScheduledThreadPoolExecutor -import java.util.concurrent.atomic.AtomicReference - -import com.typesafe.config.Config -import kamon.metric.instrument.InstrumentFactory - -import scala.collection.concurrent.TrieMap - - -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[EntityFilter]() - 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(EntityFilter.fromConfig(config)) - - val refreshSchedulerPoolSize = config.getInt("kamon.metric.refresh-scheduler-pool-size") - scheduler.setCorePoolSize(refreshSchedulerPoolSize) - } - - private[kamon] def snapshot(): Seq[EntitySnapshot] = { - entities.values.map(_.snapshot()).toSeq - } - - //private[kamon] def diagnosticData -} - -case class RecorderRegistryDiagnostic(entities: Seq[Entity]) - - - - - - - - - diff --git a/kamon-core/src/main/scala/kamon/metric/Registry.scala b/kamon-core/src/main/scala/kamon/metric/Registry.scala new file mode 100644 index 00000000..3f549802 --- /dev/null +++ b/kamon-core/src/main/scala/kamon/metric/Registry.scala @@ -0,0 +1,222 @@ +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")) +} + + + + + diff --git a/kamon-core/src/main/scala/kamon/metric/TickSnapshot.scala b/kamon-core/src/main/scala/kamon/metric/TickSnapshot.scala index f4578965..fe027c91 100644 --- a/kamon-core/src/main/scala/kamon/metric/TickSnapshot.scala +++ b/kamon-core/src/main/scala/kamon/metric/TickSnapshot.scala @@ -2,8 +2,16 @@ package kamon.metric import java.time.Instant -case class TickSnapshot(interval: Interval, entities: Seq[EntitySnapshot]) +import kamon.metric.instrument.{DistributionSnapshot, SingleValueSnapshot} + case class Interval(from: Instant, to: Instant) +case class RegistrySnapshot(histograms: Seq[DistributionSnapshot], minMaxCounters: Seq[DistributionSnapshot], + gauges: Seq[SingleValueSnapshot], counters: Seq[SingleValueSnapshot]) + +case class TickSnapshot(interval: Interval, metrics: RegistrySnapshot) +trait RegistrySnapshotGenerator { + def snapshot(): RegistrySnapshot +} diff --git a/kamon-core/src/main/scala/kamon/metric/instrument/Counter.scala b/kamon-core/src/main/scala/kamon/metric/instrument/Counter.scala index 10b9c3a6..f18e771c 100644 --- a/kamon-core/src/main/scala/kamon/metric/instrument/Counter.scala +++ b/kamon-core/src/main/scala/kamon/metric/instrument/Counter.scala @@ -14,8 +14,8 @@ trait Counter { def increment(times: Long): Unit } -class LongAdderCounter(entity: Entity, name: String, val measurementUnit: MeasurementUnit) - extends Counter with SingleValueSnapshotInstrument with StrictLogging { +class LongAdderCounter(name: String, tags: Map[String, String], val measurementUnit: MeasurementUnit) + extends SnapshotableCounter with StrictLogging { private val adder = new LongAdder() @@ -26,9 +26,9 @@ class LongAdderCounter(entity: Entity, name: String, val measurementUnit: Measur if (times >= 0) adder.add(times) else - logger.warn(s"Ignored attempt to decrement counter [$name] on entity [$entity]") + logger.warn(s"Ignored attempt to decrement counter [$name]") } def snapshot(): SingleValueSnapshot = - SingleValueSnapshot(name, measurementUnit, adder.sumThenReset()) + SingleValueSnapshot(name, tags, measurementUnit, adder.sumThenReset()) } diff --git a/kamon-core/src/main/scala/kamon/metric/instrument/Gauge.scala b/kamon-core/src/main/scala/kamon/metric/instrument/Gauge.scala index 5263d258..acbff912 100644 --- a/kamon-core/src/main/scala/kamon/metric/instrument/Gauge.scala +++ b/kamon-core/src/main/scala/kamon/metric/instrument/Gauge.scala @@ -1,8 +1,6 @@ package kamon.metric.instrument import java.util.concurrent.atomic.AtomicLong - -import kamon.metric.Entity import kamon.util.MeasurementUnit trait Gauge { @@ -16,8 +14,8 @@ trait Gauge { } -class AtomicLongGauge(entity: Entity, name: String, val measurementUnit: MeasurementUnit) - extends Gauge with SingleValueSnapshotInstrument { +class AtomicLongGauge(name: String, tags: Map[String, String], val measurementUnit: MeasurementUnit) + extends SnapshotableGauge { private val currentValue = new AtomicLong(0L) @@ -37,5 +35,5 @@ class AtomicLongGauge(entity: Entity, name: String, val measurementUnit: Measure currentValue.set(value) def snapshot(): SingleValueSnapshot = - SingleValueSnapshot(name, measurementUnit, currentValue.get()) + SingleValueSnapshot(name, tags, measurementUnit, currentValue.get()) } diff --git a/kamon-core/src/main/scala/kamon/metric/instrument/Histogram.scala b/kamon-core/src/main/scala/kamon/metric/instrument/Histogram.scala index 76d4ab65..29fe8c69 100644 --- a/kamon-core/src/main/scala/kamon/metric/instrument/Histogram.scala +++ b/kamon-core/src/main/scala/kamon/metric/instrument/Histogram.scala @@ -1,9 +1,10 @@ -package kamon.metric.instrument +package kamon +package metric +package instrument import java.nio.ByteBuffer import com.typesafe.scalalogging.StrictLogging -import kamon.metric.Entity import kamon.util.MeasurementUnit import org.HdrHistogram.{AtomicHistogramExtension, ZigZag} @@ -16,8 +17,8 @@ trait Histogram { } -class HdrHistogram(entity: Entity, name: String, val measurementUnit: MeasurementUnit, val dynamicRange: DynamicRange) - extends AtomicHistogramExtension(dynamicRange) with Histogram with DistributionSnapshotInstrument with StrictLogging { +class HdrHistogram(name: String, tags: Map[String, String], val measurementUnit: MeasurementUnit, val dynamicRange: DynamicRange) + extends AtomicHistogramExtension(dynamicRange) with SnapshotableHistogram with StrictLogging { def record(value: Long): Unit = tryRecord(value, 1) @@ -30,7 +31,7 @@ class HdrHistogram(entity: Entity, name: String, val measurementUnit: Measuremen recordValueWithCount(value, count) } catch { case anyException: Throwable ⇒ - logger.warn(s"Failed to store value [$value] in histogram [$name] of entity [$entity]. You might need to change " + + logger.warn(s"Failed to store value [$value] in histogram [$name]. You might need to change " + "your dynamic range configuration for this instrument.", anyException) } } @@ -81,7 +82,7 @@ class HdrHistogram(entity: Entity, name: String, val measurementUnit: Measuremen val distribution = new ZigZagCountsDistribution(totalCount, minIndex, maxIndex, ByteBuffer.wrap(zigZagCounts), protectedUnitMagnitude(), protectedSubBucketHalfCount(), protectedSubBucketHalfCountMagnitude()) - DistributionSnapshot(name, measurementUnit, dynamicRange, distribution) + DistributionSnapshot(name, tags, measurementUnit, dynamicRange, distribution) } private class ZigZagCountsDistribution(val count: Long, minIndex: Int, maxIndex: Int, zigZagCounts: ByteBuffer, diff --git a/kamon-core/src/main/scala/kamon/metric/instrument/InstrumentFactory.scala b/kamon-core/src/main/scala/kamon/metric/instrument/InstrumentFactory.scala index 33a34bdf..0e0536c6 100644 --- a/kamon-core/src/main/scala/kamon/metric/instrument/InstrumentFactory.scala +++ b/kamon-core/src/main/scala/kamon/metric/instrument/InstrumentFactory.scala @@ -9,49 +9,36 @@ 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]) { +private[kamon] class InstrumentFactory private (defaultHistogramDynamicRange: DynamicRange, defaultMMCounterDynamicRange: DynamicRange, + defaultMMCounterSampleInterval: Duration, customSettings: Map[String, CustomInstrumentSettings]) { - def buildHistogram(entity: Entity, name: String, dynamicRange: DynamicRange = defaultHistogramDynamicRange, - measurementUnit: MeasurementUnit = MeasurementUnit.none): Histogram with DistributionSnapshotInstrument = { + println("DEFAULT: " + defaultHistogramDynamicRange) - new HdrHistogram( - entity, - name, - measurementUnit, - instrumentDynamicRange(entity, name, dynamicRange) - ) - } + def buildHistogram(dynamicRange: Option[DynamicRange])(name: String, tags: Map[String, String], unit: MeasurementUnit): SnapshotableHistogram = + new HdrHistogram(name, tags, unit, instrumentDynamicRange(name, dynamicRange.getOrElse(defaultHistogramDynamicRange))) - 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) + def buildMinMaxCounter(dynamicRange: Option[DynamicRange], sampleInterval: Option[Duration]) + (name: String, tags: Map[String, String], unit: MeasurementUnit): SnapshotableMinMaxCounter = new PaddedMinMaxCounter( - entity, name, - underlyingHistogram, - instrumentSampleInterval(entity, name, sampleInterval) - ) - } + tags, + buildHistogram(dynamicRange.orElse(Some(defaultMMCounterDynamicRange)))(name, tags, unit), + instrumentSampleInterval(name, sampleInterval.getOrElse(defaultMMCounterSampleInterval)) ) - def buildGauge(entity: Entity, name: String, measurementUnit: MeasurementUnit = MeasurementUnit.none): Gauge with SingleValueSnapshotInstrument = - new AtomicLongGauge(entity, name, measurementUnit) + def buildGauge(name: String, tags: Map[String, String], unit: MeasurementUnit): SnapshotableGauge = + new AtomicLongGauge(name, tags, unit) - def buildCounter(entity: Entity, name: String, measurementUnit: MeasurementUnit = MeasurementUnit.none): Counter with SingleValueSnapshotInstrument = - new LongAdderCounter(entity, name, measurementUnit) + def buildCounter(name: String, tags: Map[String, String], unit: MeasurementUnit): SnapshotableCounter = + new LongAdderCounter(name, tags, unit) - private def instrumentDynamicRange(entity: Entity, instrumentName: String, dynamicRange: DynamicRange): DynamicRange = - customSettings.get((entity.category, instrumentName)).fold(dynamicRange) { cs => + private def instrumentDynamicRange(instrumentName: String, dynamicRange: DynamicRange): DynamicRange = + customSettings.get(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 => + private def instrumentSampleInterval(instrumentName: String, sampleInterval: Duration): Duration = + customSettings.get(instrumentName).fold(sampleInterval) { cs => cs.sampleInterval.getOrElse(sampleInterval) } @@ -73,21 +60,26 @@ object InstrumentFactory { val customSettings = factoryConfig.getConfig("custom-settings") .configurations - .filter(nonEmptyCategories) - .flatMap(buildCustomInstrumentSettings) + .filter(nonEmptySection) + .map(readCustomInstrumentSettings) new InstrumentFactory(histogramDynamicRange, mmCounterDynamicRange, mmCounterSampleInterval, customSettings) } - private def nonEmptyCategories(entry: (String, Config)): Boolean = entry match { + private def nonEmptySection(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 readCustomInstrumentSettings(entry: (String, Config)): (String, CustomInstrumentSettings) = { + val (metricName, metricConfig) = entry + val customSettings = CustomInstrumentSettings( + if (metricConfig.hasPath("lowest-discernible-value")) Some(metricConfig.getLong("lowest-discernible-value")) else None, + if (metricConfig.hasPath("highest-trackable-value")) Some(metricConfig.getLong("highest-trackable-value")) else None, + if (metricConfig.hasPath("significant-value-digits")) Some(metricConfig.getInt("significant-value-digits")) else None, + if (metricConfig.hasPath("sample-interval")) Some(metricConfig.getDuration("sample-interval")) else None + ) + + (metricName -> customSettings) } private def readDynamicRange(config: Config): DynamicRange = @@ -103,12 +95,4 @@ object InstrumentFactory { 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 - ) }
\ No newline at end of file diff --git a/kamon-core/src/main/scala/kamon/metric/instrument/InstrumentSnapshot.scala b/kamon-core/src/main/scala/kamon/metric/instrument/InstrumentSnapshot.scala index ffb00080..1364c2d8 100644 --- a/kamon-core/src/main/scala/kamon/metric/instrument/InstrumentSnapshot.scala +++ b/kamon-core/src/main/scala/kamon/metric/instrument/InstrumentSnapshot.scala @@ -6,13 +6,14 @@ import kamon.util.MeasurementUnit * Snapshot for instruments that internally track a single value. Meant to be used for counters and gauges. * */ -case class SingleValueSnapshot(name: String, measurementUnit: MeasurementUnit, value: Long) +case class SingleValueSnapshot(name: String, tags: Map[String, String], measurementUnit: MeasurementUnit, value: Long) /** * Snapshot for instruments that internally the distribution of values in a defined dynamic range. Meant to be used * with histograms and min max counters. */ -case class DistributionSnapshot(name: String, measurementUnit: MeasurementUnit, dynamicRange: DynamicRange, distribution: Distribution) +case class DistributionSnapshot(name: String, tags: Map[String, String], measurementUnit: MeasurementUnit, + dynamicRange: DynamicRange, distribution: Distribution) trait Distribution { @@ -48,3 +49,9 @@ trait DistributionSnapshotInstrument { trait SingleValueSnapshotInstrument { private[kamon] def snapshot(): SingleValueSnapshot } + +trait SnapshotableHistogram extends Histogram with DistributionSnapshotInstrument +trait SnapshotableMinMaxCounter extends MinMaxCounter with DistributionSnapshotInstrument +trait SnapshotableCounter extends Counter with SingleValueSnapshotInstrument +trait SnapshotableGauge extends Gauge with SingleValueSnapshotInstrument + diff --git a/kamon-core/src/main/scala/kamon/metric/instrument/MinMaxCounter.scala b/kamon-core/src/main/scala/kamon/metric/instrument/MinMaxCounter.scala index cddd8ed9..70094b7b 100644 --- a/kamon-core/src/main/scala/kamon/metric/instrument/MinMaxCounter.scala +++ b/kamon-core/src/main/scala/kamon/metric/instrument/MinMaxCounter.scala @@ -5,7 +5,6 @@ import java.time.Duration import java.util.concurrent.atomic.{AtomicLong, AtomicReference} import kamon.jsr166.LongMaxUpdater -import kamon.metric.Entity import kamon.util.MeasurementUnit trait MinMaxCounter { @@ -21,8 +20,8 @@ trait MinMaxCounter { } -class PaddedMinMaxCounter(entity: Entity, name: String, underlyingHistogram: Histogram with DistributionSnapshotInstrument, - val sampleInterval: Duration) extends MinMaxCounter with DistributionSnapshotInstrument { +class PaddedMinMaxCounter(name: String, tags: Map[String, String], underlyingHistogram: Histogram with DistributionSnapshotInstrument, + val sampleInterval: Duration) extends SnapshotableMinMaxCounter { private val min = new LongMaxUpdater(0L) private val max = new LongMaxUpdater(0L) diff --git a/kamon-core/src/main/scala/kamon/package.scala b/kamon-core/src/main/scala/kamon/package.scala index b65022bc..64a0a72e 100644 --- a/kamon-core/src/main/scala/kamon/package.scala +++ b/kamon-core/src/main/scala/kamon/package.scala @@ -35,6 +35,10 @@ package object kamon { } } + implicit class PrettyPrintTags(val tags: Map[String, String]) extends AnyVal { + def prettyPrint(): String = + tags.map { case (k, v) => k + "=" + v } mkString("{", ",", "}") + } /** * Workaround to the non thread-safe [[scala.collection.concurrent.TrieMap#getOrElseUpdate()]] method. More details on diff --git a/kamon-core/src/main/scala/kamon/trace/Span.scala b/kamon-core/src/main/scala/kamon/trace/Span.scala index 904c0a22..e64d8118 100644 --- a/kamon-core/src/main/scala/kamon/trace/Span.scala +++ b/kamon-core/src/main/scala/kamon/trace/Span.scala @@ -1,11 +1,8 @@ package kamon package trace -import kamon.metric.{Entity, RecorderRegistry} -import kamon.metric.instrument.DynamicRange - import scala.collection.JavaConverters._ -import kamon.util.{Clock, MeasurementUnit} +import kamon.util.Clock object Span { val MetricCategory = "span" @@ -29,7 +26,7 @@ object Span { class Span(spanContext: SpanContext, initialOperationName: String, initialTags: Map[String, String], startTimestampMicros: Long, - recorderRegistry: RecorderRegistry, reporterRegistry: ReporterRegistryImpl) extends io.opentracing.Span { + recorderRegistry: Any, reporterRegistry: ReporterRegistryImpl) extends io.opentracing.Span { private var isOpen: Boolean = true private val sampled: Boolean = spanContext.sampled @@ -156,17 +153,17 @@ class Span(spanContext: SpanContext, initialOperationName: String, initialTags: private def recordSpanMetrics(): Unit = { val elapsedTime = endTimestampMicros - startTimestampMicros - val entity = Entity(operationName, Span.MetricCategory, metricTags) - val recorder = recorderRegistry.getRecorder(entity) - - recorder - .histogram(Span.LatencyMetricName, MeasurementUnit.time.microseconds, DynamicRange.Default) - .record(elapsedTime) - - tags.get("error").foreach { errorTag => - if(errorTag != null && errorTag.equals(Span.BooleanTagTrueValue)) { - recorder.counter(Span.ErrorMetricName).increment() - } - } +// val entity = Entity(operationName, Span.MetricCategory, metricTags) +// val recorder = recorderRegistry.getRecorder(entity) + +// recorder +// .histogram(Span.LatencyMetricName, MeasurementUnit.time.microseconds, DynamicRange.Default) +// .record(elapsedTime) +// +// tags.get("error").foreach { errorTag => +// if(errorTag != null && errorTag.equals(Span.BooleanTagTrueValue)) { +// recorder.counter(Span.ErrorMetricName).increment() +// } +// } } }
\ No newline at end of file diff --git a/kamon-core/src/main/scala/kamon/trace/Tracer.scala b/kamon-core/src/main/scala/kamon/trace/Tracer.scala index 6bb5a252..ed42b810 100644 --- a/kamon-core/src/main/scala/kamon/trace/Tracer.scala +++ b/kamon-core/src/main/scala/kamon/trace/Tracer.scala @@ -7,12 +7,11 @@ import io.opentracing.propagation.{TextMap, Format} import io.opentracing.propagation.Format.Builtin.{BINARY, HTTP_HEADERS, TEXT_MAP} import io.opentracing.util.ThreadLocalActiveSpanSource import kamon.ReporterRegistryImpl -import kamon.metric.{Entity, EntityRecorder, RecorderRegistry} import kamon.util.Clock -class Tracer(metrics: RecorderRegistry, reporterRegistry: ReporterRegistryImpl) extends io.opentracing.Tracer { +class Tracer(metrics: Any, reporterRegistry: ReporterRegistryImpl) extends io.opentracing.Tracer { private val logger = Logger(classOf[Tracer]) - private val metricsRecorder = new TracerMetricsRecorder(metrics.getRecorder(Entity("tracer", "tracer", Map.empty))) + ///private val metricsRecorder = new TracerMetricsRecorder(metrics.getRecorder(Entity("tracer", "tracer", Map.empty))) private val activeSpanSource = new ThreadLocalActiveSpanSource() @volatile private var sampler: Sampler = Sampler.never @@ -118,15 +117,12 @@ class Tracer(metrics: RecorderRegistry, reporterRegistry: ReporterRegistryImpl) new SpanContext(traceID, traceID, 0L, sampler.decide(traceID), initialTags) } - metricsRecorder.createdSpans.increment() - new Span(spanContext, operationName, initialTags, startTimestampMicros, metrics, reporterRegistry) + //metricsRecorder.createdSpans.increment() + new Span(spanContext, operationName, initialTags, startTimestampMicros, ???, reporterRegistry) } private def createID(): Long = ThreadLocalRandom.current().nextLong() } - private class TracerMetricsRecorder(recorder: EntityRecorder) { - val createdSpans = recorder.counter("created-spans") - } } diff --git a/kamon-core/src/test/scala/kamon/LogInterceptor.scala b/kamon-core/src/test/scala/kamon/LogInterceptor.scala index b5b8a79c..abdf6ba8 100644 --- a/kamon-core/src/test/scala/kamon/LogInterceptor.scala +++ b/kamon-core/src/test/scala/kamon/LogInterceptor.scala @@ -1,14 +1,14 @@ package kamon -import uk.org.lidalia.slf4jext.Level -import uk.org.lidalia.slf4jtest.{LoggingEvent, TestLogger} - -trait LogInterceptor { - - def interceptLog[T](level: Level)(code: => T)(implicit tl: TestLogger): Seq[LoggingEvent] = { - import scala.collection.JavaConverters._ - tl.clear() - val run = code - tl.getLoggingEvents().asScala.filter(_.getLevel == level) - } -} +//import uk.org.lidalia.slf4jext.Level +//import uk.org.lidalia.slf4jtest.{LoggingEvent, TestLogger} +// +//trait LogInterceptor { +// +// def interceptLog[T](level: Level)(code: => T)(implicit tl: TestLogger): Seq[LoggingEvent] = { +// import scala.collection.JavaConverters._ +// tl.clear() +// val run = code +// tl.getLoggingEvents().asScala.filter(_.getLevel == level) +// } +//} diff --git a/kamon-core/src/test/scala/kamon/metric/EntityFilterSpec.scala b/kamon-core/src/test/scala/kamon/metric/FilterSpec.scala index 16481ccd..095c9426 100644 --- a/kamon-core/src/test/scala/kamon/metric/EntityFilterSpec.scala +++ b/kamon-core/src/test/scala/kamon/metric/FilterSpec.scala @@ -5,7 +5,7 @@ import com.typesafe.config.ConfigFactory import org.scalatest.{Matchers, WordSpec} -class EntityFilterSpec extends WordSpec with Matchers { +class FilterSpec extends WordSpec with Matchers { val testConfig = ConfigFactory.parseString( """ |kamon.metric.filters { @@ -33,15 +33,15 @@ class EntityFilterSpec extends WordSpec with Matchers { "the entity filters" should { "use the accept-unmatched-categories setting when there is no configuration for a given category" in { - val acceptUnmatched = EntityFilter.fromConfig(ConfigFactory.parseString("kamon.metric.filters.accept-unmatched-categories=true")) - val rejectUnmatched = EntityFilter.fromConfig(ConfigFactory.parseString("kamon.metric.filters.accept-unmatched-categories=false")) + val acceptUnmatched = Filter.fromConfig(ConfigFactory.parseString("kamon.metric.filters.accept-unmatched-categories=true")) + val rejectUnmatched = Filter.fromConfig(ConfigFactory.parseString("kamon.metric.filters.accept-unmatched-categories=false")) acceptUnmatched.accept(Entity("a", "b", Map.empty)) shouldBe true rejectUnmatched.accept(Entity("a", "b", Map.empty)) shouldBe false } "accept entities that are matched by any include and none exclude filters" in { - val entityFilter = EntityFilter.fromConfig(testConfig) + val entityFilter = Filter.fromConfig(testConfig) entityFilter.accept(Entity("anything", "anything", Map.empty)) shouldBe false entityFilter.accept(Entity("anything", "some-category", Map.empty)) shouldBe true @@ -49,7 +49,7 @@ class EntityFilterSpec extends WordSpec with Matchers { } "allow configuring includes only or excludes only for any category" in { - val entityFilter = EntityFilter.fromConfig(testConfig) + val entityFilter = Filter.fromConfig(testConfig) entityFilter.accept(Entity("only-me", "only-includes", Map.empty)) shouldBe true entityFilter.accept(Entity("anything", "only-includes", Map.empty)) shouldBe false @@ -58,7 +58,7 @@ class EntityFilterSpec extends WordSpec with Matchers { } "allow to explicitly decide whether patterns are treated as Glob or Regex" in { - val entityFilter = EntityFilter.fromConfig(testConfig) + val entityFilter = Filter.fromConfig(testConfig) entityFilter.accept(Entity("/user/accepted", "specific-rules", Map.empty)) shouldBe true entityFilter.accept(Entity("/other/rejected/", "specific-rules", Map.empty)) shouldBe false diff --git a/kamon-core/src/test/scala/kamon/metric/instrument/CounterSpec.scala b/kamon-core/src/test/scala/kamon/metric/instrument/CounterSpec.scala index 26b3456d..d76b3613 100644 --- a/kamon-core/src/test/scala/kamon/metric/instrument/CounterSpec.scala +++ b/kamon-core/src/test/scala/kamon/metric/instrument/CounterSpec.scala @@ -1,46 +1,46 @@ package kamon.metric.instrument -import kamon.LogInterceptor -import kamon.metric.Entity -import kamon.testkit.DefaultInstrumentFactory -import org.scalatest.{Matchers, WordSpec} -import uk.org.lidalia.slf4jext.Level -import uk.org.lidalia.slf4jtest.TestLoggerFactory - -class CounterSpec extends WordSpec with Matchers with LogInterceptor with DefaultInstrumentFactory { - implicit val testLogger = TestLoggerFactory.getTestLogger(classOf[LongAdderCounter]) - - "a Counter" should { - - "allow unit and bundled increments" in { - val counter = buildCounter("unit-increments") - counter.increment() - counter.increment() - counter.increment(40) - - counter.snapshot().value shouldBe(42) - } - - "warn the user and ignore attempts to decrement the counter" in { - val counter = buildCounter("attempt-to-decrement") - counter.increment(100) - counter.increment(100) - counter.increment(100) - - interceptLog(Level.WARN) { - counter.increment(-10L) - }.head.getMessage() shouldBe(s"Ignored attempt to decrement counter [attempt-to-decrement] on entity [$defaultEntity]") - - counter.snapshot().value shouldBe(300) - } - - "reset the internal state to zero after taking snapshots" in { - val counter = buildCounter("reset-after-snapshot") - counter.increment() - counter.increment(10) - - counter.snapshot().value shouldBe(11) - counter.snapshot().value shouldBe(0) - } - } -} +//import kamon.LogInterceptor +//import kamon.metric.Entity +//import kamon.testkit.DefaultInstrumentFactory +//import org.scalatest.{Matchers, WordSpec} +//import uk.org.lidalia.slf4jext.Level +//import uk.org.lidalia.slf4jtest.TestLoggerFactory +// +//class CounterSpec extends WordSpec with Matchers with LogInterceptor with DefaultInstrumentFactory { +// implicit val testLogger = TestLoggerFactory.getTestLogger(classOf[LongAdderCounter]) +//// +//// "a Counter" should { +//// +//// "allow unit and bundled increments" in { +//// val counter = buildCounter("unit-increments") +//// counter.increment() +//// counter.increment() +//// counter.increment(40) +//// +//// counter.snapshot().value shouldBe(42) +//// } +//// +//// "warn the user and ignore attempts to decrement the counter" in { +//// val counter = buildCounter("attempt-to-decrement") +//// counter.increment(100) +//// counter.increment(100) +//// counter.increment(100) +//// +//// interceptLog(Level.WARN) { +//// counter.increment(-10L) +//// }.head.getMessage() shouldBe(s"Ignored attempt to decrement counter [attempt-to-decrement] on entity [$defaultEntity]") +//// +//// counter.snapshot().value shouldBe(300) +//// } +//// +//// "reset the internal state to zero after taking snapshots" in { +//// val counter = buildCounter("reset-after-snapshot") +//// counter.increment() +//// counter.increment(10) +//// +//// counter.snapshot().value shouldBe(11) +//// counter.snapshot().value shouldBe(0) +//// } +//// } +//} diff --git a/kamon-core/src/test/scala/kamon/metric/instrument/InstrumentFactorySpec.scala b/kamon-core/src/test/scala/kamon/metric/instrument/InstrumentFactorySpec.scala index eda838d5..21fe2b4d 100644 --- a/kamon-core/src/test/scala/kamon/metric/instrument/InstrumentFactorySpec.scala +++ b/kamon-core/src/test/scala/kamon/metric/instrument/InstrumentFactorySpec.scala @@ -1,114 +1,114 @@ package kamon.metric.instrument -import java.time.Duration - -import com.typesafe.config.ConfigFactory -import kamon.metric.Entity -import org.scalatest.{Matchers, WordSpec} - -class InstrumentFactorySpec extends WordSpec with Matchers{ - val testEntity = Entity("test", "test-category", Map.empty) - val customEntity = Entity("test", "custom-category", Map.empty) - val baseConfiguration = ConfigFactory.parseString( - """ - |kamon.metric.instrument-factory { - | default-settings { - | histogram { - | lowest-discernible-value = 100 - | highest-trackable-value = 5000 - | significant-value-digits = 2 - | } - | - | min-max-counter { - | lowest-discernible-value = 200 - | highest-trackable-value = 6000 - | significant-value-digits = 3 - | sample-interval = 647 millis - | } - | } - | - | custom-settings { - | - | } - |} - """.stripMargin - ) - - - "the metrics InstrumentFactory" should { - "create instruments using the default configuration settings" in { - val factory = InstrumentFactory.fromConfig(baseConfiguration) - val histogram = factory.buildHistogram(testEntity, "my-histogram") - val mmCounter = factory.buildMinMaxCounter(testEntity, "my-mm-counter") - - histogram.dynamicRange.lowestDiscernibleValue shouldBe(100) - histogram.dynamicRange.highestTrackableValue shouldBe(5000) - histogram.dynamicRange.significantValueDigits shouldBe(2) - - mmCounter.dynamicRange.lowestDiscernibleValue shouldBe(200) - mmCounter.dynamicRange.highestTrackableValue shouldBe(6000) - mmCounter.dynamicRange.significantValueDigits shouldBe(3) - mmCounter.sampleInterval shouldBe(Duration.ofMillis(647)) - } - - "accept custom settings when building instruments" in { - val factory = InstrumentFactory.fromConfig(baseConfiguration) - val histogram = factory.buildHistogram(testEntity, "my-histogram", DynamicRange.Loose) - val mmCounter = factory.buildMinMaxCounter(testEntity, "my-mm-counter", DynamicRange.Fine, Duration.ofMillis(500)) - - histogram.dynamicRange shouldBe(DynamicRange.Loose) - - mmCounter.dynamicRange shouldBe(DynamicRange.Fine) - mmCounter.sampleInterval shouldBe(Duration.ofMillis(500)) - } - - "allow overriding any default and provided settings via the custom-settings configuration key" in { - val customConfig = ConfigFactory.parseString( - """ - |kamon.metric.instrument-factory.custom-settings { - | custom-category { - | modified-histogram { - | lowest-discernible-value = 99 - | highest-trackable-value = 999 - | significant-value-digits = 4 - | } - | - | modified-mm-counter { - | lowest-discernible-value = 784 - | highest-trackable-value = 14785 - | significant-value-digits = 1 - | sample-interval = 3 seconds - | } - | } - |} - """.stripMargin - ).withFallback(baseConfiguration) - - val factory = InstrumentFactory.fromConfig(customConfig) - val defaultHistogram = factory.buildHistogram(customEntity, "default-histogram") - val modifiedHistogram = factory.buildHistogram(customEntity, "modified-histogram", DynamicRange.Loose) - - defaultHistogram.dynamicRange.lowestDiscernibleValue shouldBe(100) - defaultHistogram.dynamicRange.highestTrackableValue shouldBe(5000) - defaultHistogram.dynamicRange.significantValueDigits shouldBe(2) - - modifiedHistogram.dynamicRange.lowestDiscernibleValue shouldBe(99) - modifiedHistogram.dynamicRange.highestTrackableValue shouldBe(999) - modifiedHistogram.dynamicRange.significantValueDigits shouldBe(4) - - - val defaultMMCounter = factory.buildMinMaxCounter(customEntity, "default-mm-counter") - val modifiedMMCounter = factory.buildMinMaxCounter(customEntity, "modified-mm-counter", DynamicRange.Loose) - - defaultMMCounter.dynamicRange.lowestDiscernibleValue shouldBe(200) - defaultMMCounter.dynamicRange.highestTrackableValue shouldBe(6000) - defaultMMCounter.dynamicRange.significantValueDigits shouldBe(3) - defaultMMCounter.sampleInterval shouldBe(Duration.ofMillis(647)) - - modifiedMMCounter.dynamicRange.lowestDiscernibleValue shouldBe(784) - modifiedMMCounter.dynamicRange.highestTrackableValue shouldBe(14785) - modifiedMMCounter.dynamicRange.significantValueDigits shouldBe(1) - modifiedMMCounter.sampleInterval shouldBe(Duration.ofSeconds(3)) - } - } -} +//import java.time.Duration +// +//import com.typesafe.config.ConfigFactory +//import kamon.metric.Entity +//import org.scalatest.{Matchers, WordSpec} +// +//class InstrumentFactorySpec extends WordSpec with Matchers{ +// val testEntity = Entity("test", "test-category", Map.empty) +// val customEntity = Entity("test", "custom-category", Map.empty) +// val baseConfiguration = ConfigFactory.parseString( +// """ +// |kamon.metric.instrument-factory { +// | default-settings { +// | histogram { +// | lowest-discernible-value = 100 +// | highest-trackable-value = 5000 +// | significant-value-digits = 2 +// | } +// | +// | min-max-counter { +// | lowest-discernible-value = 200 +// | highest-trackable-value = 6000 +// | significant-value-digits = 3 +// | sample-interval = 647 millis +// | } +// | } +// | +// | custom-settings { +// | +// | } +// |} +// """.stripMargin +// ) +// +// +// "the metrics InstrumentFactory" should { +// "create instruments using the default configuration settings" in { +// val factory = InstrumentFactory.fromConfig(baseConfiguration) +// val histogram = factory.buildHistogram(testEntity, "my-histogram") +// val mmCounter = factory.buildMinMaxCounter(testEntity, "my-mm-counter") +// +// histogram.dynamicRange.lowestDiscernibleValue shouldBe(100) +// histogram.dynamicRange.highestTrackableValue shouldBe(5000) +// histogram.dynamicRange.significantValueDigits shouldBe(2) +// +// mmCounter.dynamicRange.lowestDiscernibleValue shouldBe(200) +// mmCounter.dynamicRange.highestTrackableValue shouldBe(6000) +// mmCounter.dynamicRange.significantValueDigits shouldBe(3) +// mmCounter.sampleInterval shouldBe(Duration.ofMillis(647)) +// } +// +// "accept custom settings when building instruments" in { +// val factory = InstrumentFactory.fromConfig(baseConfiguration) +// val histogram = factory.buildHistogram(testEntity, "my-histogram", DynamicRange.Loose) +// val mmCounter = factory.buildMinMaxCounter(testEntity, "my-mm-counter", DynamicRange.Fine, Duration.ofMillis(500)) +// +// histogram.dynamicRange shouldBe(DynamicRange.Loose) +// +// mmCounter.dynamicRange shouldBe(DynamicRange.Fine) +// mmCounter.sampleInterval shouldBe(Duration.ofMillis(500)) +// } +// +// "allow overriding any default and provided settings via the custom-settings configuration key" in { +// val customConfig = ConfigFactory.parseString( +// """ +// |kamon.metric.instrument-factory.custom-settings { +// | custom-category { +// | modified-histogram { +// | lowest-discernible-value = 99 +// | highest-trackable-value = 999 +// | significant-value-digits = 4 +// | } +// | +// | modified-mm-counter { +// | lowest-discernible-value = 784 +// | highest-trackable-value = 14785 +// | significant-value-digits = 1 +// | sample-interval = 3 seconds +// | } +// | } +// |} +// """.stripMargin +// ).withFallback(baseConfiguration) +// +// val factory = InstrumentFactory.fromConfig(customConfig) +// val defaultHistogram = factory.buildHistogram(customEntity, "default-histogram") +// val modifiedHistogram = factory.buildHistogram(customEntity, "modified-histogram", DynamicRange.Loose) +// +// defaultHistogram.dynamicRange.lowestDiscernibleValue shouldBe(100) +// defaultHistogram.dynamicRange.highestTrackableValue shouldBe(5000) +// defaultHistogram.dynamicRange.significantValueDigits shouldBe(2) +// +// modifiedHistogram.dynamicRange.lowestDiscernibleValue shouldBe(99) +// modifiedHistogram.dynamicRange.highestTrackableValue shouldBe(999) +// modifiedHistogram.dynamicRange.significantValueDigits shouldBe(4) +// +// +// val defaultMMCounter = factory.buildMinMaxCounter(customEntity, "default-mm-counter") +// val modifiedMMCounter = factory.buildMinMaxCounter(customEntity, "modified-mm-counter", DynamicRange.Loose) +// +// defaultMMCounter.dynamicRange.lowestDiscernibleValue shouldBe(200) +// defaultMMCounter.dynamicRange.highestTrackableValue shouldBe(6000) +// defaultMMCounter.dynamicRange.significantValueDigits shouldBe(3) +// defaultMMCounter.sampleInterval shouldBe(Duration.ofMillis(647)) +// +// modifiedMMCounter.dynamicRange.lowestDiscernibleValue shouldBe(784) +// modifiedMMCounter.dynamicRange.highestTrackableValue shouldBe(14785) +// modifiedMMCounter.dynamicRange.significantValueDigits shouldBe(1) +// modifiedMMCounter.sampleInterval shouldBe(Duration.ofSeconds(3)) +// } +// } +//} diff --git a/kamon-core/src/test/scala/kamon/testkit/DefaultInstrumentFactory.scala b/kamon-core/src/test/scala/kamon/testkit/DefaultInstrumentFactory.scala index 6fd193d6..88a95936 100644 --- a/kamon-core/src/test/scala/kamon/testkit/DefaultInstrumentFactory.scala +++ b/kamon-core/src/test/scala/kamon/testkit/DefaultInstrumentFactory.scala @@ -1,13 +1,12 @@ package kamon.testkit import com.typesafe.config.ConfigFactory -import kamon.metric.Entity import kamon.metric.instrument.InstrumentFactory trait DefaultInstrumentFactory { val defaultEntity = Entity("default-entity", "default-category", Map.empty) val instrumentFactory = InstrumentFactory.fromConfig(ConfigFactory.load()) - def buildCounter(name: String) = instrumentFactory.buildCounter(defaultEntity, name) + def buildCounter(name: String) = ???//instrumentFactory.buildCounter(defaultEntity, name) } |