diff options
48 files changed, 783 insertions, 798 deletions
diff --git a/kamon-akka/src/main/scala/kamon/akka/instrumentation/ActorCellInstrumentation.scala b/kamon-akka/src/main/scala/kamon/akka/instrumentation/ActorCellInstrumentation.scala index 4783484f..d1d420fe 100644 --- a/kamon-akka/src/main/scala/kamon/akka/instrumentation/ActorCellInstrumentation.scala +++ b/kamon-akka/src/main/scala/kamon/akka/instrumentation/ActorCellInstrumentation.scala @@ -34,11 +34,14 @@ class ActorCellInstrumentation { @After("actorCellCreation(cell, system, ref, props, dispatcher, parent)") def afterCreation(cell: ActorCell, system: ActorSystem, ref: ActorRef, props: Props, dispatcher: MessageDispatcher, parent: ActorRef): Unit = { - Kamon.metrics.register(ActorMetrics, ref.path.elements.mkString("/")).map { registration ⇒ + val actorEntity = Entity(ref.path.elements.mkString("/"), ActorMetrics.category) + + if (Kamon.metrics.shouldTrack(actorEntity)) { + val actorMetricsRecorder = Kamon.metrics.entity(ActorMetrics, actorEntity) val cellMetrics = cell.asInstanceOf[ActorCellMetrics] - cellMetrics.entity = registration.entity - cellMetrics.recorder = Some(registration.recorder) + cellMetrics.entity = actorEntity + cellMetrics.recorder = Some(actorMetricsRecorder) } } @@ -90,14 +93,14 @@ class ActorCellInstrumentation { def afterStop(cell: ActorCell): Unit = { val cellMetrics = cell.asInstanceOf[ActorCellMetrics] cellMetrics.recorder.map { _ ⇒ - Kamon.metrics.unregister(cellMetrics.entity) + Kamon.metrics.removeEntity(cellMetrics.entity) } // The Stop can't be captured from the RoutedActorCell so we need to put this piece of cleanup here. if (cell.isInstanceOf[RoutedActorCell]) { val routedCellMetrics = cell.asInstanceOf[RoutedActorCellMetrics] routedCellMetrics.routerRecorder.map { _ ⇒ - Kamon.metrics.unregister(routedCellMetrics.routerEntity) + Kamon.metrics.removeEntity(routedCellMetrics.routerEntity) } } } @@ -124,11 +127,13 @@ class RoutedActorCellInstrumentation { @After("routedActorCellCreation(cell, system, ref, props, dispatcher, routeeProps, supervisor)") def afterRoutedActorCellCreation(cell: RoutedActorCell, system: ActorSystem, ref: ActorRef, props: Props, dispatcher: MessageDispatcher, routeeProps: Props, supervisor: ActorRef): Unit = { - Kamon.metrics.register(RouterMetrics, ref.path.elements.mkString("/")).map { registration ⇒ + val routerEntity = Entity(ref.path.elements.mkString("/"), RouterMetrics.category) + + if (Kamon.metrics.shouldTrack(routerEntity)) { val cellMetrics = cell.asInstanceOf[RoutedActorCellMetrics] - cellMetrics.routerEntity = registration.entity - cellMetrics.routerRecorder = Some(registration.recorder) + cellMetrics.routerEntity = routerEntity + cellMetrics.routerRecorder = Some(Kamon.metrics.entity(RouterMetrics, routerEntity)) } } diff --git a/kamon-akka/src/main/scala/kamon/akka/instrumentation/DispatcherInstrumentation.scala b/kamon-akka/src/main/scala/kamon/akka/instrumentation/DispatcherInstrumentation.scala index 7b15c443..eb6b5293 100644 --- a/kamon-akka/src/main/scala/kamon/akka/instrumentation/DispatcherInstrumentation.scala +++ b/kamon-akka/src/main/scala/kamon/akka/instrumentation/DispatcherInstrumentation.scala @@ -59,10 +59,16 @@ class DispatcherInstrumentation { private def registerDispatcher(dispatcherName: String, executorService: ExecutorService, system: ActorSystem): Unit = executorService match { case fjp: AkkaForkJoinPool ⇒ - Kamon.metrics.register(ForkJoinPoolDispatcherMetrics.factory(fjp), dispatcherName) + val dispatcherEntity = Entity(dispatcherName, AkkaDispatcherMetrics.Category) + + if (Kamon.metrics.shouldTrack(dispatcherEntity)) + Kamon.metrics.entity(ForkJoinPoolDispatcherMetrics.factory(fjp), dispatcherName) case tpe: ThreadPoolExecutor ⇒ - Kamon.metrics.register(ThreadPoolExecutorDispatcherMetrics.factory(tpe), dispatcherName) + val dispatcherEntity = Entity(dispatcherName, AkkaDispatcherMetrics.Category) + + if (Kamon.metrics.shouldTrack(dispatcherEntity)) + Kamon.metrics.entity(ThreadPoolExecutorDispatcherMetrics.factory(tpe), dispatcherName) case others ⇒ // Currently not interested in other kinds of dispatchers. } @@ -120,7 +126,7 @@ class DispatcherInstrumentation { import lazyExecutor.lookupData if (lookupData.actorSystem != null) - Kamon.metrics.unregister(Entity(lookupData.dispatcherName, AkkaDispatcherMetrics.Category)) + Kamon.metrics.removeEntity(Entity(lookupData.dispatcherName, AkkaDispatcherMetrics.Category)) } } diff --git a/kamon-akka/src/test/scala/kamon/akka/ActorMetricsSpec.scala b/kamon-akka/src/test/scala/kamon/akka/ActorMetricsSpec.scala index 19a71053..f4db8b8c 100644 --- a/kamon-akka/src/test/scala/kamon/akka/ActorMetricsSpec.scala +++ b/kamon-akka/src/test/scala/kamon/akka/ActorMetricsSpec.scala @@ -151,7 +151,7 @@ class ActorMetricsSpec extends BaseKamonSpec("actor-metrics-spec") { trackedActor ! PoisonPill deathWatcher.expectTerminated(trackedActor) - actorMetricsRecorderOf(trackedActor).get shouldNot be theSameInstanceAs (firstRecorder) + actorMetricsRecorderOf(trackedActor) shouldBe empty } } @@ -165,7 +165,7 @@ class ActorMetricsSpec extends BaseKamonSpec("actor-metrics-spec") { def actorRecorderName(ref: ActorRef): String = ref.path.elements.mkString("/") def actorMetricsRecorderOf(ref: ActorRef): Option[ActorMetrics] = - Kamon.metrics.register(ActorMetrics, actorRecorderName(ref)).map(_.recorder) + Kamon.metrics.find(actorRecorderName(ref), ActorMetrics.category).map(_.asInstanceOf[ActorMetrics]) def collectMetricsOf(ref: ActorRef): Option[EntitySnapshot] = { Thread.sleep(5) // Just in case the test advances a bit faster than the actor being tested. diff --git a/kamon-akka/src/test/scala/kamon/akka/DispatcherMetricsSpec.scala b/kamon-akka/src/test/scala/kamon/akka/DispatcherMetricsSpec.scala index 2379bff5..dd5cfa45 100644 --- a/kamon-akka/src/test/scala/kamon/akka/DispatcherMetricsSpec.scala +++ b/kamon-akka/src/test/scala/kamon/akka/DispatcherMetricsSpec.scala @@ -15,7 +15,6 @@ package kamon.akka - import akka.actor.ActorRef import akka.dispatch.MessageDispatcher import akka.testkit.TestProbe diff --git a/kamon-akka/src/test/scala/kamon/akka/RouterMetricsSpec.scala b/kamon-akka/src/test/scala/kamon/akka/RouterMetricsSpec.scala index ec55648b..41c329d6 100644 --- a/kamon-akka/src/test/scala/kamon/akka/RouterMetricsSpec.scala +++ b/kamon-akka/src/test/scala/kamon/akka/RouterMetricsSpec.scala @@ -180,7 +180,7 @@ class RouterMetricsSpec extends BaseKamonSpec("router-metrics-spec") { trackedRouter ! PoisonPill deathWatcher.expectTerminated(trackedRouter) - routerMetricsRecorderOf("user/stop-in-pool-router").get shouldNot be theSameInstanceAs (firstRecorder) + routerMetricsRecorderOf("user/stop-in-pool-router") shouldBe empty } "clean up the associated recorder when the group router is stopped" in new RouterMetricsFixtures { @@ -193,7 +193,7 @@ class RouterMetricsSpec extends BaseKamonSpec("router-metrics-spec") { trackedRouter ! PoisonPill deathWatcher.expectTerminated(trackedRouter) - routerMetricsRecorderOf("user/stop-in-group-router").get shouldNot be theSameInstanceAs (firstRecorder) + routerMetricsRecorderOf("user/stop-in-group-router") shouldBe empty } } @@ -205,7 +205,7 @@ class RouterMetricsSpec extends BaseKamonSpec("router-metrics-spec") { } def routerMetricsRecorderOf(routerName: String): Option[RouterMetrics] = - Kamon.metrics.register(RouterMetrics, routerName).map(_.recorder) + Kamon.metrics.find(routerName, RouterMetrics.category).map(_.asInstanceOf[RouterMetrics]) def collectMetricsOf(routerName: String): Option[EntitySnapshot] = { Thread.sleep(5) // Just in case the test advances a bit faster than the actor being tested. diff --git a/kamon-akka/src/test/scala/kamon/akka/instrumentation/ActorLoggingInstrumentationSpec.scala b/kamon-akka/src/test/scala/kamon/akka/instrumentation/ActorLoggingInstrumentationSpec.scala index 42a26cdd..85f41795 100644 --- a/kamon-akka/src/test/scala/kamon/akka/instrumentation/ActorLoggingInstrumentationSpec.scala +++ b/kamon-akka/src/test/scala/kamon/akka/instrumentation/ActorLoggingInstrumentationSpec.scala @@ -21,7 +21,7 @@ import com.typesafe.config.ConfigFactory import kamon.testkit.BaseKamonSpec import kamon.trace.TraceLocal.AvailableToMdc import kamon.trace.logging.MdcKeysSupport -import kamon.trace.{Tracer, TraceContextAware, TraceLocal} +import kamon.trace.{ Tracer, TraceContextAware, TraceLocal } import org.scalatest.Inspectors import org.slf4j.MDC diff --git a/kamon-akka/src/test/scala/kamon/akka/instrumentation/ActorSystemMessageInstrumentationSpec.scala b/kamon-akka/src/test/scala/kamon/akka/instrumentation/ActorSystemMessageInstrumentationSpec.scala index fd9f58d0..1635fadc 100644 --- a/kamon-akka/src/test/scala/kamon/akka/instrumentation/ActorSystemMessageInstrumentationSpec.scala +++ b/kamon-akka/src/test/scala/kamon/akka/instrumentation/ActorSystemMessageInstrumentationSpec.scala @@ -21,7 +21,7 @@ import akka.actor._ import akka.testkit.ImplicitSender import com.typesafe.config.ConfigFactory import kamon.testkit.BaseKamonSpec -import kamon.trace.{Tracer, EmptyTraceContext} +import kamon.trace.{ Tracer, EmptyTraceContext } import org.scalatest.WordSpecLike import scala.concurrent.duration._ diff --git a/kamon-akka/src/test/scala/kamon/akka/instrumentation/AskPatternInstrumentationSpec.scala b/kamon-akka/src/test/scala/kamon/akka/instrumentation/AskPatternInstrumentationSpec.scala index a44945ea..4268e53d 100644 --- a/kamon-akka/src/test/scala/kamon/akka/instrumentation/AskPatternInstrumentationSpec.scala +++ b/kamon-akka/src/test/scala/kamon/akka/instrumentation/AskPatternInstrumentationSpec.scala @@ -27,7 +27,7 @@ import com.typesafe.config.ConfigFactory import kamon.Kamon import kamon.akka.Akka import kamon.testkit.BaseKamonSpec -import kamon.trace.{Tracer, TraceContext, TraceContextAware} +import kamon.trace.{ Tracer, TraceContext, TraceContextAware } import scala.concurrent.duration._ diff --git a/kamon-annotation/src/main/scala/kamon/annotation/instrumentation/BaseAnnotationInstrumentation.scala b/kamon-annotation/src/main/scala/kamon/annotation/instrumentation/BaseAnnotationInstrumentation.scala index 57e8c4d7..2074e237 100644 --- a/kamon-annotation/src/main/scala/kamon/annotation/instrumentation/BaseAnnotationInstrumentation.scala +++ b/kamon-annotation/src/main/scala/kamon/annotation/instrumentation/BaseAnnotationInstrumentation.scala @@ -39,7 +39,7 @@ class BaseAnnotationInstrumentation { val time = method.getAnnotation(classOf[Time]) val name = evalString(time.name()) val tags = evalTags(time.tags()) - val currentHistogram = Kamon.simpleMetrics.histogram(HistogramKey(name, tags)) + val currentHistogram = Kamon.metrics.histogram(name, tags) histograms.set(jps.getId, currentHistogram) currentHistogram } @@ -50,7 +50,7 @@ class BaseAnnotationInstrumentation { val name = evalString(histogram.name()) val tags = evalTags(histogram.tags()) val dynamicRange = DynamicRange(histogram.lowestDiscernibleValue(), histogram.highestTrackableValue(), histogram.precision()) - val currentHistogram = Kamon.simpleMetrics.histogram(HistogramKey(name, tags), dynamicRange) + val currentHistogram = Kamon.metrics.histogram(name, tags, dynamicRange) histograms.set(jps.getId, currentHistogram) currentHistogram } @@ -60,7 +60,7 @@ class BaseAnnotationInstrumentation { val minMaxCount = method.getAnnotation(classOf[MinMaxCount]) val name = evalString(minMaxCount.name()) val tags = evalTags(minMaxCount.tags()) - val minMaxCounter = Kamon.simpleMetrics.minMaxCounter(MinMaxCounterKey(name, tags)) + val minMaxCounter = Kamon.metrics.minMaxCounter(name, tags) minMaxCounters.set(jps.getId, minMaxCounter) minMaxCounter } @@ -70,7 +70,7 @@ class BaseAnnotationInstrumentation { val count = method.getAnnotation(classOf[Count]) val name = evalString(count.name()) val tags = evalTags(count.tags()) - val counter = Kamon.simpleMetrics.counter(CounterKey(name, tags)) + val counter = Kamon.metrics.counter(name, tags) counters.set(jps.getId, counter) counter } diff --git a/kamon-annotation/src/test/scala/kamon/annotation/AnnotationInstrumentationSpec.scala b/kamon-annotation/src/test/scala/kamon/annotation/AnnotationInstrumentationSpec.scala index 41f0fc34..3d94d246 100644 --- a/kamon-annotation/src/test/scala/kamon/annotation/AnnotationInstrumentationSpec.scala +++ b/kamon-annotation/src/test/scala/kamon/annotation/AnnotationInstrumentationSpec.scala @@ -19,10 +19,9 @@ package kamon.annotation import com.typesafe.config.ConfigFactory import kamon.metric._ import kamon.testkit.BaseKamonSpec +import kamon.trace.SegmentCategory class AnnotationInstrumentationSpec extends BaseKamonSpec("annotation-instrumentation-spec") { - import kamon.metric.TraceMetricsSpec.SegmentSyntax - override lazy val config = ConfigFactory.parseString( """ @@ -38,7 +37,6 @@ class AnnotationInstrumentationSpec extends BaseKamonSpec("annotation-instrument val snapshot = takeSnapshotOf("trace", "trace") snapshot.histogram("elapsed-time").get.numberOfMeasurements should be(10) - snapshot.segments.size should be(0) } "create a segment when is invoked a method annotated with @Segment" in { @@ -47,8 +45,13 @@ class AnnotationInstrumentationSpec extends BaseKamonSpec("annotation-instrument val snapshot = takeSnapshotOf("trace-with-segment", "trace") snapshot.histogram("elapsed-time").get.numberOfMeasurements should be(10) - snapshot.segments.size should be(1) - snapshot.segment("inner-segment", "inner", "segment") should not be empty + val segmentMetricsSnapshot = takeSnapshotOf("inner-segment", "trace-segment", + tags = Map( + "trace" -> "trace-with-segment", + "category" -> "inner", + "library" -> "segment")) + + segmentMetricsSnapshot.histogram("elapsed-time").get.numberOfMeasurements should be(10) } "create a segment when is invoked a method annotated with @Segment and evaluate EL expressions" in { @@ -57,28 +60,30 @@ class AnnotationInstrumentationSpec extends BaseKamonSpec("annotation-instrument val snapshot = takeSnapshotOf("trace-with-segment-el", "trace") snapshot.histogram("elapsed-time").get.numberOfMeasurements should be(10) - snapshot.segments.size should be(10) - snapshot.segment("inner-segment:1", "inner", "segment") should not be empty + val segmentMetricsSnapshot = takeSnapshotOf("inner-segment:1", "trace-segment", + tags = Map( + "trace" -> "trace-with-segment-el", + "category" -> "inner", + "library" -> "segment")) + + segmentMetricsSnapshot.histogram("elapsed-time").get.numberOfMeasurements should be(1) } "count the invocations of a method annotated with @Count" in { for (id ← 1 to 10) Annotated(id).count() - val snapshot = takeSnapshotOf("simple-metric", "simple-metric") - snapshot.counter("count").get.count should be(10) + val snapshot = takeSnapshotOf("count", "counter") + snapshot.counter("counter").get.count should be(10) } "count the invocations of a method annotated with @Count and evaluate EL expressions" in { for (id ← 1 to 2) Annotated(id).countWithEL() - val snapshot = takeSnapshotOf("simple-metric", "simple-metric") - snapshot.counter("count:1").get.count should be(1) - snapshot.counter("count:2").get.count should be(1) + val counter1Snapshot = takeSnapshotOf("count:1", "counter", Map("counter" -> "1", "env" -> "prod")) + counter1Snapshot.counter("counter").get.count should be(1) - val counterKey = (name: String) ⇒ (key: CounterKey) ⇒ key.name == name - - snapshot.counters.keys.find(counterKey("count:1")).get.metadata should be(Map("counter" -> "1", "env" -> "prod")) - snapshot.counters.keys.find(counterKey("count:2")).get.metadata should be(Map("counter" -> "1", "env" -> "prod")) + val counter2Snapshot = takeSnapshotOf("count:2", "counter", Map("counter" -> "1", "env" -> "prod")) + counter2Snapshot.counter("counter").get.count should be(1) } "count the current invocations of a method annotated with @MinMaxCount" in { @@ -86,45 +91,38 @@ class AnnotationInstrumentationSpec extends BaseKamonSpec("annotation-instrument Annotated(id).countMinMax() } - val snapshot = takeSnapshotOf("simple-metric", "simple-metric") - snapshot.minMaxCounter("minMax").get.max should be(1) + val snapshot = takeSnapshotOf("minMax", "min-max-counter") + snapshot.minMaxCounter("min-max-counter").get.max should be(1) } "count the current invocations of a method annotated with @MinMaxCount and evaluate EL expressions" in { for (id ← 1 to 10) Annotated(id).countMinMaxWithEL() - val snapshot = takeSnapshotOf("simple-metric", "simple-metric") - snapshot.minMaxCounter("minMax:1").get.sum should be(1) - snapshot.minMaxCounter("minMax:2").get.sum should be(1) - - val minMaxKey = (name: String) ⇒ (key: MinMaxCounterKey) ⇒ key.name == name + val minMaxCounter1Snapshot = takeSnapshotOf("minMax:1", "min-max-counter", tags = Map("minMax" -> "1", "env" -> "dev")) + minMaxCounter1Snapshot.minMaxCounter("min-max-counter").get.sum should be(1) - snapshot.minMaxCounters.keys.find(minMaxKey("minMax:1")).get.metadata should be(Map("minMax" -> "1", "env" -> "dev")) - snapshot.minMaxCounters.keys.find(minMaxKey("minMax:2")).get.metadata should be(Map("minMax" -> "1", "env" -> "dev")) + val minMaxCounter2Snapshot = takeSnapshotOf("minMax:2", "min-max-counter", tags = Map("minMax" -> "1", "env" -> "dev")) + minMaxCounter2Snapshot.minMaxCounter("min-max-counter").get.sum should be(1) } "measure the time spent in the execution of a method annotated with @Time" in { for (id ← 1 to 1) Annotated(id).time() - val snapshot = takeSnapshotOf("simple-metric", "simple-metric") - snapshot.histogram("time").get.numberOfMeasurements should be(1) + val snapshot = takeSnapshotOf("time", "histogram") + snapshot.histogram("histogram").get.numberOfMeasurements should be(1) } "measure the time spent in the execution of a method annotated with @Time and evaluate EL expressions" in { for (id ← 1 to 1) Annotated(id).timeWithEL() - val snapshot = takeSnapshotOf("simple-metric", "simple-metric") - snapshot.histogram("time:1").get.numberOfMeasurements should be(1) - - val histogramKey = (name: String) ⇒ (key: HistogramKey) ⇒ key.name == name - - snapshot.histograms.keys.find(histogramKey("time:1")).get.metadata should be(Map("slow-service" -> "service", "env" -> "prod")) + val snapshot = takeSnapshotOf("time:1", "histogram", tags = Map("slow-service" -> "service", "env" -> "prod")) + snapshot.histogram("histogram").get.numberOfMeasurements should be(1) } "record the value returned by a method annotated with @Histogram" in { for (value ← 1 to 5) Annotated().histogram(value) - val snapshot = takeSnapshotOf("simple-metric", "simple-metric") + val snapshot = takeSnapshotOf("histogram", "histogram") snapshot.histogram("histogram").get.numberOfMeasurements should be(5) snapshot.histogram("histogram").get.min should be(1) snapshot.histogram("histogram").get.max should be(5) @@ -134,23 +132,18 @@ class AnnotationInstrumentationSpec extends BaseKamonSpec("annotation-instrument "record the value returned by a method annotated with @Histogram and evaluate EL expressions" in { for (value ← 1 to 2) Annotated(value).histogramWithEL(value) - val snapshot = takeSnapshotOf("simple-metric", "simple-metric") - snapshot.histogram("histogram:1").get.numberOfMeasurements should be(1) - snapshot.histogram("histogram:1").get.min should be(1) - snapshot.histogram("histogram:1").get.max should be(1) - snapshot.histogram("histogram:1").get.sum should be(1) - - snapshot.histogram("histogram:2").get.numberOfMeasurements should be(1) - snapshot.histogram("histogram:2").get.min should be(2) - snapshot.histogram("histogram:2").get.max should be(2) - snapshot.histogram("histogram:2").get.sum should be(2) - - val histogramKey = (name: String) ⇒ (key: HistogramKey) ⇒ key.name == name - - snapshot.histograms.keys.find(histogramKey("histogram:1")).get.metadata should be(Map("histogram" -> "hdr", "env" -> "prod")) - snapshot.histograms.keys.find(histogramKey("histogram:2")).get.metadata should be(Map("histogram" -> "hdr", "env" -> "prod")) + val snapshot1 = takeSnapshotOf("histogram:1", "histogram", tags = Map("histogram" -> "hdr", "env" -> "prod")) + snapshot1.histogram("histogram").get.numberOfMeasurements should be(1) + snapshot1.histogram("histogram").get.min should be(1) + snapshot1.histogram("histogram").get.max should be(1) + snapshot1.histogram("histogram").get.sum should be(1) + + val snapshot2 = takeSnapshotOf("histogram:2", "histogram", tags = Map("histogram" -> "hdr", "env" -> "prod")) + snapshot2.histogram("histogram").get.numberOfMeasurements should be(1) + snapshot2.histogram("histogram").get.min should be(2) + snapshot2.histogram("histogram").get.max should be(2) + snapshot2.histogram("histogram").get.sum should be(2) } - } } diff --git a/kamon-annotation/src/test/scala/kamon/annotation/StaticAnnotationInstrumentationJavaSpec.scala b/kamon-annotation/src/test/scala/kamon/annotation/StaticAnnotationInstrumentationJavaSpec.scala index 4bae9f1d..6e0fbd02 100644 --- a/kamon-annotation/src/test/scala/kamon/annotation/StaticAnnotationInstrumentationJavaSpec.scala +++ b/kamon-annotation/src/test/scala/kamon/annotation/StaticAnnotationInstrumentationJavaSpec.scala @@ -21,8 +21,6 @@ import kamon.metric.{ HistogramKey, MinMaxCounterKey, CounterKey } import kamon.testkit.BaseKamonSpec class StaticAnnotationInstrumentationJavaSpec extends BaseKamonSpec("static-annotation-instrumentation-java-spec") { - import kamon.metric.TraceMetricsSpec.SegmentSyntax - override lazy val config = ConfigFactory.parseString( """ @@ -38,16 +36,17 @@ class StaticAnnotationInstrumentationJavaSpec extends BaseKamonSpec("static-anno val snapshot = takeSnapshotOf("trace", "trace") snapshot.histogram("elapsed-time").get.numberOfMeasurements should be(10) - snapshot.segments.size should be(0) } "create a segment when is invoked a static method annotated with @Segment" in { - for (id ← 1 to 10) AnnotatedJavaClass.segment() + for (id ← 1 to 7) AnnotatedJavaClass.segment() - val snapshot = takeSnapshotOf("trace-with-segment", "trace") - snapshot.histogram("elapsed-time").get.numberOfMeasurements should be(10) + val segmentMetricsSnapshot = takeSnapshotOf("inner-segment", "trace-segment", + tags = Map( + "trace" -> "trace-with-segment", + "category" -> "inner", + "library" -> "segment")) - snapshot.segments.size should be(1) - snapshot.segment("inner-segment", "inner", "segment") should not be empty + segmentMetricsSnapshot.histogram("elapsed-time").get.numberOfMeasurements should be(7) } "create a segment when is invoked a static method annotated with @Segment and evaluate EL expressions" in { @@ -56,26 +55,27 @@ class StaticAnnotationInstrumentationJavaSpec extends BaseKamonSpec("static-anno val snapshot = takeSnapshotOf("trace-with-segment-el", "trace") snapshot.histogram("elapsed-time").get.numberOfMeasurements should be(10) - snapshot.segments.size should be(1) - snapshot.segment("inner-segment:10", "segments", "segment") should not be empty + val segmentMetricsSnapshot = takeSnapshotOf("inner-segment:10", "trace-segment", + tags = Map( + "trace" -> "trace-with-segment-el", + "category" -> "segments", + "library" -> "segment")) + + segmentMetricsSnapshot.histogram("elapsed-time").get.numberOfMeasurements should be(10) } "count the invocations of a static method annotated with @Count" in { for (id ← 1 to 10) AnnotatedJavaClass.count() - val snapshot = takeSnapshotOf("simple-metric", "simple-metric") - snapshot.counter("count").get.count should be(10) + val snapshot = takeSnapshotOf("count", "counter") + snapshot.counter("counter").get.count should be(10) } "count the invocations of a static method annotated with @Count and evaluate EL expressions" in { for (id ← 1 to 2) AnnotatedJavaClass.countWithEL() - val snapshot = takeSnapshotOf("simple-metric", "simple-metric") - snapshot.counter("count:10").get.count should be(2) - - val counterKey = (name: String) ⇒ (key: CounterKey) ⇒ key.name == name - - snapshot.counters.keys.find(counterKey("count:10")).get.metadata should be(Map("counter" -> "1", "env" -> "prod")) + val snapshot = takeSnapshotOf("count:10", "counter", tags = Map("counter" -> "1", "env" -> "prod")) + snapshot.counter("counter").get.count should be(2) } "count the current invocations of a static method annotated with @MinMaxCount" in { @@ -83,43 +83,35 @@ class StaticAnnotationInstrumentationJavaSpec extends BaseKamonSpec("static-anno AnnotatedJavaClass.countMinMax() } - val snapshot = takeSnapshotOf("simple-metric", "simple-metric") - snapshot.minMaxCounter("minMax").get.max should be(1) + val snapshot = takeSnapshotOf("minMax", "min-max-counter") + snapshot.minMaxCounter("min-max-counter").get.max should be(1) } "count the current invocations of a static method annotated with @MinMaxCount and evaluate EL expressions" in { for (id ← 1 to 10) AnnotatedJavaClass.countMinMaxWithEL() - val snapshot = takeSnapshotOf("simple-metric", "simple-metric") - snapshot.minMaxCounter("minMax:10").get.max should be(1) - - val minMaxKey = (name: String) ⇒ (key: MinMaxCounterKey) ⇒ key.name == name - - snapshot.minMaxCounters.keys.find(minMaxKey("minMax:10")).get.metadata should be(Map("minMax" -> "1", "env" -> "dev")) + val snapshot = takeSnapshotOf("minMax:10", "min-max-counter", tags = Map("minMax" -> "1", "env" -> "dev")) + snapshot.minMaxCounter("min-max-counter").get.max should be(1) } "measure the time spent in the execution of a static method annotated with @Time" in { for (id ← 1 to 1) AnnotatedJavaClass.time() - val snapshot = takeSnapshotOf("simple-metric", "simple-metric") - snapshot.histogram("time").get.numberOfMeasurements should be(1) + val snapshot = takeSnapshotOf("time", "histogram") + snapshot.histogram("histogram").get.numberOfMeasurements should be(1) } "measure the time spent in the execution of a static method annotated with @Time and evaluate EL expressions" in { for (id ← 1 to 1) AnnotatedJavaClass.timeWithEL() - val snapshot = takeSnapshotOf("simple-metric", "simple-metric") - snapshot.histogram("time:10").get.numberOfMeasurements should be(1) - - val histogramKey = (name: String) ⇒ (key: HistogramKey) ⇒ key.name == name - - snapshot.histograms.keys.find(histogramKey("time:10")).get.metadata should be(Map("slow-service" -> "service", "env" -> "prod")) + val snapshot = takeSnapshotOf("time:10", "histogram", tags = Map("slow-service" -> "service", "env" -> "prod")) + snapshot.histogram("histogram").get.numberOfMeasurements should be(1) } "record the value returned by a static method annotated with @Histogram" in { for (value ← 1 to 5) AnnotatedJavaClass.histogram(value.toLong) - val snapshot = takeSnapshotOf("simple-metric", "simple-metric") + val snapshot = takeSnapshotOf("histogram", "histogram") snapshot.histogram("histogram").get.numberOfMeasurements should be(5) snapshot.histogram("histogram").get.min should be(1) snapshot.histogram("histogram").get.max should be(5) @@ -129,14 +121,10 @@ class StaticAnnotationInstrumentationJavaSpec extends BaseKamonSpec("static-anno "record the value returned by a static method annotated with @Histogram and evaluate EL expressions" in { for (value ← 1 to 2) AnnotatedJavaClass.histogramWithEL(value.toLong) - val snapshot = takeSnapshotOf("simple-metric", "simple-metric") - snapshot.histogram("histogram:10").get.numberOfMeasurements should be(2) - snapshot.histogram("histogram:10").get.min should be(1) - snapshot.histogram("histogram:10").get.max should be(2) - - val histogramKey = (name: String) ⇒ (key: HistogramKey) ⇒ key.name == name - - snapshot.histograms.keys.find(histogramKey("histogram:10")).get.metadata should be(Map("histogram" -> "hdr", "env" -> "prod")) + val snapshot = takeSnapshotOf("histogram:10", "histogram", tags = Map("histogram" -> "hdr", "env" -> "prod")) + snapshot.histogram("histogram").get.numberOfMeasurements should be(2) + snapshot.histogram("histogram").get.min should be(1) + snapshot.histogram("histogram").get.max should be(2) } } }
\ No newline at end of file diff --git a/kamon-annotation/src/test/scala/kamon/annotation/StaticAnnotationInstrumentationSpec.scala b/kamon-annotation/src/test/scala/kamon/annotation/StaticAnnotationInstrumentationSpec.scala index aea83409..a8e68009 100644 --- a/kamon-annotation/src/test/scala/kamon/annotation/StaticAnnotationInstrumentationSpec.scala +++ b/kamon-annotation/src/test/scala/kamon/annotation/StaticAnnotationInstrumentationSpec.scala @@ -21,8 +21,6 @@ import kamon.metric.{ HistogramKey, MinMaxCounterKey, CounterKey } import kamon.testkit.BaseKamonSpec class StaticAnnotationInstrumentationSpec extends BaseKamonSpec("static-annotation-instrumentation-spec") { - import kamon.metric.TraceMetricsSpec.SegmentSyntax - override lazy val config = ConfigFactory.parseString( """ @@ -31,53 +29,62 @@ class StaticAnnotationInstrumentationSpec extends BaseKamonSpec("static-annotati | default-collection-context-buffer-size = 100 |} """.stripMargin) - "the Kamon Annotation module" should { "create a new trace when is invoked a method annotated with @Trace in a Scala Object" in { - for (id ← 1 to 10) AnnotatedObject.trace() + for (id ← 1 to 42) AnnotatedObject.trace() val snapshot = takeSnapshotOf("trace", "trace") - snapshot.histogram("elapsed-time").get.numberOfMeasurements should be(10) - snapshot.segments.size should be(0) + snapshot.histogram("elapsed-time").get.numberOfMeasurements should be(42) } + "create a segment when is invoked a method annotated with @Trace and @Segment in a Scala Object" in { - for (id ← 1 to 10) AnnotatedObject.segment() + for (id ← 1 to 15) AnnotatedObject.segment() - val snapshot = takeSnapshotOf("trace-with-segment", "trace") - snapshot.histogram("elapsed-time").get.numberOfMeasurements should be(10) + val segmentMetricsSnapshot = takeSnapshotOf("segment", "trace-segment", + tags = Map( + "trace" -> "trace-with-segment", + "category" -> "segments", + "library" -> "segment")) - snapshot.segments.size should be(2) - snapshot.segment("segment", "segments", "segment") should not be empty - snapshot.segment("inner-segment", "inner", "segment") should not be empty + segmentMetricsSnapshot.histogram("elapsed-time").get.numberOfMeasurements should be(15) } "create a segment when is invoked a method annotated with @Trace and @Segment and evaluate EL expressions in a Scala Object" in { - for (id ← 1 to 10) AnnotatedObject.segmentWithEL() + for (id ← 1 to 18) AnnotatedObject.segmentWithEL() val snapshot = takeSnapshotOf("trace-with-segment-el", "trace") - snapshot.histogram("elapsed-time").get.numberOfMeasurements should be(10) + snapshot.histogram("elapsed-time").get.numberOfMeasurements should be(18) + + val segment10Snapshot = takeSnapshotOf("segment:10", "trace-segment", + tags = Map( + "trace" -> "trace-with-segment-el", + "category" -> "segments", + "library" -> "segment")) - snapshot.segments.size should be(2) - snapshot.segment("segment:10", "segments", "segment") should not be empty - snapshot.segment("inner-segment", "inner", "segment") should not be empty + segment10Snapshot.histogram("elapsed-time").get.numberOfMeasurements should be(18) + + val innerSegmentSnapshot = takeSnapshotOf("inner-segment", "trace-segment", + tags = Map( + "trace" -> "trace-with-segment-el", + "category" -> "inner", + "library" -> "segment")) + + innerSegmentSnapshot.histogram("elapsed-time").get.numberOfMeasurements should be(18) } "count the invocations of a method annotated with @Count in a Scala Object" in { for (id ← 1 to 10) AnnotatedObject.count() - val snapshot = takeSnapshotOf("simple-metric", "simple-metric") - snapshot.counter("count").get.count should be(10) + val snapshot = takeSnapshotOf("count", "counter") + snapshot.counter("counter").get.count should be(10) } "count the invocations of a method annotated with @Count and evaluate EL expressions in a Scala Object" in { for (id ← 1 to 2) AnnotatedObject.countWithEL() - val snapshot = takeSnapshotOf("simple-metric", "simple-metric") - snapshot.counter("count:10").get.count should be(2) - - val counterKey = (name: String) ⇒ (key: CounterKey) ⇒ key.name == name + val snapshot = takeSnapshotOf("count:10", "counter", tags = Map("counter" -> "1", "env" -> "prod")) + snapshot.counter("counter").get.count should be(2) - snapshot.counters.keys.find(counterKey("count:10")).get.metadata should be(Map("counter" -> "1", "env" -> "prod")) } "count the current invocations of a method annotated with @MinMaxCount in a Scala Object" in { @@ -85,43 +92,36 @@ class StaticAnnotationInstrumentationSpec extends BaseKamonSpec("static-annotati AnnotatedObject.countMinMax() } - val snapshot = takeSnapshotOf("simple-metric", "simple-metric") - snapshot.minMaxCounter("minMax").get.max should be(1) + val snapshot = takeSnapshotOf("minMax", "min-max-counter") + snapshot.minMaxCounter("min-max-counter").get.max should be(1) } "count the current invocations of a method annotated with @MinMaxCount and evaluate EL expressions in a Scala Object" in { for (id ← 1 to 10) AnnotatedObject.countMinMaxWithEL() - val snapshot = takeSnapshotOf("simple-metric", "simple-metric") - snapshot.minMaxCounter("minMax:10").get.max should be(1) + val snapshot = takeSnapshotOf("minMax:10", "min-max-counter", tags = Map("minMax" -> "1", "env" -> "dev")) + snapshot.minMaxCounter("min-max-counter").get.max should be(1) - val minMaxKey = (name: String) ⇒ (key: MinMaxCounterKey) ⇒ key.name == name - - snapshot.minMaxCounters.keys.find(minMaxKey("minMax:10")).get.metadata should be(Map("minMax" -> "1", "env" -> "dev")) } "measure the time spent in the execution of a method annotated with @Time in a Scala Object" in { for (id ← 1 to 1) AnnotatedObject.time() - val snapshot = takeSnapshotOf("simple-metric", "simple-metric") - snapshot.histogram("time").get.numberOfMeasurements should be(1) + val snapshot = takeSnapshotOf("time", "histogram") + snapshot.histogram("histogram").get.numberOfMeasurements should be(1) } "measure the time spent in the execution of a method annotated with @Time and evaluate EL expressions in a Scala Object" in { for (id ← 1 to 1) AnnotatedObject.timeWithEL() - val snapshot = takeSnapshotOf("simple-metric", "simple-metric") - snapshot.histogram("time:10").get.numberOfMeasurements should be(1) - - val histogramKey = (name: String) ⇒ (key: HistogramKey) ⇒ key.name == name - - snapshot.histograms.keys.find(histogramKey("time:10")).get.metadata should be(Map("slow-service" -> "service", "env" -> "prod")) + val snapshot = takeSnapshotOf("time:10", "histogram", tags = Map("slow-service" -> "service", "env" -> "prod")) + snapshot.histogram("histogram").get.numberOfMeasurements should be(1) } "record the value returned by a method annotated with @Histogram in a Scala Object" in { for (value ← 1 to 5) AnnotatedObject.histogram(value) - val snapshot = takeSnapshotOf("simple-metric", "simple-metric") + val snapshot = takeSnapshotOf("histogram", "histogram") snapshot.histogram("histogram").get.numberOfMeasurements should be(5) snapshot.histogram("histogram").get.min should be(1) snapshot.histogram("histogram").get.max should be(5) @@ -131,14 +131,10 @@ class StaticAnnotationInstrumentationSpec extends BaseKamonSpec("static-annotati "record the value returned by a method annotated with @Histogram and evaluate EL expressions in a Scala Object" in { for (value ← 1 to 2) AnnotatedObject.histogramWithEL(value) - val snapshot = takeSnapshotOf("simple-metric", "simple-metric") - snapshot.histogram("histogram:10").get.numberOfMeasurements should be(2) - snapshot.histogram("histogram:10").get.min should be(1) - snapshot.histogram("histogram:10").get.max should be(2) - - val histogramKey = (name: String) ⇒ (key: HistogramKey) ⇒ key.name == name - - snapshot.histograms.keys.find(histogramKey("histogram:10")).get.metadata should be(Map("histogram" -> "hdr", "env" -> "prod")) + val snapshot = takeSnapshotOf("histogram:10", "histogram", tags = Map("histogram" -> "hdr", "env" -> "prod")) + snapshot.histogram("histogram").get.numberOfMeasurements should be(2) + snapshot.histogram("histogram").get.min should be(1) + snapshot.histogram("histogram").get.max should be(2) } } } diff --git a/kamon-core/src/main/scala/kamon/Kamon.scala b/kamon-core/src/main/scala/kamon/Kamon.scala index a2a24f49..a6469039 100644 --- a/kamon-core/src/main/scala/kamon/Kamon.scala +++ b/kamon-core/src/main/scala/kamon/Kamon.scala @@ -18,15 +18,13 @@ import _root_.akka.actor import _root_.akka.actor._ import com.typesafe.config.{ ConfigFactory, Config } import kamon.metric._ +import kamon.metric.instrument.Gauge import kamon.trace.{ TracerImpl, Tracer } object Kamon { trait Extension extends actor.Extension - private case class KamonCoreComponents( - metrics: Metrics, - tracer: Tracer, - simpleMetrics: SimpleMetrics) + private case class KamonCoreComponents(metrics: Metrics, tracer: Tracer) @volatile private var _system: ActorSystem = _ @volatile private var _coreComponents: Option[KamonCoreComponents] = None @@ -43,10 +41,9 @@ object Kamon { if (_coreComponents.isEmpty) { val metrics = MetricsImpl(config) - val simpleMetrics = SimpleMetricsImpl(metrics) val tracer = TracerImpl(metrics, config) - _coreComponents = Some(KamonCoreComponents(metrics, tracer, simpleMetrics)) + _coreComponents = Some(KamonCoreComponents(metrics, tracer)) _system = ActorSystem("kamon", resolveInternalConfig) metrics.start(_system) @@ -70,9 +67,6 @@ object Kamon { def tracer: Tracer = ifStarted(_.tracer) - def simpleMetrics: SimpleMetrics = - ifStarted(_.simpleMetrics) - def apply[T <: Kamon.Extension](key: ExtensionId[T]): T = ifStarted { _ ⇒ if (_system ne null) diff --git a/kamon-core/src/main/scala/kamon/metric/Entity.scala b/kamon-core/src/main/scala/kamon/metric/Entity.scala index 8d328f83..91249af0 100644 --- a/kamon-core/src/main/scala/kamon/metric/Entity.scala +++ b/kamon-core/src/main/scala/kamon/metric/Entity.scala @@ -23,36 +23,15 @@ package kamon.metric * * // TODO: Find a better word for `thing`. */ -class Entity(val name: String, val category: String, val metadata: Map[String, String]) { - - override def equals(o: Any): Boolean = { - if (this eq o.asInstanceOf[AnyRef]) - true - else if ((o.asInstanceOf[AnyRef] eq null) || !o.isInstanceOf[Entity]) - false - else { - val thatAsEntity = o.asInstanceOf[Entity] - category == thatAsEntity.category && name == thatAsEntity.name - } - } - - override def hashCode: Int = { - var result: Int = name.hashCode - result = 31 * result + category.hashCode - return result - } -} +case class Entity(name: String, category: String, tags: Map[String, String]) object Entity { def apply(name: String, category: String): Entity = apply(name, category, Map.empty) - def apply(name: String, category: String, metadata: Map[String, String]): Entity = - new Entity(name, category, metadata) - def create(name: String, category: String): Entity = apply(name, category, Map.empty) - def create(name: String, category: String, metadata: Map[String, String]): Entity = - new Entity(name, category, metadata) + def create(name: String, category: String, tags: Map[String, String]): Entity = + new Entity(name, category, tags) }
\ No newline at end of file diff --git a/kamon-core/src/main/scala/kamon/metric/EntityRecorder.scala b/kamon-core/src/main/scala/kamon/metric/EntityRecorder.scala index 6e0a4248..65dafa9a 100644 --- a/kamon-core/src/main/scala/kamon/metric/EntityRecorder.scala +++ b/kamon-core/src/main/scala/kamon/metric/EntityRecorder.scala @@ -19,6 +19,7 @@ package kamon.metric import kamon.metric.instrument.Gauge.CurrentValueCollector import kamon.metric.instrument.Histogram.DynamicRange import kamon.metric.instrument._ +import kamon.util.Function import scala.collection.concurrent.TrieMap import scala.concurrent.duration.FiniteDuration @@ -33,6 +34,64 @@ trait EntityRecorderFactory[T <: EntityRecorder] { def createRecorder(instrumentFactory: InstrumentFactory): T } +object EntityRecorderFactory { + def apply[T <: EntityRecorder](entityCategory: String, factory: InstrumentFactory ⇒ T): EntityRecorderFactory[T] = + new EntityRecorderFactory[T] { + def category: String = entityCategory + def createRecorder(instrumentFactory: InstrumentFactory): T = factory(instrumentFactory) + } + + def create[T <: EntityRecorder](entityCategory: String, factory: Function[InstrumentFactory, T]): EntityRecorderFactory[T] = + new EntityRecorderFactory[T] { + def category: String = entityCategory + def createRecorder(instrumentFactory: InstrumentFactory): T = factory(instrumentFactory) + } +} + +private[kamon] sealed trait SingleInstrumentEntityRecorder extends EntityRecorder { + def key: MetricKey + def instrument: Instrument + + def collect(collectionContext: CollectionContext): EntitySnapshot = + new DefaultEntitySnapshot(Map(key -> instrument.collect(collectionContext))) + + def cleanup: Unit = instrument.cleanup +} + +object SingleInstrumentEntityRecorder { + val Histogram = "histogram" + val MinMaxCounter = "min-max-counter" + val Gauge = "gauge" + val Counter = "counter" + + val AllCategories = List("histogram", "gauge", "counter", "min-max-counter") +} + +/** + * Entity recorder for a single Counter instrument. + */ +case class CounterRecorder(key: MetricKey, instrument: Counter) extends SingleInstrumentEntityRecorder + +/** + * Entity recorder for a single Histogram instrument. + */ +case class HistogramRecorder(key: MetricKey, instrument: Histogram) extends SingleInstrumentEntityRecorder + +/** + * Entity recorder for a single MinMaxCounter instrument. + */ +case class MinMaxCounterRecorder(key: MetricKey, instrument: MinMaxCounter) extends SingleInstrumentEntityRecorder + +/** + * Entity recorder for a single Gauge instrument. + */ +case class GaugeRecorder(key: MetricKey, instrument: Gauge) extends SingleInstrumentEntityRecorder + +/** + * Base class with plenty of utility methods to facilitate the creation of [[EntityRecorder]] implementations. + * It is not required to use this base class for defining custom a custom [[EntityRecorder]], but it is certainly + * the most convenient way to do it and the preferred approach throughout the Kamon codebase. + */ abstract class GenericEntityRecorder(instrumentFactory: InstrumentFactory) extends EntityRecorder { import kamon.util.TriemapAtomicGetOrElseUpdate.Syntax @@ -41,10 +100,10 @@ abstract class GenericEntityRecorder(instrumentFactory: InstrumentFactory) exten _instruments.atomicGetOrElseUpdate(key, instrument, _.cleanup).asInstanceOf[T] protected def histogram(name: String): Histogram = - register(HistogramKey(name), instrumentFactory.createHistogram(name)) + register(HistogramKey(name, UnitOfMeasurement.Unknown), instrumentFactory.createHistogram(name)) protected def histogram(name: String, dynamicRange: DynamicRange): Histogram = - register(HistogramKey(name), instrumentFactory.createHistogram(name, Some(dynamicRange))) + register(HistogramKey(name, UnitOfMeasurement.Unknown), instrumentFactory.createHistogram(name, Some(dynamicRange))) protected def histogram(name: String, unitOfMeasurement: UnitOfMeasurement): Histogram = register(HistogramKey(name, unitOfMeasurement), instrumentFactory.createHistogram(name)) @@ -52,32 +111,26 @@ abstract class GenericEntityRecorder(instrumentFactory: InstrumentFactory) exten protected def histogram(name: String, dynamicRange: DynamicRange, unitOfMeasurement: UnitOfMeasurement): Histogram = register(HistogramKey(name, unitOfMeasurement), instrumentFactory.createHistogram(name, Some(dynamicRange))) - protected def histogram(key: HistogramKey): Histogram = - register(key, instrumentFactory.createHistogram(key.name)) - - protected def histogram(key: HistogramKey, dynamicRange: DynamicRange): Histogram = - register(key, instrumentFactory.createHistogram(key.name, Some(dynamicRange))) - protected def removeHistogram(name: String): Unit = - _instruments.remove(HistogramKey(name)) + _instruments.remove(HistogramKey(name, UnitOfMeasurement.Unknown)) - protected def removeHistogram(key: HistogramKey): Unit = - _instruments.remove(key) + protected def removeHistogram(name: String, unitOfMeasurement: UnitOfMeasurement): Unit = + _instruments.remove(HistogramKey(name, unitOfMeasurement)) protected def minMaxCounter(name: String): MinMaxCounter = - register(MinMaxCounterKey(name), instrumentFactory.createMinMaxCounter(name)) + register(MinMaxCounterKey(name, UnitOfMeasurement.Unknown), instrumentFactory.createMinMaxCounter(name)) protected def minMaxCounter(name: String, dynamicRange: DynamicRange): MinMaxCounter = - register(MinMaxCounterKey(name), instrumentFactory.createMinMaxCounter(name, Some(dynamicRange))) + register(MinMaxCounterKey(name, UnitOfMeasurement.Unknown), instrumentFactory.createMinMaxCounter(name, Some(dynamicRange))) protected def minMaxCounter(name: String, refreshInterval: FiniteDuration): MinMaxCounter = - register(MinMaxCounterKey(name), instrumentFactory.createMinMaxCounter(name, refreshInterval = Some(refreshInterval))) + register(MinMaxCounterKey(name, UnitOfMeasurement.Unknown), instrumentFactory.createMinMaxCounter(name, refreshInterval = Some(refreshInterval))) protected def minMaxCounter(name: String, unitOfMeasurement: UnitOfMeasurement): MinMaxCounter = register(MinMaxCounterKey(name, unitOfMeasurement), instrumentFactory.createMinMaxCounter(name)) protected def minMaxCounter(name: String, dynamicRange: DynamicRange, refreshInterval: FiniteDuration): MinMaxCounter = - register(MinMaxCounterKey(name), instrumentFactory.createMinMaxCounter(name, Some(dynamicRange), Some(refreshInterval))) + register(MinMaxCounterKey(name, UnitOfMeasurement.Unknown), instrumentFactory.createMinMaxCounter(name, Some(dynamicRange), Some(refreshInterval))) protected def minMaxCounter(name: String, dynamicRange: DynamicRange, unitOfMeasurement: UnitOfMeasurement): MinMaxCounter = register(MinMaxCounterKey(name, unitOfMeasurement), instrumentFactory.createMinMaxCounter(name, Some(dynamicRange))) @@ -86,7 +139,7 @@ abstract class GenericEntityRecorder(instrumentFactory: InstrumentFactory) exten register(MinMaxCounterKey(name, unitOfMeasurement), instrumentFactory.createMinMaxCounter(name, refreshInterval = Some(refreshInterval))) protected def minMaxCounter(name: String, dynamicRange: DynamicRange, refreshInterval: FiniteDuration, unitOfMeasurement: UnitOfMeasurement): MinMaxCounter = - register(MinMaxCounterKey(name), instrumentFactory.createMinMaxCounter(name, Some(dynamicRange), Some(refreshInterval))) + register(MinMaxCounterKey(name, UnitOfMeasurement.Unknown), instrumentFactory.createMinMaxCounter(name, Some(dynamicRange), Some(refreshInterval))) protected def minMaxCounter(key: MinMaxCounterKey): MinMaxCounter = register(key, instrumentFactory.createMinMaxCounter(key.name)) @@ -101,31 +154,31 @@ abstract class GenericEntityRecorder(instrumentFactory: InstrumentFactory) exten register(key, instrumentFactory.createMinMaxCounter(key.name, Some(dynamicRange), Some(refreshInterval))) protected def removeMinMaxCounter(name: String): Unit = - _instruments.remove(MinMaxCounterKey(name)) + _instruments.remove(MinMaxCounterKey(name, UnitOfMeasurement.Unknown)) protected def removeMinMaxCounter(key: MinMaxCounterKey): Unit = _instruments.remove(key) protected def gauge(name: String, valueCollector: CurrentValueCollector): Gauge = - register(GaugeKey(name), instrumentFactory.createGauge(name, valueCollector = valueCollector)) + register(GaugeKey(name, UnitOfMeasurement.Unknown), instrumentFactory.createGauge(name, valueCollector = valueCollector)) protected def gauge(name: String, dynamicRange: DynamicRange, valueCollector: CurrentValueCollector): Gauge = - register(GaugeKey(name), instrumentFactory.createGauge(name, Some(dynamicRange), valueCollector = valueCollector)) + register(GaugeKey(name, UnitOfMeasurement.Unknown), instrumentFactory.createGauge(name, Some(dynamicRange), valueCollector = valueCollector)) protected def gauge(name: String, refreshInterval: FiniteDuration, valueCollector: CurrentValueCollector): Gauge = - register(GaugeKey(name), instrumentFactory.createGauge(name, refreshInterval = Some(refreshInterval), valueCollector = valueCollector)) + register(GaugeKey(name, UnitOfMeasurement.Unknown), instrumentFactory.createGauge(name, refreshInterval = Some(refreshInterval), valueCollector = valueCollector)) protected def gauge(name: String, unitOfMeasurement: UnitOfMeasurement, valueCollector: CurrentValueCollector): Gauge = register(GaugeKey(name, unitOfMeasurement), instrumentFactory.createGauge(name, valueCollector = valueCollector)) protected def gauge(name: String, dynamicRange: DynamicRange, refreshInterval: FiniteDuration, valueCollector: CurrentValueCollector): Gauge = - register(GaugeKey(name), instrumentFactory.createGauge(name, Some(dynamicRange), Some(refreshInterval), valueCollector = valueCollector)) + register(GaugeKey(name, UnitOfMeasurement.Unknown), instrumentFactory.createGauge(name, Some(dynamicRange), Some(refreshInterval), valueCollector = valueCollector)) protected def gauge(name: String, dynamicRange: DynamicRange, unitOfMeasurement: UnitOfMeasurement, valueCollector: CurrentValueCollector): Gauge = register(GaugeKey(name, unitOfMeasurement), instrumentFactory.createGauge(name, Some(dynamicRange), valueCollector = valueCollector)) protected def gauge(name: String, refreshInterval: FiniteDuration, unitOfMeasurement: UnitOfMeasurement, valueCollector: CurrentValueCollector): Gauge = - register(GaugeKey(name), instrumentFactory.createGauge(name, refreshInterval = Some(refreshInterval), valueCollector = valueCollector)) + register(GaugeKey(name, UnitOfMeasurement.Unknown), instrumentFactory.createGauge(name, refreshInterval = Some(refreshInterval), valueCollector = valueCollector)) protected def gauge(name: String, dynamicRange: DynamicRange, refreshInterval: FiniteDuration, unitOfMeasurement: UnitOfMeasurement, valueCollector: CurrentValueCollector): Gauge = register(GaugeKey(name, unitOfMeasurement), instrumentFactory.createGauge(name, Some(dynamicRange), Some(refreshInterval), valueCollector)) @@ -143,19 +196,19 @@ abstract class GenericEntityRecorder(instrumentFactory: InstrumentFactory) exten register(key, instrumentFactory.createGauge(key.name, Some(dynamicRange), Some(refreshInterval), valueCollector = valueCollector)) protected def removeGauge(name: String): Unit = - _instruments.remove(GaugeKey(name)) + _instruments.remove(GaugeKey(name, UnitOfMeasurement.Unknown)) protected def removeGauge(key: GaugeKey): Unit = _instruments.remove(key) protected def counter(name: String): Counter = - register(CounterKey(name), instrumentFactory.createCounter()) + register(CounterKey(name, UnitOfMeasurement.Unknown), instrumentFactory.createCounter()) protected def counter(key: CounterKey): Counter = register(key, instrumentFactory.createCounter()) protected def removeCounter(name: String): Unit = - _instruments.remove(CounterKey(name)) + _instruments.remove(CounterKey(name, UnitOfMeasurement.Unknown)) protected def removeCounter(key: CounterKey): Unit = _instruments.remove(key) diff --git a/kamon-core/src/main/scala/kamon/metric/MetricKey.scala b/kamon-core/src/main/scala/kamon/metric/MetricKey.scala index c655665b..2c710a19 100644 --- a/kamon-core/src/main/scala/kamon/metric/MetricKey.scala +++ b/kamon-core/src/main/scala/kamon/metric/MetricKey.scala @@ -26,144 +26,32 @@ sealed trait MetricKey { def name: String def unitOfMeasurement: UnitOfMeasurement def instrumentType: InstrumentType - def metadata: Map[String, String] } -// Wish that there was a shorter way to describe the operations bellow, but apparently there is no way to generalize all -// the apply/create versions that would produce the desired return types when used from Java. - /** * MetricKey for all Histogram-based metrics. */ -case class HistogramKey(name: String, unitOfMeasurement: UnitOfMeasurement, metadata: Map[String, String]) extends MetricKey { +private[kamon] case class HistogramKey(name: String, unitOfMeasurement: UnitOfMeasurement) extends MetricKey { val instrumentType = InstrumentTypes.Histogram } -object HistogramKey { - def apply(name: String): HistogramKey = - apply(name, UnitOfMeasurement.Unknown) - - def apply(name: String, unitOfMeasurement: UnitOfMeasurement): HistogramKey = - apply(name, unitOfMeasurement, Map.empty) - - def apply(name: String, metadata: Map[String, String]): HistogramKey = - apply(name, UnitOfMeasurement.Unknown, metadata) - - /** - * Java friendly versions: - */ - - def create(name: String): HistogramKey = - apply(name, UnitOfMeasurement.Unknown) - - def create(name: String, unitOfMeasurement: UnitOfMeasurement): HistogramKey = - apply(name, unitOfMeasurement) - - def create(name: String, metadata: Map[String, String]): HistogramKey = - apply(name, metadata) - - def create(name: String, unitOfMeasurement: UnitOfMeasurement, metadata: Map[String, String]): HistogramKey = - apply(name, unitOfMeasurement, metadata) -} - /** * MetricKey for all MinMaxCounter-based metrics. */ -case class MinMaxCounterKey(name: String, unitOfMeasurement: UnitOfMeasurement, metadata: Map[String, String]) extends MetricKey { +case class MinMaxCounterKey(name: String, unitOfMeasurement: UnitOfMeasurement) extends MetricKey { val instrumentType = InstrumentTypes.MinMaxCounter } -object MinMaxCounterKey { - def apply(name: String): MinMaxCounterKey = - apply(name, UnitOfMeasurement.Unknown) - - def apply(name: String, unitOfMeasurement: UnitOfMeasurement): MinMaxCounterKey = - apply(name, unitOfMeasurement, Map.empty) - - def apply(name: String, metadata: Map[String, String]): MinMaxCounterKey = - apply(name, UnitOfMeasurement.Unknown, metadata) - - /** - * Java friendly versions: - */ - - def create(name: String): MinMaxCounterKey = - apply(name, UnitOfMeasurement.Unknown) - - def create(name: String, unitOfMeasurement: UnitOfMeasurement): MinMaxCounterKey = - apply(name, unitOfMeasurement) - - def create(name: String, metadata: Map[String, String]): MinMaxCounterKey = - apply(name, metadata) - - def create(name: String, unitOfMeasurement: UnitOfMeasurement, metadata: Map[String, String]): MinMaxCounterKey = - apply(name, unitOfMeasurement, metadata) -} - /** * MetricKey for all Gauge-based metrics. */ -case class GaugeKey(name: String, unitOfMeasurement: UnitOfMeasurement, metadata: Map[String, String]) extends MetricKey { +case class GaugeKey(name: String, unitOfMeasurement: UnitOfMeasurement) extends MetricKey { val instrumentType = InstrumentTypes.Gauge } -object GaugeKey { - def apply(name: String): GaugeKey = - apply(name, UnitOfMeasurement.Unknown) - - def apply(name: String, unitOfMeasurement: UnitOfMeasurement): GaugeKey = - apply(name, unitOfMeasurement, Map.empty) - - def apply(name: String, metadata: Map[String, String]): GaugeKey = - apply(name, UnitOfMeasurement.Unknown, metadata) - - /** - * Java friendly versions: - */ - - def create(name: String): GaugeKey = - apply(name, UnitOfMeasurement.Unknown) - - def create(name: String, unitOfMeasurement: UnitOfMeasurement): GaugeKey = - apply(name, unitOfMeasurement) - - def create(name: String, metadata: Map[String, String]): GaugeKey = - apply(name, metadata) - - def create(name: String, unitOfMeasurement: UnitOfMeasurement, metadata: Map[String, String]): GaugeKey = - apply(name, unitOfMeasurement, metadata) -} - /** * MetricKey for all Counter-based metrics. */ -case class CounterKey(name: String, unitOfMeasurement: UnitOfMeasurement, metadata: Map[String, String]) extends MetricKey { +case class CounterKey(name: String, unitOfMeasurement: UnitOfMeasurement) extends MetricKey { val instrumentType = InstrumentTypes.Counter } - -object CounterKey { - def apply(name: String): CounterKey = - apply(name, UnitOfMeasurement.Unknown) - - def apply(name: String, unitOfMeasurement: UnitOfMeasurement): CounterKey = - apply(name, unitOfMeasurement, Map.empty) - - def apply(name: String, metadata: Map[String, String]): CounterKey = - apply(name, UnitOfMeasurement.Unknown, metadata) - - /** - * Java friendly versions: - */ - - def create(name: String): CounterKey = - apply(name, UnitOfMeasurement.Unknown) - - def create(name: String, unitOfMeasurement: UnitOfMeasurement): CounterKey = - apply(name, unitOfMeasurement) - - def create(name: String, metadata: Map[String, String]): CounterKey = - apply(name, metadata) - - def create(name: String, unitOfMeasurement: UnitOfMeasurement, metadata: Map[String, String]): CounterKey = - apply(name, unitOfMeasurement, metadata) -}
\ No newline at end of file diff --git a/kamon-core/src/main/scala/kamon/metric/Metrics.scala b/kamon-core/src/main/scala/kamon/metric/Metrics.scala index d79b1de3..6a976a1c 100644 --- a/kamon-core/src/main/scala/kamon/metric/Metrics.scala +++ b/kamon-core/src/main/scala/kamon/metric/Metrics.scala @@ -18,26 +18,195 @@ package kamon.metric import com.typesafe.config.Config import kamon.metric.SubscriptionsDispatcher.{ Unsubscribe, Subscribe } -import kamon.metric.instrument.{ DefaultRefreshScheduler, InstrumentFactory, CollectionContext } +import kamon.metric.instrument.Gauge.CurrentValueCollector +import kamon.metric.instrument.Histogram.DynamicRange +import kamon.metric.instrument._ import scala.collection.concurrent.TrieMap import akka.actor._ -import kamon.util.{ LazyActorRef, TriemapAtomicGetOrElseUpdate } +import kamon.util.{ Supplier, LazyActorRef, TriemapAtomicGetOrElseUpdate } + +import scala.concurrent.duration.FiniteDuration case class EntityRegistration[T <: EntityRecorder](entity: Entity, recorder: T) trait Metrics { def settings: MetricsSettings + def shouldTrack(entity: Entity): Boolean + def shouldTrack(entityName: String, category: String): Boolean = shouldTrack(Entity(entityName, category)) - def register[T <: EntityRecorder](recorderFactory: EntityRecorderFactory[T], entityName: String): Option[EntityRegistration[T]] - def register[T <: EntityRecorder](entity: Entity, recorder: T): EntityRegistration[T] - def unregister(entity: Entity): Unit + // + // Histograms registration and removal + // + + def histogram(name: String): Histogram = + registerHistogram(name) + + def histogram(name: String, unitOfMeasurement: UnitOfMeasurement): Histogram = + registerHistogram(name, unitOfMeasurement = Some(unitOfMeasurement)) + + def histogram(name: String, dynamicRange: DynamicRange): Histogram = + registerHistogram(name, dynamicRange = Some(dynamicRange)) + + def histogram(name: String, unitOfMeasurement: UnitOfMeasurement, dynamicRange: DynamicRange): Histogram = + registerHistogram(name, unitOfMeasurement = Some(unitOfMeasurement), dynamicRange = Some(dynamicRange)) + + def histogram(name: String, tags: Map[String, String]): Histogram = + registerHistogram(name, tags) + + def histogram(name: String, tags: Map[String, String], unitOfMeasurement: UnitOfMeasurement): Histogram = + registerHistogram(name, tags, Some(unitOfMeasurement)) + + def histogram(name: String, tags: Map[String, String], dynamicRange: DynamicRange): Histogram = + registerHistogram(name, tags, dynamicRange = Some(dynamicRange)) + + def histogram(name: String, tags: Map[String, String], unitOfMeasurement: UnitOfMeasurement, dynamicRange: DynamicRange): Histogram = + registerHistogram(name, tags, Some(unitOfMeasurement), Some(dynamicRange)) + + def removeHistogram(name: String): Boolean = + removeHistogram(name, Map.empty) + + def registerHistogram(name: String, tags: Map[String, String] = Map.empty, unitOfMeasurement: Option[UnitOfMeasurement] = None, + dynamicRange: Option[DynamicRange] = None): Histogram + + def removeHistogram(name: String, tags: Map[String, String]): Boolean + + // + // MinMaxCounter registration and removal + // + + def minMaxCounter(name: String): MinMaxCounter = + registerMinMaxCounter(name) + + def minMaxCounter(name: String, unitOfMeasurement: UnitOfMeasurement): MinMaxCounter = + registerMinMaxCounter(name, unitOfMeasurement = Some(unitOfMeasurement)) + + def minMaxCounter(name: String, dynamicRange: DynamicRange): MinMaxCounter = + registerMinMaxCounter(name, dynamicRange = Some(dynamicRange)) + + def minMaxCounter(name: String, refreshInterval: FiniteDuration): MinMaxCounter = + registerMinMaxCounter(name, refreshInterval = Some(refreshInterval)) + + def minMaxCounter(name: String, dynamicRange: DynamicRange, refreshInterval: FiniteDuration): MinMaxCounter = + registerMinMaxCounter(name, dynamicRange = Some(dynamicRange), refreshInterval = Some(refreshInterval)) + + def minMaxCounter(name: String, unitOfMeasurement: UnitOfMeasurement, dynamicRange: DynamicRange): MinMaxCounter = + registerMinMaxCounter(name, unitOfMeasurement = Some(unitOfMeasurement), dynamicRange = Some(dynamicRange)) + + def minMaxCounter(name: String, tags: Map[String, String]): MinMaxCounter = + registerMinMaxCounter(name, tags) + + def minMaxCounter(name: String, tags: Map[String, String], unitOfMeasurement: UnitOfMeasurement): MinMaxCounter = + registerMinMaxCounter(name, tags, Some(unitOfMeasurement)) + + def minMaxCounter(name: String, tags: Map[String, String], dynamicRange: DynamicRange): MinMaxCounter = + registerMinMaxCounter(name, tags, dynamicRange = Some(dynamicRange)) + + def minMaxCounter(name: String, tags: Map[String, String], unitOfMeasurement: UnitOfMeasurement, dynamicRange: DynamicRange): MinMaxCounter = + registerMinMaxCounter(name, tags, Some(unitOfMeasurement), Some(dynamicRange)) + + def removeMinMaxCounter(name: String): Boolean = + removeMinMaxCounter(name, Map.empty) + + def removeMinMaxCounter(name: String, tags: Map[String, String]): Boolean + + def registerMinMaxCounter(name: String, tags: Map[String, String] = Map.empty, unitOfMeasurement: Option[UnitOfMeasurement] = None, + dynamicRange: Option[DynamicRange] = None, refreshInterval: Option[FiniteDuration] = None): MinMaxCounter + + // + // Gauge registration and removal + // + + def gauge(name: String)(valueCollector: CurrentValueCollector): Gauge = + registerGauge(name, valueCollector) + + def gauge(name: String, unitOfMeasurement: UnitOfMeasurement)(valueCollector: CurrentValueCollector): Gauge = + registerGauge(name, valueCollector, unitOfMeasurement = Some(unitOfMeasurement)) + + def gauge(name: String, dynamicRange: DynamicRange)(valueCollector: CurrentValueCollector): Gauge = + registerGauge(name, valueCollector, dynamicRange = Some(dynamicRange)) + + def gauge(name: String, refreshInterval: FiniteDuration)(valueCollector: CurrentValueCollector): Gauge = + registerGauge(name, valueCollector, refreshInterval = Some(refreshInterval)) + + def gauge(name: String, dynamicRange: DynamicRange, refreshInterval: FiniteDuration)(valueCollector: CurrentValueCollector): Gauge = + registerGauge(name, valueCollector, dynamicRange = Some(dynamicRange), refreshInterval = Some(refreshInterval)) + + def gauge(name: String, unitOfMeasurement: UnitOfMeasurement, dynamicRange: DynamicRange)(valueCollector: CurrentValueCollector): Gauge = + registerGauge(name, valueCollector, unitOfMeasurement = Some(unitOfMeasurement), dynamicRange = Some(dynamicRange)) + + def gauge(name: String, tags: Map[String, String])(valueCollector: CurrentValueCollector): Gauge = + registerGauge(name, valueCollector, tags) + + def gauge(name: String, tags: Map[String, String], unitOfMeasurement: UnitOfMeasurement)(valueCollector: CurrentValueCollector): Gauge = + registerGauge(name, valueCollector, tags, Some(unitOfMeasurement)) + + def gauge(name: String, tags: Map[String, String], dynamicRange: DynamicRange)(valueCollector: CurrentValueCollector): Gauge = + registerGauge(name, valueCollector, tags, dynamicRange = Some(dynamicRange)) + + def gauge(name: String, tags: Map[String, String], unitOfMeasurement: UnitOfMeasurement, dynamicRange: DynamicRange)(valueCollector: CurrentValueCollector): Gauge = + registerGauge(name, valueCollector, tags, Some(unitOfMeasurement), Some(dynamicRange)) + + def removeGauge(name: String): Boolean = + removeGauge(name, Map.empty) + + def removeGauge(name: String, tags: Map[String, String]): Boolean + + def registerGauge(name: String, valueCollector: CurrentValueCollector, tags: Map[String, String] = Map.empty, + unitOfMeasurement: Option[UnitOfMeasurement] = None, dynamicRange: Option[DynamicRange] = None, + refreshInterval: Option[FiniteDuration] = None): Gauge + + // + // Counters registration and removal + // + + def counter(name: String): Counter = + registerCounter(name) + + def counter(name: String, unitOfMeasurement: UnitOfMeasurement): Counter = + registerCounter(name, unitOfMeasurement = Some(unitOfMeasurement)) + + def counter(name: String, tags: Map[String, String]): Counter = + registerCounter(name, tags) + + def counter(name: String, tags: Map[String, String], unitOfMeasurement: UnitOfMeasurement): Counter = + registerCounter(name, tags, Some(unitOfMeasurement)) + + def removeCounter(name: String): Boolean = + removeCounter(name, Map.empty) + + def removeCounter(name: String, tags: Map[String, String]): Boolean + + def registerCounter(name: String, tags: Map[String, String] = Map.empty, unitOfMeasurement: Option[UnitOfMeasurement] = None, + dynamicRange: Option[DynamicRange] = None): Counter + + // + // Entities registration and removal + // + + def entity[T <: EntityRecorder](recorderFactory: EntityRecorderFactory[T], name: String): T = + entity(recorderFactory, Entity(name, recorderFactory.category)) + + def entity[T <: EntityRecorder](recorderFactory: EntityRecorderFactory[T], name: String, tags: Map[String, String]): T = + entity(recorderFactory, Entity(name, recorderFactory.category, tags)) + + def removeEntity(name: String, category: String): Boolean = + removeEntity(Entity(name, category, Map.empty)) + + def removeEntity(name: String, category: String, tags: Map[String, String]): Boolean = + removeEntity(Entity(name, category, tags)) + + def removeEntity(entity: Entity): Boolean + + def entity[T <: EntityRecorder](recorderFactory: EntityRecorderFactory[T], entity: Entity): T + + def find(name: String, category: String): Option[EntityRecorder] = + find(Entity(name, category)) def find(entity: Entity): Option[EntityRecorder] - def find(name: String, category: String): Option[EntityRecorder] def subscribe(filter: SubscriptionFilter, subscriber: ActorRef): Unit = subscribe(filter, subscriber, permanently = false) @@ -51,11 +220,15 @@ trait Metrics { def subscribe(filter: SubscriptionFilter, subscriber: ActorRef, permanently: Boolean): Unit def unsubscribe(subscriber: ActorRef): Unit + def buildDefaultCollectionContext: CollectionContext + def instrumentFactory(category: String): InstrumentFactory } private[kamon] class MetricsImpl(config: Config) extends Metrics { + import TriemapAtomicGetOrElseUpdate.Syntax + private val _trackedEntities = TrieMap.empty[Entity, EntityRecorder] private val _subscriptions = new LazyActorRef @@ -67,35 +240,83 @@ private[kamon] class MetricsImpl(config: Config) extends Metrics { } getOrElse (settings.trackUnmatchedEntities) - def register[T <: EntityRecorder](recorderFactory: EntityRecorderFactory[T], entityName: String): Option[EntityRegistration[T]] = { - import TriemapAtomicGetOrElseUpdate.Syntax - val entity = Entity(entityName, recorderFactory.category) + def registerHistogram(name: String, tags: Map[String, String], unitOfMeasurement: Option[UnitOfMeasurement], + dynamicRange: Option[DynamicRange]): Histogram = { - if (shouldTrack(entity)) { - val instrumentFactory = settings.instrumentFactories.get(recorderFactory.category).getOrElse(settings.defaultInstrumentFactory) - val recorder = _trackedEntities.atomicGetOrElseUpdate(entity, recorderFactory.createRecorder(instrumentFactory), _.cleanup).asInstanceOf[T] + val histogramEntity = Entity(name, "histogram", tags) + val recorder = _trackedEntities.atomicGetOrElseUpdate(histogramEntity, { + val factory = instrumentFactory(histogramEntity.category) + HistogramRecorder(HistogramKey(histogramEntity.category, unitOfMeasurement.getOrElse(UnitOfMeasurement.Unknown)), + factory.createHistogram(name, dynamicRange)) + }, _.cleanup) - Some(EntityRegistration(entity, recorder)) - } else None + recorder.asInstanceOf[HistogramRecorder].instrument } - def register[T <: EntityRecorder](entity: Entity, recorder: T): EntityRegistration[T] = { - _trackedEntities.put(entity, recorder).map { oldRecorder ⇒ - oldRecorder.cleanup - } + def removeHistogram(name: String, tags: Map[String, String]): Boolean = + _trackedEntities.remove(Entity(name, "histogram", tags)).isDefined + + def registerMinMaxCounter(name: String, tags: Map[String, String], unitOfMeasurement: Option[UnitOfMeasurement], dynamicRange: Option[DynamicRange], + refreshInterval: Option[FiniteDuration]): MinMaxCounter = { + + val minMaxCounterEntity = Entity(name, "min-max-counter", tags) + val recorder = _trackedEntities.atomicGetOrElseUpdate(minMaxCounterEntity, { + val factory = instrumentFactory(minMaxCounterEntity.category) + MinMaxCounterRecorder(MinMaxCounterKey(minMaxCounterEntity.category, unitOfMeasurement.getOrElse(UnitOfMeasurement.Unknown)), + factory.createMinMaxCounter(name, dynamicRange, refreshInterval)) + }, _.cleanup) + + recorder.asInstanceOf[MinMaxCounterRecorder].instrument + } + + def removeMinMaxCounter(name: String, tags: Map[String, String]): Boolean = + _trackedEntities.remove(Entity(name, "min-max-counter", tags)).isDefined + + def registerGauge(name: String, valueCollector: CurrentValueCollector, tags: Map[String, String] = Map.empty, + unitOfMeasurement: Option[UnitOfMeasurement] = None, dynamicRange: Option[DynamicRange] = None, + refreshInterval: Option[FiniteDuration] = None): Gauge = { + + val gaugeEntity = Entity(name, "gauge", tags) + val recorder = _trackedEntities.atomicGetOrElseUpdate(gaugeEntity, { + val factory = instrumentFactory(gaugeEntity.category) + GaugeRecorder(MinMaxCounterKey(gaugeEntity.category, unitOfMeasurement.getOrElse(UnitOfMeasurement.Unknown)), + factory.createGauge(name, dynamicRange, refreshInterval, valueCollector)) + }, _.cleanup) + + recorder.asInstanceOf[GaugeRecorder].instrument + } + + def removeGauge(name: String, tags: Map[String, String]): Boolean = + _trackedEntities.remove(Entity(name, "gauge", tags)).isDefined + + def registerCounter(name: String, tags: Map[String, String] = Map.empty, unitOfMeasurement: Option[UnitOfMeasurement] = None, + dynamicRange: Option[DynamicRange] = None): Counter = { + + val counterEntity = Entity(name, "counter", tags) + val recorder = _trackedEntities.atomicGetOrElseUpdate(counterEntity, { + val factory = instrumentFactory(counterEntity.category) + CounterRecorder(CounterKey(counterEntity.category, unitOfMeasurement.getOrElse(UnitOfMeasurement.Unknown)), + factory.createCounter()) + }, _.cleanup) + + recorder.asInstanceOf[CounterRecorder].instrument + } + + def removeCounter(name: String, tags: Map[String, String]): Boolean = + _trackedEntities.remove(Entity(name, "counter", tags)).isDefined - EntityRegistration(entity, recorder) + def entity[T <: EntityRecorder](recorderFactory: EntityRecorderFactory[T], entity: Entity): T = { + _trackedEntities.atomicGetOrElseUpdate(entity, { + recorderFactory.createRecorder(instrumentFactory(recorderFactory.category)) + }, _.cleanup).asInstanceOf[T] } - def unregister(entity: Entity): Unit = - _trackedEntities.remove(entity).map(_.cleanup) + def removeEntity(entity: Entity): Boolean = + _trackedEntities.remove(entity).isDefined def find(entity: Entity): Option[EntityRecorder] = _trackedEntities.get(entity) - def find(name: String, category: String): Option[EntityRecorder] = - find(Entity(name, category)) - def subscribe(filter: SubscriptionFilter, subscriber: ActorRef, permanent: Boolean): Unit = _subscriptions.tell(Subscribe(filter, subscriber, permanent)) diff --git a/kamon-core/src/main/scala/kamon/metric/SimpleMetrics.scala b/kamon-core/src/main/scala/kamon/metric/SimpleMetrics.scala deleted file mode 100644 index 6324c320..00000000 --- a/kamon-core/src/main/scala/kamon/metric/SimpleMetrics.scala +++ /dev/null @@ -1,204 +0,0 @@ -/* - * ========================================================================================= - * Copyright © 2013-2015 the kamon project <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..cf43b87c 100644 --- a/kamon-core/src/main/scala/kamon/metric/TraceMetrics.scala +++ b/kamon-core/src/main/scala/kamon/metric/TraceMetrics.scala @@ -16,29 +16,30 @@ package kamon.metric -import kamon.metric.instrument.{ Time, InstrumentFactory, Histogram } +import kamon.metric.instrument.{ Time, InstrumentFactory } class TraceMetrics(instrumentFactory: InstrumentFactory) extends GenericEntityRecorder(instrumentFactory) { - import TraceMetrics.segmentKey /** * Records blah blah */ - val ElapsedTime = histogram("elapsed-time", unitOfMeasurement = Time.Nanoseconds) - - /** - * Records Blah Blah. - * - */ - def segment(name: String, category: String, library: String): Histogram = - histogram(segmentKey(name, category, library)) - + val elapsedTime = histogram("elapsed-time", unitOfMeasurement = Time.Nanoseconds) } object TraceMetrics extends EntityRecorderFactory[TraceMetrics] { def category: String = "trace" def createRecorder(instrumentFactory: InstrumentFactory): TraceMetrics = new TraceMetrics(instrumentFactory) +} + +class SegmentMetrics(instrumentFactory: InstrumentFactory) extends GenericEntityRecorder(instrumentFactory) { + + /** + * Records blah blah + */ + val elapsedTime = histogram("elapsed-time", unitOfMeasurement = Time.Nanoseconds) +} - def segmentKey(name: String, category: String, library: String): HistogramKey = - HistogramKey(name, Time.Nanoseconds, Map("category" -> category, "library" -> library)) +object SegmentMetrics extends EntityRecorderFactory[SegmentMetrics] { + def category: String = "trace-segment" + def createRecorder(instrumentFactory: InstrumentFactory): SegmentMetrics = new SegmentMetrics(instrumentFactory) }
\ No newline at end of file diff --git a/kamon-core/src/main/scala/kamon/metric/instrument/Gauge.scala b/kamon-core/src/main/scala/kamon/metric/instrument/Gauge.scala index 80214510..61b53df2 100644 --- a/kamon-core/src/main/scala/kamon/metric/instrument/Gauge.scala +++ b/kamon-core/src/main/scala/kamon/metric/instrument/Gauge.scala @@ -55,6 +55,10 @@ object Gauge { implicit def functionZeroAsCurrentValueCollector(f: () ⇒ Long): CurrentValueCollector = new CurrentValueCollector { def currentValue: Long = f.apply() } + + implicit def callByNameLongAsCurrentValueCollector(f: ⇒ Long): CurrentValueCollector = new CurrentValueCollector { + def currentValue: Long = f + } } /** diff --git a/kamon-core/src/main/scala/kamon/trace/MetricsOnlyContext.scala b/kamon-core/src/main/scala/kamon/trace/MetricsOnlyContext.scala index eb4bad6f..0f09b4be 100644 --- a/kamon-core/src/main/scala/kamon/trace/MetricsOnlyContext.scala +++ b/kamon-core/src/main/scala/kamon/trace/MetricsOnlyContext.scala @@ -19,13 +19,14 @@ package kamon.trace import java.util.concurrent.ConcurrentLinkedQueue import akka.event.LoggingAdapter -import kamon.metric.{ Metrics, TraceMetrics } +import kamon.Kamon +import kamon.metric.{ SegmentMetrics, Metrics, TraceMetrics } import kamon.util.{ NanoInterval, RelativeNanoTimestamp } import scala.annotation.tailrec private[kamon] class MetricsOnlyContext(traceName: String, val token: String, izOpen: Boolean, val levelOfDetail: LevelOfDetail, - val startTimestamp: RelativeNanoTimestamp, log: LoggingAdapter, metricsExtension: Metrics) + val startTimestamp: RelativeNanoTimestamp, log: LoggingAdapter) extends TraceContext { @volatile private var _name = traceName @@ -51,20 +52,23 @@ private[kamon] class MetricsOnlyContext(traceName: String, val token: String, iz val traceElapsedTime = NanoInterval.since(startTimestamp) _elapsedTime = traceElapsedTime - metricsExtension.register(TraceMetrics, name).map { registration ⇒ - registration.recorder.ElapsedTime.record(traceElapsedTime.nanos) - drainFinishedSegments(registration.recorder) - } + Kamon.metrics.entity(TraceMetrics, name).elapsedTime.record(traceElapsedTime.nanos) + drainFinishedSegments() } def startSegment(segmentName: String, category: String, library: String): Segment = new MetricsOnlySegment(segmentName, category, library) - @tailrec private def drainFinishedSegments(recorder: TraceMetrics): Unit = { + @tailrec private def drainFinishedSegments(): Unit = { val segment = _finishedSegments.poll() if (segment != null) { - recorder.segment(segment.name, segment.category, segment.library).record(segment.duration.nanos) - drainFinishedSegments(recorder) + val segmentTags = Map( + "trace" -> name, + "category" -> segment.category, + "library" -> segment.library) + + Kamon.metrics.entity(SegmentMetrics, segment.name, segmentTags).elapsedTime.record(segment.duration.nanos) + drainFinishedSegments() } } @@ -72,9 +76,7 @@ private[kamon] class MetricsOnlyContext(traceName: String, val token: String, iz _finishedSegments.add(SegmentLatencyData(segmentName, category, library, duration)) if (isClosed) { - metricsExtension.register(TraceMetrics, name).map { registration ⇒ - drainFinishedSegments(registration.recorder) - } + drainFinishedSegments() } } diff --git a/kamon-core/src/main/scala/kamon/trace/Tracer.scala b/kamon-core/src/main/scala/kamon/trace/Tracer.scala index cf83b36b..472c1d65 100644 --- a/kamon-core/src/main/scala/kamon/trace/Tracer.scala +++ b/kamon-core/src/main/scala/kamon/trace/Tracer.scala @@ -80,7 +80,7 @@ private[kamon] class TracerImpl(metricsExtension: Metrics, config: Config) exten private def createTraceContext(traceName: String, token: String = newToken, startTimestamp: RelativeNanoTimestamp = RelativeNanoTimestamp.now, isOpen: Boolean = true, isLocal: Boolean = true): TraceContext = { - def newMetricsOnlyContext = new MetricsOnlyContext(traceName, token, isOpen, _settings.levelOfDetail, startTimestamp, null, metricsExtension) + def newMetricsOnlyContext = new MetricsOnlyContext(traceName, token, isOpen, _settings.levelOfDetail, startTimestamp, null) if (_settings.levelOfDetail == LevelOfDetail.MetricsOnly || !isLocal) newMetricsOnlyContext @@ -88,7 +88,7 @@ private[kamon] class TracerImpl(metricsExtension: Metrics, config: Config) exten if (!_settings.sampler.shouldTrace) newMetricsOnlyContext else - new TracingContext(traceName, token, true, _settings.levelOfDetail, isLocal, startTimestamp, null, metricsExtension, this, dispatchTracingContext) + new TracingContext(traceName, token, true, _settings.levelOfDetail, isLocal, startTimestamp, null, dispatchTracingContext) } } diff --git a/kamon-core/src/main/scala/kamon/trace/TracingContext.scala b/kamon-core/src/main/scala/kamon/trace/TracingContext.scala index d34526f7..9708d25f 100644 --- a/kamon-core/src/main/scala/kamon/trace/TracingContext.scala +++ b/kamon-core/src/main/scala/kamon/trace/TracingContext.scala @@ -26,9 +26,8 @@ import kamon.metric.Metrics import scala.collection.concurrent.TrieMap private[trace] class TracingContext(traceName: String, token: String, izOpen: Boolean, levelOfDetail: LevelOfDetail, - isLocal: Boolean, startTimeztamp: RelativeNanoTimestamp, log: LoggingAdapter, metricsExtension: Metrics, - traceExtension: TracerImpl, traceInfoSink: TracingContext ⇒ Unit) - extends MetricsOnlyContext(traceName, token, izOpen, levelOfDetail, startTimeztamp, log, metricsExtension) { + isLocal: Boolean, startTimeztamp: RelativeNanoTimestamp, log: LoggingAdapter, traceInfoSink: TracingContext ⇒ Unit) + extends MetricsOnlyContext(traceName, token, izOpen, levelOfDetail, startTimeztamp, log) { private val _openSegments = new AtomicInteger(0) private val _startTimestamp = NanoTimestamp.now diff --git a/kamon-core/src/main/scala/kamon/util/FunctionalInterfaces.scala b/kamon-core/src/main/scala/kamon/util/FunctionalInterfaces.scala new file mode 100644 index 00000000..1f600b78 --- /dev/null +++ b/kamon-core/src/main/scala/kamon/util/FunctionalInterfaces.scala @@ -0,0 +1,9 @@ +package kamon.util + +trait Supplier[T] { + def get: T +} + +trait Function[T, R] { + def apply(t: T): R +}
\ No newline at end of file diff --git a/kamon-core/src/test/scala/kamon/metric/SimpleMetricsSpec.scala b/kamon-core/src/test/scala/kamon/metric/SimpleMetricsSpec.scala index 60ba9a0e..0180e980 100644 --- a/kamon-core/src/test/scala/kamon/metric/SimpleMetricsSpec.scala +++ b/kamon-core/src/test/scala/kamon/metric/SimpleMetricsSpec.scala @@ -35,93 +35,81 @@ class SimpleMetricsSpec extends BaseKamonSpec("simple-metrics-spec") { "the SimpleMetrics extension" should { "allow registering a fully configured Histogram and get the same Histogram if registering again" in { - val histogramA = Kamon.simpleMetrics.histogram("histogram-with-settings", DynamicRange(1, 10000, 2)) - val histogramB = Kamon.simpleMetrics.histogram("histogram-with-settings", DynamicRange(1, 10000, 2)) + val histogramA = Kamon.metrics.histogram("histogram-with-settings", DynamicRange(1, 10000, 2)) + val histogramB = Kamon.metrics.histogram("histogram-with-settings", DynamicRange(1, 10000, 2)) histogramA shouldBe theSameInstanceAs(histogramB) } "return the original Histogram when registering a fully configured Histogram for second time but with different settings" in { - val histogramA = Kamon.simpleMetrics.histogram("histogram-with-settings", DynamicRange(1, 10000, 2)) - val histogramB = Kamon.simpleMetrics.histogram("histogram-with-settings", DynamicRange(1, 50000, 2)) + val histogramA = Kamon.metrics.histogram("histogram-with-settings", DynamicRange(1, 10000, 2)) + val histogramB = Kamon.metrics.histogram("histogram-with-settings", DynamicRange(1, 50000, 2)) histogramA shouldBe theSameInstanceAs(histogramB) } "allow registering a Histogram that takes the default configuration from the kamon.metrics.precision settings" in { - Kamon.simpleMetrics.histogram("histogram-with-default-configuration") + Kamon.metrics.histogram("histogram-with-default-configuration") } "allow registering a Counter and get the same Counter if registering again" in { - val counterA = Kamon.simpleMetrics.counter("counter") - val counterB = Kamon.simpleMetrics.counter("counter") + val counterA = Kamon.metrics.counter("counter") + val counterB = Kamon.metrics.counter("counter") counterA shouldBe theSameInstanceAs(counterB) } "allow registering a fully configured MinMaxCounter and get the same MinMaxCounter if registering again" in { - val minMaxCounterA = Kamon.simpleMetrics.minMaxCounter("min-max-counter-with-settings", DynamicRange(1, 10000, 2), 1 second) - val minMaxCounterB = Kamon.simpleMetrics.minMaxCounter("min-max-counter-with-settings", DynamicRange(1, 10000, 2), 1 second) + val minMaxCounterA = Kamon.metrics.minMaxCounter("min-max-counter-with-settings", DynamicRange(1, 10000, 2), 1 second) + val minMaxCounterB = Kamon.metrics.minMaxCounter("min-max-counter-with-settings", DynamicRange(1, 10000, 2), 1 second) minMaxCounterA shouldBe theSameInstanceAs(minMaxCounterB) } "return the original MinMaxCounter when registering a fully configured MinMaxCounter for second time but with different settings" in { - val minMaxCounterA = Kamon.simpleMetrics.minMaxCounter("min-max-counter-with-settings", DynamicRange(1, 10000, 2), 1 second) - val minMaxCounterB = Kamon.simpleMetrics.minMaxCounter("min-max-counter-with-settings", DynamicRange(1, 50000, 2), 1 second) + val minMaxCounterA = Kamon.metrics.minMaxCounter("min-max-counter-with-settings", DynamicRange(1, 10000, 2), 1 second) + val minMaxCounterB = Kamon.metrics.minMaxCounter("min-max-counter-with-settings", DynamicRange(1, 50000, 2), 1 second) minMaxCounterA shouldBe theSameInstanceAs(minMaxCounterB) } "allow registering a MinMaxCounter that takes the default configuration from the kamon.metrics.precision settings" in { - Kamon.simpleMetrics.minMaxCounter("min-max-counter-with-default-configuration") + Kamon.metrics.minMaxCounter("min-max-counter-with-default-configuration") } "allow registering a fully configured Gauge and get the same Gauge if registering again" in { - val gaugeA = Kamon.simpleMetrics.gauge("gauge-with-settings", DynamicRange(1, 10000, 2), 1 second, { - () ⇒ 1L - }) - - val gaugeB = Kamon.simpleMetrics.gauge("gauge-with-settings", DynamicRange(1, 10000, 2), 1 second, { - () ⇒ 1L - }) + val gaugeA = Kamon.metrics.gauge("gauge-with-settings", DynamicRange(1, 10000, 2), 1 second)(1L) + val gaugeB = Kamon.metrics.gauge("gauge-with-settings", DynamicRange(1, 10000, 2), 1 second)(1L) gaugeA shouldBe theSameInstanceAs(gaugeB) } "return the original Gauge when registering a fully configured Gauge for second time but with different settings" in { - val gaugeA = Kamon.simpleMetrics.gauge("gauge-with-settings", DynamicRange(1, 10000, 2), 1 second, { - () ⇒ 1L - }) - - val gaugeB = Kamon.simpleMetrics.gauge("gauge-with-settings", DynamicRange(1, 10000, 2), 1 second, { - () ⇒ 1L - }) + val gaugeA = Kamon.metrics.gauge("gauge-with-settings", DynamicRange(1, 10000, 2), 1 second)(1L) + val gaugeB = Kamon.metrics.gauge("gauge-with-settings", DynamicRange(1, 10000, 2), 1 second)(1L) gaugeA shouldBe theSameInstanceAs(gaugeB) } "allow registering a Gauge that takes the default configuration from the kamon.metrics.precision settings" in { - Kamon.simpleMetrics.gauge("gauge-with-default-configuration", { - () ⇒ 2L - }) + Kamon.metrics.gauge("gauge-with-default-configuration")(2L) } "allow un-registering user metrics" in { - val counter = Kamon.simpleMetrics.counter("counter-for-remove") - val histogram = Kamon.simpleMetrics.histogram("histogram-for-remove") - val minMaxCounter = Kamon.simpleMetrics.minMaxCounter("min-max-counter-for-remove") - val gauge = Kamon.simpleMetrics.gauge("gauge-for-remove", { () ⇒ 2L }) - - Kamon.simpleMetrics.removeCounter("counter-for-remove") - Kamon.simpleMetrics.removeHistogram("histogram-for-remove") - Kamon.simpleMetrics.removeMinMaxCounter("min-max-counter-for-remove") - Kamon.simpleMetrics.removeGauge("gauge-for-remove") - - counter should not be (theSameInstanceAs(Kamon.simpleMetrics.counter("counter-for-remove"))) - histogram should not be (theSameInstanceAs(Kamon.simpleMetrics.histogram("histogram-for-remove"))) - minMaxCounter should not be (theSameInstanceAs(Kamon.simpleMetrics.minMaxCounter("min-max-counter-for-remove"))) - gauge should not be (theSameInstanceAs(Kamon.simpleMetrics.gauge("gauge-for-remove", { () ⇒ 2L }))) + val counter = Kamon.metrics.counter("counter-for-remove") + val histogram = Kamon.metrics.histogram("histogram-for-remove") + val minMaxCounter = Kamon.metrics.minMaxCounter("min-max-counter-for-remove") + val gauge = Kamon.metrics.gauge("gauge-for-remove")(2L) + + Kamon.metrics.removeCounter("counter-for-remove") + Kamon.metrics.removeHistogram("histogram-for-remove") + Kamon.metrics.removeMinMaxCounter("min-max-counter-for-remove") + Kamon.metrics.removeGauge("gauge-for-remove") + + counter should not be (theSameInstanceAs(Kamon.metrics.counter("counter-for-remove"))) + histogram should not be (theSameInstanceAs(Kamon.metrics.histogram("histogram-for-remove"))) + minMaxCounter should not be (theSameInstanceAs(Kamon.metrics.minMaxCounter("min-max-counter-for-remove"))) + gauge should not be (theSameInstanceAs(Kamon.metrics.gauge("gauge-for-remove")(2L))) } } } diff --git a/kamon-core/src/test/scala/kamon/metric/SubscriptionsProtocolSpec.scala b/kamon-core/src/test/scala/kamon/metric/SubscriptionsProtocolSpec.scala index 53ae5273..b8131f6e 100644 --- a/kamon-core/src/test/scala/kamon/metric/SubscriptionsProtocolSpec.scala +++ b/kamon-core/src/test/scala/kamon/metric/SubscriptionsProtocolSpec.scala @@ -34,12 +34,12 @@ class SubscriptionsProtocolSpec extends BaseKamonSpec("subscriptions-protocol-sp """.stripMargin) lazy val metricsModule = Kamon.metrics - import metricsModule.{ register, subscribe, unsubscribe } + import metricsModule.{ entity, subscribe, unsubscribe } "the Subscriptions messaging protocol" should { "allow subscribing for a single tick" in { val subscriber = TestProbe() - register(TraceMetrics, "one-shot") + entity(TraceMetrics, "one-shot") subscribe("trace", "one-shot", subscriber.ref, permanently = false) flushSubscriptions() @@ -54,7 +54,7 @@ class SubscriptionsProtocolSpec extends BaseKamonSpec("subscriptions-protocol-sp "allow subscribing permanently to a metric" in { val subscriber = TestProbe() - register(TraceMetrics, "permanent") + entity(TraceMetrics, "permanent") subscribe("trace", "permanent", subscriber.ref, permanently = true) for (repetition ← 1 to 5) { @@ -68,9 +68,9 @@ class SubscriptionsProtocolSpec extends BaseKamonSpec("subscriptions-protocol-sp "allow subscribing to metrics matching a glob pattern" in { val subscriber = TestProbe() - register(TraceMetrics, "include-one") - register(TraceMetrics, "exclude-two") - register(TraceMetrics, "include-three") + entity(TraceMetrics, "include-one") + entity(TraceMetrics, "exclude-two") + entity(TraceMetrics, "include-three") subscribe("trace", "include-*", subscriber.ref, permanently = true) for (repetition ← 1 to 5) { @@ -85,9 +85,9 @@ class SubscriptionsProtocolSpec extends BaseKamonSpec("subscriptions-protocol-sp "send a single TickMetricSnapshot to each subscriber, even if subscribed multiple times" in { val subscriber = TestProbe() - register(TraceMetrics, "include-one") - register(TraceMetrics, "exclude-two") - register(TraceMetrics, "include-three") + entity(TraceMetrics, "include-one") + entity(TraceMetrics, "exclude-two") + entity(TraceMetrics, "include-three") subscribe("trace", "include-one", subscriber.ref, permanently = true) subscribe("trace", "include-three", subscriber.ref, permanently = true) @@ -103,7 +103,7 @@ class SubscriptionsProtocolSpec extends BaseKamonSpec("subscriptions-protocol-sp "allow un-subscribing a subscriber" in { val subscriber = TestProbe() - register(TraceMetrics, "one-shot") + entity(TraceMetrics, "one-shot") subscribe("trace", "one-shot", subscriber.ref, permanently = true) flushSubscriptions() diff --git a/kamon-core/src/test/scala/kamon/metric/TickMetricSnapshotBufferSpec.scala b/kamon-core/src/test/scala/kamon/metric/TickMetricSnapshotBufferSpec.scala index 0c9ced32..ac35cf58 100644 --- a/kamon-core/src/test/scala/kamon/metric/TickMetricSnapshotBufferSpec.scala +++ b/kamon-core/src/test/scala/kamon/metric/TickMetricSnapshotBufferSpec.scala @@ -88,21 +88,21 @@ class TickMetricSnapshotBufferSpec extends BaseKamonSpec("trace-metrics-spec") w trait SnapshotFixtures { val collectionContext = Kamon.metrics.buildDefaultCollectionContext val testTraceIdentity = Entity("buffer-spec-test-trace", "trace") - val traceRecorder = Kamon.metrics.register(TraceMetrics, "buffer-spec-test-trace").get.recorder + val traceRecorder = Kamon.metrics.entity(TraceMetrics, "buffer-spec-test-trace") val firstEmpty = TickMetricSnapshot(new MilliTimestamp(1000), new MilliTimestamp(2000), Map.empty) val secondEmpty = TickMetricSnapshot(new MilliTimestamp(2000), new MilliTimestamp(3000), Map.empty) val thirdEmpty = TickMetricSnapshot(new MilliTimestamp(3000), new MilliTimestamp(4000), Map.empty) - traceRecorder.ElapsedTime.record(10L) - traceRecorder.ElapsedTime.record(20L) - traceRecorder.ElapsedTime.record(30L) + traceRecorder.elapsedTime.record(10L) + traceRecorder.elapsedTime.record(20L) + traceRecorder.elapsedTime.record(30L) val firstNonEmpty = TickMetricSnapshot(new MilliTimestamp(1000), new MilliTimestamp(2000), Map( (testTraceIdentity -> traceRecorder.collect(collectionContext)))) - traceRecorder.ElapsedTime.record(10L) - traceRecorder.ElapsedTime.record(10L) - traceRecorder.ElapsedTime.record(300L) + traceRecorder.elapsedTime.record(10L) + traceRecorder.elapsedTime.record(10L) + traceRecorder.elapsedTime.record(300L) val secondNonEmpty = TickMetricSnapshot(new MilliTimestamp(1000), new MilliTimestamp(2000), Map( (testTraceIdentity -> traceRecorder.collect(collectionContext)))) } diff --git a/kamon-core/src/test/scala/kamon/metric/TraceMetricsSpec.scala b/kamon-core/src/test/scala/kamon/metric/TraceMetricsSpec.scala index 03a09b7f..efdcb79b 100644 --- a/kamon-core/src/test/scala/kamon/metric/TraceMetricsSpec.scala +++ b/kamon-core/src/test/scala/kamon/metric/TraceMetricsSpec.scala @@ -23,8 +23,6 @@ import kamon.trace.Tracer import kamon.metric.instrument.Histogram class TraceMetricsSpec extends BaseKamonSpec("trace-metrics-spec") with ImplicitSender { - import TraceMetricsSpec.SegmentSyntax - override lazy val config = ConfigFactory.parseString( """ @@ -60,10 +58,13 @@ class TraceMetricsSpec extends BaseKamonSpec("trace-metrics-spec") with Implicit Tracer.currentContext.finish() } - val snapshot = takeSnapshotOf("trace-with-segments", "trace") + val snapshot = takeSnapshotOf("test-segment", "trace-segment", + tags = Map( + "trace" -> "trace-with-segments", + "category" -> "test-category", + "library" -> "test-library")) + snapshot.histogram("elapsed-time").get.numberOfMeasurements should be(1) - snapshot.segments.size should be(1) - snapshot.segment("test-segment", "test-category", "test-library").numberOfMeasurements should be(1) } "record the elapsed time for segments that finish after their correspondent trace has finished" in { @@ -75,25 +76,26 @@ class TraceMetricsSpec extends BaseKamonSpec("trace-metrics-spec") with Implicit val beforeFinishSegmentSnapshot = takeSnapshotOf("closing-segment-after-trace", "trace") beforeFinishSegmentSnapshot.histogram("elapsed-time").get.numberOfMeasurements should be(1) - beforeFinishSegmentSnapshot.segments.size should be(0) + + intercept[NoSuchElementException] { + // The segment metric should not exist before we it has finished. + + takeSnapshotOf("test-segment", "trace-segment", + tags = Map( + "trace" -> "closing-segment-after-trace", + "category" -> "test-category", + "library" -> "test-library")) + } segment.finish() - val afterFinishSegmentSnapshot = takeSnapshotOf("closing-segment-after-trace", "trace") - afterFinishSegmentSnapshot.histogram("elapsed-time").get.numberOfMeasurements should be(0) - afterFinishSegmentSnapshot.segments.size should be(1) - afterFinishSegmentSnapshot.segment("test-segment", "test-category", "test-library").numberOfMeasurements should be(1) - } - } -} + val afterFinishSegmentSnapshot = takeSnapshotOf("test-segment", "trace-segment", + tags = Map( + "trace" -> "closing-segment-after-trace", + "category" -> "test-category", + "library" -> "test-library")) -object TraceMetricsSpec { - implicit class SegmentSyntax(val entitySnapshot: EntitySnapshot) extends AnyVal { - def segments: Map[HistogramKey, Histogram.Snapshot] = { - entitySnapshot.histograms.filterKeys(_.metadata.contains("category")) + afterFinishSegmentSnapshot.histogram("elapsed-time").get.numberOfMeasurements should be(1) } - - def segment(name: String, category: String, library: String): Histogram.Snapshot = - segments(TraceMetrics.segmentKey(name, category, library)) } } diff --git a/kamon-core/src/test/scala/kamon/testkit/BaseKamonSpec.scala b/kamon-core/src/test/scala/kamon/testkit/BaseKamonSpec.scala index f3d809bf..e7b18770 100644 --- a/kamon-core/src/test/scala/kamon/testkit/BaseKamonSpec.scala +++ b/kamon-core/src/test/scala/kamon/testkit/BaseKamonSpec.scala @@ -20,7 +20,7 @@ import akka.testkit.{ ImplicitSender, TestKitBase } import akka.actor.ActorSystem import com.typesafe.config.{ Config, ConfigFactory } import kamon.Kamon -import kamon.metric.{ SubscriptionsDispatcher, EntitySnapshot, MetricsImpl } +import kamon.metric.{ Entity, SubscriptionsDispatcher, EntitySnapshot, MetricsImpl } import kamon.trace.TraceContext import kamon.util.LazyActorRef import org.scalatest.{ BeforeAndAfterAll, Matchers, WordSpecLike } @@ -48,6 +48,11 @@ abstract class BaseKamonSpec(actorSystemName: String) extends TestKitBase with W recorder.collect(collectionContext) } + def takeSnapshotOf(name: String, category: String, tags: Map[String, String]): EntitySnapshot = { + val recorder = Kamon.metrics.find(Entity(name, category, tags)).get + recorder.collect(collectionContext) + } + def flushSubscriptions(): Unit = { val subscriptionsField = Kamon.metrics.getClass.getDeclaredField("_subscriptions") subscriptionsField.setAccessible(true) diff --git a/kamon-datadog/src/main/scala/kamon/datadog/DatadogMetricsSender.scala b/kamon-datadog/src/main/scala/kamon/datadog/DatadogMetricsSender.scala index 80d4f098..4a73f5aa 100644 --- a/kamon-datadog/src/main/scala/kamon/datadog/DatadogMetricsSender.scala +++ b/kamon-datadog/src/main/scala/kamon/datadog/DatadogMetricsSender.scala @@ -23,7 +23,7 @@ import akka.util.ByteString import kamon.metric.SubscriptionsDispatcher.TickMetricSnapshot import java.text.{ DecimalFormatSymbols, DecimalFormat } import kamon.metric.instrument.{ Counter, Histogram } -import kamon.metric.{ MetricKey, Entity } +import kamon.metric.{ SingleInstrumentEntityRecorder, MetricKey, Entity } import java.util.Locale class DatadogMetricsSender(remote: InetSocketAddress, maxPacketSizeInBytes: Long) extends Actor with UdpExtensionProvider { @@ -90,11 +90,18 @@ class DatadogMetricsSender(remote: InetSocketAddress, maxPacketSizeInBytes: Long def encodeDatadogCounter(count: Long): String = count.toString + "|c" def buildMetricName(entity: Entity, metricKey: MetricKey): String = - s"$appName.${entity.category}.${metricKey.name}" + if (SingleInstrumentEntityRecorder.AllCategories.contains(entity.category)) + s"$appName.${entity.category}" + else + s"$appName.${entity.category}.${metricKey.name}" def buildIdentificationTag(entity: Entity, metricKey: MetricKey): String = { - val normalizedEntityName = entity.name.replace(": ", ":") - s"|#${entity.category}:${normalizedEntityName}" + val normalizedEntityName = entity.name.replace(" ", "") + if (entity.tags.nonEmpty) { + val tagsString = entity.tags.map { case (k, v) ⇒ k + ":" + v } mkString "," + s"|#${entity.category}:${normalizedEntityName},$tagsString" + } else + s"|#${entity.category}:${normalizedEntityName}" } } diff --git a/kamon-datadog/src/test/scala/kamon/datadog/DatadogMetricSenderSpec.scala b/kamon-datadog/src/test/scala/kamon/datadog/DatadogMetricSenderSpec.scala index b35902f9..22ce1f8e 100644 --- a/kamon-datadog/src/test/scala/kamon/datadog/DatadogMetricSenderSpec.scala +++ b/kamon-datadog/src/test/scala/kamon/datadog/DatadogMetricSenderSpec.scala @@ -96,7 +96,20 @@ class DatadogMetricSenderSpec extends BaseKamonSpec("datadog-metric-sender-spec" val udp = setup(Map(entity -> testRecorder.collect(collectionContext))) val Udp.Send(data, _, _) = udp.expectMsgType[Udp.Send] - data.utf8String should be("kamon.category.metric-one:10|ms|@0.5|#category:datadog\nkamon.category.counter:4|c|#category:datadog\nkamon.category.metric-two:21|ms|#category:datadog") + data.utf8String.split("\n") should contain allOf ( + "kamon.category.metric-one:10|ms|@0.5|#category:datadog", + "kamon.category.metric-two:21|ms|#category:datadog", + "kamon.category.counter:4|c|#category:datadog") + } + + "include all entity tags, if available in the metric packet" in new UdpListenerFixture { + val (entity, testRecorder) = buildRecorder("datadog", tags = Map("my-cool-tag" -> "some-value")) + testRecorder.metricTwo.record(10L, 2) + + val udp = setup(Map(entity -> testRecorder.collect(collectionContext))) + val Udp.Send(data, _, _) = udp.expectMsgType[Udp.Send] + + data.utf8String should be(s"kamon.category.metric-two:10|ms|@0.5|#category:datadog,my-cool-tag:some-value") } } @@ -105,9 +118,10 @@ class DatadogMetricSenderSpec extends BaseKamonSpec("datadog-metric-sender-spec" val localhostName = ManagementFactory.getRuntimeMXBean.getName.split('@')(1) val testMaxPacketSize = system.settings.config.getBytes("kamon.datadog.max-packet-size") - def buildRecorder(name: String): (Entity, TestEntityRecorder) = { - val registration = Kamon.metrics.register(TestEntityRecorder, name).get - (registration.entity, registration.recorder) + def buildRecorder(name: String, tags: Map[String, String] = Map.empty): (Entity, TestEntityRecorder) = { + val entity = Entity(name, TestEntityRecorder.category, tags) + val recorder = Kamon.metrics.entity(TestEntityRecorder, entity) + (entity, recorder) } def setup(metrics: Map[Entity, EntitySnapshot]): TestProbe = { diff --git a/kamon-jdbc/src/main/scala/kamon/jdbc/instrumentation/StatementInstrumentation.scala b/kamon-jdbc/src/main/scala/kamon/jdbc/instrumentation/StatementInstrumentation.scala index aa9295db..bef20667 100644 --- a/kamon-jdbc/src/main/scala/kamon/jdbc/instrumentation/StatementInstrumentation.scala +++ b/kamon-jdbc/src/main/scala/kamon/jdbc/instrumentation/StatementInstrumentation.scala @@ -44,9 +44,8 @@ class StatementInstrumentation { @Around("onExecuteStatement(sql) || onExecutePreparedStatement(sql) || onExecutePreparedCall(sql)") def aroundExecuteStatement(pjp: ProceedingJoinPoint, sql: String): Any = { Tracer.currentContext.collect { ctx ⇒ - val metricsExtension = Kamon.metrics val jdbcExtension = Kamon(Jdbc) - implicit val statementRecorder = metricsExtension.register(StatementsMetrics, "jdbc-statements").map(_.recorder) + implicit val statementRecorder = Kamon.metrics.entity(StatementsMetrics, "jdbc-statements") sql.replaceAll(CommentPattern, Empty) match { case SelectStatement(_) ⇒ withSegment(ctx, Select, jdbcExtension)(recordRead(pjp, sql, jdbcExtension)) @@ -71,22 +70,22 @@ class StatementInstrumentation { try thunk finally segment.finish() } - def recordRead(pjp: ProceedingJoinPoint, sql: String, jdbcExtension: JdbcExtension)(implicit statementRecorder: Option[StatementsMetrics]): Any = { + def recordRead(pjp: ProceedingJoinPoint, sql: String, jdbcExtension: JdbcExtension)(implicit statementRecorder: StatementsMetrics): Any = { withTimeSpent(pjp.proceedWithErrorHandler(sql, jdbcExtension)) { timeSpent ⇒ - statementRecorder.map(stmr ⇒ stmr.reads.record(timeSpent)) + statementRecorder.reads.record(timeSpent) val timeSpentInMillis = nanos.toMillis(timeSpent) if (timeSpentInMillis >= jdbcExtension.slowQueryThreshold) { - statementRecorder.map(stmr ⇒ stmr.slows.increment()) + statementRecorder.slows.increment() jdbcExtension.processSlowQuery(sql, timeSpentInMillis) } } } - def recordWrite(pjp: ProceedingJoinPoint, sql: String, jdbcExtension: JdbcExtension)(implicit statementRecorder: Option[StatementsMetrics]): Any = { + def recordWrite(pjp: ProceedingJoinPoint, sql: String, jdbcExtension: JdbcExtension)(implicit statementRecorder: StatementsMetrics): Any = { withTimeSpent(pjp.proceedWithErrorHandler(sql, jdbcExtension)) { timeSpent ⇒ - statementRecorder.map(stmr ⇒ stmr.writes.record(timeSpent)) + statementRecorder.writes.record(timeSpent) } } } @@ -107,13 +106,13 @@ object StatementInstrumentation { val Delete = "Delete" implicit class PimpedProceedingJoinPoint(pjp: ProceedingJoinPoint) { - def proceedWithErrorHandler(sql: String, jdbcExtension: JdbcExtension)(implicit statementRecorder: Option[StatementsMetrics]): Any = { + def proceedWithErrorHandler(sql: String, jdbcExtension: JdbcExtension)(implicit statementRecorder: StatementsMetrics): Any = { try { pjp.proceed() } catch { case NonFatal(cause) ⇒ jdbcExtension.processSqlError(sql, cause) - statementRecorder.map(stmr ⇒ stmr.errors.increment()) + statementRecorder.errors.increment() throw cause } } diff --git a/kamon-jdbc/src/test/scala/kamon/jdbc/instrumentation/StatementInstrumentationSpec.scala b/kamon-jdbc/src/test/scala/kamon/jdbc/instrumentation/StatementInstrumentationSpec.scala index 8ad5faa8..80107dff 100644 --- a/kamon-jdbc/src/test/scala/kamon/jdbc/instrumentation/StatementInstrumentationSpec.scala +++ b/kamon-jdbc/src/test/scala/kamon/jdbc/instrumentation/StatementInstrumentationSpec.scala @@ -24,8 +24,6 @@ import kamon.testkit.BaseKamonSpec import kamon.trace.{ Tracer, SegmentCategory } class StatementInstrumentationSpec extends BaseKamonSpec("jdbc-spec") { - import TraceMetricsSpec.SegmentSyntax - override lazy val config = ConfigFactory.parseString( """ @@ -76,8 +74,14 @@ class StatementInstrumentationSpec extends BaseKamonSpec("jdbc-spec") { val traceSnapshot = takeSnapshotOf("jdbc-trace-insert", "trace") traceSnapshot.histogram("elapsed-time").get.numberOfMeasurements should be(1) - traceSnapshot.segments.size should be(1) - traceSnapshot.segment("Jdbc[Insert]", SegmentCategory.Database, Jdbc.SegmentLibraryName).numberOfMeasurements should be(100) + + val segmentSnapshot = takeSnapshotOf("Jdbc[Insert]", "trace-segment", + tags = Map( + "trace" -> "jdbc-trace-insert", + "category" -> SegmentCategory.Database, + "library" -> Jdbc.SegmentLibraryName)) + + segmentSnapshot.histogram("elapsed-time").get.numberOfMeasurements should be(100) } "record the execution time of SELECT operation" in { @@ -96,8 +100,14 @@ class StatementInstrumentationSpec extends BaseKamonSpec("jdbc-spec") { val traceSnapshot = takeSnapshotOf("jdbc-trace-select", "trace") traceSnapshot.histogram("elapsed-time").get.numberOfMeasurements should be(1) - traceSnapshot.segments.size should be(1) - traceSnapshot.segment("Jdbc[Select]", SegmentCategory.Database, Jdbc.SegmentLibraryName).numberOfMeasurements should be(100) + + val segmentSnapshot = takeSnapshotOf("Jdbc[Select]", "trace-segment", + tags = Map( + "trace" -> "jdbc-trace-select", + "category" -> SegmentCategory.Database, + "library" -> Jdbc.SegmentLibraryName)) + + segmentSnapshot.histogram("elapsed-time").get.numberOfMeasurements should be(100) } "record the execution time of UPDATE operation" in { @@ -116,8 +126,14 @@ class StatementInstrumentationSpec extends BaseKamonSpec("jdbc-spec") { val traceSnapshot = takeSnapshotOf("jdbc-trace-update", "trace") traceSnapshot.histogram("elapsed-time").get.numberOfMeasurements should be(1) - traceSnapshot.segments.size should be(1) - traceSnapshot.segment("Jdbc[Update]", SegmentCategory.Database, Jdbc.SegmentLibraryName).numberOfMeasurements should be(100) + + val segmentSnapshot = takeSnapshotOf("Jdbc[Update]", "trace-segment", + tags = Map( + "trace" -> "jdbc-trace-update", + "category" -> SegmentCategory.Database, + "library" -> Jdbc.SegmentLibraryName)) + + segmentSnapshot.histogram("elapsed-time").get.numberOfMeasurements should be(100) } "record the execution time of DELETE operation" in { @@ -136,8 +152,14 @@ class StatementInstrumentationSpec extends BaseKamonSpec("jdbc-spec") { val traceSnapshot = takeSnapshotOf("jdbc-trace-delete", "trace") traceSnapshot.histogram("elapsed-time").get.numberOfMeasurements should be(1) - traceSnapshot.segments.size should be(1) - traceSnapshot.segment("Jdbc[Delete]", SegmentCategory.Database, Jdbc.SegmentLibraryName).numberOfMeasurements should be(100) + + val segmentSnapshot = takeSnapshotOf("Jdbc[Delete]", "trace-segment", + tags = Map( + "trace" -> "jdbc-trace-delete", + "category" -> SegmentCategory.Database, + "library" -> Jdbc.SegmentLibraryName)) + + segmentSnapshot.histogram("elapsed-time").get.numberOfMeasurements should be(100) } diff --git a/kamon-newrelic/src/main/scala/kamon/newrelic/CustomMetricExtractor.scala b/kamon-newrelic/src/main/scala/kamon/newrelic/CustomMetricExtractor.scala index 41ed9661..6919a967 100644 --- a/kamon-newrelic/src/main/scala/kamon/newrelic/CustomMetricExtractor.scala +++ b/kamon-newrelic/src/main/scala/kamon/newrelic/CustomMetricExtractor.scala @@ -16,17 +16,22 @@ package kamon.newrelic -import kamon.metric.{ SimpleMetricsImpl, EntitySnapshot, Entity } +import kamon.metric.{ EntitySnapshot, Entity } import kamon.metric.instrument.CollectionContext object CustomMetricExtractor extends MetricExtractor { def extract(settings: AgentSettings, collectionContext: CollectionContext, metrics: Map[Entity, EntitySnapshot]): Map[MetricID, MetricData] = { - metrics.get(SimpleMetricsImpl.SimpleMetricsEntity).map { allSimpleMetrics ⇒ - allSimpleMetrics.metrics.map { - case (key, snapshot) ⇒ Metric(snapshot, key.unitOfMeasurement, s"Custom/${key.name}", None) - } + def onlySimpleMetrics(kv: (Entity, EntitySnapshot)): Boolean = + kamon.metric.SingleInstrumentEntityRecorder.AllCategories.contains(kv._1.category) - } getOrElse (Map.empty) + def toNewRelicMetric(kv: (Entity, EntitySnapshot)): (MetricID, MetricData) = { + val (entity, entitySnapshot) = kv + val (metricKey, instrumentSnapshot) = entitySnapshot.metrics.head + + Metric(instrumentSnapshot, metricKey.unitOfMeasurement, s"Custom/${entity.name}", None) + } + + metrics.filter(onlySimpleMetrics).map(toNewRelicMetric) } } diff --git a/kamon-newrelic/src/main/scala/kamon/newrelic/WebTransactionMetricExtractor.scala b/kamon-newrelic/src/main/scala/kamon/newrelic/WebTransactionMetricExtractor.scala index d0144f4b..76cf0757 100644 --- a/kamon-newrelic/src/main/scala/kamon/newrelic/WebTransactionMetricExtractor.scala +++ b/kamon-newrelic/src/main/scala/kamon/newrelic/WebTransactionMetricExtractor.scala @@ -17,6 +17,7 @@ package kamon.newrelic import kamon.metric.{ EntitySnapshot, Entity } +import kamon.trace.SegmentCategory import scala.collection.mutable import kamon.metric.instrument.{ Time, CollectionContext, Histogram } @@ -35,38 +36,36 @@ object WebTransactionMetricExtractor extends MetricExtractor { val externalScopedByHostAndLibrarySnapshots = mutable.Map.empty[(String, String, String), List[Histogram.Snapshot]] val transactionMetrics = metrics.filterKeys(_.category == "trace").map { - case (entity: Entity, es: EntitySnapshot) ⇒ - // Trace metrics only have elapsed-time and segments and all of them are Histograms. - es.histograms.foreach { - case (key, segmentSnapshot) if key.metadata.get("category").filter(_ == "http-client").nonEmpty ⇒ - val library = key.metadata("library") - accumulatedExternalServices = accumulatedExternalServices.merge(segmentSnapshot, collectionContext) - - // Accumulate externals by host - externalByHostSnapshots.update(key.name, segmentSnapshot :: externalByHostSnapshots.getOrElse(key.name, Nil)) + case (entity, entitySnapshot) ⇒ + val elapsedTime = entitySnapshot.histogram("elapsed-time").get + accumulatedHttpDispatcher = accumulatedHttpDispatcher.merge(elapsedTime, collectionContext) + elapsedTime.recordsIterator.foreach { record ⇒ + apdexBuilder.record(Time.Nanoseconds.scale(Time.Seconds)(record.level), record.count) + } - // Accumulate externals by host and library - externalByHostAndLibrarySnapshots.update((key.name, library), - segmentSnapshot :: externalByHostAndLibrarySnapshots.getOrElse((key.name, library), Nil)) + Metric(elapsedTime, Time.Nanoseconds, "WebTransaction/Custom/" + entity.name, None) + } - // Accumulate externals by host and library, including the transaction as scope. - externalScopedByHostAndLibrarySnapshots.update((key.name, library, entity.name), - segmentSnapshot :: externalScopedByHostAndLibrarySnapshots.getOrElse((key.name, library, entity.name), Nil)) + // Accumulate all segment metrics + metrics.filterKeys(_.category == "trace-segment").map { + case (entity, entitySnapshot) if entity.tags("category") == SegmentCategory.HttpClient ⇒ + val library = entity.tags("library") + val trace = entity.tags("trace") + val elapsedTime = entitySnapshot.histogram("elapsed-time").get - case otherSegments ⇒ + accumulatedExternalServices = accumulatedExternalServices.merge(elapsedTime, collectionContext) - } + // Accumulate externals by host + externalByHostSnapshots.update(entity.name, elapsedTime :: externalByHostSnapshots.getOrElse(entity.name, Nil)) - es.histograms.collect { - case (key, elapsedTime) if key.name == "elapsed-time" ⇒ - accumulatedHttpDispatcher = accumulatedHttpDispatcher.merge(elapsedTime, collectionContext) - elapsedTime.recordsIterator.foreach { record ⇒ - apdexBuilder.record(Time.Nanoseconds.scale(Time.Seconds)(record.level), record.count) - } + // Accumulate externals by host and library + externalByHostAndLibrarySnapshots.update((entity.name, library), + elapsedTime :: externalByHostAndLibrarySnapshots.getOrElse((entity.name, library), Nil)) - Metric(elapsedTime, key.unitOfMeasurement, "WebTransaction/Custom/" + entity.name, None) - } - } flatten + // Accumulate externals by host and library, including the transaction as scope. + externalScopedByHostAndLibrarySnapshots.update((entity.name, library, trace), + elapsedTime :: externalScopedByHostAndLibrarySnapshots.getOrElse((entity.name, library, trace), Nil)) + } val httpDispatcher = Metric(accumulatedHttpDispatcher, Time.Seconds, "HttpDispatcher", None) val webTransaction = httpDispatcher.copy(MetricID("WebTransaction", None)) diff --git a/kamon-newrelic/src/test/scala/kamon/newrelic/MetricReporterSpec.scala b/kamon-newrelic/src/test/scala/kamon/newrelic/MetricReporterSpec.scala index 04380677..d4e815e5 100644 --- a/kamon-newrelic/src/test/scala/kamon/newrelic/MetricReporterSpec.scala +++ b/kamon-newrelic/src/test/scala/kamon/newrelic/MetricReporterSpec.scala @@ -139,19 +139,19 @@ class MetricReporterSpec extends BaseKamonSpec("metric-reporter-spec") with Spra trait FakeTickSnapshotsFixture { val testTraceID = Entity("example-trace", "trace") - val recorder = Kamon.metrics.register(TraceMetrics, testTraceID.name).get.recorder + val recorder = Kamon.metrics.entity(TraceMetrics, testTraceID.name) val collectionContext = Kamon.metrics.buildDefaultCollectionContext def collectRecorder = recorder.collect(collectionContext) - recorder.ElapsedTime.record(1000000) - recorder.ElapsedTime.record(2000000) - recorder.ElapsedTime.record(3000000) + recorder.elapsedTime.record(1000000) + recorder.elapsedTime.record(2000000) + recorder.elapsedTime.record(3000000) val firstSnapshot = TickMetricSnapshot(new MilliTimestamp(1415587618000L), new MilliTimestamp(1415587678000L), Map(testTraceID -> collectRecorder)) - recorder.ElapsedTime.record(6000000) - recorder.ElapsedTime.record(5000000) - recorder.ElapsedTime.record(4000000) + recorder.elapsedTime.record(6000000) + recorder.elapsedTime.record(5000000) + recorder.elapsedTime.record(4000000) val secondSnapshot = TickMetricSnapshot(new MilliTimestamp(1415587678000L), new MilliTimestamp(1415587738000L), Map(testTraceID -> collectRecorder)) } }
\ No newline at end of file diff --git a/kamon-play/src/main/scala/kamon/play/Play.scala b/kamon-play/src/main/scala/kamon/play/Play.scala index 9e160d58..270d244f 100644 --- a/kamon-play/src/main/scala/kamon/play/Play.scala +++ b/kamon-play/src/main/scala/kamon/play/Play.scala @@ -36,13 +36,7 @@ class PlayExtension(private val system: ExtendedActorSystem) extends Kamon.Exten log.info(s"Starting the Kamon(Play) extension") private val config = system.settings.config.getConfig("kamon.play") - val httpServerMetrics = { - val metricsExtension = Kamon.metrics - val factory = metricsExtension.instrumentFactory(HttpServerMetrics.category) - val entity = Entity("play-server", HttpServerMetrics.category) - - metricsExtension.register(entity, new HttpServerMetrics(factory)).recorder - } + val httpServerMetrics = Kamon.metrics.entity(HttpServerMetrics, "play-server") val defaultDispatcher = system.dispatcher val includeTraceToken: Boolean = config.getBoolean("automatic-trace-token-propagation") diff --git a/kamon-play/src/test/scala/kamon/play/WSInstrumentationSpec.scala b/kamon-play/src/test/scala/kamon/play/WSInstrumentationSpec.scala index d639fd9f..fe16ccbf 100644 --- a/kamon-play/src/test/scala/kamon/play/WSInstrumentationSpec.scala +++ b/kamon-play/src/test/scala/kamon/play/WSInstrumentationSpec.scala @@ -17,7 +17,7 @@ package kamon.play import kamon.Kamon -import kamon.metric.{ EntitySnapshot, TraceMetrics } +import kamon.metric.{ Entity, EntitySnapshot, TraceMetrics } import kamon.trace.{ Tracer, TraceContext, SegmentCategory } import org.scalatest.{ Matchers, WordSpecLike } import org.scalatestplus.play.OneServerPerSuite @@ -32,7 +32,7 @@ import scala.concurrent.duration._ class WSInstrumentationSpec extends WordSpecLike with Matchers with OneServerPerSuite { Kamon.start() - import kamon.metric.TraceMetricsSpec.SegmentSyntax + System.setProperty("config.file", "./kamon-play/src/test/resources/conf/application.conf") override lazy val port: Port = 19003 @@ -46,10 +46,16 @@ class WSInstrumentationSpec extends WordSpecLike with Matchers with OneServerPer "propagate the TraceContext inside an Action and complete the WS request" in { Await.result(route(FakeRequest(GET, "/inside")).get, 10 seconds) - val snapshot = takeSnapshotOf("GET: /inside") + val snapshot = takeSnapshotOf("GET: /inside", "trace") snapshot.histogram("elapsed-time").get.numberOfMeasurements should be(1) - snapshot.segments.size should be(1) - snapshot.segment(s"http://localhost:$port/async", SegmentCategory.HttpClient, Play.SegmentLibraryName).numberOfMeasurements should be(1) + + val segmentMetricsSnapshot = takeSnapshotOf(s"http://localhost:$port/async", "trace-segment", + tags = Map( + "trace" -> "GET: /inside", + "category" -> SegmentCategory.HttpClient, + "library" -> Play.SegmentLibraryName)) + + segmentMetricsSnapshot.histogram("elapsed-time").get.numberOfMeasurements should be(1) } "propagate the TraceContext outside an Action and complete the WS request" in { @@ -58,22 +64,26 @@ class WSInstrumentationSpec extends WordSpecLike with Matchers with OneServerPer Tracer.currentContext.finish() } - val snapshot = takeSnapshotOf("trace-outside-action") + val snapshot = takeSnapshotOf("trace-outside-action", "trace") snapshot.histogram("elapsed-time").get.numberOfMeasurements should be(1) - snapshot.segments.size should be(1) - snapshot.segment(s"http://localhost:$port/outside", SegmentCategory.HttpClient, Play.SegmentLibraryName).numberOfMeasurements should be(1) - } + val segmentMetricsSnapshot = takeSnapshotOf(s"http://localhost:$port/outside", "trace-segment", + tags = Map( + "trace" -> "trace-outside-action", + "category" -> SegmentCategory.HttpClient, + "library" -> Play.SegmentLibraryName)) + + segmentMetricsSnapshot.histogram("elapsed-time").get.numberOfMeasurements should be(1) + } } + lazy val collectionContext = Kamon.metrics.buildDefaultCollectionContext + def newContext(name: String): TraceContext = Kamon.tracer.newContext(name) - def takeSnapshotOf(traceName: String): EntitySnapshot = { - // Give some time for async segments to finish. - Thread.sleep(300) - val recorder = Kamon.metrics.register(TraceMetrics, traceName).get.recorder - val collectionContext = Kamon.metrics.buildDefaultCollectionContext + def takeSnapshotOf(name: String, category: String, tags: Map[String, String] = Map.empty): EntitySnapshot = { + val recorder = Kamon.metrics.find(Entity(name, category, tags)).get recorder.collect(collectionContext) } diff --git a/kamon-playground/src/main/scala/test/SimpleRequestProcessor.scala b/kamon-playground/src/main/scala/test/SimpleRequestProcessor.scala index 141c8768..e4cafb45 100644 --- a/kamon-playground/src/main/scala/test/SimpleRequestProcessor.scala +++ b/kamon-playground/src/main/scala/test/SimpleRequestProcessor.scala @@ -49,7 +49,7 @@ object SimpleRequestProcessor extends App with SimpleRoutingApp with RequestBuil implicit val timeout = Timeout(30 seconds) - val counter = Kamon.simpleMetrics.counter("requests") + val counter = Kamon.metrics.counter("requests") val pipeline = sendReceive val replier = system.actorOf(Props[Replier].withRouter(RoundRobinPool(nrOfInstances = 4)), "replier") diff --git a/kamon-spray/src/main/scala/kamon/spray/SprayExtension.scala b/kamon-spray/src/main/scala/kamon/spray/SprayExtension.scala index ab0fe50b..a5aa33cb 100644 --- a/kamon-spray/src/main/scala/kamon/spray/SprayExtension.scala +++ b/kamon-spray/src/main/scala/kamon/spray/SprayExtension.scala @@ -46,11 +46,8 @@ class SprayExtensionImpl(system: ExtendedActorSystem) extends SprayExtension { val log = Logging(system, "SprayExtension") val httpServerMetrics = { - val metricsExtension = Kamon.metrics - val factory = metricsExtension.instrumentFactory(HttpServerMetrics.category) val entity = Entity("spray-server", HttpServerMetrics.category) - - metricsExtension.register(entity, new HttpServerMetrics(factory)).recorder + Kamon.metrics.entity(HttpServerMetrics, entity) } def generateTraceName(request: HttpRequest): String = diff --git a/kamon-spray/src/test/scala/kamon/spray/ClientRequestInstrumentationSpec.scala b/kamon-spray/src/test/scala/kamon/spray/ClientRequestInstrumentationSpec.scala index 67e6725f..4b99022e 100644 --- a/kamon-spray/src/test/scala/kamon/spray/ClientRequestInstrumentationSpec.scala +++ b/kamon-spray/src/test/scala/kamon/spray/ClientRequestInstrumentationSpec.scala @@ -34,8 +34,6 @@ import scala.concurrent.duration._ class ClientRequestInstrumentationSpec extends BaseKamonSpec("client-request-instrumentation-spec") with ScalaFutures with RequestBuilding with TestServer { - import TraceMetricsSpec.SegmentSyntax - override lazy val config = ConfigFactory.parseString( """ @@ -130,8 +128,14 @@ class ClientRequestInstrumentationSpec extends BaseKamonSpec("client-request-ins val traceMetricsSnapshot = takeSnapshotOf("assign-name-to-segment-with-request-level-api", "trace") traceMetricsSnapshot.histogram("elapsed-time").get.numberOfMeasurements should be(1) - traceMetricsSnapshot.segment("request-level /request-level-api-segment", SegmentCategory.HttpClient, Spray.SegmentLibraryName) - .numberOfMeasurements should be(1) + + val segmentMetricsSnapshot = takeSnapshotOf("request-level /request-level-api-segment", "trace-segment", + tags = Map( + "trace" -> "assign-name-to-segment-with-request-level-api", + "category" -> SegmentCategory.HttpClient, + "library" -> Spray.SegmentLibraryName)) + + segmentMetricsSnapshot.histogram("elapsed-time").get.numberOfMeasurements should be(1) } "rename a request level api segment once it reaches the relevant host connector" in { @@ -161,8 +165,14 @@ class ClientRequestInstrumentationSpec extends BaseKamonSpec("client-request-ins val traceMetricsSnapshot = takeSnapshotOf("rename-segment-with-request-level-api", "trace") traceMetricsSnapshot.histogram("elapsed-time").get.numberOfMeasurements should be(1) - traceMetricsSnapshot.segment("host-level /request-level-api-segment", SegmentCategory.HttpClient, Spray.SegmentLibraryName) - .numberOfMeasurements should be(1) + + val segmentMetricsSnapshot = takeSnapshotOf("host-level /request-level-api-segment", "trace-segment", + tags = Map( + "trace" -> "rename-segment-with-request-level-api", + "category" -> SegmentCategory.HttpClient, + "library" -> Spray.SegmentLibraryName)) + + segmentMetricsSnapshot.histogram("elapsed-time").get.numberOfMeasurements should be(1) } } @@ -249,8 +259,14 @@ class ClientRequestInstrumentationSpec extends BaseKamonSpec("client-request-ins val traceMetricsSnapshot = takeSnapshotOf("create-segment-with-host-level-api", "trace") traceMetricsSnapshot.histogram("elapsed-time").get.numberOfMeasurements should be(1) - traceMetricsSnapshot.segment("host-level /host-level-api-segment", SegmentCategory.HttpClient, Spray.SegmentLibraryName) - .numberOfMeasurements should be(1) + + val segmentMetricsSnapshot = takeSnapshotOf("host-level /host-level-api-segment", "trace-segment", + tags = Map( + "trace" -> "create-segment-with-host-level-api", + "category" -> SegmentCategory.HttpClient, + "library" -> Spray.SegmentLibraryName)) + + segmentMetricsSnapshot.histogram("elapsed-time").get.numberOfMeasurements should be(1) } } } diff --git a/kamon-statsd/src/test/scala/kamon/statsd/SimpleMetricKeyGeneratorSpec.scala b/kamon-statsd/src/test/scala/kamon/statsd/SimpleMetricKeyGeneratorSpec.scala index 0edeb3df..2e03a59d 100644 --- a/kamon-statsd/src/test/scala/kamon/statsd/SimpleMetricKeyGeneratorSpec.scala +++ b/kamon-statsd/src/test/scala/kamon/statsd/SimpleMetricKeyGeneratorSpec.scala @@ -69,7 +69,7 @@ class SimpleMetricKeyGeneratorSpec extends WordSpec with Matchers { } def buildMetricKey(categoryName: String, entityName: String, metricName: String)(implicit metricKeyGenerator: SimpleMetricKeyGenerator): String = { - val metric = HistogramKey(metricName, UnitOfMeasurement.Unknown, Map.empty) + val metric = HistogramKey(metricName, UnitOfMeasurement.Unknown) val entity = Entity(entityName, categoryName) metricKeyGenerator.generateKey(entity, metric) } diff --git a/kamon-statsd/src/test/scala/kamon/statsd/StatsDMetricSenderSpec.scala b/kamon-statsd/src/test/scala/kamon/statsd/StatsDMetricSenderSpec.scala index 0211ac0f..1e53f48f 100644 --- a/kamon-statsd/src/test/scala/kamon/statsd/StatsDMetricSenderSpec.scala +++ b/kamon-statsd/src/test/scala/kamon/statsd/StatsDMetricSenderSpec.scala @@ -128,12 +128,12 @@ class StatsDMetricSenderSpec extends BaseKamonSpec("statsd-metric-sender-spec") val testEntity = Entity("user/kamon", "test") def buildMetricKey(entity: Entity, metricName: String)(implicit metricKeyGenerator: SimpleMetricKeyGenerator): String = { - val metricKey = HistogramKey(metricName, UnitOfMeasurement.Unknown, Map.empty) + val metricKey = HistogramKey(metricName, UnitOfMeasurement.Unknown) metricKeyGenerator.generateKey(entity, metricKey) } def buildRecorder(name: String): TestEntityRecorder = { - Kamon.metrics.register(TestEntityRecorder, name).get.recorder + Kamon.metrics.entity(TestEntityRecorder, name) } def setup(metrics: Map[Entity, EntitySnapshot]): TestProbe = { diff --git a/kamon-system-metrics/src/main/scala/kamon/system/custom/ContextSwitchesMetrics.scala b/kamon-system-metrics/src/main/scala/kamon/system/custom/ContextSwitchesMetrics.scala index 384c89f1..5090f3dd 100644 --- a/kamon-system-metrics/src/main/scala/kamon/system/custom/ContextSwitchesMetrics.scala +++ b/kamon-system-metrics/src/main/scala/kamon/system/custom/ContextSwitchesMetrics.scala @@ -88,12 +88,10 @@ class ContextSwitchesMetrics(pid: Long, log: LoggingAdapter, instrumentFactory: object ContextSwitchesMetrics { def register(system: ActorSystem, refreshInterval: FiniteDuration): ContextSwitchesMetrics = { - val metricsExtension = Kamon.metrics val log = Logging(system, "ContextSwitchesMetrics") val pid = (new Sigar).getPid - val instrumentFactory = metricsExtension.instrumentFactory("system-metric") - metricsExtension.register(Entity("context-switches", "system-metric"), new ContextSwitchesMetrics(pid, log, instrumentFactory)).recorder + Kamon.metrics.entity(EntityRecorderFactory("system-metric", new ContextSwitchesMetrics(pid, log, _)), "context-switches") } } diff --git a/kamon-system-metrics/src/main/scala/kamon/system/jmx/GarbageCollectionMetrics.scala b/kamon-system-metrics/src/main/scala/kamon/system/jmx/GarbageCollectionMetrics.scala index 59d4050c..7a5770d8 100644 --- a/kamon-system-metrics/src/main/scala/kamon/system/jmx/GarbageCollectionMetrics.scala +++ b/kamon-system-metrics/src/main/scala/kamon/system/jmx/GarbageCollectionMetrics.scala @@ -18,7 +18,8 @@ package kamon.system.jmx import java.lang.management.{ GarbageCollectorMXBean, ManagementFactory } -import kamon.metric.{ Entity, Metrics, GenericEntityRecorder } +import kamon.Kamon +import kamon.metric.{ EntityRecorderFactory, Entity, Metrics, GenericEntityRecorder } import kamon.metric.instrument.{ DifferentialValueCollector, Time, InstrumentFactory } import scala.collection.JavaConverters._ @@ -44,11 +45,9 @@ object GarbageCollectionMetrics { name.replaceAll("""[^\w]""", "-").toLowerCase def register(metricsExtension: Metrics): Unit = { - - val instrumentFactory = metricsExtension.instrumentFactory("system-metric") ManagementFactory.getGarbageCollectorMXBeans.asScala.filter(_.isValid) map { gc ⇒ val gcName = sanitizeCollectorName(gc.getName) - metricsExtension.register(Entity(s"$gcName-garbage-collector", "system-metric"), new GarbageCollectionMetrics(gc, instrumentFactory)) + Kamon.metrics.entity(EntityRecorderFactory("system-metric", new GarbageCollectionMetrics(gc, _)), s"$gcName-garbage-collector") } } } diff --git a/kamon-system-metrics/src/main/scala/kamon/system/jmx/JmxSystemMetricRecorderCompanion.scala b/kamon-system-metrics/src/main/scala/kamon/system/jmx/JmxSystemMetricRecorderCompanion.scala index 8837aec0..15bd399e 100644 --- a/kamon-system-metrics/src/main/scala/kamon/system/jmx/JmxSystemMetricRecorderCompanion.scala +++ b/kamon-system-metrics/src/main/scala/kamon/system/jmx/JmxSystemMetricRecorderCompanion.scala @@ -17,13 +17,11 @@ package kamon.system.jmx import kamon.metric.instrument.InstrumentFactory -import kamon.metric.{ Entity, EntityRecorder, Metrics } +import kamon.metric.{ EntityRecorderFactory, EntityRecorder, Metrics } abstract class JmxSystemMetricRecorderCompanion(metricName: String) { - def register(metricsExtension: Metrics): EntityRecorder = { - val instrumentFactory = metricsExtension.instrumentFactory("system-metric") - metricsExtension.register(Entity(metricName, "system-metric"), apply(instrumentFactory)).recorder - } + def register(metricsExtension: Metrics): EntityRecorder = + metricsExtension.entity(EntityRecorderFactory("system-metric", apply(_)), metricName) def apply(instrumentFactory: InstrumentFactory): EntityRecorder }
\ No newline at end of file diff --git a/kamon-system-metrics/src/main/scala/kamon/system/sigar/SigarMetricsUpdater.scala b/kamon-system-metrics/src/main/scala/kamon/system/sigar/SigarMetricsUpdater.scala index 68b133b0..a1bd3e01 100644 --- a/kamon-system-metrics/src/main/scala/kamon/system/sigar/SigarMetricsUpdater.scala +++ b/kamon-system-metrics/src/main/scala/kamon/system/sigar/SigarMetricsUpdater.scala @@ -19,7 +19,7 @@ package kamon.system.sigar import akka.actor.{ Props, Actor } import kamon.Kamon import kamon.metric.instrument.InstrumentFactory -import kamon.metric.{ Entity, EntityRecorder, Metrics } +import kamon.metric.{ EntityRecorderFactory, Entity, EntityRecorder, Metrics } import kamon.system.sigar.SigarMetricsUpdater.UpdateSigarMetrics import org.hyperic.sigar.Sigar @@ -65,10 +65,8 @@ trait SigarMetric extends EntityRecorder { } abstract class SigarMetricRecorderCompanion(metricName: String) { - def register(sigar: Sigar, metricsExtension: Metrics): SigarMetric = { - val instrumentFactory = metricsExtension.instrumentFactory("system-metric") - metricsExtension.register(Entity(metricName, "system-metric"), apply(sigar, instrumentFactory)).recorder - } + def register(sigar: Sigar, metricsExtension: Metrics): SigarMetric = + metricsExtension.entity(EntityRecorderFactory("system-metric", apply(sigar, _)), metricName) def apply(sigar: Sigar, instrumentFactory: InstrumentFactory): SigarMetric } diff --git a/project/Settings.scala b/project/Settings.scala index 8f839914..c6306dc6 100644 --- a/project/Settings.scala +++ b/project/Settings.scala @@ -32,6 +32,7 @@ object Settings { scalaVersion := ScalaVersion, resolvers ++= Dependencies.resolutionRepos, fork in run := true, + parallelExecution in Test := false, testGrouping in Test := singleTestPerJvm((definedTests in Test).value, (javaOptions in Test).value), javacOptions in compile := Seq( "-Xlint:-options", |