From 29068fc70a3e5a17a630c2c7fff951572bb5fa21 Mon Sep 17 00:00:00 2001 From: Ivan Topolnjak Date: Thu, 3 Jul 2014 14:36:42 -0300 Subject: ! all: refactor the core metric recording instruments and accomodate UserMetrics This PR is including several changes to the kamon-core, most notably: - Formalize the interface for Histograms, Counters and MinMaxCounters. Making sure that the interfaces are as clean as possible. - Move away from the all Vector[Measurement] based Histogram snapshot to a new approach in which we use a single long to store both the index in the counts array and the frequency on that bucket. The leftmost 2 bytes of each long are used for storing the counts array index and the remaining 6 bytes are used for the actual count, and everything is put into a simple long array. This way only the buckets that actually have values will be included in the snapshot with the smallest possible memory footprint. - Introduce Gauges. - Reorganize the instrumentation for Akka and Scala and rewrite most of the tests of this components to avoid going through the subscription protocol to test. - Introduce trace tests and fixes on various tests. - Necessary changes on new relic, datadog and statsd modules to compile with the new codebase. Pending: - Finish the upgrade of the new relic to the current model. - Introduce proper limit checks for histograms to ensure that we never pass the 2/6 bytes limits. - More testing, more testing, more testing. - Create the KamonStandalone module. --- .../src/main/scala/kamon/datadog/Datadog.scala | 2 +- .../scala/kamon/datadog/DatadogMetricsSender.scala | 47 +++++++++++----------- 2 files changed, 25 insertions(+), 24 deletions(-) (limited to 'kamon-datadog/src/main/scala/kamon') diff --git a/kamon-datadog/src/main/scala/kamon/datadog/Datadog.scala b/kamon-datadog/src/main/scala/kamon/datadog/Datadog.scala index 15d5d3fe..b4358ce7 100644 --- a/kamon-datadog/src/main/scala/kamon/datadog/Datadog.scala +++ b/kamon-datadog/src/main/scala/kamon/datadog/Datadog.scala @@ -18,7 +18,7 @@ package kamon.datadog import akka.actor._ import kamon.Kamon -import kamon.metrics._ +import kamon.metric._ import scala.concurrent.duration._ import scala.collection.JavaConverters._ import com.typesafe.config.Config diff --git a/kamon-datadog/src/main/scala/kamon/datadog/DatadogMetricsSender.scala b/kamon-datadog/src/main/scala/kamon/datadog/DatadogMetricsSender.scala index 028e9608..17e19d0b 100644 --- a/kamon-datadog/src/main/scala/kamon/datadog/DatadogMetricsSender.scala +++ b/kamon-datadog/src/main/scala/kamon/datadog/DatadogMetricsSender.scala @@ -20,11 +20,10 @@ import akka.actor.{ ActorSystem, Props, ActorRef, Actor } import akka.io.{ Udp, IO } import java.net.InetSocketAddress import akka.util.ByteString -import kamon.metrics.Subscriptions.TickMetricSnapshot -import kamon.metrics.MetricSnapshot.Measurement -import kamon.metrics.InstrumentTypes.{ Counter, Gauge, Histogram, InstrumentType } +import kamon.metric.Subscriptions.TickMetricSnapshot import java.text.{ DecimalFormatSymbols, DecimalFormat } -import kamon.metrics.{ MetricIdentity, MetricGroupIdentity } +import kamon.metric.instrument.{ Counter, Histogram } +import kamon.metric.{ MetricIdentity, MetricGroupIdentity } import java.util.Locale class DatadogMetricsSender(remote: InetSocketAddress, maxPacketSizeInBytes: Long) extends Actor with UdpExtensionProvider { @@ -50,7 +49,7 @@ class DatadogMetricsSender(remote: InetSocketAddress, maxPacketSizeInBytes: Long } def writeMetricsToRemote(tick: TickMetricSnapshot, udpSender: ActorRef): Unit = { - val dataBuilder = new MetricDataPacketBuilder(maxPacketSizeInBytes, udpSender, remote) + val packetBuilder = new MetricDataPacketBuilder(maxPacketSizeInBytes, udpSender, remote) for { (groupIdentity, groupSnapshot) ← tick.metrics @@ -59,33 +58,35 @@ class DatadogMetricsSender(remote: InetSocketAddress, maxPacketSizeInBytes: Long val key = buildMetricName(groupIdentity, metricIdentity) - for (measurement ← metricSnapshot.measurements) { - val measurementData = formatMeasurement(groupIdentity, metricIdentity, measurement, metricSnapshot.instrumentType) - dataBuilder.appendMeasurement(key, measurementData) + metricSnapshot match { + case hs: Histogram.Snapshot ⇒ + hs.recordsIterator.foreach { record ⇒ + val measurementData = formatMeasurement(groupIdentity, metricIdentity, encodeStatsDTimer(record.level, record.count)) + packetBuilder.appendMeasurement(key, measurementData) + + } + + case cs: Counter.Snapshot ⇒ + val measurementData = formatMeasurement(groupIdentity, metricIdentity, encodeStatsDCounter(cs.count)) + packetBuilder.appendMeasurement(key, measurementData) } } - dataBuilder.flush() + packetBuilder.flush() } - def formatMeasurement(groupIdentity: MetricGroupIdentity, metricIdentity: MetricIdentity, measurement: Measurement, - instrumentType: InstrumentType): String = { - - StringBuilder.newBuilder.append(buildMeasurementData(measurement, instrumentType)) + def formatMeasurement(groupIdentity: MetricGroupIdentity, metricIdentity: MetricIdentity, measurementData: String): String = + StringBuilder.newBuilder + .append(measurementData) .append(buildIdentificationTag(groupIdentity, metricIdentity)) .result() - } - def buildMeasurementData(measurement: Measurement, instrumentType: InstrumentType): String = { - def dataDogDMetricFormat(value: String, metricType: String, samplingRate: Double = 1D): String = - s"$value|$metricType${(if (samplingRate != 1D) "|@" + samplingRateFormat.format(samplingRate) else "")}" - - instrumentType match { - case Histogram ⇒ dataDogDMetricFormat(measurement.value.toString, "ms", (1D / measurement.count)) - case Gauge ⇒ dataDogDMetricFormat(measurement.value.toString, "g") - case Counter ⇒ dataDogDMetricFormat(measurement.count.toString, "c") - } + def encodeStatsDTimer(level: Long, count: Long): String = { + val samplingRate: Double = 1D / count + level.toString + "|ms" + (if (samplingRate != 1D) "|@" + samplingRateFormat.format(samplingRate) else "") } + def encodeStatsDCounter(count: Long): String = count.toString + "|c" + def buildMetricName(groupIdentity: MetricGroupIdentity, metricIdentity: MetricIdentity): String = s"$appName.${groupIdentity.category.name}.${metricIdentity.name}" -- cgit v1.2.3