aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--kamon-core/src/main/resources/META-INF/aop.xml2
-rw-r--r--kamon-core/src/main/scala/kamon/Kamon.scala13
-rw-r--r--kamon-core/src/main/scala/kamon/ModuleLoader.scala123
-rw-r--r--kamon-core/src/main/scala/kamon/metric/Entity.scala27
-rw-r--r--kamon-core/src/main/scala/kamon/metric/EntityRecorder.scala103
-rw-r--r--kamon-core/src/main/scala/kamon/metric/MetricKey.scala134
-rw-r--r--kamon-core/src/main/scala/kamon/metric/Metrics.scala279
-rw-r--r--kamon-core/src/main/scala/kamon/metric/SimpleMetrics.scala204
-rw-r--r--kamon-core/src/main/scala/kamon/metric/TraceMetrics.scala33
-rw-r--r--kamon-core/src/main/scala/kamon/metric/instrument/Gauge.scala4
-rw-r--r--kamon-core/src/main/scala/kamon/metric/instrument/Instrument.scala16
-rw-r--r--kamon-core/src/main/scala/kamon/metric/instrument/RefreshScheduler.scala16
-rw-r--r--kamon-core/src/main/scala/kamon/metric/instrument/UnitOfMeasurement.scala28
-rw-r--r--kamon-core/src/main/scala/kamon/supervisor/ModuleSupervisorExtension.scala125
-rw-r--r--kamon-core/src/main/scala/kamon/supervisor/ModuleSupervisorSettings.scala49
-rw-r--r--kamon-core/src/main/scala/kamon/trace/MetricsOnlyContext.scala26
-rw-r--r--kamon-core/src/main/scala/kamon/trace/Tracer.scala4
-rw-r--r--kamon-core/src/main/scala/kamon/trace/TracingContext.scala5
-rw-r--r--kamon-core/src/main/scala/kamon/util/FunctionalInterfaces.scala (renamed from kamon-core/src/main/scala/kamon/supervisor/AspectJPresent.scala)20
-rw-r--r--kamon-core/src/main/scala/kamon/util/JavaTags.scala14
-rw-r--r--kamon-core/src/main/scala/kamon/util/Latency.scala (renamed from kamon-core/src/main/scala/kamon/instrumentation/AspectJWeaverMissingWarning.scala)22
-rw-r--r--kamon-core/src/main/scala/kamon/util/LazyActorRef.scala16
-rw-r--r--kamon-core/src/main/scala/kamon/util/MapMerge.scala2
-rw-r--r--kamon-core/src/main/scala/kamon/util/SameThreadExecutionContext.scala30
-rw-r--r--kamon-core/src/test/scala/kamon/metric/SimpleMetricsSpec.scala74
-rw-r--r--kamon-core/src/test/scala/kamon/metric/SubscriptionsProtocolSpec.scala20
-rw-r--r--kamon-core/src/test/scala/kamon/metric/TickMetricSnapshotBufferSpec.scala14
-rw-r--r--kamon-core/src/test/scala/kamon/metric/TraceMetricsSpec.scala42
-rw-r--r--kamon-core/src/test/scala/kamon/testkit/BaseKamonSpec.scala7
29 files changed, 703 insertions, 749 deletions
diff --git a/kamon-core/src/main/resources/META-INF/aop.xml b/kamon-core/src/main/resources/META-INF/aop.xml
index 2ffb8b09..b13f9aac 100644
--- a/kamon-core/src/main/resources/META-INF/aop.xml
+++ b/kamon-core/src/main/resources/META-INF/aop.xml
@@ -4,7 +4,7 @@
<aspects>
<!-- Notify that AspectJ is present -->
- <aspect name="kamon.supervisor.AspectJPresent"/>
+ <aspect name="kamon.AspectJPresent"/>
</aspects>
diff --git a/kamon-core/src/main/scala/kamon/Kamon.scala b/kamon-core/src/main/scala/kamon/Kamon.scala
index a2a24f49..f8253875 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,14 +41,14 @@ 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)
tracer.start(_system)
+ _system.registerExtension(ModuleLoader)
} else sys.error("Kamon has already been started.")
}
@@ -70,9 +68,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/ModuleLoader.scala b/kamon-core/src/main/scala/kamon/ModuleLoader.scala
new file mode 100644
index 00000000..d1b7466e
--- /dev/null
+++ b/kamon-core/src/main/scala/kamon/ModuleLoader.scala
@@ -0,0 +1,123 @@
+/*
+ * =========================================================================================
+ * Copyright © 2013-2015 the kamon project <http://kamon.io/>
+ *
+ * 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
+
+import _root_.akka.actor
+import _root_.akka.actor._
+import _root_.akka.event.Logging
+import org.aspectj.lang.ProceedingJoinPoint
+import org.aspectj.lang.annotation.{ Around, Pointcut, Aspect }
+
+private[kamon] object ModuleLoader extends ExtensionId[ModuleLoaderExtension] with ExtensionIdProvider {
+ def lookup(): ExtensionId[_ <: actor.Extension] = ModuleLoader
+ def createExtension(system: ExtendedActorSystem): ModuleLoaderExtension = new ModuleLoaderExtension(system)
+}
+
+private[kamon] class ModuleLoaderExtension(system: ExtendedActorSystem) extends Kamon.Extension {
+ val log = Logging(system, "ModuleLoader")
+ val settings = ModuleLoaderSettings(system)
+
+ if (settings.modulesRequiringAspectJ.nonEmpty && !isAspectJPresent && settings.showAspectJMissingWarning)
+ logAspectJWeaverMissing(settings.modulesRequiringAspectJ)
+
+ // Force initialization of all modules marked with auto-start.
+ settings.availableModules.filter(_.autoStart).foreach { module ⇒
+ if (module.extensionClass == "none")
+ log.debug("Ignoring auto start of the [{}] module with no extension class.")
+ else
+ system.dynamicAccess.getObjectFor[ExtensionId[Kamon.Extension]](module.extensionClass).map { moduleID ⇒
+ log.debug("Auto starting the [{}] module.", module.name)
+ moduleID.get(system)
+
+ } recover {
+ case th: Throwable ⇒ log.error(th, "Failed to auto start the [{}] module.", module.name)
+ }
+
+ }
+
+ // When AspectJ is present the kamon.supervisor.AspectJPresent aspect will make this return true.
+ def isAspectJPresent: Boolean = false
+
+ def logAspectJWeaverMissing(modulesRequiringAspectJ: List[AvailableModuleInfo]): Unit = {
+ val moduleNames = modulesRequiringAspectJ.map(_.name).mkString(", ")
+ val weaverMissingMessage =
+ """
+ |
+ | ___ _ ___ _ _ ___ ___ _ _
+ | / _ \ | | |_ | | | | | | \/ |(_) (_)
+ |/ /_\ \ ___ _ __ ___ ___ | |_ | | | | | | ___ __ _ __ __ ___ _ __ | . . | _ ___ ___ _ _ __ __ _
+ || _ |/ __|| '_ \ / _ \ / __|| __| | | | |/\| | / _ \ / _` |\ \ / // _ \| '__| | |\/| || |/ __|/ __|| || '_ \ / _` |
+ || | | |\__ \| |_) || __/| (__ | |_ /\__/ / \ /\ /| __/| (_| | \ V /| __/| | | | | || |\__ \\__ \| || | | || (_| |
+ |\_| |_/|___/| .__/ \___| \___| \__|\____/ \/ \/ \___| \__,_| \_/ \___||_| \_| |_/|_||___/|___/|_||_| |_| \__, |
+ | | | __/ |
+ | |_| |___/
+ |
+ | It seems like your application was not started with the -javaagent:/path-to-aspectj-weaver.jar option but Kamon detected
+ | the following modules which require AspecJ to work properly:
+ |
+ """.stripMargin + moduleNames +
+ """
+ |
+ | If you need help on setting up the aspectj weaver go to http://kamon.io/introduction/get-started/ for more info. On the
+ | other hand, if you are sure that you do not need or do not want to use the weaver then you can disable this error message
+ | by changing the kamon.show-aspectj-missing-warning setting in your configuration file.
+ |
+ """.stripMargin
+
+ log.error(weaverMissingMessage)
+ }
+}
+
+private[kamon] case class AvailableModuleInfo(name: String, extensionClass: String, requiresAspectJ: Boolean, autoStart: Boolean)
+private[kamon] case class ModuleLoaderSettings(showAspectJMissingWarning: Boolean, availableModules: List[AvailableModuleInfo]) {
+ val modulesRequiringAspectJ = availableModules.filter(_.requiresAspectJ)
+}
+
+private[kamon] object ModuleLoaderSettings {
+
+ def apply(system: ActorSystem): ModuleLoaderSettings = {
+ import kamon.util.ConfigTools.Syntax
+
+ val config = system.settings.config.getConfig("kamon.modules")
+ val showAspectJMissingWarning = system.settings.config.getBoolean("kamon.show-aspectj-missing-warning")
+
+ val modules = config.firstLevelKeys
+ val availableModules = modules.map { moduleName ⇒
+ val moduleConfig = config.getConfig(moduleName)
+
+ AvailableModuleInfo(
+ moduleName,
+ moduleConfig.getString("extension-id"),
+ moduleConfig.getBoolean("requires-aspectj"),
+ moduleConfig.getBoolean("auto-start"))
+
+ } toList
+
+ ModuleLoaderSettings(showAspectJMissingWarning, availableModules)
+ }
+}
+
+@Aspect
+private[kamon] class AspectJPresent {
+
+ @Pointcut("execution(* kamon.ModuleLoaderExtension.isAspectJPresent())")
+ def isAspectJPresentAtModuleSupervisor(): Unit = {}
+
+ @Around("isAspectJPresentAtModuleSupervisor()")
+ def aroundIsAspectJPresentAtModuleSupervisor(pjp: ProceedingJoinPoint): Boolean = true
+
+}
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 a5d30c81..0d4e0163 100644
--- a/kamon-core/src/main/scala/kamon/metric/MetricKey.scala
+++ b/kamon-core/src/main/scala/kamon/metric/MetricKey.scala
@@ -16,154 +16,32 @@
package kamon.metric
-import kamon.metric.instrument.{ InstrumentTypes, InstrumentType, UnitOfMeasurement }
+import kamon.metric.instrument.UnitOfMeasurement
/**
- * MetricKeys are used to identify a given metric in entity recorders and snapshots. MetricKeys can be used to encode
- * additional metadata for a metric being recorded, as well as the unit of measurement of the data being recorder.
+ * MetricKeys are used to identify a given metric in entity recorders and snapshots.
*/
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 {
- 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, Map.empty)
-
- /**
- * 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)
-}
+private[kamon] case class HistogramKey(name: String, unitOfMeasurement: UnitOfMeasurement) extends MetricKey
/**
* MetricKey for all MinMaxCounter-based metrics.
*/
-case class MinMaxCounterKey(name: String, unitOfMeasurement: UnitOfMeasurement, metadata: Map[String, String]) 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, Map.empty)
-
- /**
- * 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)
-}
+private[kamon] case class MinMaxCounterKey(name: String, unitOfMeasurement: UnitOfMeasurement) extends MetricKey
/**
* MetricKey for all Gauge-based metrics.
*/
-case class GaugeKey(name: String, unitOfMeasurement: UnitOfMeasurement, metadata: Map[String, String]) 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, Map.empty)
-
- /**
- * 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)
-}
+private[kamon] case class GaugeKey(name: String, unitOfMeasurement: UnitOfMeasurement) extends MetricKey
/**
* MetricKey for all Counter-based metrics.
*/
-case class CounterKey(name: String, unitOfMeasurement: UnitOfMeasurement, metadata: Map[String, String]) 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, Map.empty)
-
- /**
- * 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
+private[kamon] case class CounterKey(name: String, unitOfMeasurement: UnitOfMeasurement) extends MetricKey
diff --git a/kamon-core/src/main/scala/kamon/metric/Metrics.scala b/kamon-core/src/main/scala/kamon/metric/Metrics.scala
index d79b1de3..9fd9e771 100644
--- a/kamon-core/src/main/scala/kamon/metric/Metrics.scala
+++ b/kamon-core/src/main/scala/kamon/metric/Metrics.scala
@@ -16,46 +16,221 @@
package kamon.metric
+import akka.actor._
import com.typesafe.config.Config
-import kamon.metric.SubscriptionsDispatcher.{ Unsubscribe, Subscribe }
-import kamon.metric.instrument.{ DefaultRefreshScheduler, InstrumentFactory, CollectionContext }
+import kamon.metric.SubscriptionsDispatcher.{ Subscribe, Unsubscribe }
+import kamon.metric.instrument.Gauge.CurrentValueCollector
+import kamon.metric.instrument.Histogram.DynamicRange
+import kamon.metric.instrument._
+import kamon.util.LazyActorRef
import scala.collection.concurrent.TrieMap
-import akka.actor._
-import kamon.util.{ 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(name: String, category: String, tags: Map[String, String]): Option[EntityRecorder] =
+ find(Entity(name, category, tags))
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)
+ subscribe(filter, subscriber, permanently = true)
def subscribe(category: String, selection: String, subscriber: ActorRef, permanently: Boolean): Unit =
subscribe(SubscriptionFilter(category, selection), subscriber, permanently)
def subscribe(category: String, selection: String, subscriber: ActorRef): Unit =
- subscribe(SubscriptionFilter(category, selection), subscriber, permanently = false)
+ subscribe(SubscriptionFilter(category, selection), subscriber, permanently = true)
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 kamon.util.TriemapAtomicGetOrElseUpdate.Syntax
+
private val _trackedEntities = TrieMap.empty[Entity, EntityRecorder]
private val _subscriptions = new LazyActorRef
@@ -67,35 +242,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, SingleInstrumentEntityRecorder.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, SingleInstrumentEntityRecorder.Histogram, tags)).isDefined
- EntityRegistration(entity, recorder)
+ def registerMinMaxCounter(name: String, tags: Map[String, String], unitOfMeasurement: Option[UnitOfMeasurement], dynamicRange: Option[DynamicRange],
+ refreshInterval: Option[FiniteDuration]): MinMaxCounter = {
+
+ val minMaxCounterEntity = Entity(name, SingleInstrumentEntityRecorder.MinMaxCounter, 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 unregister(entity: Entity): Unit =
- _trackedEntities.remove(entity).map(_.cleanup)
+ def removeMinMaxCounter(name: String, tags: Map[String, String]): Boolean =
+ _trackedEntities.remove(Entity(name, SingleInstrumentEntityRecorder.MinMaxCounter, 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, SingleInstrumentEntityRecorder.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, SingleInstrumentEntityRecorder.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, SingleInstrumentEntityRecorder.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, SingleInstrumentEntityRecorder.Counter, tags)).isDefined
+
+ def entity[T <: EntityRecorder](recorderFactory: EntityRecorderFactory[T], entity: Entity): T = {
+ _trackedEntities.atomicGetOrElseUpdate(entity, {
+ recorderFactory.createRecorder(instrumentFactory(recorderFactory.category))
+ }, _.cleanup).asInstanceOf[T]
+ }
+
+ 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 <http://kamon.io/>
- *
- * 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..eb4f327a 100644
--- a/kamon-core/src/main/scala/kamon/metric/TraceMetrics.scala
+++ b/kamon-core/src/main/scala/kamon/metric/TraceMetrics.scala
@@ -16,29 +16,36 @@
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)
- def segmentKey(name: String, category: String, library: String): HistogramKey =
- HistogramKey(name, Time.Nanoseconds, Map("category" -> category, "library" -> library))
+ // Java API.
+ def factory: EntityRecorderFactory[TraceMetrics] = this
+}
+
+class SegmentMetrics(instrumentFactory: InstrumentFactory) extends GenericEntityRecorder(instrumentFactory) {
+
+ /**
+ * Records blah blah
+ */
+ val elapsedTime = histogram("elapsed-time", unitOfMeasurement = Time.Nanoseconds)
+}
+
+object SegmentMetrics extends EntityRecorderFactory[SegmentMetrics] {
+ def category: String = "trace-segment"
+ def createRecorder(instrumentFactory: InstrumentFactory): SegmentMetrics = new SegmentMetrics(instrumentFactory)
+
+ // Java API.
+ def factory: EntityRecorderFactory[SegmentMetrics] = this
} \ 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/metric/instrument/Instrument.scala b/kamon-core/src/main/scala/kamon/metric/instrument/Instrument.scala
index 59b4b443..089dbeec 100644
--- a/kamon-core/src/main/scala/kamon/metric/instrument/Instrument.scala
+++ b/kamon-core/src/main/scala/kamon/metric/instrument/Instrument.scala
@@ -33,14 +33,6 @@ trait InstrumentSnapshot {
def merge(that: InstrumentSnapshot, context: CollectionContext): InstrumentSnapshot
}
-class InstrumentType private[kamon] (val id: Int) extends AnyVal
-object InstrumentTypes {
- val Histogram = new InstrumentType(1)
- val MinMaxCounter = new InstrumentType(2)
- val Gauge = new InstrumentType(3)
- val Counter = new InstrumentType(4)
-}
-
trait CollectionContext {
def buffer: LongBuffer
}
@@ -51,3 +43,11 @@ object CollectionContext {
}
}
+sealed trait InstrumentType
+
+object InstrumentTypes {
+ case object Histogram extends InstrumentType
+ case object MinMaxCounter extends InstrumentType
+ case object Gauge extends InstrumentType
+ case object Counter extends InstrumentType
+}
diff --git a/kamon-core/src/main/scala/kamon/metric/instrument/RefreshScheduler.scala b/kamon-core/src/main/scala/kamon/metric/instrument/RefreshScheduler.scala
index adb08713..4809ac0d 100644
--- a/kamon-core/src/main/scala/kamon/metric/instrument/RefreshScheduler.scala
+++ b/kamon-core/src/main/scala/kamon/metric/instrument/RefreshScheduler.scala
@@ -1,3 +1,19 @@
+/*
+ * =========================================================================================
+ * Copyright © 2013-2015 the kamon project <http://kamon.io/>
+ *
+ * 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.instrument
import akka.actor.{ Scheduler, Cancellable }
diff --git a/kamon-core/src/main/scala/kamon/metric/instrument/UnitOfMeasurement.scala b/kamon-core/src/main/scala/kamon/metric/instrument/UnitOfMeasurement.scala
index f2a061d1..c5a1b81a 100644
--- a/kamon-core/src/main/scala/kamon/metric/instrument/UnitOfMeasurement.scala
+++ b/kamon-core/src/main/scala/kamon/metric/instrument/UnitOfMeasurement.scala
@@ -16,17 +16,20 @@
package kamon.metric.instrument
+/**
+ * A UnitOfMeasurement implementation describes the magnitude of a quantity being measured, such as Time and computer
+ * Memory space. Kamon uses UnitOfMeasurement implementations just as a informative companion to metrics inside entity
+ * recorders and might be used to scale certain kinds of measurements in metric backends.
+ */
trait UnitOfMeasurement {
def name: String
def label: String
- def factor: Double
}
object UnitOfMeasurement {
case object Unknown extends UnitOfMeasurement {
val name = "unknown"
val label = "unknown"
- val factor = 1D
}
def isUnknown(uom: UnitOfMeasurement): Boolean =
@@ -35,19 +38,18 @@ object UnitOfMeasurement {
def isTime(uom: UnitOfMeasurement): Boolean =
uom.isInstanceOf[Time]
+ def isMemory(uom: UnitOfMeasurement): Boolean =
+ uom.isInstanceOf[Memory]
+
}
+/**
+ * UnitOfMeasurement representing time.
+ */
case class Time(factor: Double, label: String) extends UnitOfMeasurement {
val name = "time"
- /**
- * Scale a value from this scale factor to a different scale factor.
- *
- * @param toUnit Time unit of the expected result.
- * @param value Value to scale.
- * @return Equivalent of value on the target time unit.
- */
- def scale(toUnit: Time)(value: Long): Double =
+ def scale(toUnit: Time)(value: Double): Double =
(value * factor) / toUnit.factor
}
@@ -58,8 +60,14 @@ object Time {
val Seconds = Time(1, "s")
}
+/**
+ * UnitOfMeasurement representing computer memory space.
+ */
case class Memory(factor: Double, label: String) extends UnitOfMeasurement {
val name = "bytes"
+
+ def scale(toUnit: Memory)(value: Double): Double =
+ (value * factor) / toUnit.factor
}
object Memory {
diff --git a/kamon-core/src/main/scala/kamon/supervisor/ModuleSupervisorExtension.scala b/kamon-core/src/main/scala/kamon/supervisor/ModuleSupervisorExtension.scala
deleted file mode 100644
index ddce63fb..00000000
--- a/kamon-core/src/main/scala/kamon/supervisor/ModuleSupervisorExtension.scala
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * =========================================================================================
- * Copyright © 2013-2015 the kamon project <http://kamon.io/>
- *
- * 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.supervisor
-
-import akka.actor
-import akka.actor._
-import kamon.Kamon
-import kamon.supervisor.KamonSupervisor.CreateModule
-
-import scala.concurrent.{ Promise, Future }
-import scala.util.Success
-
-object ModuleSupervisor extends ExtensionId[ModuleSupervisorExtension] with ExtensionIdProvider {
- def lookup(): ExtensionId[_ <: actor.Extension] = ModuleSupervisor
- def createExtension(system: ExtendedActorSystem): ModuleSupervisorExtension = new ModuleSupervisorExtensionImpl(system)
-}
-
-trait ModuleSupervisorExtension extends actor.Extension {
- def createModule(name: String, props: Props): Future[ActorRef]
-}
-
-class ModuleSupervisorExtensionImpl(system: ExtendedActorSystem) extends ModuleSupervisorExtension {
- import system.dispatcher
-
- private val _settings = ModuleSupervisorSettings(system)
- private val _supervisor = system.actorOf(KamonSupervisor.props(_settings, system.dynamicAccess), "kamon")
-
- def createModule(name: String, props: Props): Future[ActorRef] = Future {} flatMap { _: Unit ⇒
- val modulePromise = Promise[ActorRef]()
- _supervisor ! CreateModule(name, props, modulePromise)
- modulePromise.future
- }
-}
-
-class KamonSupervisor(settings: ModuleSupervisorSettings, dynamicAccess: DynamicAccess) extends Actor with ActorLogging {
-
- init()
-
- def receive = {
- case CreateModule(name, props, childPromise) ⇒ createChildModule(name, props, childPromise)
- }
-
- def createChildModule(name: String, props: Props, childPromise: Promise[ActorRef]): Unit =
- context.child(name).map { alreadyAvailableModule ⇒
- log.warning("Received a request to create module [{}] but the module is already available, returning the existent instance.")
- childPromise.complete(Success(alreadyAvailableModule))
-
- } getOrElse (childPromise.complete(Success(context.actorOf(props, name))))
-
- def init(): Unit = {
- if (settings.modulesRequiringAspectJ.nonEmpty && !isAspectJPresent && settings.showAspectJMissingWarning)
- logAspectJWeaverMissing(settings.modulesRequiringAspectJ)
-
- // Force initialization of all modules marked with auto-start.
- settings.availableModules.filter(_.autoStart).foreach { module ⇒
- if (module.extensionClass == "none")
- log.debug("Ignoring auto start of the [{}] module with no extension class.")
- else
- dynamicAccess.getObjectFor[ExtensionId[Kamon.Extension]](module.extensionClass).map { moduleID ⇒
- moduleID.get(context.system)
- log.debug("Auto starting the [{}] module.", module.name)
-
- } recover {
- case th: Throwable ⇒ log.error(th, "Failed to auto start the [{}] module.", module.name)
- }
-
- }
- }
-
- // When AspectJ is present the kamon.supervisor.AspectJPresent aspect will make this return true.
- def isAspectJPresent: Boolean = false
-
- def logAspectJWeaverMissing(modulesRequiringAspectJ: List[AvailableModuleInfo]): Unit = {
- val moduleNames = modulesRequiringAspectJ.map(_.name).mkString(", ")
- val weaverMissingMessage =
- """
- |
- | ___ _ ___ _ _ ___ ___ _ _
- | / _ \ | | |_ | | | | | | \/ |(_) (_)
- |/ /_\ \ ___ _ __ ___ ___ | |_ | | | | | | ___ __ _ __ __ ___ _ __ | . . | _ ___ ___ _ _ __ __ _
- || _ |/ __|| '_ \ / _ \ / __|| __| | | | |/\| | / _ \ / _` |\ \ / // _ \| '__| | |\/| || |/ __|/ __|| || '_ \ / _` |
- || | | |\__ \| |_) || __/| (__ | |_ /\__/ / \ /\ /| __/| (_| | \ V /| __/| | | | | || |\__ \\__ \| || | | || (_| |
- |\_| |_/|___/| .__/ \___| \___| \__|\____/ \/ \/ \___| \__,_| \_/ \___||_| \_| |_/|_||___/|___/|_||_| |_| \__, |
- | | | __/ |
- | |_| |___/
- |
- | It seems like your application was not started with the -javaagent:/path-to-aspectj-weaver.jar option but Kamon detected
- | the following modules which require AspecJ to work properly:
- |
- """.stripMargin + moduleNames +
- """
- |
- | If you need help on setting up the aspectj weaver go to http://kamon.io/introduction/get-started/ for more info. On the
- | other hand, if you are sure that you do not need or do not want to use the weaver then you can disable this error message
- | by changing the kamon.show-aspectj-missing-warning setting in your configuration file.
- |
- """.stripMargin
-
- log.error(weaverMissingMessage)
- }
-
-}
-
-object KamonSupervisor {
- case class CreateModule(name: String, props: Props, childPromise: Promise[ActorRef])
-
- def props(settings: ModuleSupervisorSettings, dynamicAccess: DynamicAccess): Props =
- Props(new KamonSupervisor(settings, dynamicAccess))
-
-}
-
diff --git a/kamon-core/src/main/scala/kamon/supervisor/ModuleSupervisorSettings.scala b/kamon-core/src/main/scala/kamon/supervisor/ModuleSupervisorSettings.scala
deleted file mode 100644
index c04157aa..00000000
--- a/kamon-core/src/main/scala/kamon/supervisor/ModuleSupervisorSettings.scala
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * =========================================================================================
- * Copyright © 2013-2015 the kamon project <http://kamon.io/>
- *
- * 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.supervisor
-
-import akka.actor.ActorSystem
-
-case class AvailableModuleInfo(name: String, extensionClass: String, requiresAspectJ: Boolean, autoStart: Boolean)
-case class ModuleSupervisorSettings(showAspectJMissingWarning: Boolean, availableModules: List[AvailableModuleInfo]) {
- val modulesRequiringAspectJ = availableModules.filter(_.requiresAspectJ)
-}
-
-object ModuleSupervisorSettings {
-
- def apply(system: ActorSystem): ModuleSupervisorSettings = {
- import kamon.util.ConfigTools.Syntax
-
- val config = system.settings.config.getConfig("kamon.modules")
- val showAspectJMissingWarning = system.settings.config.getBoolean("kamon.show-aspectj-missing-warning")
-
- val modules = config.firstLevelKeys
- val availableModules = modules.map { moduleName ⇒
- val moduleConfig = config.getConfig(moduleName)
-
- AvailableModuleInfo(
- moduleName,
- moduleConfig.getString("extension-id"),
- moduleConfig.getBoolean("requires-aspectj"),
- moduleConfig.getBoolean("auto-start"))
-
- } toList
-
- ModuleSupervisorSettings(showAspectJMissingWarning, availableModules)
- }
-
-}
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/supervisor/AspectJPresent.scala b/kamon-core/src/main/scala/kamon/util/FunctionalInterfaces.scala
index 0df9539f..8dab6519 100644
--- a/kamon-core/src/main/scala/kamon/supervisor/AspectJPresent.scala
+++ b/kamon-core/src/main/scala/kamon/util/FunctionalInterfaces.scala
@@ -14,18 +14,12 @@
* =========================================================================================
*/
-package kamon.supervisor
-
-import org.aspectj.lang.ProceedingJoinPoint
-import org.aspectj.lang.annotation.{ Around, Aspect, Pointcut }
-
-@Aspect
-class AspectJPresent {
-
- @Pointcut("execution(* kamon.supervisor.KamonSupervisor.isAspectJPresent())")
- def isAspectJPresentAtModuleSupervisor(): Unit = {}
-
- @Around("isAspectJPresentAtModuleSupervisor()")
- def aroundIsAspectJPresentAtModuleSupervisor(pjp: ProceedingJoinPoint): Boolean = true
+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/main/scala/kamon/util/JavaTags.scala b/kamon-core/src/main/scala/kamon/util/JavaTags.scala
new file mode 100644
index 00000000..90bece5c
--- /dev/null
+++ b/kamon-core/src/main/scala/kamon/util/JavaTags.scala
@@ -0,0 +1,14 @@
+package kamon.util
+
+object JavaTags {
+
+ /**
+ * Helper method to transform Java maps into Scala maps. Typically this will be used as a static import from
+ * Java code that wants to use tags, as tags are defined as scala.collection.mutable.Map[String, String] and
+ * creating them directly from Java is quite verbose.
+ */
+ def tagsFromMap(tags: java.util.Map[String, String]): Map[String, String] = {
+ import scala.collection.JavaConversions._
+ tags.toMap
+ }
+}
diff --git a/kamon-core/src/main/scala/kamon/instrumentation/AspectJWeaverMissingWarning.scala b/kamon-core/src/main/scala/kamon/util/Latency.scala
index 4dc5ff41..52e044f8 100644
--- a/kamon-core/src/main/scala/kamon/instrumentation/AspectJWeaverMissingWarning.scala
+++ b/kamon-core/src/main/scala/kamon/util/Latency.scala
@@ -14,20 +14,16 @@
* =========================================================================================
*/
-package kamon.instrumentation
+package kamon.util
-import _root_.akka.event.EventStream
-import org.aspectj.lang.ProceedingJoinPoint
-import org.aspectj.lang.annotation.{ Around, Pointcut, Aspect }
+import kamon.metric.instrument.Histogram
-@Aspect
-class AspectJWeaverMissingWarning {
-
- @Pointcut("execution(* kamon.metric.MetricsExtension.printInitializationMessage(..)) && args(eventStream, *)")
- def printInitializationMessage(eventStream: EventStream): Unit = {}
-
- @Around("printInitializationMessage(eventStream)")
- def aroundPrintInitializationMessage(pjp: ProceedingJoinPoint, eventStream: EventStream): Unit = {
- pjp.proceed(Array[AnyRef](eventStream, Boolean.box(true)))
+object Latency {
+ def measure[A](histogram: Histogram)(thunk: ⇒ A): A = {
+ val start = RelativeNanoTimestamp.now
+ try thunk finally {
+ val latency = NanoInterval.since(start).nanos
+ histogram.record(latency)
+ }
}
}
diff --git a/kamon-core/src/main/scala/kamon/util/LazyActorRef.scala b/kamon-core/src/main/scala/kamon/util/LazyActorRef.scala
index 855bf1fc..e2fb747a 100644
--- a/kamon-core/src/main/scala/kamon/util/LazyActorRef.scala
+++ b/kamon-core/src/main/scala/kamon/util/LazyActorRef.scala
@@ -1,3 +1,19 @@
+/*
+ * =========================================================================================
+ * Copyright © 2013-2015 the kamon project <http://kamon.io/>
+ *
+ * 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.util
import java.util
diff --git a/kamon-core/src/main/scala/kamon/util/MapMerge.scala b/kamon-core/src/main/scala/kamon/util/MapMerge.scala
index 64b4f7ae..8573358b 100644
--- a/kamon-core/src/main/scala/kamon/util/MapMerge.scala
+++ b/kamon-core/src/main/scala/kamon/util/MapMerge.scala
@@ -19,7 +19,7 @@ package kamon.util
object MapMerge {
/**
- * Merge to immutable maps with the same key and value types, using the provided valueMerge function.
+ * Merge two immutable maps with the same key and value types, using the provided valueMerge function.
*/
implicit class Syntax[K, V](val map: Map[K, V]) extends AnyVal {
def merge(that: Map[K, V], valueMerge: (V, V) ⇒ V): Map[K, V] = {
diff --git a/kamon-core/src/main/scala/kamon/util/SameThreadExecutionContext.scala b/kamon-core/src/main/scala/kamon/util/SameThreadExecutionContext.scala
new file mode 100644
index 00000000..2aae526f
--- /dev/null
+++ b/kamon-core/src/main/scala/kamon/util/SameThreadExecutionContext.scala
@@ -0,0 +1,30 @@
+/*
+ * =========================================================================================
+ * Copyright © 2013-2015 the kamon project <http://kamon.io/>
+ *
+ * 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.util
+
+import scala.concurrent.ExecutionContext
+import org.slf4j.LoggerFactory
+
+/**
+ * For small code blocks that don't need to be run on a separate thread.
+ */
+object SameThreadExecutionContext extends ExecutionContext {
+ val logger = LoggerFactory.getLogger("SameThreadExecutionContext")
+
+ override def execute(runnable: Runnable): Unit = runnable.run
+ override def reportFailure(t: Throwable): Unit = logger.error(t.getMessage, t)
+}
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)