aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--kamon-datadog/src/main/scala/kamon/datadog/Datadog.scala6
-rw-r--r--kamon-datadog/src/main/scala/kamon/datadog/DatadogMetricsSender.scala7
-rw-r--r--kamon-datadog/src/test/scala/kamon/datadog/DatadogMetricSenderSpec.scala15
-rw-r--r--kamon-statsd/src/main/scala/kamon/statsd/StatsD.scala26
-rw-r--r--kamon-statsd/src/main/scala/kamon/statsd/StatsDMetricsSender.scala7
-rw-r--r--kamon-statsd/src/test/scala/kamon/statsd/StatsDMetricSenderSpec.scala72
6 files changed, 94 insertions, 39 deletions
diff --git a/kamon-datadog/src/main/scala/kamon/datadog/Datadog.scala b/kamon-datadog/src/main/scala/kamon/datadog/Datadog.scala
index b4358ce7..1ae493f7 100644
--- a/kamon-datadog/src/main/scala/kamon/datadog/Datadog.scala
+++ b/kamon-datadog/src/main/scala/kamon/datadog/Datadog.scala
@@ -70,12 +70,12 @@ class DatadogExtension(system: ExtendedActorSystem) extends Kamon.Extension {
def buildMetricsListener(tickInterval: Long, flushInterval: Long): ActorRef = {
assert(flushInterval >= tickInterval, "Datadog flush-interval needs to be equal or greater to the tick-interval")
- val metricsTranslator = system.actorOf(DatadogMetricsSender.props(datadogHost, maxPacketSizeInBytes), "datadog-metrics-sender")
+ val metricsSender = system.actorOf(DatadogMetricsSender.props(datadogHost, maxPacketSizeInBytes), "datadog-metrics-sender")
if (flushInterval == tickInterval) {
// No need to buffer the metrics, let's go straight to the metrics sender.
- metricsTranslator
+ metricsSender
} else {
- system.actorOf(TickMetricSnapshotBuffer.props(flushInterval.toInt.millis, metricsTranslator), "datadog-metrics-buffer")
+ system.actorOf(TickMetricSnapshotBuffer.props(flushInterval.toInt.millis, metricsSender), "datadog-metrics-buffer")
}
}
}
diff --git a/kamon-datadog/src/main/scala/kamon/datadog/DatadogMetricsSender.scala b/kamon-datadog/src/main/scala/kamon/datadog/DatadogMetricsSender.scala
index 17e19d0b..0f67cc34 100644
--- a/kamon-datadog/src/main/scala/kamon/datadog/DatadogMetricsSender.scala
+++ b/kamon-datadog/src/main/scala/kamon/datadog/DatadogMetricsSender.scala
@@ -90,8 +90,11 @@ class DatadogMetricsSender(remote: InetSocketAddress, maxPacketSizeInBytes: Long
def buildMetricName(groupIdentity: MetricGroupIdentity, metricIdentity: MetricIdentity): String =
s"$appName.${groupIdentity.category.name}.${metricIdentity.name}"
- def buildIdentificationTag(groupIdentity: MetricGroupIdentity, metricIdentity: MetricIdentity): String =
- s"|#${groupIdentity.category.name}:${groupIdentity.name}"
+ def buildIdentificationTag(groupIdentity: MetricGroupIdentity, metricIdentity: MetricIdentity): String = {
+ // Make the automatic HTTP trace names a bit more friendly
+ val normalizedEntityName = groupIdentity.name.replace(": ", ":")
+ s"|#${groupIdentity.category.name}:${normalizedEntityName}"
+ }
}
object DatadogMetricsSender {
diff --git a/kamon-datadog/src/test/scala/kamon/datadog/DatadogMetricSenderSpec.scala b/kamon-datadog/src/test/scala/kamon/datadog/DatadogMetricSenderSpec.scala
index 91b503e2..713db30d 100644
--- a/kamon-datadog/src/test/scala/kamon/datadog/DatadogMetricSenderSpec.scala
+++ b/kamon-datadog/src/test/scala/kamon/datadog/DatadogMetricSenderSpec.scala
@@ -30,8 +30,19 @@ import java.net.InetSocketAddress
import com.typesafe.config.ConfigFactory
class DatadogMetricSenderSpec extends TestKitBase with WordSpecLike with Matchers {
- implicit lazy val system = ActorSystem("datadog-metric-sender-spec",
- ConfigFactory.parseString("kamon.datadog.max-packet-size = 256 bytes"))
+ implicit lazy val system: ActorSystem = ActorSystem("datadog-metric-sender-spec", ConfigFactory.parseString(
+ """
+ |kamon {
+ | metrics {
+ | disable-aspectj-weaver-missing-error = true
+ | }
+ |
+ | datadog {
+ | max-packet-size = 256 bytes
+ | }
+ |}
+ |
+ """.stripMargin))
val collectionContext = Kamon(Metrics).buildDefaultCollectionContext
diff --git a/kamon-statsd/src/main/scala/kamon/statsd/StatsD.scala b/kamon-statsd/src/main/scala/kamon/statsd/StatsD.scala
index dcd78f78..299b1acc 100644
--- a/kamon-statsd/src/main/scala/kamon/statsd/StatsD.scala
+++ b/kamon-statsd/src/main/scala/kamon/statsd/StatsD.scala
@@ -32,6 +32,8 @@ object StatsD extends ExtensionId[StatsDExtension] with ExtensionIdProvider {
override def createExtension(system: ExtendedActorSystem): StatsDExtension = new StatsDExtension(system)
trait MetricKeyGenerator {
+ def localhostName: String
+ def normalizedLocalhostName: String
def generateKey(groupIdentity: MetricGroupIdentity, metricIdentity: MetricIdentity): String
}
}
@@ -69,22 +71,34 @@ class StatsDExtension(system: ExtendedActorSystem) extends Kamon.Extension {
def buildMetricsListener(tickInterval: Long, flushInterval: Long): ActorRef = {
assert(flushInterval >= tickInterval, "StatsD flush-interval needs to be equal or greater to the tick-interval")
+ val defaultMetricKeyGenerator = new SimpleMetricKeyGenerator(system.settings.config)
+
+ val metricsSender = system.actorOf(StatsDMetricsSender.props(
+ statsDHost,
+ maxPacketSizeInBytes,
+ defaultMetricKeyGenerator), "statsd-metrics-sender")
- val metricsTranslator = system.actorOf(StatsDMetricsSender.props(statsDHost, maxPacketSizeInBytes), "statsd-metrics-sender")
if (flushInterval == tickInterval) {
// No need to buffer the metrics, let's go straight to the metrics sender.
- metricsTranslator
+ metricsSender
} else {
- system.actorOf(TickMetricSnapshotBuffer.props(flushInterval.toInt.millis, metricsTranslator), "statsd-metrics-buffer")
+ system.actorOf(TickMetricSnapshotBuffer.props(flushInterval.toInt.millis, metricsSender), "statsd-metrics-buffer")
}
}
}
class SimpleMetricKeyGenerator(config: Config) extends StatsD.MetricKeyGenerator {
val application = config.getString("kamon.statsd.simple-metric-key-generator.application")
- val localhostName = ManagementFactory.getRuntimeMXBean.getName.split('@')(1)
+ val _localhostName = ManagementFactory.getRuntimeMXBean.getName.split('@')(1)
+ val _normalizedLocalhostName = _localhostName.replace('.', '_')
+
+ def localhostName: String = _localhostName
- def generateKey(groupIdentity: MetricGroupIdentity, metricIdentity: MetricIdentity): String =
- s"${application}.${localhostName}.${groupIdentity.category.name}.${groupIdentity.name}.${metricIdentity.name}"
+ def normalizedLocalhostName: String = _normalizedLocalhostName
+
+ def generateKey(groupIdentity: MetricGroupIdentity, metricIdentity: MetricIdentity): String = {
+ val normalizedGroupName = groupIdentity.name.replace(": ", "-").replace(" ", "_").replace("/", "_")
+ s"${application}.${normalizedLocalhostName}.${groupIdentity.category.name}.${normalizedGroupName}.${metricIdentity.name}"
+ }
}
diff --git a/kamon-statsd/src/main/scala/kamon/statsd/StatsDMetricsSender.scala b/kamon-statsd/src/main/scala/kamon/statsd/StatsDMetricsSender.scala
index 94bab27c..8fbf4fee 100644
--- a/kamon-statsd/src/main/scala/kamon/statsd/StatsDMetricsSender.scala
+++ b/kamon-statsd/src/main/scala/kamon/statsd/StatsDMetricsSender.scala
@@ -26,10 +26,10 @@ import java.util.Locale
import kamon.metric.instrument.{ Counter, Histogram }
-class StatsDMetricsSender(remote: InetSocketAddress, maxPacketSizeInBytes: Long) extends Actor with UdpExtensionProvider {
+class StatsDMetricsSender(remote: InetSocketAddress, maxPacketSizeInBytes: Long, metricKeyGenerator: StatsD.MetricKeyGenerator)
+ extends Actor with UdpExtensionProvider {
import context.system
- val metricKeyGenerator = new SimpleMetricKeyGenerator(context.system.settings.config)
val symbols = DecimalFormatSymbols.getInstance(Locale.US)
symbols.setDecimalSeparator('.') // Just in case there is some weird locale config we are not aware of.
@@ -80,7 +80,8 @@ class StatsDMetricsSender(remote: InetSocketAddress, maxPacketSizeInBytes: Long)
}
object StatsDMetricsSender {
- def props(remote: InetSocketAddress, maxPacketSize: Long): Props = Props(new StatsDMetricsSender(remote, maxPacketSize))
+ def props(remote: InetSocketAddress, maxPacketSize: Long, metricKeyGenerator: StatsD.MetricKeyGenerator): Props =
+ Props(new StatsDMetricsSender(remote, maxPacketSize, metricKeyGenerator))
}
trait UdpExtensionProvider {
diff --git a/kamon-statsd/src/test/scala/kamon/statsd/StatsDMetricSenderSpec.scala b/kamon-statsd/src/test/scala/kamon/statsd/StatsDMetricSenderSpec.scala
index 60d52491..3bc1364c 100644
--- a/kamon-statsd/src/test/scala/kamon/statsd/StatsDMetricSenderSpec.scala
+++ b/kamon-statsd/src/test/scala/kamon/statsd/StatsDMetricSenderSpec.scala
@@ -30,15 +30,31 @@ import java.net.InetSocketAddress
import com.typesafe.config.ConfigFactory
class StatsDMetricSenderSpec extends TestKitBase with WordSpecLike with Matchers {
- implicit lazy val system = ActorSystem("statsd-metric-sender-spec",
- ConfigFactory.parseString("kamon.statsd.max-packet-size = 256 bytes"))
+ implicit lazy val system: ActorSystem = ActorSystem("statsd-metric-sender-spec", ConfigFactory.parseString(
+ """
+ |kamon {
+ | metrics {
+ | disable-aspectj-weaver-missing-error = true
+ | }
+ |
+ | statsd {
+ | max-packet-size = 256 bytes
+ | }
+ |}
+ |
+ """.stripMargin))
val collectionContext = Kamon(Metrics).buildDefaultCollectionContext
"the StatsDMetricSender" should {
+ "normalize the group entity name to remove spaces, colons and replace '/' with '_'" in new UdpListenerFixture {
+ val testMetricKey = buildMetricKey("trace", "POST: /kamon/example", "elapsed-time")
+ testMetricKey should be(s"kamon.localhost_local.trace.POST-_kamon_example.elapsed-time")
+ }
+
"flush the metrics data after processing the tick, even if the max-packet-size is not reached" in new UdpListenerFixture {
- val testMetricName = "test-metric"
- val testMetricKey = buildMetricKey(testMetricName)
+ val testMetricName = "processing-time"
+ val testMetricKey = buildMetricKey("actor", "/user/kamon", testMetricName)
val testRecorder = Histogram(1000L, Precision.Normal, Scale.Unit)
testRecorder.record(10L)
@@ -49,8 +65,8 @@ class StatsDMetricSenderSpec extends TestKitBase with WordSpecLike with Matchers
}
"render several measurements of the same key under a single (key + multiple measurements) packet" in new UdpListenerFixture {
- val testMetricName = "test-metric"
- val testMetricKey = buildMetricKey(testMetricName)
+ val testMetricName = "processing-time"
+ val testMetricKey = buildMetricKey("actor", "/user/kamon", testMetricName)
val testRecorder = Histogram(1000L, Precision.Normal, Scale.Unit)
testRecorder.record(10L)
testRecorder.record(11L)
@@ -63,8 +79,8 @@ class StatsDMetricSenderSpec extends TestKitBase with WordSpecLike with Matchers
}
"include the correspondent sampling rate when rendering multiple occurrences of the same value" in new UdpListenerFixture {
- val testMetricName = "test-metric"
- val testMetricKey = buildMetricKey(testMetricName)
+ val testMetricName = "processing-time"
+ val testMetricKey = buildMetricKey("actor", "/user/kamon", testMetricName)
val testRecorder = Histogram(1000L, Precision.Normal, Scale.Unit)
testRecorder.record(10L)
testRecorder.record(10L)
@@ -76,8 +92,8 @@ class StatsDMetricSenderSpec extends TestKitBase with WordSpecLike with Matchers
}
"flush the packet when the max-packet-size is reached" in new UdpListenerFixture {
- val testMetricName = "test-metric"
- val testMetricKey = buildMetricKey(testMetricName)
+ val testMetricName = "processing-time"
+ val testMetricKey = buildMetricKey("actor", "/user/kamon", testMetricName)
val testRecorder = Histogram(10000L, Precision.Normal, Scale.Unit)
var bytes = testMetricKey.length
@@ -97,9 +113,9 @@ class StatsDMetricSenderSpec extends TestKitBase with WordSpecLike with Matchers
"render multiple keys in the same packet using newline as separator" in new UdpListenerFixture {
val firstTestMetricName = "first-test-metric"
- val firstTestMetricKey = buildMetricKey(firstTestMetricName)
+ val firstTestMetricKey = buildMetricKey("actor", "/user/kamon", firstTestMetricName)
val secondTestMetricName = "second-test-metric"
- val secondTestMetricKey = buildMetricKey(secondTestMetricName)
+ val secondTestMetricKey = buildMetricKey("actor", "/user/kamon", secondTestMetricName)
val firstTestRecorder = Histogram(1000L, Precision.Normal, Scale.Unit)
val secondTestRecorder = Histogram(1000L, Precision.Normal, Scale.Unit)
@@ -121,14 +137,32 @@ class StatsDMetricSenderSpec extends TestKitBase with WordSpecLike with Matchers
}
trait UdpListenerFixture {
- val localhostName = ManagementFactory.getRuntimeMXBean.getName.split('@')(1)
val testMaxPacketSize = system.settings.config.getBytes("kamon.statsd.max-packet-size")
+ val metricKeyGenerator = new SimpleMetricKeyGenerator(system.settings.config) {
+ override def normalizedLocalhostName: String = "localhost_local"
+ }
- def buildMetricKey(metricName: String): String = s"kamon.$localhostName.test-metric-category.test-group.$metricName"
+ val testGroupIdentity = new MetricGroupIdentity {
+ val name: String = "/user/kamon"
+ val category: MetricGroupCategory = new MetricGroupCategory {
+ val name: String = "actor"
+ }
+ }
+
+ def buildMetricKey(categoryName: String, entityName: String, metricName: String): String = {
+ val metricIdentity = new MetricIdentity { val name: String = metricName }
+ val groupIdentity = new MetricGroupIdentity {
+ val name: String = entityName
+ val category: MetricGroupCategory = new MetricGroupCategory {
+ val name: String = categoryName
+ }
+ }
+ metricKeyGenerator.generateKey(groupIdentity, metricIdentity)
+ }
def setup(metrics: Map[String, MetricSnapshot]): TestProbe = {
val udp = TestProbe()
- val metricsSender = system.actorOf(Props(new StatsDMetricsSender(new InetSocketAddress(localhostName, 0), testMaxPacketSize) {
+ val metricsSender = system.actorOf(Props(new StatsDMetricsSender(new InetSocketAddress("127.0.0.1", 0), testMaxPacketSize, metricKeyGenerator) {
override def udpExtension(implicit system: ActorSystem): ActorRef = udp.ref
}))
@@ -136,17 +170,9 @@ class StatsDMetricSenderSpec extends TestKitBase with WordSpecLike with Matchers
udp.expectMsgType[Udp.SimpleSender]
udp.reply(Udp.SimpleSenderReady)
- val testGroupIdentity = new MetricGroupIdentity {
- val name: String = "test-group"
- val category: MetricGroupCategory = new MetricGroupCategory {
- val name: String = "test-metric-category"
- }
- }
-
val testMetrics = for ((metricName, snapshot) ← metrics) yield {
val testMetricIdentity = new MetricIdentity {
val name: String = metricName
- val tag: String = ""
}
(testMetricIdentity, snapshot)