packages feed

hs-hath-1.1.1: src/Metrics/Registry.hs

module Metrics.Registry
  ( newRegistry
  , registerCounter
  , registerGauge
  , registerCounterWith
  , registerGaugeWith
  ) where

import           Metrics.Types

import           Relude

-- | Create a new empty registry
newRegistry :: IO Registry
newRegistry = do
  counters <- newIORef []
  gauges <- newIORef []
  cachedSnapshot <- newTVarIO ""
  pure $ Registry counters gauges cachedSnapshot

-- | Register a counter without labels
registerCounter :: Text -> Text -> Registry -> IO Counter
registerCounter name help = registerCounterWith name help mempty

-- | Register a counter with labels
registerCounterWith :: Text -> Text -> Labels -> Registry -> IO Counter
registerCounterWith name help labels reg = do
  ref <- newIORef 0
  let metricId = MetricId name labels
      counter  = Counter metricId help ref
  -- Atomically prepend to counter list
  atomicModifyIORef' (registryCounters reg) $ \cs -> ( counter : cs, () )
  pure counter

-- | Register a gauge without labels
registerGauge :: Text -> Text -> Registry -> IO Gauge
registerGauge name help = registerGaugeWith name help mempty

-- | Register a gauge with labels
registerGaugeWith :: Text -> Text -> Labels -> Registry -> IO Gauge
registerGaugeWith name help labels reg = do
  ref <- newIORef 0
  let metricId = MetricId name labels
      gauge    = Gauge metricId help ref
  -- Atomically prepend to gauge list
  atomicModifyIORef' (registryGauges reg) $ \gs -> ( gauge : gs, () )
  pure gauge

-- Note: Registration is typically done at startup, so performance is not critical.
-- Using atomicModifyIORef' ensures thread-safety if multiple threads register metrics.
--
-- Label usage example (for future):
--   errorCounter <- registerCounterWith
--     "hath_errors_total"
--     "Total errors by type"
--     (Map.fromList [("type", "network")])
--     registry
--
-- This creates a counter with fixed labels at registration time.