From 0759505be988ad2b8c9d14ec322681e48033a687 Mon Sep 17 00:00:00 2001 From: Ivan Topolnjak Date: Tue, 27 Jun 2017 15:05:11 +0200 Subject: add timer utility metric, based on histograms --- .../src/main/scala/kamon/metric/Metric.scala | 1 + .../src/main/scala/kamon/metric/MetricLookup.scala | 9 ++ .../main/scala/kamon/metric/MetricRegistry.scala | 4 + kamon-core/src/main/scala/kamon/metric/Timer.scala | 100 +++++++++++++++++++++ 4 files changed, 114 insertions(+) create mode 100644 kamon-core/src/main/scala/kamon/metric/Timer.scala (limited to 'kamon-core/src/main/scala/kamon/metric') diff --git a/kamon-core/src/main/scala/kamon/metric/Metric.scala b/kamon-core/src/main/scala/kamon/metric/Metric.scala index 1e19c2a4..87a7ca48 100644 --- a/kamon-core/src/main/scala/kamon/metric/Metric.scala +++ b/kamon-core/src/main/scala/kamon/metric/Metric.scala @@ -46,6 +46,7 @@ trait Metric[T] { } trait HistogramMetric extends Metric[Histogram] with Histogram +trait TimerMetric extends Metric[Timer] with Timer trait MinMaxCounterMetric extends Metric[MinMaxCounter] with MinMaxCounter trait GaugeMetric extends Metric[Gauge] with Gauge trait CounterMetric extends Metric[Counter] with Counter diff --git a/kamon-core/src/main/scala/kamon/metric/MetricLookup.scala b/kamon-core/src/main/scala/kamon/metric/MetricLookup.scala index 7e58a722..564a213d 100644 --- a/kamon-core/src/main/scala/kamon/metric/MetricLookup.scala +++ b/kamon-core/src/main/scala/kamon/metric/MetricLookup.scala @@ -32,6 +32,13 @@ trait MetricLookup { histogram(name, unit, Some(dynamicRange)) + def timer(name: String): TimerMetric = + timer(name, None) + + def timer(name: String, dynamicRange: DynamicRange): TimerMetric = + timer(name, Some(dynamicRange)) + + def counter(name: String): CounterMetric = counter(name, MeasurementUnit.none) @@ -55,6 +62,8 @@ trait MetricLookup { def histogram(name: String, unit: MeasurementUnit, dynamicRange: Option[DynamicRange]): HistogramMetric + def timer(name: String, dynamicRange: Option[DynamicRange]): TimerMetric + def counter(name: String, unit: MeasurementUnit): CounterMetric def gauge(name: String, unit: MeasurementUnit): GaugeMetric diff --git a/kamon-core/src/main/scala/kamon/metric/MetricRegistry.scala b/kamon-core/src/main/scala/kamon/metric/MetricRegistry.scala index 07c1d202..07a0ebaa 100644 --- a/kamon-core/src/main/scala/kamon/metric/MetricRegistry.scala +++ b/kamon-core/src/main/scala/kamon/metric/MetricRegistry.scala @@ -21,6 +21,7 @@ import java.util.concurrent.atomic.AtomicReference import com.typesafe.config.Config import kamon.metric.InstrumentFactory.{InstrumentType, InstrumentTypes} import kamon.util.MeasurementUnit +import kamon.util.MeasurementUnit.time import scala.collection.concurrent.TrieMap import java.time.Duration @@ -53,6 +54,9 @@ class MetricRegistry(initialConfig: Config, scheduler: ScheduledExecutorService) def minMaxCounter(name: String, unit: MeasurementUnit, dynamicRange: Option[DynamicRange], sampleInterval: Option[Duration]): MinMaxCounterMetric = lookupMetric(name, unit, InstrumentTypes.MinMaxCounter)(new MinMaxCounterMetricImpl(name, unit, dynamicRange, sampleInterval, instrumentFactory, scheduler)) + def timer(name: String, dynamicRange: Option[DynamicRange]): TimerMetric = + new TimerMetricImpl(histogram(name, time.nanoseconds, dynamicRange)) + override def snapshot(): MetricsSnapshot = synchronized { var histograms = Seq.empty[MetricDistribution] diff --git a/kamon-core/src/main/scala/kamon/metric/Timer.scala b/kamon-core/src/main/scala/kamon/metric/Timer.scala new file mode 100644 index 00000000..4750856d --- /dev/null +++ b/kamon-core/src/main/scala/kamon/metric/Timer.scala @@ -0,0 +1,100 @@ +/* ========================================================================================= + * Copyright © 2013-2017 the kamon project + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, + * either express or implied. See the License for the specific language governing permissions + * and limitations under the License. + * ========================================================================================= + */ + +package kamon.metric + +import kamon.Tags +import kamon.util.MeasurementUnit + +trait Timer extends Histogram { + def start(): StartedTimer +} + +trait StartedTimer { + def stop(): Unit +} + +object StartedTimer { + + def createFor(histogram: Histogram): StartedTimer = new StartedTimer { + var running = true + val startTimestamp = System.nanoTime() + + override def stop(): Unit = synchronized { + if(running) { + histogram.record(System.nanoTime() - startTimestamp) + running = false + } + } + } +} + +private[kamon] final class TimerImpl(val histogram: Histogram) extends Timer { + + override def unit: MeasurementUnit = + histogram.unit + + override def dynamicRange: DynamicRange = + histogram.dynamicRange + + override def record(value: Long): Unit = + histogram.record(value) + + override def record(value: Long, times: Long): Unit = + histogram.record(value, times) + + override def start(): StartedTimer = + StartedTimer.createFor(histogram) +} + + +private[kamon] final class TimerMetricImpl(val underlyingHistogram: HistogramMetric) extends TimerMetric { + + override def unit: MeasurementUnit = + underlyingHistogram.unit + + override def dynamicRange: DynamicRange = + underlyingHistogram.dynamicRange + + override def record(value: Long): Unit = + underlyingHistogram.record(value) + + override def record(value: Long, times: Long): Unit = + underlyingHistogram.record(value, times) + + override def name: String = + underlyingHistogram.name + + override def refine(tags: Tags): Timer = + new TimerImpl(underlyingHistogram.refine(tags)) + + override def refine(tags: (String, String)*): Timer = + new TimerImpl(underlyingHistogram.refine(tags: _*)) + + override def refine(tag: String, value: String): Timer = + new TimerImpl(underlyingHistogram.refine(Map(tag -> value))) + + override def remove(tags: Tags): Boolean = + underlyingHistogram.remove(tags) + + override def remove(tags: (String, String)*): Boolean = + underlyingHistogram.remove(tags: _*) + + override def remove(tag: String, value: String): Boolean = + underlyingHistogram.remove(tag, value) + + override def start(): StartedTimer = + StartedTimer.createFor(underlyingHistogram) +} \ No newline at end of file -- cgit v1.2.3