From a4deb46e942241a8922152de4eaf5725996c6669 Mon Sep 17 00:00:00 2001 From: Ivan Topolnjak Date: Thu, 5 Mar 2015 23:39:44 +0100 Subject: ! all: introduced support for metric tags. --- kamon-core/src/main/scala/kamon/Kamon.scala | 12 +- .../src/main/scala/kamon/metric/Entity.scala | 27 +-- .../main/scala/kamon/metric/EntityRecorder.scala | 103 ++++++-- .../src/main/scala/kamon/metric/MetricKey.scala | 120 +-------- .../src/main/scala/kamon/metric/Metrics.scala | 269 +++++++++++++++++++-- .../main/scala/kamon/metric/SimpleMetrics.scala | 204 ---------------- .../src/main/scala/kamon/metric/TraceMetrics.scala | 27 ++- .../main/scala/kamon/metric/instrument/Gauge.scala | 4 + .../scala/kamon/trace/MetricsOnlyContext.scala | 26 +- kamon-core/src/main/scala/kamon/trace/Tracer.scala | 4 +- .../main/scala/kamon/trace/TracingContext.scala | 5 +- .../scala/kamon/util/FunctionalInterfaces.scala | 9 + .../scala/kamon/metric/SimpleMetricsSpec.scala | 74 +++--- .../kamon/metric/SubscriptionsProtocolSpec.scala | 20 +- .../metric/TickMetricSnapshotBufferSpec.scala | 14 +- .../test/scala/kamon/metric/TraceMetricsSpec.scala | 42 ++-- .../test/scala/kamon/testkit/BaseKamonSpec.scala | 7 +- 17 files changed, 454 insertions(+), 513 deletions(-) delete mode 100644 kamon-core/src/main/scala/kamon/metric/SimpleMetrics.scala create mode 100644 kamon-core/src/main/scala/kamon/util/FunctionalInterfaces.scala (limited to 'kamon-core') diff --git a/kamon-core/src/main/scala/kamon/Kamon.scala b/kamon-core/src/main/scala/kamon/Kamon.scala index a2a24f49..a6469039 100644 --- a/kamon-core/src/main/scala/kamon/Kamon.scala +++ b/kamon-core/src/main/scala/kamon/Kamon.scala @@ -18,15 +18,13 @@ import _root_.akka.actor import _root_.akka.actor._ import com.typesafe.config.{ ConfigFactory, Config } import kamon.metric._ +import kamon.metric.instrument.Gauge import kamon.trace.{ TracerImpl, Tracer } object Kamon { trait Extension extends actor.Extension - private case class KamonCoreComponents( - metrics: Metrics, - tracer: Tracer, - simpleMetrics: SimpleMetrics) + private case class KamonCoreComponents(metrics: Metrics, tracer: Tracer) @volatile private var _system: ActorSystem = _ @volatile private var _coreComponents: Option[KamonCoreComponents] = None @@ -43,10 +41,9 @@ object Kamon { if (_coreComponents.isEmpty) { val metrics = MetricsImpl(config) - val simpleMetrics = SimpleMetricsImpl(metrics) val tracer = TracerImpl(metrics, config) - _coreComponents = Some(KamonCoreComponents(metrics, tracer, simpleMetrics)) + _coreComponents = Some(KamonCoreComponents(metrics, tracer)) _system = ActorSystem("kamon", resolveInternalConfig) metrics.start(_system) @@ -70,9 +67,6 @@ object Kamon { def tracer: Tracer = ifStarted(_.tracer) - def simpleMetrics: SimpleMetrics = - ifStarted(_.simpleMetrics) - def apply[T <: Kamon.Extension](key: ExtensionId[T]): T = ifStarted { _ ⇒ if (_system ne null) diff --git a/kamon-core/src/main/scala/kamon/metric/Entity.scala b/kamon-core/src/main/scala/kamon/metric/Entity.scala index 8d328f83..91249af0 100644 --- a/kamon-core/src/main/scala/kamon/metric/Entity.scala +++ b/kamon-core/src/main/scala/kamon/metric/Entity.scala @@ -23,36 +23,15 @@ package kamon.metric * * // TODO: Find a better word for `thing`. */ -class Entity(val name: String, val category: String, val metadata: Map[String, String]) { - - override def equals(o: Any): Boolean = { - if (this eq o.asInstanceOf[AnyRef]) - true - else if ((o.asInstanceOf[AnyRef] eq null) || !o.isInstanceOf[Entity]) - false - else { - val thatAsEntity = o.asInstanceOf[Entity] - category == thatAsEntity.category && name == thatAsEntity.name - } - } - - override def hashCode: Int = { - var result: Int = name.hashCode - result = 31 * result + category.hashCode - return result - } -} +case class Entity(name: String, category: String, tags: Map[String, String]) object Entity { def apply(name: String, category: String): Entity = apply(name, category, Map.empty) - def apply(name: String, category: String, metadata: Map[String, String]): Entity = - new Entity(name, category, metadata) - def create(name: String, category: String): Entity = apply(name, category, Map.empty) - def create(name: String, category: String, metadata: Map[String, String]): Entity = - new Entity(name, category, metadata) + def create(name: String, category: String, tags: Map[String, String]): Entity = + new Entity(name, category, tags) } \ No newline at end of file diff --git a/kamon-core/src/main/scala/kamon/metric/EntityRecorder.scala b/kamon-core/src/main/scala/kamon/metric/EntityRecorder.scala index 6e0a4248..65dafa9a 100644 --- a/kamon-core/src/main/scala/kamon/metric/EntityRecorder.scala +++ b/kamon-core/src/main/scala/kamon/metric/EntityRecorder.scala @@ -19,6 +19,7 @@ package kamon.metric import kamon.metric.instrument.Gauge.CurrentValueCollector import kamon.metric.instrument.Histogram.DynamicRange import kamon.metric.instrument._ +import kamon.util.Function import scala.collection.concurrent.TrieMap import scala.concurrent.duration.FiniteDuration @@ -33,6 +34,64 @@ trait EntityRecorderFactory[T <: EntityRecorder] { def createRecorder(instrumentFactory: InstrumentFactory): T } +object EntityRecorderFactory { + def apply[T <: EntityRecorder](entityCategory: String, factory: InstrumentFactory ⇒ T): EntityRecorderFactory[T] = + new EntityRecorderFactory[T] { + def category: String = entityCategory + def createRecorder(instrumentFactory: InstrumentFactory): T = factory(instrumentFactory) + } + + def create[T <: EntityRecorder](entityCategory: String, factory: Function[InstrumentFactory, T]): EntityRecorderFactory[T] = + new EntityRecorderFactory[T] { + def category: String = entityCategory + def createRecorder(instrumentFactory: InstrumentFactory): T = factory(instrumentFactory) + } +} + +private[kamon] sealed trait SingleInstrumentEntityRecorder extends EntityRecorder { + def key: MetricKey + def instrument: Instrument + + def collect(collectionContext: CollectionContext): EntitySnapshot = + new DefaultEntitySnapshot(Map(key -> instrument.collect(collectionContext))) + + def cleanup: Unit = instrument.cleanup +} + +object SingleInstrumentEntityRecorder { + val Histogram = "histogram" + val MinMaxCounter = "min-max-counter" + val Gauge = "gauge" + val Counter = "counter" + + val AllCategories = List("histogram", "gauge", "counter", "min-max-counter") +} + +/** + * Entity recorder for a single Counter instrument. + */ +case class CounterRecorder(key: MetricKey, instrument: Counter) extends SingleInstrumentEntityRecorder + +/** + * Entity recorder for a single Histogram instrument. + */ +case class HistogramRecorder(key: MetricKey, instrument: Histogram) extends SingleInstrumentEntityRecorder + +/** + * Entity recorder for a single MinMaxCounter instrument. + */ +case class MinMaxCounterRecorder(key: MetricKey, instrument: MinMaxCounter) extends SingleInstrumentEntityRecorder + +/** + * Entity recorder for a single Gauge instrument. + */ +case class GaugeRecorder(key: MetricKey, instrument: Gauge) extends SingleInstrumentEntityRecorder + +/** + * Base class with plenty of utility methods to facilitate the creation of [[EntityRecorder]] implementations. + * It is not required to use this base class for defining custom a custom [[EntityRecorder]], but it is certainly + * the most convenient way to do it and the preferred approach throughout the Kamon codebase. + */ abstract class GenericEntityRecorder(instrumentFactory: InstrumentFactory) extends EntityRecorder { import kamon.util.TriemapAtomicGetOrElseUpdate.Syntax @@ -41,10 +100,10 @@ abstract class GenericEntityRecorder(instrumentFactory: InstrumentFactory) exten _instruments.atomicGetOrElseUpdate(key, instrument, _.cleanup).asInstanceOf[T] protected def histogram(name: String): Histogram = - register(HistogramKey(name), instrumentFactory.createHistogram(name)) + register(HistogramKey(name, UnitOfMeasurement.Unknown), instrumentFactory.createHistogram(name)) protected def histogram(name: String, dynamicRange: DynamicRange): Histogram = - register(HistogramKey(name), instrumentFactory.createHistogram(name, Some(dynamicRange))) + register(HistogramKey(name, UnitOfMeasurement.Unknown), instrumentFactory.createHistogram(name, Some(dynamicRange))) protected def histogram(name: String, unitOfMeasurement: UnitOfMeasurement): Histogram = register(HistogramKey(name, unitOfMeasurement), instrumentFactory.createHistogram(name)) @@ -52,32 +111,26 @@ abstract class GenericEntityRecorder(instrumentFactory: InstrumentFactory) exten protected def histogram(name: String, dynamicRange: DynamicRange, unitOfMeasurement: UnitOfMeasurement): Histogram = register(HistogramKey(name, unitOfMeasurement), instrumentFactory.createHistogram(name, Some(dynamicRange))) - protected def histogram(key: HistogramKey): Histogram = - register(key, instrumentFactory.createHistogram(key.name)) - - protected def histogram(key: HistogramKey, dynamicRange: DynamicRange): Histogram = - register(key, instrumentFactory.createHistogram(key.name, Some(dynamicRange))) - protected def removeHistogram(name: String): Unit = - _instruments.remove(HistogramKey(name)) + _instruments.remove(HistogramKey(name, UnitOfMeasurement.Unknown)) - protected def removeHistogram(key: HistogramKey): Unit = - _instruments.remove(key) + protected def removeHistogram(name: String, unitOfMeasurement: UnitOfMeasurement): Unit = + _instruments.remove(HistogramKey(name, unitOfMeasurement)) protected def minMaxCounter(name: String): MinMaxCounter = - register(MinMaxCounterKey(name), instrumentFactory.createMinMaxCounter(name)) + register(MinMaxCounterKey(name, UnitOfMeasurement.Unknown), instrumentFactory.createMinMaxCounter(name)) protected def minMaxCounter(name: String, dynamicRange: DynamicRange): MinMaxCounter = - register(MinMaxCounterKey(name), instrumentFactory.createMinMaxCounter(name, Some(dynamicRange))) + register(MinMaxCounterKey(name, UnitOfMeasurement.Unknown), instrumentFactory.createMinMaxCounter(name, Some(dynamicRange))) protected def minMaxCounter(name: String, refreshInterval: FiniteDuration): MinMaxCounter = - register(MinMaxCounterKey(name), instrumentFactory.createMinMaxCounter(name, refreshInterval = Some(refreshInterval))) + register(MinMaxCounterKey(name, UnitOfMeasurement.Unknown), instrumentFactory.createMinMaxCounter(name, refreshInterval = Some(refreshInterval))) protected def minMaxCounter(name: String, unitOfMeasurement: UnitOfMeasurement): MinMaxCounter = register(MinMaxCounterKey(name, unitOfMeasurement), instrumentFactory.createMinMaxCounter(name)) protected def minMaxCounter(name: String, dynamicRange: DynamicRange, refreshInterval: FiniteDuration): MinMaxCounter = - register(MinMaxCounterKey(name), instrumentFactory.createMinMaxCounter(name, Some(dynamicRange), Some(refreshInterval))) + register(MinMaxCounterKey(name, UnitOfMeasurement.Unknown), instrumentFactory.createMinMaxCounter(name, Some(dynamicRange), Some(refreshInterval))) protected def minMaxCounter(name: String, dynamicRange: DynamicRange, unitOfMeasurement: UnitOfMeasurement): MinMaxCounter = register(MinMaxCounterKey(name, unitOfMeasurement), instrumentFactory.createMinMaxCounter(name, Some(dynamicRange))) @@ -86,7 +139,7 @@ abstract class GenericEntityRecorder(instrumentFactory: InstrumentFactory) exten register(MinMaxCounterKey(name, unitOfMeasurement), instrumentFactory.createMinMaxCounter(name, refreshInterval = Some(refreshInterval))) protected def minMaxCounter(name: String, dynamicRange: DynamicRange, refreshInterval: FiniteDuration, unitOfMeasurement: UnitOfMeasurement): MinMaxCounter = - register(MinMaxCounterKey(name), instrumentFactory.createMinMaxCounter(name, Some(dynamicRange), Some(refreshInterval))) + register(MinMaxCounterKey(name, UnitOfMeasurement.Unknown), instrumentFactory.createMinMaxCounter(name, Some(dynamicRange), Some(refreshInterval))) protected def minMaxCounter(key: MinMaxCounterKey): MinMaxCounter = register(key, instrumentFactory.createMinMaxCounter(key.name)) @@ -101,31 +154,31 @@ abstract class GenericEntityRecorder(instrumentFactory: InstrumentFactory) exten register(key, instrumentFactory.createMinMaxCounter(key.name, Some(dynamicRange), Some(refreshInterval))) protected def removeMinMaxCounter(name: String): Unit = - _instruments.remove(MinMaxCounterKey(name)) + _instruments.remove(MinMaxCounterKey(name, UnitOfMeasurement.Unknown)) protected def removeMinMaxCounter(key: MinMaxCounterKey): Unit = _instruments.remove(key) protected def gauge(name: String, valueCollector: CurrentValueCollector): Gauge = - register(GaugeKey(name), instrumentFactory.createGauge(name, valueCollector = valueCollector)) + register(GaugeKey(name, UnitOfMeasurement.Unknown), instrumentFactory.createGauge(name, valueCollector = valueCollector)) protected def gauge(name: String, dynamicRange: DynamicRange, valueCollector: CurrentValueCollector): Gauge = - register(GaugeKey(name), instrumentFactory.createGauge(name, Some(dynamicRange), valueCollector = valueCollector)) + register(GaugeKey(name, UnitOfMeasurement.Unknown), instrumentFactory.createGauge(name, Some(dynamicRange), valueCollector = valueCollector)) protected def gauge(name: String, refreshInterval: FiniteDuration, valueCollector: CurrentValueCollector): Gauge = - register(GaugeKey(name), instrumentFactory.createGauge(name, refreshInterval = Some(refreshInterval), valueCollector = valueCollector)) + register(GaugeKey(name, UnitOfMeasurement.Unknown), instrumentFactory.createGauge(name, refreshInterval = Some(refreshInterval), valueCollector = valueCollector)) protected def gauge(name: String, unitOfMeasurement: UnitOfMeasurement, valueCollector: CurrentValueCollector): Gauge = register(GaugeKey(name, unitOfMeasurement), instrumentFactory.createGauge(name, valueCollector = valueCollector)) protected def gauge(name: String, dynamicRange: DynamicRange, refreshInterval: FiniteDuration, valueCollector: CurrentValueCollector): Gauge = - register(GaugeKey(name), instrumentFactory.createGauge(name, Some(dynamicRange), Some(refreshInterval), valueCollector = valueCollector)) + register(GaugeKey(name, UnitOfMeasurement.Unknown), instrumentFactory.createGauge(name, Some(dynamicRange), Some(refreshInterval), valueCollector = valueCollector)) protected def gauge(name: String, dynamicRange: DynamicRange, unitOfMeasurement: UnitOfMeasurement, valueCollector: CurrentValueCollector): Gauge = register(GaugeKey(name, unitOfMeasurement), instrumentFactory.createGauge(name, Some(dynamicRange), valueCollector = valueCollector)) protected def gauge(name: String, refreshInterval: FiniteDuration, unitOfMeasurement: UnitOfMeasurement, valueCollector: CurrentValueCollector): Gauge = - register(GaugeKey(name), instrumentFactory.createGauge(name, refreshInterval = Some(refreshInterval), valueCollector = valueCollector)) + register(GaugeKey(name, UnitOfMeasurement.Unknown), instrumentFactory.createGauge(name, refreshInterval = Some(refreshInterval), valueCollector = valueCollector)) protected def gauge(name: String, dynamicRange: DynamicRange, refreshInterval: FiniteDuration, unitOfMeasurement: UnitOfMeasurement, valueCollector: CurrentValueCollector): Gauge = register(GaugeKey(name, unitOfMeasurement), instrumentFactory.createGauge(name, Some(dynamicRange), Some(refreshInterval), valueCollector)) @@ -143,19 +196,19 @@ abstract class GenericEntityRecorder(instrumentFactory: InstrumentFactory) exten register(key, instrumentFactory.createGauge(key.name, Some(dynamicRange), Some(refreshInterval), valueCollector = valueCollector)) protected def removeGauge(name: String): Unit = - _instruments.remove(GaugeKey(name)) + _instruments.remove(GaugeKey(name, UnitOfMeasurement.Unknown)) protected def removeGauge(key: GaugeKey): Unit = _instruments.remove(key) protected def counter(name: String): Counter = - register(CounterKey(name), instrumentFactory.createCounter()) + register(CounterKey(name, UnitOfMeasurement.Unknown), instrumentFactory.createCounter()) protected def counter(key: CounterKey): Counter = register(key, instrumentFactory.createCounter()) protected def removeCounter(name: String): Unit = - _instruments.remove(CounterKey(name)) + _instruments.remove(CounterKey(name, UnitOfMeasurement.Unknown)) protected def removeCounter(key: CounterKey): Unit = _instruments.remove(key) diff --git a/kamon-core/src/main/scala/kamon/metric/MetricKey.scala b/kamon-core/src/main/scala/kamon/metric/MetricKey.scala index c655665b..2c710a19 100644 --- a/kamon-core/src/main/scala/kamon/metric/MetricKey.scala +++ b/kamon-core/src/main/scala/kamon/metric/MetricKey.scala @@ -26,144 +26,32 @@ sealed trait MetricKey { def name: String def unitOfMeasurement: UnitOfMeasurement def instrumentType: InstrumentType - def metadata: Map[String, String] } -// Wish that there was a shorter way to describe the operations bellow, but apparently there is no way to generalize all -// the apply/create versions that would produce the desired return types when used from Java. - /** * MetricKey for all Histogram-based metrics. */ -case class HistogramKey(name: String, unitOfMeasurement: UnitOfMeasurement, metadata: Map[String, String]) extends MetricKey { +private[kamon] case class HistogramKey(name: String, unitOfMeasurement: UnitOfMeasurement) extends MetricKey { val instrumentType = InstrumentTypes.Histogram } -object HistogramKey { - def apply(name: String): HistogramKey = - apply(name, UnitOfMeasurement.Unknown) - - def apply(name: String, unitOfMeasurement: UnitOfMeasurement): HistogramKey = - apply(name, unitOfMeasurement, Map.empty) - - def apply(name: String, metadata: Map[String, String]): HistogramKey = - apply(name, UnitOfMeasurement.Unknown, metadata) - - /** - * Java friendly versions: - */ - - def create(name: String): HistogramKey = - apply(name, UnitOfMeasurement.Unknown) - - def create(name: String, unitOfMeasurement: UnitOfMeasurement): HistogramKey = - apply(name, unitOfMeasurement) - - def create(name: String, metadata: Map[String, String]): HistogramKey = - apply(name, metadata) - - def create(name: String, unitOfMeasurement: UnitOfMeasurement, metadata: Map[String, String]): HistogramKey = - apply(name, unitOfMeasurement, metadata) -} - /** * MetricKey for all MinMaxCounter-based metrics. */ -case class MinMaxCounterKey(name: String, unitOfMeasurement: UnitOfMeasurement, metadata: Map[String, String]) extends MetricKey { +case class MinMaxCounterKey(name: String, unitOfMeasurement: UnitOfMeasurement) extends MetricKey { val instrumentType = InstrumentTypes.MinMaxCounter } -object MinMaxCounterKey { - def apply(name: String): MinMaxCounterKey = - apply(name, UnitOfMeasurement.Unknown) - - def apply(name: String, unitOfMeasurement: UnitOfMeasurement): MinMaxCounterKey = - apply(name, unitOfMeasurement, Map.empty) - - def apply(name: String, metadata: Map[String, String]): MinMaxCounterKey = - apply(name, UnitOfMeasurement.Unknown, metadata) - - /** - * Java friendly versions: - */ - - def create(name: String): MinMaxCounterKey = - apply(name, UnitOfMeasurement.Unknown) - - def create(name: String, unitOfMeasurement: UnitOfMeasurement): MinMaxCounterKey = - apply(name, unitOfMeasurement) - - def create(name: String, metadata: Map[String, String]): MinMaxCounterKey = - apply(name, metadata) - - def create(name: String, unitOfMeasurement: UnitOfMeasurement, metadata: Map[String, String]): MinMaxCounterKey = - apply(name, unitOfMeasurement, metadata) -} - /** * MetricKey for all Gauge-based metrics. */ -case class GaugeKey(name: String, unitOfMeasurement: UnitOfMeasurement, metadata: Map[String, String]) extends MetricKey { +case class GaugeKey(name: String, unitOfMeasurement: UnitOfMeasurement) extends MetricKey { val instrumentType = InstrumentTypes.Gauge } -object GaugeKey { - def apply(name: String): GaugeKey = - apply(name, UnitOfMeasurement.Unknown) - - def apply(name: String, unitOfMeasurement: UnitOfMeasurement): GaugeKey = - apply(name, unitOfMeasurement, Map.empty) - - def apply(name: String, metadata: Map[String, String]): GaugeKey = - apply(name, UnitOfMeasurement.Unknown, metadata) - - /** - * Java friendly versions: - */ - - def create(name: String): GaugeKey = - apply(name, UnitOfMeasurement.Unknown) - - def create(name: String, unitOfMeasurement: UnitOfMeasurement): GaugeKey = - apply(name, unitOfMeasurement) - - def create(name: String, metadata: Map[String, String]): GaugeKey = - apply(name, metadata) - - def create(name: String, unitOfMeasurement: UnitOfMeasurement, metadata: Map[String, String]): GaugeKey = - apply(name, unitOfMeasurement, metadata) -} - /** * MetricKey for all Counter-based metrics. */ -case class CounterKey(name: String, unitOfMeasurement: UnitOfMeasurement, metadata: Map[String, String]) extends MetricKey { +case class CounterKey(name: String, unitOfMeasurement: UnitOfMeasurement) extends MetricKey { val instrumentType = InstrumentTypes.Counter } - -object CounterKey { - def apply(name: String): CounterKey = - apply(name, UnitOfMeasurement.Unknown) - - def apply(name: String, unitOfMeasurement: UnitOfMeasurement): CounterKey = - apply(name, unitOfMeasurement, Map.empty) - - def apply(name: String, metadata: Map[String, String]): CounterKey = - apply(name, UnitOfMeasurement.Unknown, metadata) - - /** - * Java friendly versions: - */ - - def create(name: String): CounterKey = - apply(name, UnitOfMeasurement.Unknown) - - def create(name: String, unitOfMeasurement: UnitOfMeasurement): CounterKey = - apply(name, unitOfMeasurement) - - def create(name: String, metadata: Map[String, String]): CounterKey = - apply(name, metadata) - - def create(name: String, unitOfMeasurement: UnitOfMeasurement, metadata: Map[String, String]): CounterKey = - apply(name, unitOfMeasurement, metadata) -} \ No newline at end of file diff --git a/kamon-core/src/main/scala/kamon/metric/Metrics.scala b/kamon-core/src/main/scala/kamon/metric/Metrics.scala index d79b1de3..6a976a1c 100644 --- a/kamon-core/src/main/scala/kamon/metric/Metrics.scala +++ b/kamon-core/src/main/scala/kamon/metric/Metrics.scala @@ -18,26 +18,195 @@ package kamon.metric import com.typesafe.config.Config import kamon.metric.SubscriptionsDispatcher.{ Unsubscribe, Subscribe } -import kamon.metric.instrument.{ DefaultRefreshScheduler, InstrumentFactory, CollectionContext } +import kamon.metric.instrument.Gauge.CurrentValueCollector +import kamon.metric.instrument.Histogram.DynamicRange +import kamon.metric.instrument._ import scala.collection.concurrent.TrieMap import akka.actor._ -import kamon.util.{ LazyActorRef, TriemapAtomicGetOrElseUpdate } +import kamon.util.{ Supplier, LazyActorRef, TriemapAtomicGetOrElseUpdate } + +import scala.concurrent.duration.FiniteDuration case class EntityRegistration[T <: EntityRecorder](entity: Entity, recorder: T) trait Metrics { def settings: MetricsSettings + def shouldTrack(entity: Entity): Boolean + def shouldTrack(entityName: String, category: String): Boolean = shouldTrack(Entity(entityName, category)) - def register[T <: EntityRecorder](recorderFactory: EntityRecorderFactory[T], entityName: String): Option[EntityRegistration[T]] - def register[T <: EntityRecorder](entity: Entity, recorder: T): EntityRegistration[T] - def unregister(entity: Entity): Unit + // + // Histograms registration and removal + // + + def histogram(name: String): Histogram = + registerHistogram(name) + + def histogram(name: String, unitOfMeasurement: UnitOfMeasurement): Histogram = + registerHistogram(name, unitOfMeasurement = Some(unitOfMeasurement)) + + def histogram(name: String, dynamicRange: DynamicRange): Histogram = + registerHistogram(name, dynamicRange = Some(dynamicRange)) + + def histogram(name: String, unitOfMeasurement: UnitOfMeasurement, dynamicRange: DynamicRange): Histogram = + registerHistogram(name, unitOfMeasurement = Some(unitOfMeasurement), dynamicRange = Some(dynamicRange)) + + def histogram(name: String, tags: Map[String, String]): Histogram = + registerHistogram(name, tags) + + def histogram(name: String, tags: Map[String, String], unitOfMeasurement: UnitOfMeasurement): Histogram = + registerHistogram(name, tags, Some(unitOfMeasurement)) + + def histogram(name: String, tags: Map[String, String], dynamicRange: DynamicRange): Histogram = + registerHistogram(name, tags, dynamicRange = Some(dynamicRange)) + + def histogram(name: String, tags: Map[String, String], unitOfMeasurement: UnitOfMeasurement, dynamicRange: DynamicRange): Histogram = + registerHistogram(name, tags, Some(unitOfMeasurement), Some(dynamicRange)) + + def removeHistogram(name: String): Boolean = + removeHistogram(name, Map.empty) + + def registerHistogram(name: String, tags: Map[String, String] = Map.empty, unitOfMeasurement: Option[UnitOfMeasurement] = None, + dynamicRange: Option[DynamicRange] = None): Histogram + + def removeHistogram(name: String, tags: Map[String, String]): Boolean + + // + // MinMaxCounter registration and removal + // + + def minMaxCounter(name: String): MinMaxCounter = + registerMinMaxCounter(name) + + def minMaxCounter(name: String, unitOfMeasurement: UnitOfMeasurement): MinMaxCounter = + registerMinMaxCounter(name, unitOfMeasurement = Some(unitOfMeasurement)) + + def minMaxCounter(name: String, dynamicRange: DynamicRange): MinMaxCounter = + registerMinMaxCounter(name, dynamicRange = Some(dynamicRange)) + + def minMaxCounter(name: String, refreshInterval: FiniteDuration): MinMaxCounter = + registerMinMaxCounter(name, refreshInterval = Some(refreshInterval)) + + def minMaxCounter(name: String, dynamicRange: DynamicRange, refreshInterval: FiniteDuration): MinMaxCounter = + registerMinMaxCounter(name, dynamicRange = Some(dynamicRange), refreshInterval = Some(refreshInterval)) + + def minMaxCounter(name: String, unitOfMeasurement: UnitOfMeasurement, dynamicRange: DynamicRange): MinMaxCounter = + registerMinMaxCounter(name, unitOfMeasurement = Some(unitOfMeasurement), dynamicRange = Some(dynamicRange)) + + def minMaxCounter(name: String, tags: Map[String, String]): MinMaxCounter = + registerMinMaxCounter(name, tags) + + def minMaxCounter(name: String, tags: Map[String, String], unitOfMeasurement: UnitOfMeasurement): MinMaxCounter = + registerMinMaxCounter(name, tags, Some(unitOfMeasurement)) + + def minMaxCounter(name: String, tags: Map[String, String], dynamicRange: DynamicRange): MinMaxCounter = + registerMinMaxCounter(name, tags, dynamicRange = Some(dynamicRange)) + + def minMaxCounter(name: String, tags: Map[String, String], unitOfMeasurement: UnitOfMeasurement, dynamicRange: DynamicRange): MinMaxCounter = + registerMinMaxCounter(name, tags, Some(unitOfMeasurement), Some(dynamicRange)) + + def removeMinMaxCounter(name: String): Boolean = + removeMinMaxCounter(name, Map.empty) + + def removeMinMaxCounter(name: String, tags: Map[String, String]): Boolean + + def registerMinMaxCounter(name: String, tags: Map[String, String] = Map.empty, unitOfMeasurement: Option[UnitOfMeasurement] = None, + dynamicRange: Option[DynamicRange] = None, refreshInterval: Option[FiniteDuration] = None): MinMaxCounter + + // + // Gauge registration and removal + // + + def gauge(name: String)(valueCollector: CurrentValueCollector): Gauge = + registerGauge(name, valueCollector) + + def gauge(name: String, unitOfMeasurement: UnitOfMeasurement)(valueCollector: CurrentValueCollector): Gauge = + registerGauge(name, valueCollector, unitOfMeasurement = Some(unitOfMeasurement)) + + def gauge(name: String, dynamicRange: DynamicRange)(valueCollector: CurrentValueCollector): Gauge = + registerGauge(name, valueCollector, dynamicRange = Some(dynamicRange)) + + def gauge(name: String, refreshInterval: FiniteDuration)(valueCollector: CurrentValueCollector): Gauge = + registerGauge(name, valueCollector, refreshInterval = Some(refreshInterval)) + + def gauge(name: String, dynamicRange: DynamicRange, refreshInterval: FiniteDuration)(valueCollector: CurrentValueCollector): Gauge = + registerGauge(name, valueCollector, dynamicRange = Some(dynamicRange), refreshInterval = Some(refreshInterval)) + + def gauge(name: String, unitOfMeasurement: UnitOfMeasurement, dynamicRange: DynamicRange)(valueCollector: CurrentValueCollector): Gauge = + registerGauge(name, valueCollector, unitOfMeasurement = Some(unitOfMeasurement), dynamicRange = Some(dynamicRange)) + + def gauge(name: String, tags: Map[String, String])(valueCollector: CurrentValueCollector): Gauge = + registerGauge(name, valueCollector, tags) + + def gauge(name: String, tags: Map[String, String], unitOfMeasurement: UnitOfMeasurement)(valueCollector: CurrentValueCollector): Gauge = + registerGauge(name, valueCollector, tags, Some(unitOfMeasurement)) + + def gauge(name: String, tags: Map[String, String], dynamicRange: DynamicRange)(valueCollector: CurrentValueCollector): Gauge = + registerGauge(name, valueCollector, tags, dynamicRange = Some(dynamicRange)) + + def gauge(name: String, tags: Map[String, String], unitOfMeasurement: UnitOfMeasurement, dynamicRange: DynamicRange)(valueCollector: CurrentValueCollector): Gauge = + registerGauge(name, valueCollector, tags, Some(unitOfMeasurement), Some(dynamicRange)) + + def removeGauge(name: String): Boolean = + removeGauge(name, Map.empty) + + def removeGauge(name: String, tags: Map[String, String]): Boolean + + def registerGauge(name: String, valueCollector: CurrentValueCollector, tags: Map[String, String] = Map.empty, + unitOfMeasurement: Option[UnitOfMeasurement] = None, dynamicRange: Option[DynamicRange] = None, + refreshInterval: Option[FiniteDuration] = None): Gauge + + // + // Counters registration and removal + // + + def counter(name: String): Counter = + registerCounter(name) + + def counter(name: String, unitOfMeasurement: UnitOfMeasurement): Counter = + registerCounter(name, unitOfMeasurement = Some(unitOfMeasurement)) + + def counter(name: String, tags: Map[String, String]): Counter = + registerCounter(name, tags) + + def counter(name: String, tags: Map[String, String], unitOfMeasurement: UnitOfMeasurement): Counter = + registerCounter(name, tags, Some(unitOfMeasurement)) + + def removeCounter(name: String): Boolean = + removeCounter(name, Map.empty) + + def removeCounter(name: String, tags: Map[String, String]): Boolean + + def registerCounter(name: String, tags: Map[String, String] = Map.empty, unitOfMeasurement: Option[UnitOfMeasurement] = None, + dynamicRange: Option[DynamicRange] = None): Counter + + // + // Entities registration and removal + // + + def entity[T <: EntityRecorder](recorderFactory: EntityRecorderFactory[T], name: String): T = + entity(recorderFactory, Entity(name, recorderFactory.category)) + + def entity[T <: EntityRecorder](recorderFactory: EntityRecorderFactory[T], name: String, tags: Map[String, String]): T = + entity(recorderFactory, Entity(name, recorderFactory.category, tags)) + + def removeEntity(name: String, category: String): Boolean = + removeEntity(Entity(name, category, Map.empty)) + + def removeEntity(name: String, category: String, tags: Map[String, String]): Boolean = + removeEntity(Entity(name, category, tags)) + + def removeEntity(entity: Entity): Boolean + + def entity[T <: EntityRecorder](recorderFactory: EntityRecorderFactory[T], entity: Entity): T + + def find(name: String, category: String): Option[EntityRecorder] = + find(Entity(name, category)) def find(entity: Entity): Option[EntityRecorder] - def find(name: String, category: String): Option[EntityRecorder] def subscribe(filter: SubscriptionFilter, subscriber: ActorRef): Unit = subscribe(filter, subscriber, permanently = false) @@ -51,11 +220,15 @@ trait Metrics { def subscribe(filter: SubscriptionFilter, subscriber: ActorRef, permanently: Boolean): Unit def unsubscribe(subscriber: ActorRef): Unit + def buildDefaultCollectionContext: CollectionContext + def instrumentFactory(category: String): InstrumentFactory } private[kamon] class MetricsImpl(config: Config) extends Metrics { + import TriemapAtomicGetOrElseUpdate.Syntax + private val _trackedEntities = TrieMap.empty[Entity, EntityRecorder] private val _subscriptions = new LazyActorRef @@ -67,35 +240,83 @@ private[kamon] class MetricsImpl(config: Config) extends Metrics { } getOrElse (settings.trackUnmatchedEntities) - def register[T <: EntityRecorder](recorderFactory: EntityRecorderFactory[T], entityName: String): Option[EntityRegistration[T]] = { - import TriemapAtomicGetOrElseUpdate.Syntax - val entity = Entity(entityName, recorderFactory.category) + def registerHistogram(name: String, tags: Map[String, String], unitOfMeasurement: Option[UnitOfMeasurement], + dynamicRange: Option[DynamicRange]): Histogram = { - if (shouldTrack(entity)) { - val instrumentFactory = settings.instrumentFactories.get(recorderFactory.category).getOrElse(settings.defaultInstrumentFactory) - val recorder = _trackedEntities.atomicGetOrElseUpdate(entity, recorderFactory.createRecorder(instrumentFactory), _.cleanup).asInstanceOf[T] + val histogramEntity = Entity(name, "histogram", tags) + val recorder = _trackedEntities.atomicGetOrElseUpdate(histogramEntity, { + val factory = instrumentFactory(histogramEntity.category) + HistogramRecorder(HistogramKey(histogramEntity.category, unitOfMeasurement.getOrElse(UnitOfMeasurement.Unknown)), + factory.createHistogram(name, dynamicRange)) + }, _.cleanup) - Some(EntityRegistration(entity, recorder)) - } else None + recorder.asInstanceOf[HistogramRecorder].instrument } - def register[T <: EntityRecorder](entity: Entity, recorder: T): EntityRegistration[T] = { - _trackedEntities.put(entity, recorder).map { oldRecorder ⇒ - oldRecorder.cleanup - } + def removeHistogram(name: String, tags: Map[String, String]): Boolean = + _trackedEntities.remove(Entity(name, "histogram", tags)).isDefined + + def registerMinMaxCounter(name: String, tags: Map[String, String], unitOfMeasurement: Option[UnitOfMeasurement], dynamicRange: Option[DynamicRange], + refreshInterval: Option[FiniteDuration]): MinMaxCounter = { + + val minMaxCounterEntity = Entity(name, "min-max-counter", tags) + val recorder = _trackedEntities.atomicGetOrElseUpdate(minMaxCounterEntity, { + val factory = instrumentFactory(minMaxCounterEntity.category) + MinMaxCounterRecorder(MinMaxCounterKey(minMaxCounterEntity.category, unitOfMeasurement.getOrElse(UnitOfMeasurement.Unknown)), + factory.createMinMaxCounter(name, dynamicRange, refreshInterval)) + }, _.cleanup) + + recorder.asInstanceOf[MinMaxCounterRecorder].instrument + } + + def removeMinMaxCounter(name: String, tags: Map[String, String]): Boolean = + _trackedEntities.remove(Entity(name, "min-max-counter", tags)).isDefined + + def registerGauge(name: String, valueCollector: CurrentValueCollector, tags: Map[String, String] = Map.empty, + unitOfMeasurement: Option[UnitOfMeasurement] = None, dynamicRange: Option[DynamicRange] = None, + refreshInterval: Option[FiniteDuration] = None): Gauge = { + + val gaugeEntity = Entity(name, "gauge", tags) + val recorder = _trackedEntities.atomicGetOrElseUpdate(gaugeEntity, { + val factory = instrumentFactory(gaugeEntity.category) + GaugeRecorder(MinMaxCounterKey(gaugeEntity.category, unitOfMeasurement.getOrElse(UnitOfMeasurement.Unknown)), + factory.createGauge(name, dynamicRange, refreshInterval, valueCollector)) + }, _.cleanup) + + recorder.asInstanceOf[GaugeRecorder].instrument + } + + def removeGauge(name: String, tags: Map[String, String]): Boolean = + _trackedEntities.remove(Entity(name, "gauge", tags)).isDefined + + def registerCounter(name: String, tags: Map[String, String] = Map.empty, unitOfMeasurement: Option[UnitOfMeasurement] = None, + dynamicRange: Option[DynamicRange] = None): Counter = { + + val counterEntity = Entity(name, "counter", tags) + val recorder = _trackedEntities.atomicGetOrElseUpdate(counterEntity, { + val factory = instrumentFactory(counterEntity.category) + CounterRecorder(CounterKey(counterEntity.category, unitOfMeasurement.getOrElse(UnitOfMeasurement.Unknown)), + factory.createCounter()) + }, _.cleanup) + + recorder.asInstanceOf[CounterRecorder].instrument + } + + def removeCounter(name: String, tags: Map[String, String]): Boolean = + _trackedEntities.remove(Entity(name, "counter", tags)).isDefined - EntityRegistration(entity, recorder) + def entity[T <: EntityRecorder](recorderFactory: EntityRecorderFactory[T], entity: Entity): T = { + _trackedEntities.atomicGetOrElseUpdate(entity, { + recorderFactory.createRecorder(instrumentFactory(recorderFactory.category)) + }, _.cleanup).asInstanceOf[T] } - def unregister(entity: Entity): Unit = - _trackedEntities.remove(entity).map(_.cleanup) + def removeEntity(entity: Entity): Boolean = + _trackedEntities.remove(entity).isDefined def find(entity: Entity): Option[EntityRecorder] = _trackedEntities.get(entity) - def find(name: String, category: String): Option[EntityRecorder] = - find(Entity(name, category)) - def subscribe(filter: SubscriptionFilter, subscriber: ActorRef, permanent: Boolean): Unit = _subscriptions.tell(Subscribe(filter, subscriber, permanent)) diff --git a/kamon-core/src/main/scala/kamon/metric/SimpleMetrics.scala b/kamon-core/src/main/scala/kamon/metric/SimpleMetrics.scala deleted file mode 100644 index 6324c320..00000000 --- a/kamon-core/src/main/scala/kamon/metric/SimpleMetrics.scala +++ /dev/null @@ -1,204 +0,0 @@ -/* - * ========================================================================================= - * Copyright © 2013-2015 the kamon project - * - * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file - * except in compliance with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software distributed under the - * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, - * either express or implied. See the License for the specific language governing permissions - * and limitations under the License. - * ========================================================================================= - */ - -package kamon.metric - -import kamon.metric.instrument.Gauge.CurrentValueCollector -import kamon.metric.instrument.Histogram.DynamicRange -import kamon.metric.instrument._ - -import scala.concurrent.duration.FiniteDuration - -trait SimpleMetrics { - def histogram(name: String): Histogram - def histogram(name: String, dynamicRange: DynamicRange): Histogram - def histogram(name: String, unitOfMeasurement: UnitOfMeasurement): Histogram - def histogram(name: String, dynamicRange: DynamicRange, unitOfMeasurement: UnitOfMeasurement): Histogram - def histogram(key: HistogramKey): Histogram - def histogram(key: HistogramKey, dynamicRange: DynamicRange): Histogram - def removeHistogram(name: String): Unit - def removeHistogram(key: HistogramKey): Unit - - def minMaxCounter(name: String): MinMaxCounter - def minMaxCounter(name: String, dynamicRange: DynamicRange): MinMaxCounter - def minMaxCounter(name: String, refreshInterval: FiniteDuration): MinMaxCounter - def minMaxCounter(name: String, unitOfMeasurement: UnitOfMeasurement): MinMaxCounter - def minMaxCounter(name: String, dynamicRange: DynamicRange, refreshInterval: FiniteDuration): MinMaxCounter - def minMaxCounter(name: String, dynamicRange: DynamicRange, unitOfMeasurement: UnitOfMeasurement): MinMaxCounter - def minMaxCounter(name: String, refreshInterval: FiniteDuration, unitOfMeasurement: UnitOfMeasurement): MinMaxCounter - def minMaxCounter(name: String, dynamicRange: DynamicRange, refreshInterval: FiniteDuration, unitOfMeasurement: UnitOfMeasurement): MinMaxCounter - def minMaxCounter(key: MinMaxCounterKey): MinMaxCounter - def minMaxCounter(key: MinMaxCounterKey, dynamicRange: DynamicRange): MinMaxCounter - def minMaxCounter(key: MinMaxCounterKey, refreshInterval: FiniteDuration): MinMaxCounter - def minMaxCounter(key: MinMaxCounterKey, dynamicRange: DynamicRange, refreshInterval: FiniteDuration): MinMaxCounter - def removeMinMaxCounter(name: String): Unit - def removeMinMaxCounter(key: MinMaxCounterKey): Unit - - def gauge(name: String, valueCollector: CurrentValueCollector): Gauge - def gauge(name: String, dynamicRange: DynamicRange, valueCollector: CurrentValueCollector): Gauge - def gauge(name: String, refreshInterval: FiniteDuration, valueCollector: CurrentValueCollector): Gauge - def gauge(name: String, unitOfMeasurement: UnitOfMeasurement, valueCollector: CurrentValueCollector): Gauge - def gauge(name: String, dynamicRange: DynamicRange, refreshInterval: FiniteDuration, valueCollector: CurrentValueCollector): Gauge - def gauge(name: String, dynamicRange: DynamicRange, unitOfMeasurement: UnitOfMeasurement, valueCollector: CurrentValueCollector): Gauge - def gauge(name: String, refreshInterval: FiniteDuration, unitOfMeasurement: UnitOfMeasurement, valueCollector: CurrentValueCollector): Gauge - def gauge(name: String, dynamicRange: DynamicRange, refreshInterval: FiniteDuration, unitOfMeasurement: UnitOfMeasurement, valueCollector: CurrentValueCollector): Gauge - def gauge(key: GaugeKey, valueCollector: CurrentValueCollector): Gauge - def gauge(key: GaugeKey, dynamicRange: DynamicRange, valueCollector: CurrentValueCollector): Gauge - def gauge(key: GaugeKey, refreshInterval: FiniteDuration, valueCollector: CurrentValueCollector): Gauge - def gauge(key: GaugeKey, dynamicRange: DynamicRange, refreshInterval: FiniteDuration, valueCollector: CurrentValueCollector): Gauge - def removeGauge(name: String): Unit - def removeGauge(key: GaugeKey): Unit - - def counter(name: String): Counter - def counter(key: CounterKey): Counter - def removeCounter(name: String): Unit - def removeCounter(key: CounterKey): Unit - -} - -private[kamon] class SimpleMetricsImpl(instrumentFactory: InstrumentFactory) extends GenericEntityRecorder(instrumentFactory) with SimpleMetrics { - override def histogram(name: String): Histogram = - super.histogram(name) - - override def histogram(name: String, dynamicRange: DynamicRange): Histogram = - super.histogram(name, dynamicRange) - - override def histogram(name: String, unitOfMeasurement: UnitOfMeasurement): Histogram = - super.histogram(name, unitOfMeasurement) - - override def histogram(name: String, dynamicRange: DynamicRange, unitOfMeasurement: UnitOfMeasurement): Histogram = - super.histogram(name, dynamicRange, unitOfMeasurement) - - override def histogram(key: HistogramKey): Histogram = - super.histogram(key) - - override def histogram(key: HistogramKey, dynamicRange: DynamicRange): Histogram = - super.histogram(key, dynamicRange) - - override def removeHistogram(name: String): Unit = - super.removeHistogram(name) - - override def removeHistogram(key: HistogramKey): Unit = - super.removeHistogram(key) - - override def minMaxCounter(name: String): MinMaxCounter = - super.minMaxCounter(name) - - override def minMaxCounter(name: String, dynamicRange: DynamicRange): MinMaxCounter = - super.minMaxCounter(name, dynamicRange) - - override def minMaxCounter(name: String, refreshInterval: FiniteDuration): MinMaxCounter = - super.minMaxCounter(name, refreshInterval) - - override def minMaxCounter(name: String, unitOfMeasurement: UnitOfMeasurement): MinMaxCounter = - super.minMaxCounter(name, unitOfMeasurement) - - override def minMaxCounter(name: String, dynamicRange: DynamicRange, refreshInterval: FiniteDuration): MinMaxCounter = - super.minMaxCounter(name, dynamicRange, refreshInterval) - - override def minMaxCounter(name: String, dynamicRange: DynamicRange, unitOfMeasurement: UnitOfMeasurement): MinMaxCounter = - super.minMaxCounter(name, dynamicRange, unitOfMeasurement) - - override def minMaxCounter(name: String, refreshInterval: FiniteDuration, unitOfMeasurement: UnitOfMeasurement): MinMaxCounter = - super.minMaxCounter(name, refreshInterval, unitOfMeasurement) - - override def minMaxCounter(name: String, dynamicRange: DynamicRange, refreshInterval: FiniteDuration, unitOfMeasurement: UnitOfMeasurement): MinMaxCounter = - super.minMaxCounter(name, dynamicRange, refreshInterval, unitOfMeasurement) - - override def minMaxCounter(key: MinMaxCounterKey): MinMaxCounter = - super.minMaxCounter(key) - - override def minMaxCounter(key: MinMaxCounterKey, dynamicRange: DynamicRange): MinMaxCounter = - super.minMaxCounter(key, dynamicRange) - - override def minMaxCounter(key: MinMaxCounterKey, refreshInterval: FiniteDuration): MinMaxCounter = - super.minMaxCounter(key, refreshInterval) - - override def minMaxCounter(key: MinMaxCounterKey, dynamicRange: DynamicRange, refreshInterval: FiniteDuration): MinMaxCounter = - super.minMaxCounter(key, dynamicRange, refreshInterval) - - override def removeMinMaxCounter(name: String): Unit = - super.removeMinMaxCounter(name) - - override def removeMinMaxCounter(key: MinMaxCounterKey): Unit = - super.removeMinMaxCounter(key) - - override def gauge(name: String, valueCollector: CurrentValueCollector): Gauge = - super.gauge(name, valueCollector) - - override def gauge(name: String, dynamicRange: DynamicRange, valueCollector: CurrentValueCollector): Gauge = - super.gauge(name, dynamicRange, valueCollector) - - override def gauge(name: String, refreshInterval: FiniteDuration, valueCollector: CurrentValueCollector): Gauge = - super.gauge(name, refreshInterval, valueCollector) - - override def gauge(name: String, unitOfMeasurement: UnitOfMeasurement, valueCollector: CurrentValueCollector): Gauge = - super.gauge(name, unitOfMeasurement, valueCollector) - - override def gauge(name: String, dynamicRange: DynamicRange, refreshInterval: FiniteDuration, valueCollector: CurrentValueCollector): Gauge = - super.gauge(name, dynamicRange, refreshInterval, valueCollector) - - override def gauge(name: String, dynamicRange: DynamicRange, unitOfMeasurement: UnitOfMeasurement, valueCollector: CurrentValueCollector): Gauge = - super.gauge(name, dynamicRange, unitOfMeasurement, valueCollector) - - override def gauge(name: String, refreshInterval: FiniteDuration, unitOfMeasurement: UnitOfMeasurement, valueCollector: CurrentValueCollector): Gauge = - super.gauge(name, refreshInterval, unitOfMeasurement, valueCollector) - - override def gauge(name: String, dynamicRange: DynamicRange, refreshInterval: FiniteDuration, unitOfMeasurement: UnitOfMeasurement, valueCollector: CurrentValueCollector): Gauge = - super.gauge(name, dynamicRange, refreshInterval, unitOfMeasurement, valueCollector) - - override def gauge(key: GaugeKey, valueCollector: CurrentValueCollector): Gauge = - super.gauge(key, valueCollector) - - override def gauge(key: GaugeKey, dynamicRange: DynamicRange, valueCollector: CurrentValueCollector): Gauge = - super.gauge(key, dynamicRange, valueCollector) - - override def gauge(key: GaugeKey, refreshInterval: FiniteDuration, valueCollector: CurrentValueCollector): Gauge = - super.gauge(key, refreshInterval, valueCollector) - - override def gauge(key: GaugeKey, dynamicRange: DynamicRange, refreshInterval: FiniteDuration, valueCollector: CurrentValueCollector): Gauge = - super.gauge(key, dynamicRange, refreshInterval, valueCollector) - - override def removeGauge(name: String): Unit = - super.removeGauge(name) - - override def removeGauge(key: GaugeKey): Unit = - super.removeGauge(key) - - override def counter(name: String): Counter = - super.counter(name) - - override def counter(key: CounterKey): Counter = - super.counter(key) - - override def removeCounter(name: String): Unit = - super.removeCounter(name) - - override def removeCounter(key: CounterKey): Unit = - super.removeCounter(key) -} - -private[kamon] object SimpleMetricsImpl { - val SimpleMetricsEntity = Entity("simple-metric", "simple-metric") - - def apply(metricsExtension: Metrics): SimpleMetricsImpl = { - val instrumentFactory = metricsExtension.instrumentFactory(SimpleMetricsEntity.category) - val simpleMetricsExtension = new SimpleMetricsImpl(instrumentFactory) - - metricsExtension.register(SimpleMetricsEntity, simpleMetricsExtension).recorder - } - -} \ No newline at end of file diff --git a/kamon-core/src/main/scala/kamon/metric/TraceMetrics.scala b/kamon-core/src/main/scala/kamon/metric/TraceMetrics.scala index 3da9c1d4..cf43b87c 100644 --- a/kamon-core/src/main/scala/kamon/metric/TraceMetrics.scala +++ b/kamon-core/src/main/scala/kamon/metric/TraceMetrics.scala @@ -16,29 +16,30 @@ package kamon.metric -import kamon.metric.instrument.{ Time, InstrumentFactory, Histogram } +import kamon.metric.instrument.{ Time, InstrumentFactory } class TraceMetrics(instrumentFactory: InstrumentFactory) extends GenericEntityRecorder(instrumentFactory) { - import TraceMetrics.segmentKey /** * Records blah blah */ - val ElapsedTime = histogram("elapsed-time", unitOfMeasurement = Time.Nanoseconds) - - /** - * Records Blah Blah. - * - */ - def segment(name: String, category: String, library: String): Histogram = - histogram(segmentKey(name, category, library)) - + val elapsedTime = histogram("elapsed-time", unitOfMeasurement = Time.Nanoseconds) } object TraceMetrics extends EntityRecorderFactory[TraceMetrics] { def category: String = "trace" def createRecorder(instrumentFactory: InstrumentFactory): TraceMetrics = new TraceMetrics(instrumentFactory) +} + +class SegmentMetrics(instrumentFactory: InstrumentFactory) extends GenericEntityRecorder(instrumentFactory) { + + /** + * Records blah blah + */ + val elapsedTime = histogram("elapsed-time", unitOfMeasurement = Time.Nanoseconds) +} - def segmentKey(name: String, category: String, library: String): HistogramKey = - HistogramKey(name, Time.Nanoseconds, Map("category" -> category, "library" -> library)) +object SegmentMetrics extends EntityRecorderFactory[SegmentMetrics] { + def category: String = "trace-segment" + def createRecorder(instrumentFactory: InstrumentFactory): SegmentMetrics = new SegmentMetrics(instrumentFactory) } \ No newline at end of file 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 80214510..61b53df2 100644 --- a/kamon-core/src/main/scala/kamon/metric/instrument/Gauge.scala +++ b/kamon-core/src/main/scala/kamon/metric/instrument/Gauge.scala @@ -55,6 +55,10 @@ object Gauge { implicit def functionZeroAsCurrentValueCollector(f: () ⇒ Long): CurrentValueCollector = new CurrentValueCollector { def currentValue: Long = f.apply() } + + implicit def callByNameLongAsCurrentValueCollector(f: ⇒ Long): CurrentValueCollector = new CurrentValueCollector { + def currentValue: Long = f + } } /** diff --git a/kamon-core/src/main/scala/kamon/trace/MetricsOnlyContext.scala b/kamon-core/src/main/scala/kamon/trace/MetricsOnlyContext.scala index eb4bad6f..0f09b4be 100644 --- a/kamon-core/src/main/scala/kamon/trace/MetricsOnlyContext.scala +++ b/kamon-core/src/main/scala/kamon/trace/MetricsOnlyContext.scala @@ -19,13 +19,14 @@ package kamon.trace import java.util.concurrent.ConcurrentLinkedQueue import akka.event.LoggingAdapter -import kamon.metric.{ Metrics, TraceMetrics } +import kamon.Kamon +import kamon.metric.{ SegmentMetrics, Metrics, TraceMetrics } import kamon.util.{ NanoInterval, RelativeNanoTimestamp } import scala.annotation.tailrec private[kamon] class MetricsOnlyContext(traceName: String, val token: String, izOpen: Boolean, val levelOfDetail: LevelOfDetail, - val startTimestamp: RelativeNanoTimestamp, log: LoggingAdapter, metricsExtension: Metrics) + val startTimestamp: RelativeNanoTimestamp, log: LoggingAdapter) extends TraceContext { @volatile private var _name = traceName @@ -51,20 +52,23 @@ private[kamon] class MetricsOnlyContext(traceName: String, val token: String, iz val traceElapsedTime = NanoInterval.since(startTimestamp) _elapsedTime = traceElapsedTime - metricsExtension.register(TraceMetrics, name).map { registration ⇒ - registration.recorder.ElapsedTime.record(traceElapsedTime.nanos) - drainFinishedSegments(registration.recorder) - } + Kamon.metrics.entity(TraceMetrics, name).elapsedTime.record(traceElapsedTime.nanos) + drainFinishedSegments() } def startSegment(segmentName: String, category: String, library: String): Segment = new MetricsOnlySegment(segmentName, category, library) - @tailrec private def drainFinishedSegments(recorder: TraceMetrics): Unit = { + @tailrec private def drainFinishedSegments(): Unit = { val segment = _finishedSegments.poll() if (segment != null) { - recorder.segment(segment.name, segment.category, segment.library).record(segment.duration.nanos) - drainFinishedSegments(recorder) + val segmentTags = Map( + "trace" -> name, + "category" -> segment.category, + "library" -> segment.library) + + Kamon.metrics.entity(SegmentMetrics, segment.name, segmentTags).elapsedTime.record(segment.duration.nanos) + drainFinishedSegments() } } @@ -72,9 +76,7 @@ private[kamon] class MetricsOnlyContext(traceName: String, val token: String, iz _finishedSegments.add(SegmentLatencyData(segmentName, category, library, duration)) if (isClosed) { - metricsExtension.register(TraceMetrics, name).map { registration ⇒ - drainFinishedSegments(registration.recorder) - } + drainFinishedSegments() } } diff --git a/kamon-core/src/main/scala/kamon/trace/Tracer.scala b/kamon-core/src/main/scala/kamon/trace/Tracer.scala index cf83b36b..472c1d65 100644 --- a/kamon-core/src/main/scala/kamon/trace/Tracer.scala +++ b/kamon-core/src/main/scala/kamon/trace/Tracer.scala @@ -80,7 +80,7 @@ private[kamon] class TracerImpl(metricsExtension: Metrics, config: Config) exten private def createTraceContext(traceName: String, token: String = newToken, startTimestamp: RelativeNanoTimestamp = RelativeNanoTimestamp.now, isOpen: Boolean = true, isLocal: Boolean = true): TraceContext = { - def newMetricsOnlyContext = new MetricsOnlyContext(traceName, token, isOpen, _settings.levelOfDetail, startTimestamp, null, metricsExtension) + def newMetricsOnlyContext = new MetricsOnlyContext(traceName, token, isOpen, _settings.levelOfDetail, startTimestamp, null) if (_settings.levelOfDetail == LevelOfDetail.MetricsOnly || !isLocal) newMetricsOnlyContext @@ -88,7 +88,7 @@ private[kamon] class TracerImpl(metricsExtension: Metrics, config: Config) exten if (!_settings.sampler.shouldTrace) newMetricsOnlyContext else - new TracingContext(traceName, token, true, _settings.levelOfDetail, isLocal, startTimestamp, null, metricsExtension, this, dispatchTracingContext) + new TracingContext(traceName, token, true, _settings.levelOfDetail, isLocal, startTimestamp, null, dispatchTracingContext) } } diff --git a/kamon-core/src/main/scala/kamon/trace/TracingContext.scala b/kamon-core/src/main/scala/kamon/trace/TracingContext.scala index d34526f7..9708d25f 100644 --- a/kamon-core/src/main/scala/kamon/trace/TracingContext.scala +++ b/kamon-core/src/main/scala/kamon/trace/TracingContext.scala @@ -26,9 +26,8 @@ import kamon.metric.Metrics import scala.collection.concurrent.TrieMap private[trace] class TracingContext(traceName: String, token: String, izOpen: Boolean, levelOfDetail: LevelOfDetail, - isLocal: Boolean, startTimeztamp: RelativeNanoTimestamp, log: LoggingAdapter, metricsExtension: Metrics, - traceExtension: TracerImpl, traceInfoSink: TracingContext ⇒ Unit) - extends MetricsOnlyContext(traceName, token, izOpen, levelOfDetail, startTimeztamp, log, metricsExtension) { + isLocal: Boolean, startTimeztamp: RelativeNanoTimestamp, log: LoggingAdapter, traceInfoSink: TracingContext ⇒ Unit) + extends MetricsOnlyContext(traceName, token, izOpen, levelOfDetail, startTimeztamp, log) { private val _openSegments = new AtomicInteger(0) private val _startTimestamp = NanoTimestamp.now diff --git a/kamon-core/src/main/scala/kamon/util/FunctionalInterfaces.scala b/kamon-core/src/main/scala/kamon/util/FunctionalInterfaces.scala new file mode 100644 index 00000000..1f600b78 --- /dev/null +++ b/kamon-core/src/main/scala/kamon/util/FunctionalInterfaces.scala @@ -0,0 +1,9 @@ +package kamon.util + +trait Supplier[T] { + def get: T +} + +trait Function[T, R] { + def apply(t: T): R +} \ No newline at end of file diff --git a/kamon-core/src/test/scala/kamon/metric/SimpleMetricsSpec.scala b/kamon-core/src/test/scala/kamon/metric/SimpleMetricsSpec.scala index 60ba9a0e..0180e980 100644 --- a/kamon-core/src/test/scala/kamon/metric/SimpleMetricsSpec.scala +++ b/kamon-core/src/test/scala/kamon/metric/SimpleMetricsSpec.scala @@ -35,93 +35,81 @@ class SimpleMetricsSpec extends BaseKamonSpec("simple-metrics-spec") { "the SimpleMetrics extension" should { "allow registering a fully configured Histogram and get the same Histogram if registering again" in { - val histogramA = Kamon.simpleMetrics.histogram("histogram-with-settings", DynamicRange(1, 10000, 2)) - val histogramB = Kamon.simpleMetrics.histogram("histogram-with-settings", DynamicRange(1, 10000, 2)) + val histogramA = Kamon.metrics.histogram("histogram-with-settings", DynamicRange(1, 10000, 2)) + val histogramB = Kamon.metrics.histogram("histogram-with-settings", DynamicRange(1, 10000, 2)) histogramA shouldBe theSameInstanceAs(histogramB) } "return the original Histogram when registering a fully configured Histogram for second time but with different settings" in { - val histogramA = Kamon.simpleMetrics.histogram("histogram-with-settings", DynamicRange(1, 10000, 2)) - val histogramB = Kamon.simpleMetrics.histogram("histogram-with-settings", DynamicRange(1, 50000, 2)) + val histogramA = Kamon.metrics.histogram("histogram-with-settings", DynamicRange(1, 10000, 2)) + val histogramB = Kamon.metrics.histogram("histogram-with-settings", DynamicRange(1, 50000, 2)) histogramA shouldBe theSameInstanceAs(histogramB) } "allow registering a Histogram that takes the default configuration from the kamon.metrics.precision settings" in { - Kamon.simpleMetrics.histogram("histogram-with-default-configuration") + Kamon.metrics.histogram("histogram-with-default-configuration") } "allow registering a Counter and get the same Counter if registering again" in { - val counterA = Kamon.simpleMetrics.counter("counter") - val counterB = Kamon.simpleMetrics.counter("counter") + val counterA = Kamon.metrics.counter("counter") + val counterB = Kamon.metrics.counter("counter") counterA shouldBe theSameInstanceAs(counterB) } "allow registering a fully configured MinMaxCounter and get the same MinMaxCounter if registering again" in { - val minMaxCounterA = Kamon.simpleMetrics.minMaxCounter("min-max-counter-with-settings", DynamicRange(1, 10000, 2), 1 second) - val minMaxCounterB = Kamon.simpleMetrics.minMaxCounter("min-max-counter-with-settings", DynamicRange(1, 10000, 2), 1 second) + val minMaxCounterA = Kamon.metrics.minMaxCounter("min-max-counter-with-settings", DynamicRange(1, 10000, 2), 1 second) + val minMaxCounterB = Kamon.metrics.minMaxCounter("min-max-counter-with-settings", DynamicRange(1, 10000, 2), 1 second) minMaxCounterA shouldBe theSameInstanceAs(minMaxCounterB) } "return the original MinMaxCounter when registering a fully configured MinMaxCounter for second time but with different settings" in { - val minMaxCounterA = Kamon.simpleMetrics.minMaxCounter("min-max-counter-with-settings", DynamicRange(1, 10000, 2), 1 second) - val minMaxCounterB = Kamon.simpleMetrics.minMaxCounter("min-max-counter-with-settings", DynamicRange(1, 50000, 2), 1 second) + val minMaxCounterA = Kamon.metrics.minMaxCounter("min-max-counter-with-settings", DynamicRange(1, 10000, 2), 1 second) + val minMaxCounterB = Kamon.metrics.minMaxCounter("min-max-counter-with-settings", DynamicRange(1, 50000, 2), 1 second) minMaxCounterA shouldBe theSameInstanceAs(minMaxCounterB) } "allow registering a MinMaxCounter that takes the default configuration from the kamon.metrics.precision settings" in { - Kamon.simpleMetrics.minMaxCounter("min-max-counter-with-default-configuration") + Kamon.metrics.minMaxCounter("min-max-counter-with-default-configuration") } "allow registering a fully configured Gauge and get the same Gauge if registering again" in { - val gaugeA = Kamon.simpleMetrics.gauge("gauge-with-settings", DynamicRange(1, 10000, 2), 1 second, { - () ⇒ 1L - }) - - val gaugeB = Kamon.simpleMetrics.gauge("gauge-with-settings", DynamicRange(1, 10000, 2), 1 second, { - () ⇒ 1L - }) + val gaugeA = Kamon.metrics.gauge("gauge-with-settings", DynamicRange(1, 10000, 2), 1 second)(1L) + val gaugeB = Kamon.metrics.gauge("gauge-with-settings", DynamicRange(1, 10000, 2), 1 second)(1L) gaugeA shouldBe theSameInstanceAs(gaugeB) } "return the original Gauge when registering a fully configured Gauge for second time but with different settings" in { - val gaugeA = Kamon.simpleMetrics.gauge("gauge-with-settings", DynamicRange(1, 10000, 2), 1 second, { - () ⇒ 1L - }) - - val gaugeB = Kamon.simpleMetrics.gauge("gauge-with-settings", DynamicRange(1, 10000, 2), 1 second, { - () ⇒ 1L - }) + val gaugeA = Kamon.metrics.gauge("gauge-with-settings", DynamicRange(1, 10000, 2), 1 second)(1L) + val gaugeB = Kamon.metrics.gauge("gauge-with-settings", DynamicRange(1, 10000, 2), 1 second)(1L) gaugeA shouldBe theSameInstanceAs(gaugeB) } "allow registering a Gauge that takes the default configuration from the kamon.metrics.precision settings" in { - Kamon.simpleMetrics.gauge("gauge-with-default-configuration", { - () ⇒ 2L - }) + Kamon.metrics.gauge("gauge-with-default-configuration")(2L) } "allow un-registering user metrics" in { - val counter = Kamon.simpleMetrics.counter("counter-for-remove") - val histogram = Kamon.simpleMetrics.histogram("histogram-for-remove") - val minMaxCounter = Kamon.simpleMetrics.minMaxCounter("min-max-counter-for-remove") - val gauge = Kamon.simpleMetrics.gauge("gauge-for-remove", { () ⇒ 2L }) - - Kamon.simpleMetrics.removeCounter("counter-for-remove") - Kamon.simpleMetrics.removeHistogram("histogram-for-remove") - Kamon.simpleMetrics.removeMinMaxCounter("min-max-counter-for-remove") - Kamon.simpleMetrics.removeGauge("gauge-for-remove") - - counter should not be (theSameInstanceAs(Kamon.simpleMetrics.counter("counter-for-remove"))) - histogram should not be (theSameInstanceAs(Kamon.simpleMetrics.histogram("histogram-for-remove"))) - minMaxCounter should not be (theSameInstanceAs(Kamon.simpleMetrics.minMaxCounter("min-max-counter-for-remove"))) - gauge should not be (theSameInstanceAs(Kamon.simpleMetrics.gauge("gauge-for-remove", { () ⇒ 2L }))) + val counter = Kamon.metrics.counter("counter-for-remove") + val histogram = Kamon.metrics.histogram("histogram-for-remove") + val minMaxCounter = Kamon.metrics.minMaxCounter("min-max-counter-for-remove") + val gauge = Kamon.metrics.gauge("gauge-for-remove")(2L) + + Kamon.metrics.removeCounter("counter-for-remove") + Kamon.metrics.removeHistogram("histogram-for-remove") + Kamon.metrics.removeMinMaxCounter("min-max-counter-for-remove") + Kamon.metrics.removeGauge("gauge-for-remove") + + counter should not be (theSameInstanceAs(Kamon.metrics.counter("counter-for-remove"))) + histogram should not be (theSameInstanceAs(Kamon.metrics.histogram("histogram-for-remove"))) + minMaxCounter should not be (theSameInstanceAs(Kamon.metrics.minMaxCounter("min-max-counter-for-remove"))) + gauge should not be (theSameInstanceAs(Kamon.metrics.gauge("gauge-for-remove")(2L))) } } } diff --git a/kamon-core/src/test/scala/kamon/metric/SubscriptionsProtocolSpec.scala b/kamon-core/src/test/scala/kamon/metric/SubscriptionsProtocolSpec.scala index 53ae5273..b8131f6e 100644 --- a/kamon-core/src/test/scala/kamon/metric/SubscriptionsProtocolSpec.scala +++ b/kamon-core/src/test/scala/kamon/metric/SubscriptionsProtocolSpec.scala @@ -34,12 +34,12 @@ class SubscriptionsProtocolSpec extends BaseKamonSpec("subscriptions-protocol-sp """.stripMargin) lazy val metricsModule = Kamon.metrics - import metricsModule.{ register, subscribe, unsubscribe } + import metricsModule.{ entity, subscribe, unsubscribe } "the Subscriptions messaging protocol" should { "allow subscribing for a single tick" in { val subscriber = TestProbe() - register(TraceMetrics, "one-shot") + entity(TraceMetrics, "one-shot") subscribe("trace", "one-shot", subscriber.ref, permanently = false) flushSubscriptions() @@ -54,7 +54,7 @@ class SubscriptionsProtocolSpec extends BaseKamonSpec("subscriptions-protocol-sp "allow subscribing permanently to a metric" in { val subscriber = TestProbe() - register(TraceMetrics, "permanent") + entity(TraceMetrics, "permanent") subscribe("trace", "permanent", subscriber.ref, permanently = true) for (repetition ← 1 to 5) { @@ -68,9 +68,9 @@ class SubscriptionsProtocolSpec extends BaseKamonSpec("subscriptions-protocol-sp "allow subscribing to metrics matching a glob pattern" in { val subscriber = TestProbe() - register(TraceMetrics, "include-one") - register(TraceMetrics, "exclude-two") - register(TraceMetrics, "include-three") + entity(TraceMetrics, "include-one") + entity(TraceMetrics, "exclude-two") + entity(TraceMetrics, "include-three") subscribe("trace", "include-*", subscriber.ref, permanently = true) for (repetition ← 1 to 5) { @@ -85,9 +85,9 @@ class SubscriptionsProtocolSpec extends BaseKamonSpec("subscriptions-protocol-sp "send a single TickMetricSnapshot to each subscriber, even if subscribed multiple times" in { val subscriber = TestProbe() - register(TraceMetrics, "include-one") - register(TraceMetrics, "exclude-two") - register(TraceMetrics, "include-three") + entity(TraceMetrics, "include-one") + entity(TraceMetrics, "exclude-two") + entity(TraceMetrics, "include-three") subscribe("trace", "include-one", subscriber.ref, permanently = true) subscribe("trace", "include-three", subscriber.ref, permanently = true) @@ -103,7 +103,7 @@ class SubscriptionsProtocolSpec extends BaseKamonSpec("subscriptions-protocol-sp "allow un-subscribing a subscriber" in { val subscriber = TestProbe() - register(TraceMetrics, "one-shot") + entity(TraceMetrics, "one-shot") subscribe("trace", "one-shot", subscriber.ref, permanently = true) flushSubscriptions() diff --git a/kamon-core/src/test/scala/kamon/metric/TickMetricSnapshotBufferSpec.scala b/kamon-core/src/test/scala/kamon/metric/TickMetricSnapshotBufferSpec.scala index 0c9ced32..ac35cf58 100644 --- a/kamon-core/src/test/scala/kamon/metric/TickMetricSnapshotBufferSpec.scala +++ b/kamon-core/src/test/scala/kamon/metric/TickMetricSnapshotBufferSpec.scala @@ -88,21 +88,21 @@ class TickMetricSnapshotBufferSpec extends BaseKamonSpec("trace-metrics-spec") w trait SnapshotFixtures { val collectionContext = Kamon.metrics.buildDefaultCollectionContext val testTraceIdentity = Entity("buffer-spec-test-trace", "trace") - val traceRecorder = Kamon.metrics.register(TraceMetrics, "buffer-spec-test-trace").get.recorder + val traceRecorder = Kamon.metrics.entity(TraceMetrics, "buffer-spec-test-trace") val firstEmpty = TickMetricSnapshot(new MilliTimestamp(1000), new MilliTimestamp(2000), Map.empty) val secondEmpty = TickMetricSnapshot(new MilliTimestamp(2000), new MilliTimestamp(3000), Map.empty) val thirdEmpty = TickMetricSnapshot(new MilliTimestamp(3000), new MilliTimestamp(4000), Map.empty) - traceRecorder.ElapsedTime.record(10L) - traceRecorder.ElapsedTime.record(20L) - traceRecorder.ElapsedTime.record(30L) + traceRecorder.elapsedTime.record(10L) + traceRecorder.elapsedTime.record(20L) + traceRecorder.elapsedTime.record(30L) val firstNonEmpty = TickMetricSnapshot(new MilliTimestamp(1000), new MilliTimestamp(2000), Map( (testTraceIdentity -> traceRecorder.collect(collectionContext)))) - traceRecorder.ElapsedTime.record(10L) - traceRecorder.ElapsedTime.record(10L) - traceRecorder.ElapsedTime.record(300L) + traceRecorder.elapsedTime.record(10L) + traceRecorder.elapsedTime.record(10L) + traceRecorder.elapsedTime.record(300L) val secondNonEmpty = TickMetricSnapshot(new MilliTimestamp(1000), new MilliTimestamp(2000), Map( (testTraceIdentity -> traceRecorder.collect(collectionContext)))) } diff --git a/kamon-core/src/test/scala/kamon/metric/TraceMetricsSpec.scala b/kamon-core/src/test/scala/kamon/metric/TraceMetricsSpec.scala index 03a09b7f..efdcb79b 100644 --- a/kamon-core/src/test/scala/kamon/metric/TraceMetricsSpec.scala +++ b/kamon-core/src/test/scala/kamon/metric/TraceMetricsSpec.scala @@ -23,8 +23,6 @@ import kamon.trace.Tracer import kamon.metric.instrument.Histogram class TraceMetricsSpec extends BaseKamonSpec("trace-metrics-spec") with ImplicitSender { - import TraceMetricsSpec.SegmentSyntax - override lazy val config = ConfigFactory.parseString( """ @@ -60,10 +58,13 @@ class TraceMetricsSpec extends BaseKamonSpec("trace-metrics-spec") with Implicit Tracer.currentContext.finish() } - val snapshot = takeSnapshotOf("trace-with-segments", "trace") + val snapshot = takeSnapshotOf("test-segment", "trace-segment", + tags = Map( + "trace" -> "trace-with-segments", + "category" -> "test-category", + "library" -> "test-library")) + snapshot.histogram("elapsed-time").get.numberOfMeasurements should be(1) - snapshot.segments.size should be(1) - snapshot.segment("test-segment", "test-category", "test-library").numberOfMeasurements should be(1) } "record the elapsed time for segments that finish after their correspondent trace has finished" in { @@ -75,25 +76,26 @@ class TraceMetricsSpec extends BaseKamonSpec("trace-metrics-spec") with Implicit val beforeFinishSegmentSnapshot = takeSnapshotOf("closing-segment-after-trace", "trace") beforeFinishSegmentSnapshot.histogram("elapsed-time").get.numberOfMeasurements should be(1) - beforeFinishSegmentSnapshot.segments.size should be(0) + + intercept[NoSuchElementException] { + // The segment metric should not exist before we it has finished. + + takeSnapshotOf("test-segment", "trace-segment", + tags = Map( + "trace" -> "closing-segment-after-trace", + "category" -> "test-category", + "library" -> "test-library")) + } segment.finish() - val afterFinishSegmentSnapshot = takeSnapshotOf("closing-segment-after-trace", "trace") - afterFinishSegmentSnapshot.histogram("elapsed-time").get.numberOfMeasurements should be(0) - afterFinishSegmentSnapshot.segments.size should be(1) - afterFinishSegmentSnapshot.segment("test-segment", "test-category", "test-library").numberOfMeasurements should be(1) - } - } -} + val afterFinishSegmentSnapshot = takeSnapshotOf("test-segment", "trace-segment", + tags = Map( + "trace" -> "closing-segment-after-trace", + "category" -> "test-category", + "library" -> "test-library")) -object TraceMetricsSpec { - implicit class SegmentSyntax(val entitySnapshot: EntitySnapshot) extends AnyVal { - def segments: Map[HistogramKey, Histogram.Snapshot] = { - entitySnapshot.histograms.filterKeys(_.metadata.contains("category")) + afterFinishSegmentSnapshot.histogram("elapsed-time").get.numberOfMeasurements should be(1) } - - def segment(name: String, category: String, library: String): Histogram.Snapshot = - segments(TraceMetrics.segmentKey(name, category, library)) } } diff --git a/kamon-core/src/test/scala/kamon/testkit/BaseKamonSpec.scala b/kamon-core/src/test/scala/kamon/testkit/BaseKamonSpec.scala index f3d809bf..e7b18770 100644 --- a/kamon-core/src/test/scala/kamon/testkit/BaseKamonSpec.scala +++ b/kamon-core/src/test/scala/kamon/testkit/BaseKamonSpec.scala @@ -20,7 +20,7 @@ import akka.testkit.{ ImplicitSender, TestKitBase } import akka.actor.ActorSystem import com.typesafe.config.{ Config, ConfigFactory } import kamon.Kamon -import kamon.metric.{ SubscriptionsDispatcher, EntitySnapshot, MetricsImpl } +import kamon.metric.{ Entity, SubscriptionsDispatcher, EntitySnapshot, MetricsImpl } import kamon.trace.TraceContext import kamon.util.LazyActorRef import org.scalatest.{ BeforeAndAfterAll, Matchers, WordSpecLike } @@ -48,6 +48,11 @@ abstract class BaseKamonSpec(actorSystemName: String) extends TestKitBase with W recorder.collect(collectionContext) } + def takeSnapshotOf(name: String, category: String, tags: Map[String, String]): EntitySnapshot = { + val recorder = Kamon.metrics.find(Entity(name, category, tags)).get + recorder.collect(collectionContext) + } + def flushSubscriptions(): Unit = { val subscriptionsField = Kamon.metrics.getClass.getDeclaredField("_subscriptions") subscriptionsField.setAccessible(true) -- cgit v1.2.3