aboutsummaryrefslogtreecommitdiff
path: root/kamon-statsd
diff options
context:
space:
mode:
authorIvan Topolnjak <ivantopo@gmail.com>2014-04-28 23:15:34 -0300
committerIvan Topolnjak <ivantopo@gmail.com>2014-04-28 23:15:34 -0300
commit0952d2b6f4e571d2c949966131d857083bcdb5bd (patch)
tree6f023d3b412e2eb0b301ef84b25dd1f7159643da /kamon-statsd
parentc1dfdcbb2792304d18ad012ad2edf69388e106ff (diff)
downloadKamon-0952d2b6f4e571d2c949966131d857083bcdb5bd.tar.gz
Kamon-0952d2b6f4e571d2c949966131d857083bcdb5bd.tar.bz2
Kamon-0952d2b6f4e571d2c949966131d857083bcdb5bd.zip
= statsd: improve metrics sender performance
By building the metrics data in a simple StringBuilder instead of a ByteStringBuilder the processing time for the metrics sender was reduced by ~60% in a test application, from ~2.8ms to ~1.2ms.
Diffstat (limited to 'kamon-statsd')
-rw-r--r--kamon-statsd/src/main/scala/kamon/statsd/StatsDMetricsSender.scala50
1 files changed, 26 insertions, 24 deletions
diff --git a/kamon-statsd/src/main/scala/kamon/statsd/StatsDMetricsSender.scala b/kamon-statsd/src/main/scala/kamon/statsd/StatsDMetricsSender.scala
index e0526f8e..a3ad226a 100644
--- a/kamon-statsd/src/main/scala/kamon/statsd/StatsDMetricsSender.scala
+++ b/kamon-statsd/src/main/scala/kamon/statsd/StatsDMetricsSender.scala
@@ -51,7 +51,7 @@ class StatsDMetricsSender(remote: InetSocketAddress, maxPacketSizeInBytes: Long)
(metricIdentity, metricSnapshot) ← groupSnapshot.metrics
) {
- val key = ByteString(metricKeyGenerator.generateKey(groupIdentity, metricIdentity))
+ val key = metricKeyGenerator.generateKey(groupIdentity, metricIdentity)
for (measurement ← metricSnapshot.measurements) {
val measurementData = encodeMeasurement(measurement, metricSnapshot.instrumentType)
@@ -62,14 +62,14 @@ class StatsDMetricsSender(remote: InetSocketAddress, maxPacketSizeInBytes: Long)
dataBuilder.flush()
}
- def encodeMeasurement(measurement: Measurement, instrumentType: InstrumentType): ByteString = {
- def statsDMetricFormat(value: String, metricType: String, samplingRate: Double = 1D): ByteString =
- ByteString(value + "|" + metricType + (if (samplingRate != 1D) "|@" + samplingRateFormat.format(samplingRate) else ""))
+ def encodeMeasurement(measurement: Measurement, instrumentType: InstrumentType): String = {
+ def statsDMetricFormat(value: String, metricType: String, samplingRate: Double = 1D): String =
+ value + "|" + metricType + (if (samplingRate != 1D) "|@" + samplingRateFormat.format(samplingRate) else "")
instrumentType match {
case Histogram ⇒ statsDMetricFormat(measurement.value.toString, "ms", (1D / measurement.count))
case Gauge ⇒ statsDMetricFormat(measurement.value.toString, "g")
- case Counter ⇒ ByteString.empty // TODO: Need to decide how to report counters, when we have them!
+ case Counter ⇒ "" // TODO: Need to decide how to report counters, when we have them!
}
}
}
@@ -83,40 +83,42 @@ trait UdpExtensionProvider {
}
class MetricDataPacketBuilder(maxPacketSizeInBytes: Long, udpSender: ActorRef, remote: InetSocketAddress) {
- val metricSeparator = ByteString("\n")
- val measurementSeparator = ByteString(":")
+ val metricSeparator = "\n"
+ val measurementSeparator = ":"
- var lastKey = ByteString.empty
- var buffer = ByteString.empty
+ var lastKey = ""
+ var buffer = new StringBuilder()
- def appendMeasurement(key: ByteString, measurementData: ByteString): Unit = {
+ def appendMeasurement(key: String, measurementData: String): Unit = {
if (key == lastKey) {
- val dataWithoutKey = measurementSeparator ++ measurementData
+ val dataWithoutKey = measurementSeparator + measurementData
if (fitsOnBuffer(dataWithoutKey))
- buffer = buffer ++ dataWithoutKey
+ buffer.append(dataWithoutKey)
else {
- flushToUDP(buffer)
- buffer = key ++ dataWithoutKey
+ flushToUDP(buffer.toString())
+ buffer.clear()
+ buffer.append(key).append(dataWithoutKey)
}
} else {
lastKey = key
- val dataWithoutSeparator = key ++ measurementSeparator ++ measurementData
- if (fitsOnBuffer(metricSeparator ++ dataWithoutSeparator)) {
- val mSeparator = if (buffer.length > 0) metricSeparator else ByteString.empty
- buffer = buffer ++ mSeparator ++ dataWithoutSeparator
+ val dataWithoutSeparator = key + measurementSeparator + measurementData
+ if (fitsOnBuffer(metricSeparator + dataWithoutSeparator)) {
+ val mSeparator = if (buffer.length > 0) metricSeparator else ""
+ buffer.append(mSeparator).append(dataWithoutSeparator)
} else {
- flushToUDP(buffer)
- buffer = dataWithoutSeparator
+ flushToUDP(buffer.toString())
+ buffer.clear()
+ buffer.append(dataWithoutSeparator)
}
}
}
- def fitsOnBuffer(bs: ByteString): Boolean = (buffer.length + bs.length) <= maxPacketSizeInBytes
+ def fitsOnBuffer(data: String): Boolean = (buffer.length + data.length) <= maxPacketSizeInBytes
- private def flushToUDP(bytes: ByteString): Unit = udpSender ! Udp.Send(bytes, remote)
+ private def flushToUDP(data: String): Unit = udpSender ! Udp.Send(ByteString(data), remote)
def flush(): Unit = {
- flushToUDP(buffer)
- buffer = ByteString.empty
+ flushToUDP(buffer.toString)
+ buffer.clear()
}
} \ No newline at end of file