hstatsd-0.1/0000755000000000000000000000000012111726756011222 5ustar0000000000000000hstatsd-0.1/hstatsd.cabal0000644000000000000000000000136712111726756013667 0ustar0000000000000000name: hstatsd version: 0.1 stability: quick-hack cabal-version: >= 1.2 build-type: Simple author: James Cook maintainer: James Cook license: PublicDomain homepage: https://github.com/mokus0/hstatsd category: System synopsis: Quick and dirty statsd interface description: Quick and dirty statsd interface Library hs-source-dirs: src exposed-modules: Network.StatsD build-depends: base >= 3 && < 5, bytestring, mtl, network, text hstatsd-0.1/Setup.lhs0000644000000000000000000000011612111726756013030 0ustar0000000000000000#!/usr/bin/env runhaskell > import Distribution.Simple > main = defaultMain hstatsd-0.1/src/0000755000000000000000000000000012111726756012011 5ustar0000000000000000hstatsd-0.1/src/Network/0000755000000000000000000000000012111726756013442 5ustar0000000000000000hstatsd-0.1/src/Network/StatsD.hs0000644000000000000000000000403312111726756015200 0ustar0000000000000000{-# LANGUAGE RecordWildCards #-} module Network.StatsD ( StatsD , mkStatsD, openStatsD, closeStatsD , Stat(..), stat , push, showStat ) where import Control.Monad.Writer import qualified Data.ByteString as BS import Data.List import qualified Data.Text.Lazy as T import qualified Data.Text.Lazy.Encoding as T import Network.Socket import qualified Network.Socket.ByteString as BS import qualified Network.Socket.ByteString.Lazy as BL data StatsD = StatsD { connection :: !Socket , prefix :: !T.Text } deriving (Eq, Show) mkStatsD :: Socket -> [String] -> StatsD mkStatsD s prefix = StatsD { connection = s , prefix = T.pack . concat . concat $ [[part, "."] | part <- prefix] } openStatsD host port prefix = do let hints = defaultHints { addrFamily = AF_INET , addrSocketType = Datagram } s <- socket AF_INET Datagram defaultProtocol addrInfos <- getAddrInfo (Just hints) (Just host) (Just port) case addrInfos of [] -> fail "Could not resolve host and/or port" addrInfo : _ -> connect s (addrAddress addrInfo) return (mkStatsD s prefix) data Stat = Stat { bucket :: !T.Text , val :: !T.Text , unit :: !T.Text , sample :: !(Maybe Double) } deriving (Eq, Show) stat :: (Num a, Show a) => [String] -> a -> String -> Maybe Double -> Stat stat b v u = Stat (T.pack (intercalate "." b)) (T.pack (show v)) (T.pack u) showStat = T.unpack . fmt T.empty fmt prefix Stat{..} = T.concat $ execWriter $ do let colon = T.singleton ':' bar = T.singleton '|' bar_at = T.pack "|@" tell [prefix, bucket, colon, val, bar, unit] case sample of Nothing -> return () Just sample -> tell [bar_at, T.pack (show sample)] segment = id -- TODO: chunk things to fit within MTU fmtMany prefix = map (T.encodeUtf8 . fmt prefix) push statsd = mapM_ (BL.sendAll (connection statsd)) . segment . fmtMany (prefix statsd) closeStatsD = sClose . connection