packages feed

network-metrics 0.1.3 → 0.1.4

raw patch · 7 files changed

+185/−183 lines, 7 filesPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

API changes (from Hackage documentation)

- Network.Metrics: Handle :: Socket -> SockAddr -> Handle
- Network.Metrics: data Handle
- Network.Metrics.Ganglia: data Handle
- Network.Metrics.Ganglia: emit :: Metric -> Handle -> IO ()
- Network.Metrics.Ganglia: instance Data MetricType
- Network.Metrics.Ganglia: instance Default Metric
- Network.Metrics.Ganglia: instance Eq MetricType
- Network.Metrics.Ganglia: instance Show Metric
- Network.Metrics.Ganglia: instance Show MetricType
- Network.Metrics.Ganglia: instance Typeable MetricType
- Network.Metrics.Ganglia: test :: String -> String -> IO a
- Network.Metrics.Graphite: bucket :: Metric -> ByteString
- Network.Metrics.Graphite: data Handle
- Network.Metrics.Graphite: emit :: Metric -> Handle -> IO ()
- Network.Metrics.Graphite: instance Show Metric
- Network.Metrics.Graphite: value :: Metric -> ByteString
- Network.Metrics.Statsd: bucket :: Metric -> ByteString
- Network.Metrics.Statsd: data Handle
- Network.Metrics.Statsd: emit :: Metric -> Handle -> IO ()
- Network.Metrics.Statsd: instance Show Metric
- Network.Metrics.Statsd: instance Show MetricType
- Network.Metrics.Statsd: rate :: Metric -> Double
- Network.Metrics.Statsd: type' :: Metric -> MetricType
- Network.Metrics.Statsd: value :: Metric -> ByteString
+ Network.Metrics.Ganglia: Counter :: MetricType
+ Network.Metrics.Ganglia: Ganglia :: Handle -> Ganglia
+ Network.Metrics.Ganglia: GangliaMetric :: ByteString -> GangliaType -> ByteString -> ByteString -> ByteString -> ByteString -> ByteString -> Slope -> Word32 -> Word32 -> GangliaMetric
+ Network.Metrics.Ganglia: Gauge :: MetricType
+ Network.Metrics.Ganglia: Timer :: MetricType
+ Network.Metrics.Ganglia: class MetricSink a
+ Network.Metrics.Ganglia: data Ganglia
+ Network.Metrics.Ganglia: data GangliaMetric
+ Network.Metrics.Ganglia: data GangliaType
+ Network.Metrics.Ganglia: instance Data GangliaType
+ Network.Metrics.Ganglia: instance Default GangliaMetric
+ Network.Metrics.Ganglia: instance Eq GangliaType
+ Network.Metrics.Ganglia: instance MetricSink Ganglia
+ Network.Metrics.Ganglia: instance Show GangliaMetric
+ Network.Metrics.Ganglia: instance Show GangliaType
+ Network.Metrics.Ganglia: instance Typeable GangliaType
+ Network.Metrics.Ganglia: push :: MetricSink a => Metric -> a -> IO ()
+ Network.Metrics.Ganglia: putMetaData :: GangliaMetric -> Put
+ Network.Metrics.Ganglia: putValue :: GangliaMetric -> Put
+ Network.Metrics.Ganglia: type Bucket = ByteString
+ Network.Metrics.Ganglia: type Group = ByteString
+ Network.Metrics.Ganglia: type Value = ByteString
+ Network.Metrics.Graphite: Counter :: MetricType
+ Network.Metrics.Graphite: Gauge :: MetricType
+ Network.Metrics.Graphite: Timer :: MetricType
+ Network.Metrics.Graphite: class MetricSink a
+ Network.Metrics.Graphite: data MetricType
+ Network.Metrics.Graphite: instance MetricSink Graphite
+ Network.Metrics.Graphite: push :: MetricSink a => Metric -> a -> IO ()
+ Network.Metrics.Graphite: type Bucket = ByteString
+ Network.Metrics.Graphite: type Group = ByteString
+ Network.Metrics.Graphite: type Value = ByteString
+ Network.Metrics.Statsd: class MetricSink a
+ Network.Metrics.Statsd: instance MetricSink Statsd
+ Network.Metrics.Statsd: instance Show StatsdMetric
+ Network.Metrics.Statsd: push :: MetricSink a => Metric -> a -> IO ()
+ Network.Metrics.Statsd: type Bucket = ByteString
+ Network.Metrics.Statsd: type Group = ByteString
+ Network.Metrics.Statsd: type Value = ByteString
- Network.Metrics.Ganglia: Double :: MetricType
+ Network.Metrics.Ganglia: Double :: GangliaType
- Network.Metrics.Ganglia: Float :: MetricType
+ Network.Metrics.Ganglia: Float :: GangliaType
- Network.Metrics.Ganglia: Int16 :: MetricType
+ Network.Metrics.Ganglia: Int16 :: GangliaType
- Network.Metrics.Ganglia: Int32 :: MetricType
+ Network.Metrics.Ganglia: Int32 :: GangliaType
- Network.Metrics.Ganglia: Int8 :: MetricType
+ Network.Metrics.Ganglia: Int8 :: GangliaType
- Network.Metrics.Ganglia: Metric :: ByteString -> MetricType -> ByteString -> ByteString -> ByteString -> ByteString -> ByteString -> Slope -> Word32 -> Word32 -> Metric
+ Network.Metrics.Ganglia: Metric :: MetricType -> Group -> Bucket -> Value -> Metric
- Network.Metrics.Ganglia: String :: MetricType
+ Network.Metrics.Ganglia: String :: GangliaType
- Network.Metrics.Ganglia: UInt16 :: MetricType
+ Network.Metrics.Ganglia: UInt16 :: GangliaType
- Network.Metrics.Ganglia: UInt32 :: MetricType
+ Network.Metrics.Ganglia: UInt32 :: GangliaType
- Network.Metrics.Ganglia: UInt8 :: MetricType
+ Network.Metrics.Ganglia: UInt8 :: GangliaType
- Network.Metrics.Ganglia: close :: Handle -> IO ()
+ Network.Metrics.Ganglia: close :: MetricSink a => a -> IO ()
- Network.Metrics.Ganglia: defaultMetric :: Metric
+ Network.Metrics.Ganglia: defaultMetric :: GangliaMetric
- Network.Metrics.Ganglia: dmax :: Metric -> Word32
+ Network.Metrics.Ganglia: dmax :: GangliaMetric -> Word32
- Network.Metrics.Ganglia: group :: Metric -> ByteString
+ Network.Metrics.Ganglia: group :: GangliaMetric -> ByteString
- Network.Metrics.Ganglia: host :: Metric -> ByteString
+ Network.Metrics.Ganglia: host :: GangliaMetric -> ByteString
- Network.Metrics.Ganglia: name :: Metric -> ByteString
+ Network.Metrics.Ganglia: name :: GangliaMetric -> ByteString
- Network.Metrics.Ganglia: open :: String -> String -> IO Handle
+ Network.Metrics.Ganglia: open :: String -> String -> IO Ganglia
- Network.Metrics.Ganglia: slope :: Metric -> Slope
+ Network.Metrics.Ganglia: slope :: GangliaMetric -> Slope
- Network.Metrics.Ganglia: spoof :: Metric -> ByteString
+ Network.Metrics.Ganglia: spoof :: GangliaMetric -> ByteString
- Network.Metrics.Ganglia: tmax :: Metric -> Word32
+ Network.Metrics.Ganglia: tmax :: GangliaMetric -> Word32
- Network.Metrics.Ganglia: type' :: Metric -> MetricType
+ Network.Metrics.Ganglia: type' :: GangliaMetric -> GangliaType
- Network.Metrics.Ganglia: units :: Metric -> ByteString
+ Network.Metrics.Ganglia: units :: GangliaMetric -> ByteString
- Network.Metrics.Ganglia: value :: Metric -> ByteString
+ Network.Metrics.Ganglia: value :: GangliaMetric -> ByteString
- Network.Metrics.Graphite: Metric :: ByteString -> ByteString -> Metric
+ Network.Metrics.Graphite: Metric :: MetricType -> Group -> Bucket -> Value -> Metric
- Network.Metrics.Graphite: close :: Handle -> IO ()
+ Network.Metrics.Graphite: close :: MetricSink a => a -> IO ()
- Network.Metrics.Graphite: open :: String -> String -> IO Handle
+ Network.Metrics.Graphite: open :: String -> String -> IO Graphite
- Network.Metrics.Statsd: Metric :: MetricType -> ByteString -> ByteString -> Double -> Metric
+ Network.Metrics.Statsd: Metric :: MetricType -> Group -> Bucket -> Value -> Metric
- Network.Metrics.Statsd: close :: Handle -> IO ()
+ Network.Metrics.Statsd: close :: MetricSink a => a -> IO ()
- Network.Metrics.Statsd: open :: String -> String -> IO Handle
+ Network.Metrics.Statsd: open :: String -> String -> IO Statsd

Files

network-metrics.cabal view
@@ -1,5 +1,5 @@ name:               network-metrics-version:            0.1.3+version:            0.1.4 synopsis:           Send metrics to Ganglia, Graphite, and statsd. license:            OtherLicense license-file:       LICENSE@@ -32,8 +32,7 @@   location: git://github.com/brendanhay/network-metrics.git  library-  exposed-modules:  Network.Metrics-                  , Network.Metrics.Ganglia+  exposed-modules:  Network.Metrics.Ganglia                   , Network.Metrics.Graphite                   , Network.Metrics.Statsd   other-modules:    Network.Metrics.Internal
src/GMetric.hs view
@@ -14,11 +14,13 @@       main     ) where -import Control.Monad          (when)-import Data.ByteString.Char8  (pack)+import Control.Monad            (when)+import Data.Binary.Put          (runPut)+import Data.ByteString.Char8    (pack) import System.Console.CmdArgs-import System.Environment     (getArgs, withArgs)-import System.Exit            (ExitCode(..), exitWith)+import System.Environment       (getArgs, withArgs)+import System.Exit              (ExitCode(..), exitWith)+import Network.Metrics.Internal  import qualified Network.Metrics.Ganglia as G @@ -27,7 +29,7 @@     , optPort  :: String     , optName  :: String     , optValue :: String-    , optType  :: G.MetricType+    , optType  :: G.GangliaType     , optGroup :: String     , optUnits :: String     , optSlope :: G.Slope@@ -49,11 +51,13 @@  emit :: Options -> IO () emit Options{..} = do-    handle <- G.open optHost optPort-    G.emit metric handle-    G.close handle+    sink@(G.Ganglia hd) <- G.open optHost optPort+    _ <- push' G.putMetaData hd+    _ <- push' G.putValue hd+    G.close sink   where-    metric = G.Metric+    push' f = hPush . runPut $ f metric+    metric  = G.GangliaMetric         (pack optName)         optType         (pack optUnits)
− src/Network/Metrics.hs
@@ -1,18 +0,0 @@--- |--- Module      : Network.Metrics--- Copyright   : (c) 2012 Brendan Hay <brendan@soundcloud.com>--- License     : This Source Code Form is subject to the terms of---               the Mozilla Public License, v. 2.0.---               A copy of the MPL can be found in the LICENSE file or---               you can obtain it at http://mozilla.org/MPL/2.0/.--- Maintainer  : Brendan Hay <brendan@soundcloud.com>--- Stability   : experimental--- Portability : non-portable (GHC extensions)-----module Network.Metrics (-    -- * Re-exported types-      Handle(..)-    ) where--import Network.Metrics.Internal
src/Network/Metrics/Ganglia.hs view
@@ -13,53 +13,61 @@ module Network.Metrics.Ganglia (     -- * Exported types       Slope(..)-    , MetricType(..)-    , Metric(..)+    , GangliaType(..)+    , GangliaMetric(..)+    , Ganglia(..)      -- * Default constructors     , defaultMetric      -- * Socket Handle operations     , open-    , emit -    -- * Development helpers-    , test+    -- * Binary encoding+    , putMetaData+    , putValue -    -- * Re-exported from internal-    , I.Handle-    , I.close+    -- -- * Network.Metrics.Internal re-exported types+    , Group+    , Bucket+    , Value+    , MetricType(..)+    , Metric(..)+    , MetricSink(push)++    -- * Network.Metrics.Internal operations+    , close     ) where -import Control.Concurrent (threadDelay)-import Control.Monad      (unless, liftM)+import Control.Monad            (liftM) import Data.Binary.Put-import Data.Bits          ((.&.))-import Data.Char          (toLower)-import Data.Data          (Data, Typeable)-import Data.Default       (Default, def)-import Data.Int           (Int32)-import Data.Word          (Word32)-import Network.Socket-import System.Random      (randomRIO)+import Data.Bits                ((.&.))+import Data.Char                (toLower)+import Data.Data                (Data, Typeable)+import Data.Default             (Default, def)+import Data.Int                 (Int32)+import Data.Word                (Word32)+import Network.Socket           (SocketType(..))+import Network.Metrics.Internal -import qualified Data.ByteString          as B-import qualified Data.ByteString.Char8    as BS-import qualified Network.Metrics.Internal as I+import qualified Data.ByteString            as B+import qualified Data.ByteString.Char8      as BS+import qualified Data.ByteString.Lazy.Char8 as BL + -- | Allows gmetad and the PHP webfrontend to efficiently separate -- constant data metrics from volatile ones data Slope = Zero | Positive | Negative | Both | Unspecified       deriving (Data, Typeable, Show, Eq, Enum)  -- | Metric types supported by Ganglia-data MetricType = String | Int8 | UInt8 | Int16 | UInt16 | Int32 | UInt32 | Float | Double+data GangliaType = String | Int8 | UInt8 | Int16 | UInt16 | Int32 | UInt32 | Float | Double       deriving (Data, Typeable, Eq, Show) --- | Concrete metric type used to emit metadata and value packets-data Metric = Metric+-- | concrete metric type used to emit metadata and value packets+data GangliaMetric = GangliaMetric     { name  :: BS.ByteString-    , type' :: MetricType+    , type' :: GangliaType     , units :: BS.ByteString     , value :: BS.ByteString     , host  :: BS.ByteString@@ -70,20 +78,26 @@     , dmax  :: Word32     } deriving (Show) -instance Default Metric where+instance Default GangliaMetric where     def = defaultMetric +data Ganglia = Ganglia Handle++instance MetricSink Ganglia where+    push m (Ganglia h) = hPush (encode m) h+    close  (Ganglia h) = hClose h+ -- -- API --  -- | A default metric record-defaultMetric :: Metric-defaultMetric = Metric-    { name  = "magical_metric"-    , type' = UInt16+defaultMetric :: GangliaMetric+defaultMetric = GangliaMetric+    { name  = ""+    , type' = Int32     , units = ""-    , value = "0"+    , value = ""     , host  = ""     , spoof = ""     , group = ""@@ -92,41 +106,17 @@     , dmax  = 0     } --- | Create a new unconnected socket handle for UDP communication-open :: String -> String -> IO I.Handle-open = I.open Datagram---- | Emit a metric's metadata and value on the specified socket handle-emit :: Metric -> I.Handle -> IO ()-emit metric handle@(I.Handle sock addr) = do-    sIsConnected sock >>= \b -> unless b $ connect sock addr-    _ <- push putMetaData handle-    _ <- push putMetric handle-    return ()-  where-    push fn = I.emit . runPut $ fn metric------- Private------- TODO: enforce max buffer size length checks.--- Magic number is per libgmond.c-bufferSize :: Integer-bufferSize = 1500------- Binary Encoding---+open :: String -> String -> IO Ganglia+open host port = liftM Ganglia (hOpen Datagram host port)  -- | Metric metadata -- -- The format for this can be found in either: -- * gm_protocol.x in the Ganglia 3.1 sources -- * https://github.com/lookfirst/jmxtrans-putMetaData :: Metric -> Put-putMetaData metric@Metric{..} = do-    putHeader 128 metric -- 128 = metadata_msg+putMetaData :: GangliaMetric -> Put+putMetaData m@GangliaMetric{..} = do+    putHeader 128 m -- 128 = metadata_msg     putType type'     putString name     putString units@@ -136,15 +126,30 @@     putGroup group  -- | Metric value-putMetric :: Metric -> Put-putMetric metric@Metric{..} = do-    putHeader 133 metric -- 133 = string_msg+putValue :: GangliaMetric -> Put+putValue m@GangliaMetric{..} = do+    putHeader 133 m -- 133 = string_msg     putString "%s"     putString value +--+-- Private+--++-- TODO: enforce max buffer size length checks.+-- Magic number is per libgmond.c+bufferSize :: Integer+bufferSize = 1500++encode :: Metric -> BL.ByteString+encode (Metric _ g b v) = BL.concat $ map put [putMetaData, putValue]+  where+    metric = defaultMetric { name  = b, group = g, value = v }+    put f  = runPut $ f metric+ -- | Common headers for the metadata and value-putHeader :: Int32 -> Metric -> Put-putHeader code Metric{..} = do+putHeader :: Int32 -> GangliaMetric -> Put+putHeader code GangliaMetric{..} = do     putInt code     putString host     putString name@@ -178,32 +183,5 @@   where     len = BS.length bstr -putType :: MetricType -> Put+putType :: GangliaType -> Put putType = putString . BS.pack . map toLower . show------- Development------- | Exactly one second!-oneSecond :: Int-oneSecond = 1000000---- | The min, max variance of test metrics-variance :: (Int, Int)-variance = (0, 1000)---- | Sample a random element from a list-sample :: [a] -> IO a-sample xs = liftM (xs !!) (randomRIO (0, length xs - 1))---- | Used to emit a default metric via GHCi-test :: String -> String -> IO a-test host port = open host port >>= loop-  where-    loop h = do-        r <- randomRIO variance :: IO Int-        n <- sample ["magic", "candy", "unicorns"]-        emit defaultMetric { name = n, value = BS.pack $ show r } h-        threadDelay oneSecond-        loop h
src/Network/Metrics/Graphite.hs view
@@ -11,43 +11,50 @@ --  module Network.Metrics.Graphite (-    -- * Exported types-      Metric(..)-     -- * Socket Handle operations-    , open-    , emit+      open -    -- * Re-exported from internal-    , I.Handle-    , I.close+    -- * Network.Metrics.Internal re-exported types+    , Group+    , Bucket+    , Value+    , MetricType(..)+    , Metric(..)+    , MetricSink(push)++    -- * Network.Metrics.Internal operations+    , close     ) where +import Control.Monad            (liftM) import Network.Socket import Data.Time.Clock.POSIX+import Network.Metrics.Internal  import qualified Data.ByteString.Char8      as BS import qualified Data.ByteString.Lazy.Char8 as BL-import qualified Network.Metrics.Internal   as I -data Metric = Metric-    { bucket :: BS.ByteString-    , value  :: BS.ByteString-    } deriving (Show)+data Graphite = Graphite Handle +instance MetricSink Graphite where+    push m (Graphite h) = encode m >>= flip hPush h+    close  (Graphite h) = hClose h -- -- API --  -- | Create a new disconnected socket handle for TCP communication-open :: String -> String -> IO I.Handle-open = I.open Stream+open :: String -> String -> IO Graphite+open host port = liftM Graphite (hOpen Stream host port) --- | Emit a metric's metadata and value on the specified socket handle-emit :: Metric -> I.Handle -> IO ()-emit Metric{..} handle = do-    time <- getPOSIXTime-    I.emit (encoded time) handle+--+-- Private+--++encode :: Metric -> IO BL.ByteString+encode (Metric _ g b v) = liftM bstr getPOSIXTime   where-    encoded n   = BL.fromChunks [bucket, value, timestamp n]+    bucket      = BS.concat [g, ".", b]     timestamp n = BS.pack $ show (truncate n :: Integer)+    bstr n      = BL.fromChunks [bucket, v, timestamp n]+
src/Network/Metrics/Internal.hs view
@@ -13,41 +13,68 @@ module Network.Metrics.Internal (     -- * Exported types       Handle(..)+    , Group+    , Bucket+    , Value+    , MetricType(..)+    , Metric(..)+    , MetricSink(..)      -- * Socket Handle operations-    , open-    , close-    , emit+    , hOpen+    , hClose+    , hPush     ) where  import Control.Monad                  (unless) 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  -- | Socket handle data Handle = Handle Socket SockAddr deriving (Show) +-- | Metric group+type Group = BS.ByteString++-- | Metric bucket+type Bucket = BS.ByteString++-- | Metric value+type Value = BS.ByteString++-- | Metric type+data MetricType = Counter | Gauge | Timer deriving (Show)++-- | Concrete metric data type+data Metric = Metric MetricType Group Bucket Value deriving (Show)++-- | Describes a sink resource which is held open for metric emission+class MetricSink a where+    push  :: Metric -> a -> IO ()+    close :: a -> IO ()+ -- -- API --  -- | Create a new unconnected socket handle for UDP communication-open :: SocketType -> String -> String -> IO Handle-open typ host port = do+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)  -- | Close a socket handle-close :: Handle -> IO ()-close (Handle sock _) = sClose sock+hClose :: Handle -> IO ()+hClose (Handle sock _) = sClose sock --- | Push an encoded metric to the specified socket handle-emit :: BL.ByteString -> Handle -> IO ()-emit bstr (Handle sock addr) | BL.null bstr = return ()-                             | otherwise    = do+-- | Direct access for writing a bytestring to the socket handle+hPush :: BL.ByteString -> Handle -> IO ()+hPush bstr (Handle sock addr) | BL.null bstr = return ()+                              | otherwise    = do     sIsConnected sock >>= \b -> unless b $ connect sock addr     _ <- send sock bstr     return ()
src/Network/Metrics/Statsd.hs view
@@ -11,29 +11,30 @@ --  module Network.Metrics.Statsd (-    -- * Exported types-      MetricType(..)-    , Metric(..)-     -- * Socket Handle operations-    , open-    , emit+      open -    -- * Re-exported from internal-    , I.Handle-    , I.close+    -- * Network.Metrics.Internal re-exported types+    , Group+    , Bucket+    , Value+    , MetricType(..)+    , Metric(..)+    , MetricSink(push)++    -- * Network.Metrics.Internal operations+    , close     ) where -import Network.Socket-import System.Random (randomRIO)+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-import qualified Network.Metrics.Internal   as I -data MetricType = Counter | Timer | Gauge deriving (Show)--data Metric = Metric+data StatsdMetric = StatsdMetric     { type'  :: MetricType     , bucket :: BS.ByteString     , value  :: BS.ByteString@@ -42,33 +43,37 @@  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+ -- -- API --  -- | Create a new disconnected socket handle for UDP communication-open :: String -> String -> IO I.Handle-open = I.open Datagram---- | Emit a metric's metadata and value on the specified socket handle-emit :: Metric -> I.Handle -> IO ()-emit metric handle = do-    rand <- randomRIO (0.0, 1.0)-    I.emit (encoded rand) handle-  where-    encoded = BL.fromChunks . components metric . sample (rate metric)+open :: String -> String -> IO Statsd+open host port = liftM Statsd (hOpen Datagram host port)  ----- Sampling+-- Private -- +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 -components :: Metric -> Sampled -> [BS.ByteString]-components Metric{..} sampled = case sampled of+chunks :: StatsdMetric -> Sampled -> [BS.ByteString]+chunks StatsdMetric{..} sampled = case sampled of     Sampled -> base ++ ["@", BS.pack $ show rate]     Exact   -> base     Ignore  -> []