/* * ========================================================================================= * Copyright © 2013-2014 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.statsd.client import akka.actor.{ActorLogging, Props, ActorRef, Actor} import akka.io.{Udp, IO} import java.net.InetSocketAddress import akka.util.ByteString class StatsdMetricsSender(statPrefix:String, remote: InetSocketAddress) extends Actor with ActorLogging { import StatsdMetricsSender._ import context.system IO(Udp) ! Udp.SimpleSender def receive = { case Udp.SimpleSenderReady => context.become(ready(sender)) } def ready(send: ActorRef): Receive = { case metric: StatsdMetric => send ! Udp.Send(toByteString(statPrefix, metric), remote) case _ => log.error("Unknown Metric") } } object StatsdMetricsSender { sealed trait StatsdMetric case class Counter(key: String, value: Long = 1, suffix:String = "c", samplingRate: Double = 1.0) extends StatsdMetric case class Timing(key: String, millis: Long, suffix:String = "ms", samplingRate: Double = 1.0) extends StatsdMetric case class Gauge(key: String, value: Long, suffix:String = "g", samplingRate: Double = 1.0) extends StatsdMetric def props(statPrefix:String, remote: InetSocketAddress): Props = Props(new StatsdMetricsSender(statPrefix, remote)) def toByteString(statPrefix:String, metric:StatsdMetric) : ByteString = metric match { case Counter(key, value, suffix, samplingRate) => statFor(statPrefix, key, value, suffix, samplingRate) case Timing(key, value, suffix, samplingRate) => statFor(statPrefix, key, value, suffix, samplingRate) case Gauge(key, value, suffix, samplingRate) => statFor(statPrefix, key, value, suffix, samplingRate) } /* * Creates the stat string to send to statsd. * For counters, it provides something like {@code key:value|c}. * For timing, it provides something like {@code key:millis|ms}. * If sampling rate is less than 1, it provides something like {@code key:value|type|@rate} */ private[this] def statFor(statPrefix:String, key: String, value: Long, suffix: String, samplingRate: Double): ByteString = { samplingRate match { case x if x >= 1.0 => ByteString(s"${statPrefix}.${key}:${value}|$suffix") case _ => ByteString(s"${statPrefix}.${key}:${value}|${suffix}|@$samplingRate") } } }