statsd-rupp-0.4.0.1: src/System/Metrics/StatsD.hs
{-# LANGUAGE DuplicateRecordFields #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE ImportQualifiedPost #-}
{-# LANGUAGE OverloadedRecordDot #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE NoFieldSelectors #-}
module System.Metrics.StatsD
( StatCounter,
StatGauge,
StatTiming,
StatSet,
Stats,
StatConfig (..),
newStatCounter,
newStatGauge,
newStatTiming,
newStatSet,
incrementCounter,
setGauge,
incrementGauge,
decrementGauge,
addTiming,
newSetElement,
withStats,
defStatConfig,
)
where
import Control.Monad (when)
import Data.ByteString.Char8 qualified as C
import Data.HashSet qualified as HashSet
import System.Metrics.StatsD.Internal
( MetricData (..),
StatConfig (..),
StatCounter (..),
StatGauge (..),
StatSet (..),
StatTiming (..),
Stats,
Value (..),
connectStatsD,
newMetric,
newMetrics,
newStats,
processSample,
statsLoop,
)
import UnliftIO (MonadIO, MonadUnliftIO, throwIO)
import UnliftIO.Async (link, withAsync)
type Key = String
defStatConfig :: StatConfig
defStatConfig =
StatConfig
{ reportStats = True,
reportSamples = True,
namespace = "",
prefixStats = "stats",
prefixCounter = "counters",
prefixTimer = "timers",
prefixGauge = "gauges",
prefixSet = "sets",
statsdServer = "127.0.0.1",
statsdPort = 8125,
flushInterval = 1000,
timingPercentiles = [90, 95],
appendNewline = False
}
newStatCounter ::
(MonadIO m) => Stats -> Key -> Int -> m StatCounter
newStatCounter stats key sampling = do
when (sampling < 0) $
throwIO $
userError "Counter sampling rate should not be negative"
newMetric stats (C.pack key) (CounterData 0)
return $ StatCounter stats (C.pack key) sampling
newStatGauge ::
(MonadIO m) => Stats -> Key -> Int -> m StatGauge
newStatGauge stats key ini = do
newMetric stats (C.pack key) (GaugeData ini)
return $ StatGauge stats (C.pack key)
newStatTiming :: (MonadIO m) => Stats -> Key -> Int -> m StatTiming
newStatTiming stats key sampling = do
when (sampling < 0) $
throwIO $
userError "Timing sampling rate should not be negative"
newMetric stats (C.pack key) (TimingData [])
return $ StatTiming stats (C.pack key) sampling
newStatSet :: (MonadIO m) => Stats -> Key -> m StatSet
newStatSet stats key = do
newMetric stats (C.pack key) (SetData HashSet.empty)
return $ StatSet stats (C.pack key)
incrementCounter :: (MonadIO m) => StatCounter -> Int -> m ()
incrementCounter StatCounter {..} =
processSample stats sampling key . Counter
setGauge :: (MonadIO m) => StatGauge -> Int -> m ()
setGauge StatGauge {..} i =
processSample stats 1 key (Gauge i False)
incrementGauge :: (MonadIO m) => StatGauge -> Int -> m ()
incrementGauge StatGauge {..} i =
processSample stats 1 key (Gauge i True)
decrementGauge :: (MonadIO m) => StatGauge -> Int -> m ()
decrementGauge x i = incrementGauge x (negate i)
addTiming :: (MonadIO m) => StatTiming -> Int -> m ()
addTiming StatTiming {..} =
processSample stats sampling key . Timing
newSetElement :: (MonadIO m) => StatSet -> String -> m ()
newSetElement StatSet {..} =
processSample stats 1 key . Set . C.pack
withStats :: (MonadUnliftIO m) => StatConfig -> (Stats -> m a) -> m a
withStats cfg go = do
metrics <- newMetrics
socket <- connectStatsD cfg.statsdServer cfg.statsdPort
let stats = newStats cfg metrics socket
if cfg.reportStats
then withAsync (statsLoop stats) (\a -> link a >> go stats)
else go stats