{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE DeriveGeneric #-}
module Raft.Metrics
( RaftNodeMetrics(..)
, defaultRaftNodeMetrics
, getMetricsStore
, getRaftNodeMetrics
, setNodeStateLabel
, setLastLogEntryIndexGauge
, setLastLogEntryHashLabel
, setCommitIndexGauge
, incrInvalidCmdCounter
, incrEventsHandledCounter
) where
import Protolude
import qualified Control.Monad.Metrics as Metrics
import qualified Control.Monad.Metrics.Internal as Metrics
import qualified Data.HashMap.Strict as HashMap
import Data.Serialize (Serialize)
import qualified System.Metrics as EKG
import Raft.Log (LastLogEntry, EntryHash(..), hashLastLogEntry, genesisHash)
import Raft.Types (Index, Mode(..))
data RaftNodeMetrics
= RaftNodeMetrics
{ invalidCmdCounter :: Int64
, eventsHandledCounter :: Int64
, nodeStateLabel :: [Char]
, lastLogHashLabel :: [Char]
, lastLogIndexGauge :: Int64
, commitIndexGauge :: Int64
} deriving (Show, Generic, Serialize)
defaultRaftNodeMetrics :: RaftNodeMetrics
defaultRaftNodeMetrics = RaftNodeMetrics
{ invalidCmdCounter = 0
, eventsHandledCounter = 0
, nodeStateLabel = "Follower"
, lastLogHashLabel = toS (unEntryHash genesisHash)
, lastLogIndexGauge = 0
, commitIndexGauge = 0
}
getMetricsStore :: (MonadIO m, Metrics.MonadMetrics m) => m EKG.Store
getMetricsStore = Metrics._metricsStore <$> Metrics.getMetrics
getRaftNodeMetrics :: (MonadIO m, Metrics.MonadMetrics m) => m RaftNodeMetrics
getRaftNodeMetrics = do
metricsStore <- getMetricsStore
sample <- liftIO (EKG.sampleAll metricsStore)
pure RaftNodeMetrics
{ invalidCmdCounter = lookupCounterValue InvalidCmdCounter sample
, eventsHandledCounter = lookupCounterValue EventsHandledCounter sample
, nodeStateLabel = toS (lookupLabelValue NodeStateLabel sample)
, lastLogHashLabel = toS (lookupLastLogEntryHashLabel sample)
, lastLogIndexGauge = lookupGaugeValue LastLogEntryIndexGauge sample
, commitIndexGauge = lookupGaugeValue CommitIndexGauge sample
}
data RaftNodeLabel
= NodeStateLabel
| LastLogEntryHashLabel
deriving Show
lookupLabelValue :: RaftNodeLabel -> EKG.Sample -> Text
lookupLabelValue label sample =
case HashMap.lookup (show label) sample of
Just (EKG.Label text) -> text
Nothing -> ""
Just _ -> ""
setRaftNodeLabel :: (MonadIO m, Metrics.MonadMetrics m) => RaftNodeLabel -> Text -> m ()
setRaftNodeLabel label = Metrics.label (show label)
setNodeStateLabel :: (MonadIO m, Metrics.MonadMetrics m) => Mode -> m ()
setNodeStateLabel = setRaftNodeLabel NodeStateLabel . show
setLastLogEntryHashLabel
:: (MonadIO m, Metrics.MonadMetrics m, Serialize v)
=> LastLogEntry v
-> m ()
setLastLogEntryHashLabel = setRaftNodeLabel LastLogEntryHashLabel . toS . unEntryHash . hashLastLogEntry
lookupLastLogEntryHashLabel :: EKG.Sample -> Text
lookupLastLogEntryHashLabel sample =
case HashMap.lookup (show LastLogEntryHashLabel) sample of
Just (EKG.Label hashAsText) -> hashAsText
_ -> toS . unEntryHash $ genesisHash
data RaftNodeGauge
= LastLogEntryIndexGauge
| CommitIndexGauge
deriving Show
lookupGaugeValue :: RaftNodeGauge -> EKG.Sample -> Int64
lookupGaugeValue gauge sample =
case HashMap.lookup (show gauge) sample of
Nothing -> 0
Just (EKG.Gauge n) -> n
Just _ -> 0
setRaftNodeGauge :: (MonadIO m, Metrics.MonadMetrics m) => RaftNodeGauge -> Int -> m ()
setRaftNodeGauge gauge n = Metrics.gauge (show gauge) n
setLastLogEntryIndexGauge :: (MonadIO m, Metrics.MonadMetrics m) => Index -> m ()
setLastLogEntryIndexGauge = setRaftNodeGauge LastLogEntryIndexGauge . fromIntegral
setCommitIndexGauge :: (MonadIO m, Metrics.MonadMetrics m) => Index -> m ()
setCommitIndexGauge = setRaftNodeGauge CommitIndexGauge . fromIntegral
data RaftNodeCounter
= InvalidCmdCounter
| EventsHandledCounter
deriving Show
lookupCounterValue :: RaftNodeCounter -> EKG.Sample -> Int64
lookupCounterValue counter sample =
case HashMap.lookup (show counter) sample of
Nothing -> 0
Just (EKG.Counter n) -> n
Just _ -> 0
incrRaftNodeCounter :: (MonadIO m, Metrics.MonadMetrics m) => RaftNodeCounter -> m ()
incrRaftNodeCounter = Metrics.increment . show
incrInvalidCmdCounter :: (MonadIO m, Metrics.MonadMetrics m) => m ()
incrInvalidCmdCounter = incrRaftNodeCounter InvalidCmdCounter
incrEventsHandledCounter :: (MonadIO m, Metrics.MonadMetrics m) => m ()
incrEventsHandledCounter = incrRaftNodeCounter EventsHandledCounter