packages feed

network-metrics 0.1.7 → 0.1.9

raw patch · 8 files changed

+184/−111 lines, 8 filesPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

API changes (from Hackage documentation)

- Network.Metric.Sink.Statsd: MetricSink :: a -> MetricSink
- Network.Metric.Sink.Statsd: data MetricSink
- Network.Metric.Sink.Stdout: instance Show StdoutSink
- Network.Metric.Sink.Stdout: instance Sink StdoutSink
+ Network.Metric: AnyMeasurable :: a -> AnyMeasurable
+ Network.Metric: AnySink :: a -> AnySink
+ Network.Metric: class (Show a, Typeable a) => Encodable a
+ Network.Metric: class Measurable a
+ Network.Metric: data AnyMeasurable
+ Network.Metric: data AnySink
+ Network.Metric: encode :: Encodable a => a -> ByteString
+ Network.Metric: measure :: Measurable a => a -> [Metric]
+ Network.Metric.Sink.Statsd: AnySink :: a -> AnySink
+ Network.Metric.Sink.Statsd: data AnySink
+ Network.Metric.Sink.Stdout: instance Show Stdout
+ Network.Metric.Sink.Stdout: instance Sink Stdout
- Network.Metric: Counter :: Group -> Bucket -> Int -> Metric a
+ Network.Metric: Counter :: Group -> Bucket -> Integer -> Metric
- Network.Metric: Gauge :: Group -> Bucket -> a -> Metric a
+ Network.Metric: Gauge :: Group -> Bucket -> Double -> Metric
- Network.Metric: Timer :: Group -> Bucket -> Double -> Metric a
+ Network.Metric: Timer :: Group -> Bucket -> Double -> Metric
- Network.Metric: class Sink a where mpush s = void . mapM (push s)
+ Network.Metric: class Sink a
- Network.Metric: data Metric a
+ Network.Metric: data Metric
- Network.Metric: open :: SinkType -> String -> String -> IO MetricSink
+ Network.Metric: open :: SinkType -> Host -> HostName -> PortNumber -> IO AnySink
- Network.Metric: push :: (Sink a, Encodable b) => a -> Metric b -> IO ()
+ Network.Metric: push :: (Sink a, Measurable b) => a -> b -> IO ()
- Network.Metric.Sink.Ganglia: Counter :: Group -> Bucket -> Int -> Metric a
+ Network.Metric.Sink.Ganglia: Counter :: Group -> Bucket -> Integer -> Metric
- Network.Metric.Sink.Ganglia: Ganglia :: Handle -> Ganglia
+ Network.Metric.Sink.Ganglia: Ganglia :: Host -> Handle -> Ganglia
- Network.Metric.Sink.Ganglia: GangliaMetric :: ByteString -> GangliaType -> ByteString -> ByteString -> ByteString -> ByteString -> ByteString -> Slope -> Word32 -> Word32 -> GangliaMetric
+ Network.Metric.Sink.Ganglia: GangliaMetric :: Bucket -> GangliaType -> ByteString -> ByteString -> ByteString -> ByteString -> Group -> Slope -> Word32 -> Word32 -> GangliaMetric
- Network.Metric.Sink.Ganglia: Gauge :: Group -> Bucket -> a -> Metric a
+ Network.Metric.Sink.Ganglia: Gauge :: Group -> Bucket -> Double -> Metric
- Network.Metric.Sink.Ganglia: Timer :: Group -> Bucket -> Double -> Metric a
+ Network.Metric.Sink.Ganglia: Timer :: Group -> Bucket -> Double -> Metric
- Network.Metric.Sink.Ganglia: class Sink a where mpush s = void . mapM (push s)
+ Network.Metric.Sink.Ganglia: class Sink a
- Network.Metric.Sink.Ganglia: data Metric a
+ Network.Metric.Sink.Ganglia: data Metric
- Network.Metric.Sink.Ganglia: group :: GangliaMetric -> ByteString
+ Network.Metric.Sink.Ganglia: group :: GangliaMetric -> Group
- Network.Metric.Sink.Ganglia: name :: GangliaMetric -> ByteString
+ Network.Metric.Sink.Ganglia: name :: GangliaMetric -> Bucket
- Network.Metric.Sink.Ganglia: open :: String -> String -> IO MetricSink
+ Network.Metric.Sink.Ganglia: open :: Host -> HostName -> PortNumber -> IO AnySink
- Network.Metric.Sink.Ganglia: push :: (Sink a, Encodable b) => a -> Metric b -> IO ()
+ Network.Metric.Sink.Ganglia: push :: (Sink a, Measurable b) => a -> b -> IO ()
- Network.Metric.Sink.Graphite: Counter :: Group -> Bucket -> Int -> Metric a
+ Network.Metric.Sink.Graphite: Counter :: Group -> Bucket -> Integer -> Metric
- Network.Metric.Sink.Graphite: Gauge :: Group -> Bucket -> a -> Metric a
+ Network.Metric.Sink.Graphite: Gauge :: Group -> Bucket -> Double -> Metric
- Network.Metric.Sink.Graphite: Timer :: Group -> Bucket -> Double -> Metric a
+ Network.Metric.Sink.Graphite: Timer :: Group -> Bucket -> Double -> Metric
- Network.Metric.Sink.Graphite: class Sink a where mpush s = void . mapM (push s)
+ Network.Metric.Sink.Graphite: class Sink a
- Network.Metric.Sink.Graphite: data Metric a
+ Network.Metric.Sink.Graphite: data Metric
- Network.Metric.Sink.Graphite: open :: String -> String -> IO MetricSink
+ Network.Metric.Sink.Graphite: open :: Host -> HostName -> PortNumber -> IO AnySink
- Network.Metric.Sink.Graphite: push :: (Sink a, Encodable b) => a -> Metric b -> IO ()
+ Network.Metric.Sink.Graphite: push :: (Sink a, Measurable b) => a -> b -> IO ()
- Network.Metric.Sink.Statsd: class Sink a where mpush s = void . mapM (push s)
+ Network.Metric.Sink.Statsd: class Sink a
- Network.Metric.Sink.Statsd: open :: String -> String -> IO MetricSink
+ Network.Metric.Sink.Statsd: open :: Host -> HostName -> PortNumber -> IO AnySink
- Network.Metric.Sink.Statsd: push :: (Sink a, Encodable b) => a -> Metric b -> IO ()
+ Network.Metric.Sink.Statsd: push :: (Sink a, Measurable b) => a -> b -> IO ()
- Network.Metric.Sink.Stdout: Counter :: Group -> Bucket -> Int -> Metric a
+ Network.Metric.Sink.Stdout: Counter :: Group -> Bucket -> Integer -> Metric
- Network.Metric.Sink.Stdout: Gauge :: Group -> Bucket -> a -> Metric a
+ Network.Metric.Sink.Stdout: Gauge :: Group -> Bucket -> Double -> Metric
- Network.Metric.Sink.Stdout: Timer :: Group -> Bucket -> Double -> Metric a
+ Network.Metric.Sink.Stdout: Timer :: Group -> Bucket -> Double -> Metric
- Network.Metric.Sink.Stdout: class Sink a where mpush s = void . mapM (push s)
+ Network.Metric.Sink.Stdout: class Sink a
- Network.Metric.Sink.Stdout: data Metric a
+ Network.Metric.Sink.Stdout: data Metric
- Network.Metric.Sink.Stdout: open :: String -> String -> IO MetricSink
+ Network.Metric.Sink.Stdout: open :: Host -> HostName -> PortNumber -> IO AnySink
- Network.Metric.Sink.Stdout: push :: (Sink a, Encodable b) => a -> Metric b -> IO ()
+ Network.Metric.Sink.Stdout: push :: (Sink a, Measurable b) => a -> b -> IO ()

Files

network-metrics.cabal view
@@ -1,5 +1,5 @@ name:               network-metrics-version:            0.1.7+version:            0.1.9 synopsis:           Send metrics to Ganglia, Graphite, and statsd. license:            OtherLicense license-file:       LICENSE@@ -46,7 +46,7 @@                   , TypeSynonymInstances                   , FlexibleInstances -  ghc-options:      -Wall -O2 -rtsopts+  ghc-options:      -Wall -rtsopts   ghc-prof-options: -prof -auto-all    build-depends:    base >= 4.3 && < 5@@ -70,7 +70,7 @@                   , TypeSynonymInstances                   , FlexibleInstances -  ghc-options:      -Wall -O2 -threaded -rtsopts+  ghc-options:      -Wall -rtsopts   ghc-prof-options: -prof -auto-all -with-rtsopts=-p    build-depends:    base >= 4.3 && < 5
src/GMetric.hs view
@@ -17,13 +17,14 @@  import Control.Monad            (liftM, when) import Data.Binary.Put          (runPut)-import Data.ByteString.Char8    (pack)+import Data.Word                (Word16) import Network.Socket           (SocketType(..)) import System.Console.CmdArgs import System.Environment       (getArgs, withArgs) import System.Exit              (ExitCode(..), exitWith) import Network.Metric.Internal +import qualified Data.ByteString.Char8       as BS import qualified Network.Metric.Sink.Ganglia as G  data Options = Options@@ -52,24 +53,25 @@ --  emit :: Options -> IO ()-emit Options{..} = do-    sink@(G.Ganglia hd) <- liftM G.Ganglia (hOpen Datagram optHost optPort)-    _ <- push' G.putMetaData hd-    _ <- push' G.putValue hd-    G.close sink-  where-    push' f = flip hPush . runPut $ f metric-    metric  = G.GangliaMetric-        (pack optName)-        optType-        (pack optUnits)-        (pack optValue)-        ""-        (pack optSpoof)-        (pack optGroup)-        optSlope-        (fromInteger optTMax)-        (fromInteger optDMax)+emit Options{..} = return ()+  --   sink@(G.Ganglia hd) <- liftM G.Ganglia (hOpen Datagram optHost port)+  --   _ <- push' G.putMetaData hd+  --   _ <- push' G.putValue hd+  --   G.close sink+  -- where+  --   push' f = flip hPush . runPut $ f metric+  --   port    = PortNum (read optPort :: Word16)+  --   metric  = G.GangliaMetric+  --       (BS.pack optName)+  --       optType+  --       (BS.pack optUnits)+  --       (BS.pack optValue)+  --       ""+  --       (BS.pack optSpoof)+  --       (BS.pack optGroup)+  --       optSlope+  --       (fromInteger optTMax)+  --       (fromInteger optDMax)  -- -- Parsing
src/Network/Metric.hs view
@@ -14,14 +14,16 @@     -- * Exported Types       SinkType(..) -    -- * Sink Functions-    , open-    , Sink(push, close)-     -- * Re-exports     , Group     , Bucket     , Metric(..)+    , Measurable(..)+    , Encodable(..)+    , Sink(..)+    , AnyMeasurable(..)+    , AnySink(..)+    , open     ) where  import Data.Data               (Data, Typeable)@@ -45,7 +47,7 @@ --  -- | Open a new sink specified by SinkType-open :: SinkType -> String -> String -> IO MetricSink+open :: SinkType -> Host -> HostName -> PortNumber -> IO AnySink open Ganglia  = GangliaSink.open open Graphite = GraphiteSink.open open Statsd   = StatsdSink.open
src/Network/Metric/Internal.hs view
@@ -15,12 +15,17 @@ module Network.Metric.Internal (     -- * Exported Types       Handle(..)+    , Host     , Group     , Bucket     , Metric(..)-    , MetricSink(..) +    -- * Existential Types+    , AnyMeasurable(..)+    , AnySink(..)+     -- * Exported Type Classes+    , Measurable(..)     , Encodable(..)     , Sink(..) @@ -32,12 +37,17 @@     , hOpen     , hClose     , hPush++    -- * Re-exports+    , HostName+    , PortNumber(..)     ) where +import Control.Monad                  (liftM, unless) import Data.Typeable                  (Typeable)-import Control.Monad                  (liftM, unless, void) import Network.Socket                 hiding (send) import Network.Socket.ByteString.Lazy (send)+import Text.Printf                    (printf)  import qualified Data.ByteString.Char8      as BS import qualified Data.ByteString.Lazy.Char8 as BL@@ -45,69 +55,100 @@ -- | Socket handle data Handle = Handle Socket SockAddr deriving (Show) +-- | Metric host+type Host = BS.ByteString+ -- | Metric group type Group = BS.ByteString  -- | Metric bucket type Bucket = BS.ByteString -data Metric a =-      Counter Group Bucket Int+data Metric+    = Counter Group Bucket Integer     | Timer Group Bucket Double-    | Gauge Group Bucket a+    | Gauge Group Bucket Double       deriving (Show) --- | A Metric's value+--+-- Type Classes+--++-- | Measure a type for a collection of metrics+class Measurable a where+    -- | Convert a measurable instance from a host into a list of metrics+    measure :: a -> [Metric]++-- | Metric value to be encoded class (Show a, Typeable a) => Encodable a where     -- | Encode the value as a bytestring     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- -- | Sink resource to write metrics to class Sink a where     -- | Write a metric to the sink.-    push  :: Encodable b => a -> Metric b -> IO ()-+    push  :: Measurable b => a -> b -> IO ()     -- | Close the sink - subsequent writes will throw an error.     close :: a -> IO () -    -- | Effeciently write multiple metrics simultaneously.-    mpush :: Encodable b => a -> [Metric b] -> IO ()-    mpush s = void . mapM (push s)+--+-- Existential Types+-- --- | Existential sink type-data MetricSink = forall a. Sink a => MetricSink a+-- | Any instance of the Measurable type class+data AnyMeasurable = forall a. Measurable a => AnyMeasurable a +-- | Any instance of the Sink type class+data AnySink = forall a. Sink a => AnySink a++--+-- Instances+--++instance Measurable AnyMeasurable where+    measure (AnyMeasurable m) = measure m++instance Measurable Metric where+    measure = flip (:) [] . id++instance Encodable Int where+    encode = BS.pack . show++instance Encodable Integer where+    encode = BS.pack . show++instance Encodable Double where+    encode = BS.pack . printf "%.8f"++instance Encodable String where+    encode = BS.pack+ -- | Existential sink instance-instance Sink MetricSink where-    push  (MetricSink s) = push s-    mpush (MetricSink s) = mpush s-    close (MetricSink s) = close s+instance Sink AnySink where+    push  (AnySink s) = push s+    close (AnySink s) = close s  -- -- API -- --- | Combine a Group and Bucket into a single key-key :: Group -> Bucket -> BS.ByteString-key g b = BS.concat [g, ".", b]+-- | Combine a Host, Group and Bucket into a single key+key :: Host -> Group -> Bucket -> BS.ByteString+key h g b = BS.intercalate "." [h, g, b]  -- | Helper to curry a constructor function for a sink-fOpen :: Sink a => (Handle -> a) -> SocketType -> String -> String -> IO MetricSink-fOpen ctor typ = \host port -> liftM (MetricSink . ctor) (hOpen typ host port)+fOpen :: Sink a+      => (Handle -> a)+      -> SocketType+      -> HostName+      -> PortNumber+      -> IO AnySink+fOpen ctor typ host port = liftM (AnySink . ctor) (hOpen typ host port)  -- | Create a new socket handle (in a disconnected state) for UDP communication-hOpen :: SocketType -> String -> String -> IO Handle-hOpen typ host port = do-    (addr:_) <- getAddrInfo Nothing (Just host) (Just port)+hOpen :: SocketType -> HostName -> PortNumber -> IO Handle+hOpen typ host (PortNum port) = do+    (addr:_) <- getAddrInfo Nothing (Just host) (Just $ show port)     sock     <- socket (addrFamily addr) typ defaultProtocol     return $ Handle sock (addrAddress addr) 
src/Network/Metric/Sink/Ganglia.hs view
@@ -25,8 +25,8 @@     , putValue      -- * Sink Functions+    , Sink(..)     , open-    , Sink(push, close)      -- * Re-exports     , Group@@ -60,13 +60,13 @@  -- | Concrete metric type used to emit metadata and value packets data GangliaMetric = GangliaMetric-    { name  :: BS.ByteString+    { name  :: Bucket     , type' :: GangliaType     , units :: BS.ByteString     , value :: BS.ByteString     , host  :: BS.ByteString     , spoof :: BS.ByteString-    , group :: BS.ByteString+    , group :: Group     , slope :: Slope     , tmax  :: Word32     , dmax  :: Word32@@ -76,16 +76,16 @@     def = defaultMetric  -- | A handle to a Ganglia sink-data Ganglia = Ganglia Handle deriving (Show)+data Ganglia = Ganglia Host Handle deriving (Show)  instance Sink Ganglia where-    push  (Ganglia h) = hPush h . enc+    push (Ganglia host hd) = mapM_ (hPush hd . enc) . measure       where-        enc (Counter g b v) = put g b v Positive-        enc (Timer g b v)   = put g b v Both-        enc (Gauge g b v)   = put g b v Both+        enc (Counter g b v) = put host g b v Positive+        enc (Timer g b v)   = put host g b v Both+        enc (Gauge g b v)   = put host g b v Both -    close (Ganglia h) = hClose h+    close (Ganglia _ hd) = hClose hd  -- -- API@@ -107,8 +107,8 @@     }  -- | Open a new Ganglia sink-open :: String -> String -> IO MetricSink-open = fOpen Ganglia Datagram+open :: Host -> HostName -> PortNumber -> IO AnySink+open host = fOpen (Ganglia host) Datagram  -- | Encode a GangliaMetric's metadata into a Binary.Put monad --@@ -144,17 +144,20 @@  -- | Oh, the horror put :: Encodable a-    => Group+    => Host+    -> Group     -> Bucket     -> a     -> Slope     -> BL.ByteString-put group bucket value slope = BL.concat $ map run [putMetaData, putValue]+put host group bucket value slope =+    BL.concat $ map run [putMetaData, putValue]   where      run f  = runPut $ f metric      metric = defaultMetric          { name  = bucket          , group = group+         , host  = host          , value = encode value          , type' = determineType value          , slope = slope@@ -162,7 +165,7 @@  -- | TODO: more horror determineType :: Typeable a => a -> GangliaType-determineType t = case show $ typeOf t of+determineType value = case show $ typeOf value of     "Int16"   -> Int16     "Int"     -> Int32     "Integer" -> Int32
src/Network/Metric/Sink/Graphite.hs view
@@ -12,8 +12,8 @@  module Network.Metric.Sink.Graphite (     -- * Sink Functions-      open-    , Sink(push, close)+      Sink(..)+    , open      -- * Re-exports     , Group@@ -21,42 +21,49 @@     , Metric(..)     ) where -import Control.Monad           (liftM)+import Data.Time.Clock.POSIX   (POSIXTime, getPOSIXTime) import Network.Socket          (SocketType(..))-import Data.Time.Clock.POSIX   (getPOSIXTime) import Network.Metric.Internal  import qualified Data.ByteString.Char8      as BS import qualified Data.ByteString.Lazy.Char8 as BL  -- | A handle to a Graphite sink-data Graphite = Graphite Handle deriving (Show)+data Graphite = Graphite Host Handle deriving (Show)  instance Sink Graphite where-    push  (Graphite h) m = enc m >>= hPush h+    push (Graphite host hd) m = do+        time <- getPOSIXTime+        mapM_ (hPush hd . enc time) (measure m)       where-        enc (Counter g b v) = put g b v-        enc (Timer g b v)   = put g b v-        enc (Gauge g b v)   = put g b v+        enc t (Counter g b v) = put host g b v t+        enc t (Timer g b v)   = put host g b v t+        enc t (Gauge g b v)   = put host g b v t -    close (Graphite h) = hClose h+    close (Graphite _ hd) = hClose hd  -- -- API --  -- | Open a new Graphite sink-open :: String -> String -> IO MetricSink-open = fOpen Graphite Stream+open :: Host -> HostName -> PortNumber -> IO AnySink+open host = fOpen (Graphite host) Stream  -- -- Private --  -- | Encode a metric into the Graphite format-put :: Encodable a => Group -> Bucket -> a -> IO BL.ByteString-put group bucket value = liftM bstr getPOSIXTime+put :: Encodable a+    => Host+    -> Group+    -> Bucket+    -> a+    -> POSIXTime+    -> BL.ByteString+put host group bucket value time =+    BL.fromChunks [key host group bucket, encode value, timestamp]   where-    timestamp n = BS.pack $ show (truncate n :: Integer)-    bstr n      = BL.fromChunks [key group bucket, encode value, timestamp n]+    timestamp = BS.pack $ show (truncate time :: Integer) 
src/Network/Metric/Sink/Statsd.hs view
@@ -12,13 +12,13 @@  module Network.Metric.Sink.Statsd (     -- * Sink Functions-      open-    , Sink(push, close)+      Sink(..)+    , open      -- * Re-exports     , Group     , Bucket-    , MetricSink(..)+    , AnySink(..)     ) where  import Control.Monad            (liftM)@@ -33,24 +33,24 @@ data Sampled = Sampled | Exact | Ignore  -- | A handle to a Statsd sink-data Statsd = Statsd Handle deriving (Show)+data Statsd = Statsd Host Handle deriving (Show)  instance Sink Statsd where-    push  (Statsd h) m  = enc m >>= hPush h+    push (Statsd host hd) m = mapM enc (measure m) >>= mapM_ (hPush hd)       where-        enc (Counter g b v) = put g b v "c" 1.0-        enc (Gauge g b v)   = put g b v "g" 1.0-        enc (Timer g b v)   = put g b v "ms" 1.0+        enc (Counter g b v) = put host g b v "c" 1.0+        enc (Gauge g b v)   = put host g b v "g" 1.0+        enc (Timer g b v)   = put host g b v "ms" 1.0 -    close (Statsd h) = hClose h+    close (Statsd _ hd) = hClose hd  -- -- API --  -- | Open a new Statsd sink-open :: String -> String -> IO MetricSink-open = fOpen Statsd Datagram+open :: Host -> HostName -> PortNumber -> IO AnySink+open host = fOpen (Statsd host) Datagram  -- -- Private@@ -58,15 +58,17 @@ -- | Encode a metric into the Statsd format -- *TODO:* Currently statsd sampling is not exposed via the global metric type put :: Encodable a-    => Group+    => Host+    -> Group     -> Bucket     -> a     -> BS.ByteString     -> Double     -> IO BL.ByteString-put group bucket value typ rate = liftM bstr (randomRIO (0.0, 1.0))+put host group bucket value typ rate =+    liftM bstr (randomRIO (0.0, 1.0))   where-    base   = [key group bucket, ":", encode value, "|", typ]+    base   = [key host group bucket, ":", encode value, "|", typ]     bstr n = BL.fromChunks $ case sample rate n of         Sampled -> base ++ ["@", BS.pack $ show rate]         Exact   -> base
src/Network/Metric/Sink/Stdout.hs view
@@ -13,7 +13,7 @@ module Network.Metric.Sink.Stdout (     -- * Sink Functions       open-    , Sink(push, close)+    , Sink(..)      -- * Re-exports     , Group@@ -23,11 +23,18 @@  import Network.Metric.Internal +import qualified Data.ByteString.Char8 as BS+ -- | A handle to a stdout sink-data StdoutSink = StdoutSink deriving (Show)+data Stdout = Stdout Host deriving (Show) -instance Sink StdoutSink where-    push  _ = print+instance Sink Stdout where+    push (Stdout host) = mapM_ enc . measure+      where+        enc (Counter g b v) = put "Counter" host g b v+        enc (Timer g b v)   = put "Timer" host g b v+        enc (Gauge g b v)   = put "Gauge" host g b v+     close _ = return ()  --@@ -35,5 +42,14 @@ --  -- | Open a new Stdout sink-open :: String -> String -> IO MetricSink-open _ _ = return $ MetricSink StdoutSink+open :: Host -> HostName -> PortNumber -> IO AnySink+open host _ _ = return . AnySink $ Stdout host++--+-- Private+--++put :: Encodable a => BS.ByteString -> Host -> Group -> Bucket -> a -> IO ()+put prefix host group bucket value = putStrLn s+  where+    s = BS.unpack $ BS.concat [prefix, ": ", key host group bucket, " ", encode value]