module Prometheus.Metric.Counter (
Counter
, counter
, incCounter
, addCounter
, unsafeAddCounter
, addDurationToCounter
, getCounter
) where
import Prometheus.Info
import Prometheus.Metric
import Prometheus.Metric.Observer (timeAction)
import Prometheus.MonadMonitor
import Control.Monad (unless)
import qualified Data.Atomics as Atomics
import qualified Data.ByteString.UTF8 as BS
import qualified Data.IORef as IORef
newtype Counter = MkCounter (IORef.IORef Double)
counter :: Info -> IO (Metric Counter)
counter info = do
ioref <- IORef.newIORef 0
return Metric {
handle = MkCounter ioref
, collect = collectCounter info ioref
}
withCounter :: MonadMonitor m
=> Metric Counter
-> (Double -> Double)
-> m ()
withCounter Metric {handle = MkCounter ioref} f =
doIO $ Atomics.atomicModifyIORefCAS_ ioref f
incCounter :: MonadMonitor m => Metric Counter -> m ()
incCounter c = withCounter c (+ 1)
addCounter :: MonadMonitor m => Double -> Metric Counter -> m Bool
addCounter x c
| x < 0 = return False
| otherwise = do
withCounter c add
return True
where add i = i `seq` x `seq` i + x
unsafeAddCounter :: MonadMonitor m => Double -> Metric Counter -> m ()
unsafeAddCounter x c = do
added <- addCounter x c
unless added $
error $ "Tried to add negative value to counter: " ++ show x
addDurationToCounter :: IO a -> Metric Counter -> IO a
addDurationToCounter io metric = do
(result, duration) <- timeAction io
_ <- addCounter duration metric
return result
getCounter :: Metric Counter -> IO Double
getCounter Metric {handle = MkCounter ioref} = IORef.readIORef ioref
collectCounter :: Info -> IORef.IORef Double -> IO [SampleGroup]
collectCounter info c = do
value <- IORef.readIORef c
let sample = Sample (metricName info) [] (BS.fromString $ show value)
return [SampleGroup info CounterType [sample]]