module Network.Metric.Internal (
Handle(..)
, Group
, Bucket
, Metric(..)
, MetricSink(..)
, Encodable(..)
, Sink(..)
, key
, fOpen
, hOpen
, hClose
, hPush
) where
import Data.Typeable (Typeable)
import Control.Monad (liftM, unless, void)
import Network.Socket hiding (send)
import Network.Socket.ByteString.Lazy (send)
import qualified Data.ByteString.Char8 as BS
import qualified Data.ByteString.Lazy.Char8 as BL
data Handle = Handle Socket SockAddr deriving (Show)
type Group = BS.ByteString
type Bucket = BS.ByteString
data Metric a =
Counter Group Bucket Int
| Timer Group Bucket Double
| Gauge Group Bucket a
deriving (Show)
class (Show a, Typeable a) => Encodable a where
encode :: a -> BS.ByteString
instance Encodable Int where
encode = BS.pack . show
instance Encodable Double where
encode = BS.pack . show
instance Encodable String where
encode = BS.pack
class Sink a where
push :: Encodable b => a -> Metric b -> IO ()
close :: a -> IO ()
mpush :: Encodable b => a -> [Metric b] -> IO ()
mpush s = void . mapM (push s)
data MetricSink = forall a. Sink a => MetricSink a
instance Sink MetricSink where
push (MetricSink s) = push s
mpush (MetricSink s) = mpush s
close (MetricSink s) = close s
key :: Group -> Bucket -> BS.ByteString
key g b = BS.concat [g, ".", b]
fOpen :: Sink a => (Handle -> a) -> SocketType -> String -> String -> IO MetricSink
fOpen ctor typ = \host port -> liftM (MetricSink . ctor) (hOpen typ host port)
hOpen :: SocketType -> String -> String -> IO Handle
hOpen typ host port = do
(addr:_) <- getAddrInfo Nothing (Just host) (Just port)
sock <- socket (addrFamily addr) typ defaultProtocol
return $ Handle sock (addrAddress addr)
hClose :: Handle -> IO ()
hClose (Handle sock _) = sClose sock
hPush :: Handle -> BL.ByteString -> IO ()
hPush (Handle sock addr) bstr | BL.null bstr = return ()
| otherwise = do
sIsConnected sock >>= \b -> unless b $ connect sock addr
_ <- send sock bstr
return ()