module Network.Metrics.Statsd (
open
, Group
, Bucket
, Value
, MetricType(..)
, Metric(..)
, MetricSink(push)
, close
) where
import Control.Monad (liftM)
import Network.Socket (SocketType(..))
import System.Random (randomRIO)
import Network.Metrics.Internal
import qualified Data.ByteString.Char8 as BS
import qualified Data.ByteString.Lazy.Char8 as BL
data StatsdMetric = StatsdMetric
{ type' :: MetricType
, bucket :: BS.ByteString
, value :: BS.ByteString
, rate :: Double
} deriving (Show)
data Sampled = Sampled | Exact | Ignore
data Statsd = Statsd Handle
instance MetricSink Statsd where
push m (Statsd h) = encode m >>= flip hPush h
close (Statsd h) = hClose h
open :: String -> String -> IO Statsd
open host port = liftM Statsd (hOpen Datagram host port)
encode :: Metric -> IO BL.ByteString
encode (Metric t g b v) = liftM bstr (randomRIO (0.0, 1.0))
where
metric = StatsdMetric t (BS.concat [g, ".", b]) v 1.0
bstr = BL.fromChunks . chunks metric . sample (rate metric)
sample :: Double -> Double -> Sampled
sample rate rand | rate < 1.0 && rand <= rate = Sampled
| rate == 1.0 = Exact
| otherwise = Ignore
chunks :: StatsdMetric -> Sampled -> [BS.ByteString]
chunks StatsdMetric{..} sampled = case sampled of
Sampled -> base ++ ["@", BS.pack $ show rate]
Exact -> base
Ignore -> []
where
base = [bucket, ":", value, "|", suffix type']
suffix :: MetricType -> BS.ByteString
suffix typ = case typ of
Counter -> "c"
Gauge -> "g"
Timer -> "ms"