packages feed

ridley-0.4.0.0: src/System/Metrics/Prometheus/Ridley/Metrics/VirtualMemory.hs

{-# LANGUAGE CPP #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE TypeApplications #-}
module System.Metrics.Prometheus.Ridley.Metrics.VirtualMemory where

import           Control.Monad.Reader (ask, lift)
import           Data.Maybe (mapMaybe)
import           Data.Word
import           Lens.Micro
import           Shelly
import           System.Metrics.Prometheus.Ridley.Types
import           System.Remote.Monitoring.Prometheus (labels)
import           Text.Read (readMaybe)
import qualified Data.Text as T
import qualified System.Metrics.Prometheus.Metric.Gauge as P
import qualified System.Metrics.Prometheus.RegistryT as P

{- Calling 'vmstat' will report

[centos@atlas-eu ~]$ vmstat -S M -s
    130701440 M total memory
     52971728 M used memory
     92670416 M active memory
     33348008 M inactive memory
       852768 M free memory
            0 M buffer memory
     76876944 M swap cache
            0 M total swap
            0 M used swap
            0 M free swap
    ...
-}

--------------------------------------------------------------------------------
getVmStats :: IO VmStatReport
getVmStats = do
  rawOutput <- shelly $ silently $ escaping False $
    mapMaybe (readMaybe @Word64 . T.unpack) . T.words . T.strip
      <$> run "vmstat" ["-S", "M", "-s" ,"|" , "head", "-n", "10" , "|" , "awk", "-F", "\" \"" , "'{print $1}'" ]
  case rawOutput of
    [   vmstat_total_memory_mb
      , vmstat_used_memory_mb
      , vmstat_active_memory_mb
      , vmstat_inactive_memory_mb
      , vmstat_free_memory_mb
      , vmstat_buffer_memory_mb
      , vmstat_swap_cache_mb
      , vmstat_total_swap_mb
      , vmstat_used_swap_mb
      , vmstat_free_swap_mb
      ] -> pure $ VmStatReport{..}
    _ -> pure emptyVmStatReport

--------------------------------------------------------------------------------
updateVmStat :: VmStatGauges -> Bool -> IO ()
updateVmStat VmStatGauges{..} _ = do
#ifdef darwin_HOST_OS
  let VmStatReport{..} = emptyVmStatReport-- "vmstat" is not available on Darwin.
#else
  VmStatReport{..} <- getVmStats
#endif
  P.set (realToFrac vmstat_total_memory_mb    ) vmstat_total_memory_mb_g
  P.set (realToFrac vmstat_used_memory_mb     ) vmstat_used_memory_mb_g
  P.set (realToFrac vmstat_active_memory_mb   ) vmstat_active_memory_mb_g
  P.set (realToFrac vmstat_inactive_memory_mb ) vmstat_inactive_memory_mb_g
  P.set (realToFrac vmstat_free_memory_mb     ) vmstat_free_memory_mb_g
  P.set (realToFrac vmstat_buffer_memory_mb   ) vmstat_buffer_memory_mb_g
  P.set (realToFrac vmstat_swap_cache_mb      ) vmstat_swap_cache_mb_g
  P.set (realToFrac vmstat_total_swap_mb      ) vmstat_total_swap_mb_g
  P.set (realToFrac vmstat_used_swap_mb       ) vmstat_used_swap_mb_g
  P.set (realToFrac vmstat_free_swap_mb       ) vmstat_free_swap_mb_g

data VmStatReport =
  VmStatReport {
    vmstat_total_memory_mb    :: !Word64
  , vmstat_used_memory_mb     :: !Word64
  , vmstat_active_memory_mb   :: !Word64
  , vmstat_inactive_memory_mb :: !Word64
  , vmstat_free_memory_mb     :: !Word64
  , vmstat_buffer_memory_mb   :: !Word64
  , vmstat_swap_cache_mb      :: !Word64
  , vmstat_total_swap_mb      :: !Word64
  , vmstat_used_swap_mb       :: !Word64
  , vmstat_free_swap_mb       :: !Word64
  } deriving (Show, Eq)

emptyVmStatReport :: VmStatReport
emptyVmStatReport = VmStatReport
  { vmstat_total_memory_mb    = 0
  , vmstat_used_memory_mb     = 0
  , vmstat_active_memory_mb   = 0
  , vmstat_inactive_memory_mb = 0
  , vmstat_free_memory_mb     = 0
  , vmstat_buffer_memory_mb   = 0
  , vmstat_swap_cache_mb      = 0
  , vmstat_total_swap_mb      = 0
  , vmstat_used_swap_mb       = 0
  , vmstat_free_swap_mb       = 0
  }


data VmStatGauges =
  VmStatGauges {
    vmstat_total_memory_mb_g    :: !P.Gauge
  , vmstat_used_memory_mb_g     :: !P.Gauge
  , vmstat_active_memory_mb_g   :: !P.Gauge
  , vmstat_inactive_memory_mb_g :: !P.Gauge
  , vmstat_free_memory_mb_g     :: !P.Gauge
  , vmstat_buffer_memory_mb_g   :: !P.Gauge
  , vmstat_swap_cache_mb_g      :: !P.Gauge
  , vmstat_total_swap_mb_g      :: !P.Gauge
  , vmstat_used_swap_mb_g       :: !P.Gauge
  , vmstat_free_swap_mb_g       :: !P.Gauge
  }

--------------------------------------------------------------------------------
-- | Returns the virtual memory total and free as sampled from 'vmstat'.
systemVirtualMemory :: Ridley RidleyMetricHandler
systemVirtualMemory = do
  opts <- ask
  let popts = opts ^. prometheusOptions
  gauges <- lift $ VmStatGauges <$> P.registerGauge "vmstat_total_memory_mb" (popts ^. labels)
                                <*> P.registerGauge "vmstat_used_memory_mb" (popts ^. labels)
                                <*> P.registerGauge "vmstat_active_memory_mb" (popts ^. labels)
                                <*> P.registerGauge "vmstat_inactive_memory_mb" (popts ^. labels)
                                <*> P.registerGauge "vmstat_free_memory_mb" (popts ^. labels)
                                <*> P.registerGauge "vmstat_buffer_memory_mb" (popts ^. labels)
                                <*> P.registerGauge "vmstat_swap_cache_mb" (popts ^. labels)
                                <*> P.registerGauge "vmstat_total_swap_mb" (popts ^. labels)
                                <*> P.registerGauge "vmstat_used_swap_mb" (popts ^. labels)
                                <*> P.registerGauge "vmstat_free_swap_mb" (popts ^. labels)
  return $ mkRidleyMetricHandler "ridley-virtual-memory-statistics" gauges updateVmStat False